From 0752a4324e7a8f54e4ebe5efb403221388b483d3 Mon Sep 17 00:00:00 2001
From: zhongtao <zhongtao17@huawei.com>
Date: Mon, 6 Mar 2023 11:31:56 +0800
Subject: [PATCH 30/46] support isula update when runtime is runc

Signed-off-by: zhongtao <zhongtao17@huawei.com>
---
 .../executor/container_cb/execution_extend.c  |   1 +
 src/daemon/modules/api/runtime_api.h          |   1 +
 .../modules/runtime/isula/isula_rt_ops.c      | 167 +++++++++++++++++-
 3 files changed, 163 insertions(+), 6 deletions(-)

diff --git a/src/daemon/executor/container_cb/execution_extend.c b/src/daemon/executor/container_cb/execution_extend.c
index b0da705e..58303f80 100644
--- a/src/daemon/executor/container_cb/execution_extend.c
+++ b/src/daemon/executor/container_cb/execution_extend.c
@@ -1129,6 +1129,7 @@ static int do_update_resources(const container_update_request *request, containe
     if (container_is_running(cont->state)) {
         params.rootpath = cont->root_path;
         params.hostconfig = hostconfig;
+        params.state = cont->state_path;
         if (runtime_update(id, cont->runtime, &params)) {
             ERROR("Update container %s failed", id);
             ret = -1;
diff --git a/src/daemon/modules/api/runtime_api.h b/src/daemon/modules/api/runtime_api.h
index c5e05ca2..a8dfdeae 100644
--- a/src/daemon/modules/api/runtime_api.h
+++ b/src/daemon/modules/api/runtime_api.h
@@ -164,6 +164,7 @@ typedef struct _rt_attach_params_t {
 typedef struct _rt_update_params_t {
     const char *rootpath;
     const host_config *hostconfig;
+    const char *state;
 } rt_update_params_t;
 
 typedef struct _rt_listpids_params_t {
diff --git a/src/daemon/modules/runtime/isula/isula_rt_ops.c b/src/daemon/modules/runtime/isula/isula_rt_ops.c
index 51a72c4f..4553fa90 100644
--- a/src/daemon/modules/runtime/isula/isula_rt_ops.c
+++ b/src/daemon/modules/runtime/isula/isula_rt_ops.c
@@ -39,6 +39,7 @@
 #include "constants.h"
 #include "isula_libutils/shim_client_process_state.h"
 #include "isula_libutils/shim_client_runtime_stats.h"
+#include "isula_libutils/shim_client_cgroup_resources.h"
 #include "isula_libutils/oci_runtime_state.h"
 #include "isulad_config.h"
 #include "utils_string.h"
@@ -54,6 +55,9 @@
 #define RESIZE_DATA_SIZE 100
 #define PID_WAIT_TIME 120
 
+// file name formats of cgroup resources json
+#define RESOURCE_FNAME_FORMATS "%s/resources.json"
+
 // handle string from stderr output.
 typedef int(*handle_output_callback_t)(const char *output);
 
@@ -725,18 +729,18 @@ static int shim_create(bool fg, const char *id, const char *workdir, const char
     runtime_exec_param_dump(params);
 
     if (snprintf(fpid, sizeof(fpid), "%s/shim-pid", workdir) < 0) {
-        ERROR("failed make shim-pid full path");
+        ERROR("Failed make shim-pid full path");
         return -1;
     }
 
     if (pipe2(exec_fd, O_CLOEXEC) != 0) {
-        ERROR("failed to create pipe for shim create");
+        ERROR("Failed to create pipe for shim create");
         return -1;
     }
 
     pid = fork();
     if (pid < 0) {
-        ERROR("failed fork for shim parent %s", strerror(errno));
+        ERROR("Failed fork for shim parent %s", strerror(errno));
         close(exec_fd[0]);
         close(exec_fd[1]);
         return -1;
@@ -1256,13 +1260,164 @@ int rt_isula_attach(const char *id, const char *runtime, const rt_attach_params_
     return -1;
 }
 
-int rt_isula_update(const char *id, const char *runtime, const rt_update_params_t *params)
+static int to_engine_resources(const host_config *hostconfig, shim_client_cgroup_resources *cr)
+{
+    uint64_t period = 0;
+    int64_t quota = 0;
+
+    if (hostconfig == NULL || cr == NULL) {
+        return -1;
+    }
+
+    cr->block_io = util_common_calloc_s(sizeof(shim_client_cgroup_resources_block_io));
+    if (cr->block_io == NULL) {
+        ERROR("Out of memory");
+        return -1;
+    }
+
+    cr->cpu = util_common_calloc_s(sizeof(shim_client_cgroup_resources_cpu));
+    if (cr->cpu == NULL) {
+        ERROR("Out of memory");
+        return -1;
+    }
+
+    cr->memory = util_common_calloc_s(sizeof(shim_client_cgroup_resources_memory));
+    if (cr->memory == NULL) {
+        ERROR("Out of memory");
+        return -1;
+    }
+
+    cr->block_io->weight = hostconfig->blkio_weight;
+    cr->cpu->shares = (uint64_t)hostconfig->cpu_shares;
+    cr->cpu->period = (uint64_t)hostconfig->cpu_period;
+    cr->cpu->quota = hostconfig->cpu_quota;
+    cr->cpu->cpus = util_strdup_s(hostconfig->cpuset_cpus);
+    cr->cpu->mems = util_strdup_s(hostconfig->cpuset_mems);
+    cr->memory->limit = (uint64_t)hostconfig->memory;
+    cr->memory->swap = (uint64_t)hostconfig->memory_swap;
+    cr->memory->reservation = (uint64_t)hostconfig->memory_reservation;
+    cr->memory->kernel = (uint64_t)hostconfig->kernel_memory;
+    cr->cpu->realtime_period = hostconfig->cpu_realtime_period;
+    cr->cpu->realtime_runtime = hostconfig->cpu_realtime_runtime;
+
+    // when --cpus=n is set, nano_cpus = n * 1e9.
+    if (hostconfig->nano_cpus > 0) {
+        // in the case, period will be set to the default value of 100000(0.1s).
+        period = (uint64_t)(100 * Time_Milli / Time_Micro);
+        // set quota = period * n, in order to let container process fully occupy n cpus.
+        if ((hostconfig->nano_cpus / 1e9)  > (INT64_MAX / (int64_t)period)) {
+            ERROR("Overflow of quota");
+            return -1;
+        }
+        quota = hostconfig->nano_cpus / 1e9 * (int64_t)period;
+        cr->cpu->period = period;
+        cr->cpu->quota = quota;
+    }
+
+    return 0;
+}
+
+static int create_resources_json_file(const char *workdir, const shim_client_cgroup_resources *cr, char *fname,
+                                      size_t fname_size)
 {
-    ERROR("isula update not support on isulad-shim");
-    isulad_set_error_message("isula update not support on isulad-shim");
+    struct parser_context ctx = { OPT_GEN_SIMPLIFY, 0 };
+    parser_error perr = NULL;
+    char *data = NULL;
+    int retcode = 0;
+    int nret = 0;
+
+    nret = snprintf(fname, fname_size, RESOURCE_FNAME_FORMATS, workdir);
+    if (nret < 0 || (size_t)nret >= fname_size) {
+        ERROR("Failed make resources.json full path");
+        return -1;
+    }
+
+    data = shim_client_cgroup_resources_generate_json(cr, &ctx, &perr);
+    if (data == NULL) {
+        retcode = -1;
+        ERROR("Failed generate json for resources.json error=%s", perr);
+        goto out;
+    }
+
+    if (util_write_file(fname, data, strlen(data), DEFAULT_SECURE_FILE_MODE) != 0) {
+        retcode = -1;
+        ERROR("Failed write resources.json");
+        goto out;
+    }
+
+out:
+    UTIL_FREE_AND_SET_NULL(perr);
+    UTIL_FREE_AND_SET_NULL(data);
+
+    return retcode;
+}
+
+// show std error msg, always return -1.
+static int show_stderr(const char *err)
+{
+    isulad_set_error_message(err);
     return -1;
 }
 
+int rt_isula_update(const char *id, const char *runtime, const rt_update_params_t *params)
+{
+    int ret = 0;
+    char workdir[PATH_MAX] = { 0 };
+    char resources_fname[PATH_MAX] = { 0 };
+    const char *opts[2] = { 0 };
+    shim_client_cgroup_resources *cr = NULL;
+
+    if (id == NULL || runtime == NULL || params == NULL || params->state == NULL || strlen(params->state) == 0) {
+        ERROR("Nullptr arguments not allowed");
+        return -1;
+    }
+
+    ret = snprintf(workdir, sizeof(workdir), "%s/%s/update", params->state, id);
+    if (ret < 0 || (size_t)ret >= sizeof(workdir)) {
+        ERROR("Failed join update full path");
+        return -1;
+    }
+
+    ret = util_mkdir_p(workdir, DEFAULT_SECURE_DIRECTORY_MODE);
+    if (ret < 0) {
+        ERROR("Failed mkdir update workdir %s", workdir);
+        return ret;
+    }
+
+    cr = util_common_calloc_s(sizeof(shim_client_cgroup_resources));
+    if (cr == NULL) {
+        ERROR("Out of memory");
+        goto del_out;
+    }
+
+    ret = to_engine_resources(params->hostconfig, cr);
+    if (ret < 0) {
+        ERROR("Failed to get resources for update");
+        goto del_out;
+    }
+
+    ret = create_resources_json_file(workdir, cr, resources_fname, sizeof(resources_fname));
+    if (ret != 0) {
+        ERROR("%s: failed create update json file", id);
+        goto del_out;
+    }
+
+    opts[0] = "--resources";
+    opts[1] = resources_fname;
+
+    if (runtime_call_simple(workdir, runtime, "update", opts, 2, id, show_stderr) != 0) {
+        ERROR("Call runtime update id failed");
+        ret = -1;
+    }
+
+del_out:
+    if (util_recursive_rmdir(workdir, 0)) {
+        ERROR("Rmdir %s failed", workdir);
+    }
+    free_shim_client_cgroup_resources(cr);
+    return ret;
+}
+
 int rt_isula_pause(const char *id, const char *runtime, const rt_pause_params_t *params)
 {
     char workdir[PATH_MAX] = { 0 };
-- 
2.25.1

