From 403e7c323b3069c8c70088ded30de3096a216e3f Mon Sep 17 00:00:00 2001 From: Javier Sánchez Parra Date: Wed, 23 Sep 2020 11:01:22 +0200 Subject: #1004 Add GET /images This commit adds GET /images to the ogServer REST API. This call returns information of all the images in ogServer. Example response: { "images": [ { "filename": "ubuntu.img", "datasize": 2150400000, "size": 613476223, "modified": "Wed Sep 23 10:37:36 2020", "permissions": "744" }, { "filename": "test.img", "datasize": 2150400000, "size": 613236475, "modified": "Tue Sep 29 08:57:47 2020", "permissions": "744" } ], "disk": { "total": 52573995008, "free": 39624544256 } } --- src/cfg.c | 27 +++++++++- src/cfg.h | 3 ++ src/rest.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/rest.h | 1 + 4 files changed, 195 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cfg.c b/src/cfg.c index fa88fc1..f4361ec 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -88,9 +88,28 @@ static int parse_json_wol(struct og_server_cfg *cfg, json_t *element) return 0; } +static int parse_json_repo(struct og_server_cfg *cfg, json_t *element) +{ + const char *key; + json_t *value; + + json_object_foreach(element, key, value) { + if (!strcmp(key, "directory")) { + if (og_json_parse_string(value, &cfg->repo.dir) < 0) + return -1; + } else { + syslog(LOG_ERR, "unknown key `%s' in repo\n", key); + return -1; + } + } + + return 0; +} + #define OG_SERVER_CFG_REST (1 << 0) #define OG_SERVER_CFG_DB (1 << 1) #define OG_SERVER_CFG_WOL (1 << 2) +#define OG_SERVER_CFG_REPO (1 << 3) int parse_json_config(const char *filename, struct og_server_cfg *cfg) { @@ -138,6 +157,11 @@ int parse_json_config(const char *filename, struct og_server_cfg *cfg) break; } flags |= OG_SERVER_CFG_DB; + } else if (!strcmp(key, "repository")) { + if (parse_json_repo(cfg, value) < 0) + return -1; + + flags |= OG_SERVER_CFG_REPO; } else { syslog(LOG_ERR, "unknown key `%s' in %s\n", key, filename); @@ -150,7 +174,8 @@ int parse_json_config(const char *filename, struct og_server_cfg *cfg) if ((flags & OG_SERVER_CFG_REST) && (flags & OG_SERVER_CFG_DB) && - (flags & OG_SERVER_CFG_WOL)) { + (flags & OG_SERVER_CFG_WOL) && + (flags & OG_SERVER_CFG_REPO)) { ret = 0; } else { syslog(LOG_ERR, "Missing attributes in json file"); diff --git a/src/cfg.h b/src/cfg.h index c88a406..0d45bbd 100644 --- a/src/cfg.h +++ b/src/cfg.h @@ -17,6 +17,9 @@ struct og_server_cfg { struct { const char *interface; } wol; + struct { + const char *dir; + } repo; json_t *json; }; diff --git a/src/rest.c b/src/rest.c index b5b5f0c..966deaf 100644 --- a/src/rest.c +++ b/src/rest.c @@ -26,6 +26,7 @@ #include #include #include +#include struct ev_loop *og_loop; @@ -240,6 +241,7 @@ static const char *og_cmd_to_uri[OG_CMD_MAX] = { [OG_CMD_IMAGE_RESTORE] = "image/restore", [OG_CMD_SETUP] = "setup", [OG_CMD_RUN_SCHEDULE] = "run/schedule", + [OG_CMD_IMAGES] = "images", }; static bool og_client_is_busy(const struct og_client *cli, @@ -1532,6 +1534,161 @@ static int og_cmd_software(json_t *element, struct og_msg_params *params) return og_send_request(OG_METHOD_POST, OG_CMD_SOFTWARE, params, clients); } +#define OG_IMAGE_TYPE_MAXLEN 4 + +struct og_image { + const char *filename; + uint64_t datasize; + struct stat image_stats; +}; + +static int og_get_image_stats(const char *name, + struct stat *image_stats) +{ + const char *dir = cfg.repo.dir; + char filename[PATH_MAX + 1]; + + snprintf(filename, sizeof(filename), "%s/%s", dir, name); + if (stat(filename, image_stats) < 0) { + syslog(LOG_ERR, "%s image does not exists", name); + return -1; + } + return 0; +} + +static json_t *og_json_disk_alloc() +{ + const char *dir = cfg.repo.dir; + struct statvfs buffer; + json_t *disk_json; + int ret; + + ret = statvfs(dir, &buffer); + if (ret) + return NULL; + + disk_json = json_object(); + if (!disk_json) + return NULL; + + json_object_set_new(disk_json, "total", + json_integer(buffer.f_blocks * buffer.f_frsize)); + json_object_set_new(disk_json, "free", + json_integer(buffer.f_bfree * buffer.f_frsize)); + + return disk_json; +} + +#define OG_PERMS_IRWX (S_IRWXU | S_IRWXG | S_IRWXO) +#define OG_PERMS_MAXLEN 4 + +static json_t *og_json_image_alloc(struct og_image *image) +{ + char perms_string[OG_PERMS_MAXLEN]; + json_t *image_json; + char *modified; + uint16_t perms; + + image_json = json_object(); + if (!image_json) + return NULL; + + perms = image->image_stats.st_mode & OG_PERMS_IRWX; + snprintf(perms_string, sizeof(perms_string), "%o", perms); + + modified = ctime(&image->image_stats.st_mtime); + modified[strlen(modified) - 1] = '\0'; + + json_object_set_new(image_json, "filename", + json_string(image->filename)); + json_object_set_new(image_json, "datasize", + json_integer(image->datasize)); + json_object_set_new(image_json, "size", + json_integer(image->image_stats.st_size)); + json_object_set_new(image_json, "modified", + json_string(modified)); + json_object_set_new(image_json, "permissions", + json_string(perms_string)); + + return image_json; +} + +static int og_cmd_images(char *buffer_reply) +{ + json_t *root, *images, *image_json, *disk_json; + struct og_buffer og_buffer = { + .data = buffer_reply + }; + struct og_image image; + struct og_dbi *dbi; + dbi_result result; + + root = json_object(); + if (!root) + return -1; + + images = json_array(); + if (!images) { + json_decref(root); + return -1; + } + + json_object_set_new(root, "images", images); + + dbi = og_dbi_open(&dbi_config); + if (!dbi) { + syslog(LOG_ERR, "cannot open connection database (%s:%d)\n", + __func__, __LINE__); + json_decref(root); + return -1; + } + + result = dbi_conn_queryf(dbi->conn, + "SELECT i.nombreca, o.nombreordenador, " + " i.clonator, i.compressor, " + " i.filesystem, i.datasize " + "FROM imagenes i " + "LEFT JOIN ordenadores o " + "ON i.idordenador = o.idordenador"); + + while (dbi_result_next_row(result)) { + image = (struct og_image){0}; + image.filename = dbi_result_get_string(result, "nombreca"); + image.datasize = dbi_result_get_ulonglong(result, "datasize"); + + if (og_get_image_stats(image.filename, &image.image_stats)) { + continue; + } + + image_json = og_json_image_alloc(&image); + if (!image_json) { + dbi_result_free(result); + og_dbi_close(dbi); + json_decref(root); + return -1; + } + + json_array_append(images, image_json); + } + + dbi_result_free(result); + og_dbi_close(dbi); + + disk_json = og_json_disk_alloc(); + if (!disk_json) { + syslog(LOG_ERR, "cannot allocate disk json"); + json_decref(root); + return -1; + } + + json_object_set_new(root, "disk", disk_json); + + json_dump_callback(root, og_json_dump_clients, &og_buffer, 0); + json_decref(root); + + return 0; +} + static int og_cmd_create_image(json_t *element, struct og_msg_params *params) { json_t *value, *clients; @@ -3489,6 +3646,14 @@ int og_client_state_process_payload_rest(struct og_client *cli) return og_client_bad_request(cli); } err = og_cmd_software(root, ¶ms); + } else if (!strncmp(cmd, "images", strlen("images"))) { + if (method != OG_METHOD_GET) + return og_client_method_not_found(cli); + + if (!root) + err = og_cmd_images(buf_reply); + else + return og_client_method_not_found(cli); } else if (!strncmp(cmd, "image/create", strlen("image/create"))) { if (method != OG_METHOD_POST) return og_client_method_not_found(cli); diff --git a/src/rest.h b/src/rest.h index 4f2347f..58d25c7 100644 --- a/src/rest.h +++ b/src/rest.h @@ -33,6 +33,7 @@ enum og_cmd_type { OG_CMD_IMAGE_RESTORE, OG_CMD_SETUP, OG_CMD_RUN_SCHEDULE, + OG_CMD_IMAGES, OG_CMD_MAX }; -- cgit v1.2.3-18-g5258