Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -1514,8 +1514,8 @@ If an HTTP status code of 200 is returned, the body of the response will contain
"global_quotas": [
{
"group": "string",
"limit": 0,
"over": 0,
"maximum_bytes": 0,
"over_bytes": 0,
"modified_at": "string"
},

Expand All @@ -1525,8 +1525,8 @@ If an HTTP status code of 200 is returned, the body of the response will contain
{
"group": "string",
"resource": "string",
"limit": 0,
"over": 0,
"maximum_bytes": 0,
"over_bytes": 0,
"modified_at": "string"
},

Expand Down Expand Up @@ -1554,12 +1554,12 @@ curl http://localhost:<port>/irods-http-api/<version>/physical-quotas \
--data-urlencode 'op=set_group_quota' \
--data-urlencode 'group=<string>' \ # The group to which the new quota applies.
--data-urlencode 'resource=<string>' \ # The resource to which the new quota applies. Optional.
--data-urlencode 'quota=<integer>' # The number of bytes which will serve as the quota limit.
--data-urlencode 'maximum-bytes=<integer>' # The total number of bytes that can be stored by a group.
```

If a target resource is not provided via the `resource` parameter, the quota will be treated as a global quota. Writing data to one or more resources will count towards the group quota.

To remove a quota, set the quota limit to 0 (i.e. `quota=0`).
To remove a quota, set `maximum-bytes` to 0.

#### Response

Expand Down
28 changes: 14 additions & 14 deletions endpoints/physical_quotas/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ namespace
resource_quotas.emplace_back(json{
{"group", std::move(row[0])},
{"resource", std::move(row[2])},
{"limit", std::stoll(row[3])},
{"over", std::stoll(row[4])},
{"maximum_bytes", std::stoll(row[3])},
{"over_bytes", std::stoll(row[4])},
{"modified_at", std::move(row[5])}});
}

Expand All @@ -132,8 +132,8 @@ namespace
for (auto&& row : irods::query{static_cast<RcComm*>(conn), global_quotas_query}) {
global_quotas.emplace_back(json{
{"group", std::move(row[0])},
{"limit", std::stoll(row[2])},
{"over", std::stoll(row[3])},
{"maximum_bytes", std::stoll(row[2])},
{"over_bytes", std::stoll(row[3])},
{"modified_at", std::move(row[4])}});
}
}
Expand All @@ -145,8 +145,8 @@ namespace
resource_quotas.emplace_back(json{
{"group", std::move(row[0])},
{"resource", std::move(row[2])},
{"limit", std::stoll(row[3])},
{"over", std::stoll(row[4])},
{"maximum_bytes", std::stoll(row[3])},
{"over_bytes", std::stoll(row[4])},
{"modified_at", std::move(row[5])}});
}

Expand All @@ -156,8 +156,8 @@ namespace
for (auto&& row : irods::query{static_cast<RcComm*>(conn), global_quotas_query}) {
global_quotas.emplace_back(json{
{"group", std::move(row[0])},
{"limit", std::stoll(row[2])},
{"over", std::stoll(row[3])},
{"maximum_bytes", std::stoll(row[2])},
{"over_bytes", std::stoll(row[3])},
{"modified_at", std::move(row[4])}});
}
}
Expand Down Expand Up @@ -218,28 +218,28 @@ namespace
return _sess_ptr->send(irods::http::fail(res, http::status::bad_request));
}

const auto quota_iter = _args.find("quota");
const auto max_bytes_iter = _args.find("maximum-bytes");
if (group_iter == std::end(_args)) {
logging::error(*_sess_ptr, "{}: Missing [quota] parameter.", fn);
logging::error(*_sess_ptr, "{}: Missing [maximum-bytes] parameter.", fn);
return _sess_ptr->send(irods::http::fail(res, http::status::bad_request));
}

try {
if (std::stoll(quota_iter->second) < 0) {
logging::error(*_sess_ptr, "{}: Value for [quota] parameter is less than 0.", fn);
if (std::stoll(max_bytes_iter->second) < 0) {
logging::error(*_sess_ptr, "{}: Value for [maximum-bytes] parameter is less than 0.", fn);
return _sess_ptr->send(irods::http::fail(res, http::status::bad_request));
}
}
catch (const std::exception& e) {
logging::error(*_sess_ptr, "{}: Invalid value for [quota] parameter: {}", fn, e.what());
logging::error(*_sess_ptr, "{}: Invalid value for [maximum-bytes] parameter: {}", fn, e.what());
return _sess_ptr->send(irods::http::fail(res, http::status::bad_request));
}

GeneralAdminInput input{};
input.arg0 = "set-quota";
input.arg1 = "group";
input.arg2 = group_iter->second.c_str();
input.arg4 = quota_iter->second.c_str();
input.arg4 = max_bytes_iter->second.c_str();

// Apply the quota as a resource quota if the user set the resource parameter.
// Otherwise, apply it as a global quota across all resources.
Expand Down
30 changes: 15 additions & 15 deletions test/test_irods_http_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4819,7 +4819,7 @@ def test_setting_a_group_quota_for_a_specific_resource(self):
'op': 'set_group_quota',
'group': 'public',
'resource': resource,
'quota': 10
'maximum-bytes': 10
})
self.logger.debug(r.content)
self.assertEqual(r.status_code, 200)
Expand All @@ -4845,8 +4845,8 @@ def test_setting_a_group_quota_for_a_specific_resource(self):
self.assertEqual(r.status_code, 200)
result = r.json()
self.assertEqual(result['irods_response']['status_code'], 0)
self.assertEqual(result['resource_quotas'][0]['limit'], 10)
self.assertEqual(result['resource_quotas'][0]['over'], -10)
self.assertEqual(result['resource_quotas'][0]['maximum_bytes'], 10)
self.assertEqual(result['resource_quotas'][0]['over_bytes'], -10)

# Create a data object which does not violate the quota limit.
r = requests.post(f'{self.url_base}/data-objects', headers=rodsuser_headers, data={
Expand Down Expand Up @@ -4876,8 +4876,8 @@ def test_setting_a_group_quota_for_a_specific_resource(self):
self.assertEqual(r.status_code, 200)
result = r.json()
self.assertEqual(result['irods_response']['status_code'], 0)
self.assertEqual(result['resource_quotas'][0]['limit'], 10)
self.assertEqual(result['resource_quotas'][0]['over'], -8)
self.assertEqual(result['resource_quotas'][0]['maximum_bytes'], 10)
self.assertEqual(result['resource_quotas'][0]['over_bytes'], -8)

# Overwrite the data object. This puts the quota in violation. Any attempts to
# write to the data object will result in an error.
Expand Down Expand Up @@ -4939,7 +4939,7 @@ def test_setting_a_group_quota_for_a_specific_resource(self):
'op': 'set_group_quota',
'group': 'public',
'resource': resource,
'quota': 0
'maximum-bytes': 0
})
self.logger.debug(r.content)

Expand All @@ -4954,7 +4954,7 @@ def test_setting_a_group_quota_for_all_resources(self):
r = requests.post(self.url_endpoint, headers=rodsadmin_headers, data={
'op': 'set_group_quota',
'group': 'public',
'quota': 10
'maximum-bytes': 10
})
self.logger.debug(r.content)
self.assertEqual(r.status_code, 200)
Expand All @@ -4979,8 +4979,8 @@ def test_setting_a_group_quota_for_all_resources(self):
self.assertEqual(r.status_code, 200)
result = r.json()
self.assertEqual(result['irods_response']['status_code'], 0)
self.assertEqual(result['global_quotas'][0]['limit'], 10)
self.assertEqual(result['global_quotas'][0]['over'], -10)
self.assertEqual(result['global_quotas'][0]['maximum_bytes'], 10)
self.assertEqual(result['global_quotas'][0]['over_bytes'], -10)

# Create a data object which does not violate the quota limit.
r = requests.post(f'{self.url_base}/data-objects', headers=rodsuser_headers, data={
Expand Down Expand Up @@ -5008,8 +5008,8 @@ def test_setting_a_group_quota_for_all_resources(self):
self.assertEqual(r.status_code, 200)
result = r.json()
self.assertEqual(result['irods_response']['status_code'], 0)
self.assertEqual(result['global_quotas'][0]['limit'], 10)
self.assertEqual(result['global_quotas'][0]['over'], -8)
self.assertEqual(result['global_quotas'][0]['maximum_bytes'], 10)
self.assertEqual(result['global_quotas'][0]['over_bytes'], -8)

# Overwrite the data object. This puts the quota in violation. Any attempts to
# write to the data object will result in an error.
Expand Down Expand Up @@ -5067,7 +5067,7 @@ def test_setting_a_group_quota_for_all_resources(self):
r = requests.post(self.url_endpoint, headers=rodsadmin_headers, data={
'op': 'set_group_quota',
'group': 'public',
'quota': 0
'maximum-bytes': 0
})
self.logger.debug(r.content)

Expand All @@ -5080,7 +5080,7 @@ def test_server_returns_an_error_on_nonexistent_group(self):
r = requests.post(self.url_endpoint, headers=rodsadmin_headers, data={
'op': 'set_group_quota',
'group': 'does_not_exist',
'quota': 10
'maximum-bytes': 10
})
self.logger.debug(r.content)
self.assertEqual(r.status_code, 200)
Expand All @@ -5096,7 +5096,7 @@ def test_server_returns_an_error_on_nonexistent_resource(self):
'op': 'set_group_quota',
'group': 'public',
'resource': 'does_not_exist',
'quota': 10
'maximum-bytes': 10
})
self.logger.debug(r.content)
self.assertEqual(r.status_code, 200)
Expand All @@ -5119,7 +5119,7 @@ def test_server_returns_an_error_when_quota_value_is_invalid(self):
r = requests.post(self.url_endpoint, headers=rodsadmin_headers, data={
'op': 'set_group_quota',
'group': 'public',
'quota': v
'maximum-bytes': v
})
self.logger.debug(r.content)
self.assertEqual(r.status_code, 400)
Expand Down
Loading