rest: add GET,POST /image/restrict

Allow to restrict image to scope:

 POST /image/restrict
 { "image" : 49, "scopes" : [ 1,3 ] }

 response: 200 OK

This restricts image with ID 49 to scopes 1 and 3.

You can also fetch the current list of restrictions:

 GET /image/restrict
 { "image" : 49 }

 response: 200 OK

 { "image" : 49, "scopes" : [ 1,3 ] }

Existing limitations in this interface:

 - Only restriction of image to center is possible at this moment.
 - This is only used by ogCP to validate if this is possible, no existing code
   in the ogserver uses this to restrict POST image/restore.

This is a usability feature.
master
OpenGnSys Support Team 2024-07-17 14:19:39 +02:00
parent e62a55ae37
commit e9a8f467f1
3 changed files with 280 additions and 0 deletions

View File

@ -3895,6 +3895,230 @@ static int og_cmd_delete_image(json_t *element, struct og_msg_params *params)
return 0;
}
struct og_scope_image {
struct list_head list;
uint32_t id;
};
static void og_scope_image_list_free(struct list_head *scope_list)
{
struct og_scope_image *scope, *next;
list_for_each_entry_safe(scope, next, scope_list, list) {
list_del(&scope->list);
free(scope);
}
}
static int og_json_parse_scope_image_list(json_t *element, struct list_head *scope_list)
{
struct og_scope_image *scope;
unsigned int i;
json_t *k;
if (json_typeof(element) != JSON_ARRAY)
return -1;
for (i = 0; i < json_array_size(element); i++) {
k = json_array_get(element, i);
if (json_typeof(k) != JSON_INTEGER)
goto err_out;
scope = calloc(1, sizeof(struct og_scope_image));
if (!scope)
goto err_out;
scope->id = json_integer_value(k);
list_add_tail(&scope->list, scope_list);
}
return 0;
err_out:
og_scope_image_list_free(scope_list);
return -1;
}
enum {
OG_ATTR_IMAGE_ID = (1 << 0),
OG_ATTR_IMAGE_SCOPE_ID = (1 << 0),
};
static int og_cmd_image_scope_update(json_t *element, struct og_msg_params *params)
{
struct og_scope_image *scope;
LIST_HEAD(scope_list);
struct og_dbi *dbi;
const char *msglog;
uint32_t image_id;
dbi_result result;
const char *key;
json_t *value;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "image")) {
err = og_json_parse_uint(value, &image_id);
params->flags |= OG_ATTR_IMAGE_ID;
} else if (!strcmp(key, "scopes")) {
err = og_json_parse_scope_image_list(value, &scope_list);
if (err >= 0 && !list_empty(&scope_list))
params->flags |= OG_ATTR_IMAGE_SCOPE_ID;
}
if (err < 0)
return err;
}
if (!og_msg_params_validate(params, OG_ATTR_IMAGE_ID |
OG_ATTR_IMAGE_SCOPE_ID)) {
og_scope_image_list_free(&scope_list);
return -1;
}
dbi = og_dbi_open(&ogconfig.db);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
og_scope_image_list_free(&scope_list);
return -1;
}
result = dbi_conn_queryf(dbi->conn,
"DELETE FROM image_scope WHERE image_id=%d",
image_id);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
goto err_out;
}
dbi_result_free(result);
list_for_each_entry(scope, &scope_list, list) {
result = dbi_conn_queryf(dbi->conn,
"INSERT INTO image_scope (image_id, scope_id) "
"VALUES (%d, %d)", image_id, scope->id);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
goto err_out;
}
dbi_result_free(result);
}
og_dbi_close(dbi);
og_scope_image_list_free(&scope_list);
return 0;
err_out:
og_scope_image_list_free(&scope_list);
og_dbi_close(dbi);
return -1;
}
static json_t *og_json_image_scope(struct og_dbi *dbi, uint32_t image_id)
{
json_t *scope_image, *scope_array;
const char *msglog;
uint32_t scope_id;
dbi_result result;
result = dbi_conn_queryf(dbi->conn,
"SELECT scope_id FROM image_scope WHERE image_id = '%u'", image_id);
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
__func__, __LINE__, msglog);
return NULL;
}
scope_image = json_object();
if (!scope_image) {
dbi_result_free(result);
return NULL;
}
json_object_set_new(scope_image, "id", json_integer(image_id));
scope_array = json_array();
if (!scope_array) {
json_decref(scope_image);
dbi_result_free(result);
return NULL;
}
while (dbi_result_next_row(result)) {
scope_id = dbi_result_get_uint(result, "scope_id");
json_array_append_new(scope_array, json_integer(scope_id));
}
dbi_result_free(result);
json_object_set_new(scope_image, "scopes", scope_array);
return scope_image;
}
static int og_cmd_image_scope_list(json_t *element,
struct og_msg_params *params,
char *buffer_reply)
{
struct og_buffer og_buffer = {
.data = buffer_reply
};
json_t *value, *scope_image;
struct og_dbi *dbi;
uint32_t image_id;
const char *key;
int err = 0;
if (json_typeof(element) != JSON_OBJECT)
return -1;
json_object_foreach(element, key, value) {
if (!strcmp(key, "image")) {
err = og_json_parse_uint(value, &image_id);
params->flags |= OG_ATTR_IMAGE_ID;
}
if (err < 0)
return err;
}
if (!og_msg_params_validate(params, OG_ATTR_IMAGE_ID))
return -1;
dbi = og_dbi_open(&ogconfig.db);
if (!dbi) {
syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
__func__, __LINE__);
return -1;
}
scope_image = og_json_image_scope(dbi, image_id);
og_dbi_close(dbi);
if (!scope_image)
return -1;
if (json_dump_callback(scope_image, og_json_dump_clients, &og_buffer, 0)) {
json_decref(scope_image);
return -1;
}
json_decref(scope_image);
return 0;
}
static int og_dbi_client_cache_get(struct og_dbi *dbi, json_t *clients, const char *ip)
{
const char *img_name, *msglog, *img_checksum;
@ -7934,6 +8158,7 @@ struct {
[OG_URI_IMAGE_UPDATE] = { "image/update" },
[OG_URI_IMAGE_RESTORE] = { "image/restore", },
[OG_URI_IMAGE_DELETE] = { "image/delete", },
[OG_URI_IMAGE_RESTRICT] = { "image/restrict", },
[OG_URI_CACHE_LIST] = { "cache/list", },
[OG_URI_CACHE_DELETE] = { "cache/delete", },
[OG_URI_PART_SETUP] = { "setup", },
@ -8530,6 +8755,24 @@ int og_client_state_process_payload_rest(struct og_client *cli)
goto err_process_rest_payload;
}
err = og_cmd_delete_image(root, &params);
} else if (!strncmp(cmd, "image/restrict", strlen("image/restrict"))) {
if (!root) {
err = og_client_bad_request(cli);
goto err_process_rest_payload;
}
switch (method) {
case OG_METHOD_GET:
err = og_cmd_image_scope_list(root, &params, buf_reply);
break;
case OG_METHOD_POST:
err = og_cmd_image_scope_update(root, &params);
break;
default:
err = og_client_method_not_found(cli);
goto err_process_rest_payload;
}
} else if (!strncmp(cmd, "cache/list", strlen("cache/list"))) {
if (method != OG_METHOD_GET) {
err = og_client_method_not_found(cli);

View File

@ -37,6 +37,7 @@ enum og_cmd_type {
OG_CMD_IMAGE_CREATE,
OG_CMD_IMAGE_UPDATE,
OG_CMD_IMAGE_RESTORE,
OG_CMD_IMAGE_RESTRICT,
OG_CMD_SETUP,
OG_CMD_RUN_SCHEDULE,
OG_CMD_IMAGES,
@ -124,6 +125,7 @@ enum og_rest_uri {
OG_URI_IMAGE_UPDATE,
OG_URI_IMAGE_RESTORE,
OG_URI_IMAGE_DELETE,
OG_URI_IMAGE_RESTRICT,
OG_URI_CACHE_LIST,
OG_URI_CACHE_DELETE,
OG_URI_PART_SETUP,

View File

@ -335,6 +335,40 @@ static int og_dbi_schema_v7(struct og_dbi *dbi)
return 0;
}
static int og_dbi_schema_v8(struct og_dbi *dbi)
{
const char *msglog;
dbi_result result;
syslog(LOG_DEBUG, "Creating table image_scope\n");
result = dbi_conn_query(dbi->conn, "CREATE TABLE `image_scope` ("
"`id` int NOT NULL AUTO_INCREMENT,"
"`image_id` int NOT NULL,"
"`scope_id` int NOT NULL,"
"PRIMARY KEY (`id`),"
"FOREIGN KEY (`image_id`) REFERENCES `imagenes` (`idimagen`) ON DELETE CASCADE,"
"FOREIGN KEY (`scope_id`) REFERENCES `centros` (`idcentro`) ON DELETE CASCADE"
") AUTO_INCREMENT=1;");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_INFO, "Error when creating image_scope (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
dbi_result_free(result);
result = dbi_conn_query(dbi->conn, "UPDATE version SET version = 8");
if (!result) {
dbi_conn_error(dbi->conn, &msglog);
syslog(LOG_INFO, "Could not update version row (%s:%d) %s\n",
__func__, __LINE__, msglog);
return -1;
}
dbi_result_free(result);
return 0;
}
static struct og_schema_version {
int version;
int (*update)(struct og_dbi *dbi);
@ -346,6 +380,7 @@ static struct og_schema_version {
{ .version = 5, .update = og_dbi_schema_v5 },
{ .version = 6, .update = og_dbi_schema_v6 },
{ .version = 7, .update = og_dbi_schema_v7, },
{ .version = 8, .update = og_dbi_schema_v8, },
{ 0, NULL },
};