summaryrefslogtreecommitdiff
path: root/0119-nri-add-convert-and-utils-impl-for-nri.patch
diff options
context:
space:
mode:
Diffstat (limited to '0119-nri-add-convert-and-utils-impl-for-nri.patch')
-rw-r--r--0119-nri-add-convert-and-utils-impl-for-nri.patch2254
1 files changed, 2254 insertions, 0 deletions
diff --git a/0119-nri-add-convert-and-utils-impl-for-nri.patch b/0119-nri-add-convert-and-utils-impl-for-nri.patch
new file mode 100644
index 0000000..ba76c2e
--- /dev/null
+++ b/0119-nri-add-convert-and-utils-impl-for-nri.patch
@@ -0,0 +1,2254 @@
+From c0d4b523c24e88b8c70cd3b121a46b7b3c841c17 Mon Sep 17 00:00:00 2001
+From: zhongtao <zhongtao17@huawei.com>
+Date: Tue, 13 Aug 2024 20:33:28 +0800
+Subject: [PATCH 119/121] [nri] add convert and utils impl for nri
+
+Signed-off-by: zhongtao <zhongtao17@huawei.com>
+---
+ src/daemon/common/nri/nri_convert.cc | 539 ++++++++++++++++++++++++
+ src/daemon/common/nri/nri_convert.h | 9 +-
+ src/daemon/common/nri/nri_spec.c | 602 +++++++++++++++++++++++++++
+ src/daemon/common/nri/nri_utils.c | 520 +++++++++++++++++++++++
+ src/daemon/common/nri/nri_utils.h | 5 +-
+ src/daemon/config/isulad_config.c | 178 ++++++++
+ src/daemon/modules/api/specs_api.h | 5 +
+ src/daemon/modules/spec/specs.c | 32 +-
+ src/daemon/nri/nri_adaption.h | 46 +-
+ src/daemon/nri/nri_helpers.cc | 93 +++++
+ src/daemon/nri/nri_helpers.h | 2 +-
+ src/utils/cpputils/transform.cc | 2 +-
+ 12 files changed, 2002 insertions(+), 31 deletions(-)
+ create mode 100644 src/daemon/common/nri/nri_convert.cc
+ create mode 100644 src/daemon/common/nri/nri_spec.c
+ create mode 100644 src/daemon/common/nri/nri_utils.c
+ create mode 100644 src/daemon/nri/nri_helpers.cc
+
+diff --git a/src/daemon/common/nri/nri_convert.cc b/src/daemon/common/nri/nri_convert.cc
+new file mode 100644
+index 00000000..7cce64ec
+--- /dev/null
++++ b/src/daemon/common/nri/nri_convert.cc
+@@ -0,0 +1,539 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: zhongtao
++ * Create: 2024-03-16
++ * Description: provide nri convert functions
++ *********************************************************************************/
++
++#include "nri_convert.h"
++
++#include "container_api.h"
++#include "v1_cri_helpers.h"
++#include "path.h"
++#include "transform.h"
++#include "nri_utils.h"
++
++static int64_t DefaultOOMScoreAdj = 0;
++
++static bool NRILinuxCpuFromCRI(const runtime::v1::LinuxContainerResources &config, nri_linux_cpu &cpu)
++{
++ if (!config.cpuset_cpus().empty()) {
++ cpu.cpus = util_strdup_s(config.cpuset_cpus().c_str());
++ }
++
++ if (!config.cpuset_mems().empty()) {
++ cpu.mems = util_strdup_s(config.cpuset_mems().c_str());
++ }
++
++ cpu.period = (uint64_t *)util_common_calloc_s(sizeof(uint64_t));
++ if (cpu.period == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(cpu.period) = config.cpu_period();
++
++ cpu.quota = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if (cpu.quota == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(cpu.quota) = config.cpu_quota();
++
++ cpu.shares = (uint64_t *)util_common_calloc_s(sizeof(uint64_t));
++ if (cpu.shares == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(cpu.shares) = config.cpu_shares();
++
++ // consistent with other container engines,
++ // not obtained cpu.realtime_period & cpu.realtime_runtime
++ return true;
++}
++
++static bool NRILinuxMemoryFromCRI(const runtime::v1::LinuxContainerResources &config, nri_linux_memory &memory)
++{
++ memory.limit = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if (memory.limit == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(memory.limit) = config.memory_limit_in_bytes();
++
++ // consistent with other container engines,
++ // not obtained other memory info
++
++ return true;
++}
++
++static bool NRIHugePageLimitFromCRI(const runtime::v1::LinuxContainerResources &config, nri_linux_resources &resources)
++{
++ int i;
++ nri_hugepage_limit *tmp = nullptr;
++
++ if (config.hugepage_limits_size() == 0) {
++ return true;
++ }
++
++ resources.hugepage_limits = (nri_hugepage_limit **)util_smart_calloc_s(sizeof(nri_hugepage_limit *),
++ config.hugepage_limits_size());
++ if (resources.hugepage_limits == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ for (i = 0; i < config.hugepage_limits_size(); i++) {
++ tmp = (nri_hugepage_limit *)util_common_calloc_s(sizeof(nri_hugepage_limit));
++ if (tmp == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ tmp->page_size = util_strdup_s(config.hugepage_limits(i).page_size().c_str());
++ tmp->limit = config.hugepage_limits(i).limit();
++ resources.hugepage_limits[i] = tmp;
++ resources.hugepage_limits_len++;
++ tmp = nullptr;
++ }
++ return true;
++}
++
++static auto NRILinuxResourcesFromCRI(const runtime::v1::LinuxContainerResources &config,
++ nri_linux_resources &resources) -> bool
++{
++ if (!NRILinuxMemoryFromCRI(config, *resources.memory)) {
++ ERROR("Failed to transform memory to nri for container");
++ return false;
++ }
++
++ if (!NRILinuxCpuFromCRI(config, *resources.cpu)) {
++ ERROR("Failed to transform cpu to nri for container");
++ return false;
++ }
++
++ if (!NRIHugePageLimitFromCRI(config, resources)) {
++ ERROR("Failed to transform hugepage limits to nri for container");
++ return false;
++ }
++
++ // resources.blockio_class is not support
++ // resources.rdt_class is not support
++ // They are not standard fields in oci spec
++
++ Errors tmpError;
++
++ resources.unified = Transform::ProtobufMapToJsonMapForString(config.unified(), tmpError);
++ if (resources.unified == nullptr) {
++ ERROR("Failed to transform unified to nri for container : %s", tmpError.GetMessage().c_str());
++ return false;
++ }
++
++ // resources.devices is not set in pod
++
++ return true;
++}
++
++static auto NRILinuxFromCRI(const runtime::v1::LinuxPodSandboxConfig &config, nri_linux_pod_sandbox &linux) -> bool
++{
++ if (!init_nri_linux_resources(&linux.pod_overhead)) {
++ ERROR("Failed to init nri linux overhead resources for pod");
++ return false;
++ }
++ if (!init_nri_linux_resources(&linux.pod_resources)) {
++ ERROR("Failed to init nri linux resources resources for pod");
++ return false;
++ }
++ if (config.has_overhead() && !NRILinuxResourcesFromCRI(config.overhead(), *linux.pod_overhead)) {
++ ERROR("Failed to transform overhead to nri for pod");
++ return false;
++ }
++
++ if (config.has_resources() && !NRILinuxResourcesFromCRI(config.resources(), *linux.pod_resources)) {
++ ERROR("Failed to transform resources to nri for pod");
++ return false;
++ }
++
++ linux.cgroup_parent = util_strdup_s(config.cgroup_parent().c_str());
++
++ // todo: other container engines get linux.cgroups_path/linux.resourses/linux.namespace from spec.linux,
++ // How does isulad get these values ​​from CRI module?
++ return true;
++}
++
++auto PodSandboxToNRI(const std::shared_ptr<const sandbox::Sandbox> &sandbox, nri_pod_sandbox &pod) -> bool
++{
++ container_t *cont = nullptr;
++ Errors tmpError;
++
++ cont = containers_store_get(sandbox->GetName().c_str());
++ if (cont != nullptr) {
++ pod.pid = container_state_get_pid(cont->state);
++ container_unref(cont);
++ }
++
++ pod.id = util_strdup_s(sandbox->GetId().c_str());
++ pod.name = util_strdup_s(sandbox->GetName().c_str());
++ if (sandbox->GetSandboxConfig().has_metadata()) {
++ pod.uid = util_strdup_s(sandbox->GetSandboxConfig().metadata().uid().c_str());
++ pod._namespace = util_strdup_s(sandbox->GetSandboxConfig().metadata().namespace_().c_str());
++ }
++
++
++ pod.labels = Transform::ProtobufMapToJsonMapForString(sandbox->GetSandboxConfig().labels(), tmpError);
++ if (pod.labels == nullptr) {
++ ERROR("Failed to transform labels to nri for pod : %s, : %s", pod.name, tmpError.GetMessage().c_str());
++ return false;
++ }
++
++ pod.annotations = Transform::ProtobufMapToJsonMapForString(sandbox->GetSandboxConfig().annotations(), tmpError);
++ if (pod.annotations == nullptr) {
++ ERROR("Failed to transform annotations to nri for pod : %s, : %s", pod.name, tmpError.GetMessage().c_str());
++ return false;
++ }
++
++ if (sandbox->GetSandboxConfig().has_linux()) {
++ pod.linux = (nri_linux_pod_sandbox *)util_common_calloc_s(sizeof(nri_linux_pod_sandbox));
++ if (pod.linux == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ if (!NRILinuxFromCRI(sandbox->GetSandboxConfig().linux(), *pod.linux)) {
++ ERROR("Failed to transform linux to nri for pod : %s", pod.name);
++ return false;
++ }
++ }
++
++ pod.runtime_handler = util_strdup_s(sandbox->GetRuntimeHandle().c_str());
++
++ return true;
++}
++
++static auto CRIMountArrToNRI(const runtime::v1::ContainerConfig &containerConfig, nri_container &con) -> bool
++{
++ size_t i, len;
++
++ // get mount from cont
++ len = containerConfig.mounts_size();
++ if (len == 0) {
++ return true;
++ }
++ con.mounts = (nri_mount **)util_smart_calloc_s(sizeof(nri_mount *), len);
++ if (con.mounts == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ nri_mount *tmp = nullptr;
++
++ for (i = 0; i < len; i++) {
++ tmp = (nri_mount *)util_common_calloc_s(sizeof(nri_mount));
++ if (tmp == nullptr) {
++ ERROR("Out of memory");
++ goto error_out;
++ }
++
++ if (containerConfig.mounts()[i].container_path().empty() || containerConfig.mounts()[i].host_path().empty()) {
++ ERROR("Mount path is empty");
++ goto error_out;
++ }
++
++ char path[PATH_MAX] = { 0 };
++ if (!util_clean_path(containerConfig.mounts()[i].container_path().c_str(), path, sizeof(path))) {
++ ERROR("Failed to get clean path for mount src path: %s", containerConfig.mounts()[i].container_path().c_str());
++ goto error_out;
++ }
++
++ tmp->destination = util_strdup_s(path);
++
++ if (!util_clean_path(containerConfig.mounts()[i].host_path().c_str(), path, sizeof(path))) {
++ ERROR("Failed to get clean path for mount src path: %s", containerConfig.mounts()[i].host_path().c_str());
++ goto error_out;
++ }
++ tmp->source = util_strdup_s(path);
++
++ if (util_array_append(&(tmp->options), "rbind") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++
++ if (containerConfig.mounts()[i].propagation() == runtime::v1::PROPAGATION_PRIVATE) {
++ DEBUG("noop, private is default");
++ if (util_array_append(&(tmp->options), "rprivate") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ } else if (containerConfig.mounts()[i].propagation() == runtime::v1::PROPAGATION_BIDIRECTIONAL) {
++ if (util_array_append(&(tmp->options), "rshared") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ } else if (containerConfig.mounts()[i].propagation() == runtime::v1::PROPAGATION_HOST_TO_CONTAINER) {
++ if (util_array_append(&(tmp->options), "rslave") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ } else {
++ WARN("unknown propagation mode for hostPath %s", containerConfig.mounts()[i].host_path().c_str());
++ if (util_array_append(&(tmp->options), "rprivate") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ }
++
++ if (containerConfig.mounts()[i].readonly()) {
++ if (util_array_append(&(tmp->options), "ro") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ } else {
++ if (util_array_append(&(tmp->options), "rw") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ }
++
++ tmp->type = util_strdup_s("bind");
++
++ con.mounts[i] = tmp;
++ tmp = nullptr;
++ con.mounts_len++;
++ }
++ return true;
++
++error_out:
++ free_nri_mount(tmp);
++ return false;
++}
++
++static auto MountPointsElementToNRI(container_config_v2_common_config_mount_points *mp, nri_container &con) -> bool
++{
++ size_t i, len;
++ nri_mount *tmp = nullptr;
++
++ if (mp == nullptr || mp->len == 0) {
++ return true;
++ }
++ len = mp->len;
++
++ con.mounts = (nri_mount **)util_smart_calloc_s(sizeof(nri_mount *), len);
++ if (con.mounts == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ for (i = 0; i < len; i++) {
++ tmp = (nri_mount *)util_common_calloc_s(sizeof(nri_mount));
++ char path[PATH_MAX] = { 0 };
++
++ if (!util_clean_path(mp->values[i]->destination, path, sizeof(path))) {
++ ERROR("Failed to get clean path for mount dest path: %s", mp->values[i]->destination);
++ goto error_out;
++ }
++ tmp->destination = util_strdup_s(path);
++
++ if (!util_clean_path(mp->values[i]->source, path, sizeof(path))) {
++ ERROR("Failed to get clean path for mount src path: %s", mp->values[i]->source);
++ goto error_out;
++ }
++ tmp->source = util_strdup_s(path);
++
++ if (util_array_append(&(tmp->options), "rbind") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ if (util_array_append(&(tmp->options), mp->values[i]->propagation) != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++
++ if (mp->values[i]->rw) {
++ if (util_array_append(&(tmp->options), "rw") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ } else {
++ if (util_array_append(&(tmp->options), "ro") != 0) {
++ ERROR("Failed to append options");
++ goto error_out;
++ }
++ }
++
++ tmp->type = util_strdup_s("bind");
++ con.mounts[i] = tmp;
++ con.mounts_len++;
++ tmp = nullptr;
++ }
++
++ return true;
++
++error_out:
++ free_nri_mount(tmp);
++ return false;
++}
++
++// container info is incomplete because container in excution is not created
++auto ContainerToNRIByConConfig(const runtime::v1::ContainerConfig &containerConfig, nri_container &con) -> bool
++{
++ // todo: can not get container id and state from containerConfig
++ if (containerConfig.has_metadata() && !containerConfig.metadata().name().empty()) {
++ con.name = util_strdup_s(containerConfig.metadata().name().c_str());
++ }
++
++ Errors tmpError;
++
++ con.labels = Transform::ProtobufMapToJsonMapForString(containerConfig.labels(), tmpError);
++ if (con.labels == nullptr) {
++ ERROR("Failed to transform labels to nri for con : %s, : %s", con.name, tmpError.GetMessage().c_str());
++ return false;
++ }
++
++ con.annotations = Transform::ProtobufMapToJsonMapForString(containerConfig.annotations(), tmpError);
++ if (con.annotations == nullptr) {
++ ERROR("Failed to transform annotations to nri for con : %s, : %s", con.name, tmpError.GetMessage().c_str());
++ return false;
++ }
++
++ con.args = Transform::RepeatedPtrFieldToCharArray(containerConfig.args());
++ if (con.args == nullptr) {
++ ERROR("Failed to transform args to nri for con : %s, : %s", con.name, tmpError.GetMessage().c_str());
++ return false;
++ }
++ con.args_len = containerConfig.args_size();
++
++ auto envVect = CRIHelpersV1::GenerateEnvList(containerConfig.envs());
++ con.env = Transform::StringVectorToCharArray(envVect);
++ if (con.env == nullptr) {
++ ERROR("Failed to transform env to nri for con : %s", con.name);
++ return false;
++ }
++ con.env_len = containerConfig.envs_size();
++
++ if (!CRIMountArrToNRI(containerConfig, con)) {
++ ERROR("Failed to transform mounts to nri for con : %s", con.name);
++ return false;
++ }
++ return true;
++
++ // todo: can not get container hooks and pid from containerConfig
++}
++
++// container info is incomplete because container in excution is not created
++auto ContainerToNRIByID(const std::string &id, nri_container &con) -> bool
++{
++ container_t *cont = nullptr;
++ bool ret = false;
++
++ cont = containers_store_get(id.c_str());
++ if (cont == nullptr || cont->common_config == nullptr) {
++ ERROR("No such container:%s", id.c_str());
++ goto out;
++ }
++
++ con.id = util_strdup_s(id.c_str());
++
++ con.name = util_strdup_s(cont->common_config->name);
++
++ con.labels = (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string));
++ if (con.labels == nullptr) {
++ ERROR("Out of memory");
++ goto out;
++ }
++ con.annotations = (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string));
++ if (con.annotations == nullptr) {
++ ERROR("Out of memory");
++ goto out;
++ }
++ // state
++ if (dup_json_map_string_string(cont->common_config->config->labels, con.labels) != 0) {
++ ERROR("Failed to copy labels for con: %s", cont->common_config->name);
++ goto out;
++ }
++ if (dup_json_map_string_string(cont->common_config->config->annotations, con.annotations) != 0) {
++ ERROR("Failed to copy labels for con: %s", cont->common_config->name);
++ goto out;
++ }
++
++ con.args = util_copy_array_by_len(cont->common_config->args, cont->common_config->args_len);
++ if (cont->common_config->args_len != 0 && con.args == nullptr) {
++ ERROR("Failed to copy args for con: %s", cont->common_config->name);
++ goto out;
++ }
++ con.args_len = cont->common_config->args_len;
++
++ con.env = util_copy_array_by_len(cont->common_config->config->env, cont->common_config->config->env_len);
++ if (cont->common_config->config->env_len != 0 && con.env == nullptr) {
++ ERROR("Failed to copy env for con: %s", cont->common_config->name);
++ goto out;
++ }
++ con.env_len = cont->common_config->config->env_len;
++
++ if (!MountPointsElementToNRI(cont->common_config->mount_points, con)) {
++ ERROR("Failed to transform mounts to nri for con : %s", con.name);
++ goto out;
++ }
++
++ // todo: can convert hostconfig's hook_spec to nri spec
++
++ con.pid = container_state_get_pid(cont->state);
++ if (con.pid < 0) {
++ ERROR("Container %s pid %d invalid", cont->common_config->name, con.pid);
++ goto out;
++ }
++
++ con.pod_sandbox_id = util_strdup_s(cont->common_config->sandbox_info->id);
++ ret = true;
++
++out:
++ container_unref(cont);
++ return ret;
++}
++
++auto LinuxResourcesFromNRI(const nri_linux_resources *src, runtime::v1::LinuxContainerResources &resources) -> bool
++{
++ if (src == nullptr) {
++ return false;
++ }
++
++ if (src->memory != nullptr) {
++ resources.set_memory_limit_in_bytes(*src->memory->limit);
++ resources.set_oom_score_adj(DefaultOOMScoreAdj);
++ }
++
++ if (src->cpu != nullptr) {
++ if (src->cpu->shares != NULL) {
++ resources.set_cpu_shares(*src->cpu->shares);
++ }
++ if (src->cpu->quota != NULL) {
++ resources.set_cpu_quota(*src->cpu->quota);
++ }
++ if (src->cpu->period != NULL) {
++ resources.set_cpu_period(*src->cpu->period);
++ }
++
++ resources.set_cpuset_cpus(src->cpu->cpus);
++ resources.set_cpuset_mems(src->cpu->mems);
++ }
++
++ if (src->hugepage_limits != nullptr && src->hugepage_limits_len > 0) {
++ for (size_t i = 0; i < src->hugepage_limits_len; i++) {
++ if (src->hugepage_limits[i] != nullptr) {
++ auto limit = resources.add_hugepage_limits();
++ limit->set_page_size(src->hugepage_limits[i]->page_size);
++ limit->set_limit(src->hugepage_limits[i]->limit);
++ }
++ }
++ }
++
++ if (src->unified != nullptr) {
++ Transform::JsonMapToProtobufMapForString(src->unified, *resources.mutable_unified());
++ }
++
++ return true;
++}
+\ No newline at end of file
+diff --git a/src/daemon/common/nri/nri_convert.h b/src/daemon/common/nri/nri_convert.h
+index 883f7c41..c04b14e4 100644
+--- a/src/daemon/common/nri/nri_convert.h
++++ b/src/daemon/common/nri/nri_convert.h
+@@ -27,10 +27,11 @@
+ #include "sandbox.h"
+ #include "api_v1.pb.h"
+
+-auto PodSandboxToNRI(const std::shared_ptr<const sandbox::Sandbox> &sandbox, nri_pod_sandbox *pod) -> bool;
+-auto ContainerToNRIByConConfig(const runtime::v1::ContainerConfig &containerConfig, nri_container *con) -> bool;
+-auto ContainerToNRIByID(const std::string &id, nri_container *con) -> bool;
+-auto PodSandboxesToNRI(const std::vector<std::unique_ptr<sandbox::Sandbox>> &arrs, nri_pod_sandbox **pod, int pod_len) -> bool;
++auto PodSandboxToNRI(const std::shared_ptr<const sandbox::Sandbox> &sandbox, nri_pod_sandbox &pod) -> bool;
++auto ContainerToNRIByConConfig(const runtime::v1::ContainerConfig &containerConfig, nri_container &con) -> bool;
++auto ContainerToNRIByID(const std::string &id, nri_container &con) -> bool;
++auto PodSandboxesToNRI(const std::vector<std::unique_ptr<sandbox::Sandbox>> &arrs, nri_pod_sandbox **pod,
++ int pod_len) -> bool;
+
+ auto LinuxResourcesFromNRI(const nri_linux_resources *src, runtime::v1::LinuxContainerResources &resources) -> bool;
+ #endif // DAEMON_COMMON_NRI_NRI_CONVERT_H
+diff --git a/src/daemon/common/nri/nri_spec.c b/src/daemon/common/nri/nri_spec.c
+new file mode 100644
+index 00000000..855fe3b3
+--- /dev/null
++++ b/src/daemon/common/nri/nri_spec.c
+@@ -0,0 +1,602 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: zhongtao
++ * Create: 2024-07-17
++ * Description: provide nri oci functions
++ *********************************************************************************/
++
++#include "nri_spec.h"
++
++#include <isula_libutils/log.h>
++
++#include "map.h"
++#include "utils.h"
++#include "utils_string.h"
++#include "nri_utils.h"
++#include "specs_api.h"
++#include "sysinfo.h"
++#include "verify.h"
++#include "specs_extend.h"
++
++static defs_hook *nri_hook_to_oci(const nri_hook *h)
++{
++ defs_hook *oci_hook = NULL;
++
++ if (h == NULL) {
++ return NULL;
++ }
++
++ oci_hook = util_common_calloc_s(sizeof(*oci_hook));
++ if (oci_hook == NULL) {
++ ERROR("Out of memory");
++ return NULL;
++ }
++
++ oci_hook->path = util_strdup_s(h->path);
++ if (h->args_len != 0) {
++ oci_hook->args = util_copy_array_by_len(h->args, h->args_len);
++ if (oci_hook->args == NULL) {
++ ERROR("Failed to copy args");
++ goto error_out;
++ }
++ oci_hook->args_len = h->args_len;
++ }
++ if (h->env_len != 0) {
++ oci_hook->env = util_copy_array_by_len(h->env, h->env_len);
++ if (oci_hook->env == NULL) {
++ ERROR("Failed to copy env");
++ goto error_out;
++ }
++ oci_hook->env_len = h->env_len;
++ }
++ if (h->timeout != NULL) {
++ oci_hook->timeout = *(h->timeout);
++ }
++ return oci_hook;
++
++error_out:
++ free_defs_hook(oci_hook);
++ return NULL;
++}
++
++static defs_device *nri_device_to_oci(nri_linux_device *dev)
++{
++ if (dev == NULL) {
++ return NULL;
++ }
++
++ defs_device *oci_dev = util_common_calloc_s(sizeof(defs_device));
++ if (oci_dev == NULL) {
++ ERROR("Out of memory");
++ return NULL;
++ }
++
++ oci_dev->path = util_strdup_s(dev->path);
++ oci_dev->type = util_strdup_s(dev->type);
++ oci_dev->major = dev->major;
++ oci_dev->minor = dev->minor;
++ if (dev->file_mode != NULL) {
++ oci_dev->file_mode = *dev->file_mode;
++ }
++ if (dev->uid != NULL) {
++ oci_dev->uid = *dev->uid;
++ }
++ if (dev->gid != NULL) {
++ oci_dev->gid = *dev->gid;
++ }
++
++ return oci_dev;
++}
++
++static defs_mount *nri_mount_to_oci(nri_mount *mount)
++{
++ if (mount == NULL) {
++ return NULL;
++ }
++
++ defs_mount *oci_mount = util_common_calloc_s(sizeof(defs_mount));
++ if (oci_mount == NULL) {
++ ERROR("Out of memory");
++ return NULL;
++ }
++
++ oci_mount->destination = util_strdup_s(mount->destination);
++ oci_mount->type = util_strdup_s(mount->type);
++ oci_mount->source = util_strdup_s(mount->source);
++ if (mount->options_len != 0) {
++ oci_mount->options = util_copy_array_by_len(mount->options, mount->options_len);
++ if (oci_mount->options == NULL) {
++ ERROR("Failed to copy options");
++ free_defs_mount(oci_mount);
++ return NULL;
++ }
++ oci_mount->options_len = mount->options_len;
++ }
++
++ return oci_mount;
++}
++
++static int nri_adjust_annotation(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ int ret = -1;
++ size_t i;
++
++ if (adjust == NULL || adjust->annotations == NULL || adjust->annotations->len == 0) {
++ return 0;
++ }
++
++ if (make_sure_oci_spec_annotations(oci_spec) != 0) {
++ ERROR("Failed to make sure oci spec annotations");
++ return -1;
++ }
++
++ json_map_string_string *cleard = (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string));
++ if (cleard == NULL) {
++ ERROR("Out of memory");
++ return -1;
++ }
++
++ map_t *del = map_new(MAP_STR_STR, MAP_DEFAULT_CMP_FUNC, MAP_DEFAULT_FREE_FUNC);
++ if (del == NULL) {
++ ERROR("Out of memory");
++ goto free_out;
++ }
++
++ for (i = 0; i < adjust->annotations->len; i++) {
++ __isula_auto_free char *out = NULL;
++ if (is_marked_for_removal(adjust->annotations->keys[i], &out)) {
++ if (!map_insert(del, out, "")) {
++ ERROR("Failed to insert del map");
++ goto free_out;
++ }
++ continue;
++ }
++ if (append_json_map_string_string(cleard, adjust->annotations->keys[i],
++ adjust->annotations->values[i]) != 0) {
++ ERROR("Failed to append annotation");
++ goto free_out;
++ }
++ }
++
++ for (i = 0; i < oci_spec->annotations->len; i++) {
++ if (map_search(del, oci_spec->annotations->keys[i]) != NULL) {
++ continue;
++ }
++ append_json_map_string_string(cleard, oci_spec->annotations->keys[i],
++ oci_spec->annotations->values[i]);
++ }
++
++ free_json_map_string_string(oci_spec->annotations);
++ oci_spec->annotations = cleard;
++ ret = 0;
++
++free_out:
++ free_json_map_string_string(cleard);
++ map_free(del);
++ return ret;
++}
++
++static void nri_key_value_map_kvfree(void *key, void *value)
++{
++ free(key);
++
++ // no need to free nri_key_value
++ // nri_key_value *value will be free in nri_container_adjustment *adjust
++}
++
++
++static int nri_adjust_env(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ int ret = -1;
++ size_t i;
++ char **old_env = NULL;
++ size_t old_env_len = 0;
++ __isula_auto_array_t char **adjust_env = NULL;
++ size_t adjust_env_len = 0;
++
++ if (adjust->env == NULL || adjust->env_len == 0) {
++ return 0;
++ }
++
++ map_t *mod = map_new(MAP_STR_PTR, MAP_DEFAULT_CMP_FUNC, nri_key_value_map_kvfree);
++ if (mod == NULL) {
++ ERROR("Out of memory");
++ goto free_out;
++ }
++
++ for (i = 0; i < adjust->env_len; i++) {
++ nri_key_value *e = adjust->env[i];
++ char *out = NULL;
++ (void)is_marked_for_removal(e->key, &out);
++
++ if (!map_insert(mod, out, e) == false) {
++ ERROR("Failed to insert mod map");
++ goto free_out;
++ }
++ }
++
++ if (map_size(mod) <= 0 || oci_spec == NULL || oci_spec->process == NULL) {
++ ret = 0;
++ goto free_out;
++ }
++
++ // modify existing environment
++ old_env = oci_spec->process->env;
++ old_env_len = oci_spec->process->env_len;
++ oci_spec->process->env = NULL;
++ oci_spec->process->env_len = 0;
++
++ for (i = 0; i < old_env_len; i++) {
++ __isula_auto_array_t char **envArr = util_string_split_n(old_env[i], '=', 2);
++ if (envArr == NULL) {
++ continue;
++ }
++
++ nri_key_value *target = map_search(mod, envArr[0]);
++ if (target != NULL) {
++ __isula_auto_free char *out = NULL;
++ if (!is_marked_for_removal(envArr[0], &out)) {
++ // If not marked for removal, append modified value
++ __isula_auto_free char *tmp_str = util_string_append(target->key, "=");
++ __isula_auto_free char *final_str = util_string_append(tmp_str, target->value);
++
++ if (util_array_append(&adjust_env, final_str) != 0) {
++ ERROR("Failed to append env");
++ goto free_out;
++ }
++ adjust_env_len++;
++ continue;
++ }
++ }
++ // If not found in mod map, append original value
++ if (util_array_append(&adjust_env, old_env[i]) != 0) {
++ ERROR("Failed to append env");
++ goto free_out;
++ }
++ adjust_env_len++;
++ }
++
++ ret = 0;
++free_out:
++ if (merge_env(oci_spec, (const char **)adjust_env, adjust_env_len) != 0) {
++ ERROR("Failed to merge env");
++ goto free_out;
++ }
++ for (i = 0; i < old_env_len; i++) {
++ free(old_env[i]);
++ }
++ free(old_env);
++ map_free(mod);
++ return ret;
++}
++
++static int nri_adjust_hooks(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ if (adjust->hooks == NULL) {
++ return 0;
++ }
++
++ size_t i;
++ int ret = 0;
++
++ if (make_sure_oci_spec_hooks(oci_spec) != 0) {
++ ERROR("Failed to make sure oci spec hooks");
++ return -1;
++ }
++
++ // todo: change to macro definition function call
++ for (i = 0; i < adjust->hooks->prestart_len; i++) {
++ defs_hook *oci_hook = nri_hook_to_oci(adjust->hooks->prestart[i]);
++ ret = spec_add_prestart_hook(oci_spec, oci_hook);
++ if (ret != 0) {
++ ERROR("Failed add hook %s", adjust->hooks->prestart[i]->path);
++ free_defs_hook(oci_hook);
++ return -1;
++ }
++ }
++
++ for (i = 0; i < adjust->hooks->poststart_len; i++) {
++ defs_hook *oci_hook = nri_hook_to_oci(adjust->hooks->poststart[i]);
++ ret = spec_add_poststart_hook(oci_spec, oci_hook);
++ if (ret != 0) {
++ ERROR("Failed add hook %s", adjust->hooks->poststart[i]->path);
++ free_defs_hook(oci_hook);
++ return -1;
++ }
++ }
++
++ for (i = 0; i < adjust->hooks->poststop_len; i++) {
++ defs_hook *oci_hook = nri_hook_to_oci(adjust->hooks->poststop[i]);
++ ret = spec_add_poststop_hook(oci_spec, oci_hook);
++ if (ret != 0) {
++ ERROR("Failed add hook %s", adjust->hooks->poststop[i]->path);
++ free_defs_hook(oci_hook);
++ return -1;
++ }
++ }
++ /*
++ * The OCI being used by the iSulad not supportes
++ * createRuntime/createContainer/startContainer currently.
++ */
++
++ return ret;
++}
++
++static int nri_adjust_devices(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ if (adjust->linux == NULL || adjust->linux->devices == NULL || adjust->linux->devices_len == 0) {
++ return 0;
++ }
++
++ size_t i;
++
++ for (i = 0; i < adjust->linux->devices_len; i++) {
++ nri_linux_device *dev = adjust->linux->devices[i];
++ if (spec_add_device(oci_spec, nri_device_to_oci(dev)) != 0) {
++ ERROR("Failed to add device %s", dev->path);
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++static int nri_adjust_cgroup_path(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ if (adjust->linux == NULL || adjust->linux->cgroups_path == NULL) {
++ return 0;
++ }
++
++ free(oci_spec->linux->cgroups_path);
++ oci_spec->linux->cgroups_path = util_strdup_s(adjust->linux->cgroups_path);
++
++ return 0;
++}
++
++static void nri_adjust_cpu_memory(nri_linux_resources *resource, oci_runtime_spec *oci_spec)
++{
++ if (resource->cpu == NULL) {
++ return;
++ }
++ if (make_sure_oci_spec_linux_resources_cpu(oci_spec) != 0) {
++ ERROR("Failed to make sure oci spec linux resources cpu");
++ return;
++ }
++ if (resource->cpu->shares != NULL) {
++ oci_spec->linux->resources->cpu->shares = *resource->cpu->shares;
++ }
++ if (resource->cpu->quota != NULL) {
++ oci_spec->linux->resources->cpu->quota = *resource->cpu->quota;
++ }
++ if (resource->cpu->period != NULL) {
++ oci_spec->linux->resources->cpu->period = *resource->cpu->period;
++ }
++ if (resource->cpu->realtime_runtime != NULL) {
++ oci_spec->linux->resources->cpu->realtime_runtime = *resource->cpu->realtime_runtime;
++ }
++ if (resource->cpu->realtime_period != NULL) {
++ oci_spec->linux->resources->cpu->realtime_period = *resource->cpu->realtime_period;
++ }
++}
++
++static void nri_adjust_memory_resource(nri_linux_resources *resource, oci_runtime_spec *oci_spec)
++{
++ if (resource->memory == NULL) {
++ return;
++ }
++
++ if (make_sure_oci_spec_linux_resources_mem(oci_spec) != 0) {
++ ERROR("Failed to make sure oci spec linux resources memory");
++ return;
++ }
++ if (resource->memory->limit != NULL) {
++ oci_spec->linux->resources->memory->limit = *resource->memory->limit;
++ }
++ if (resource->memory->reservation != NULL) {
++ oci_spec->linux->resources->memory->reservation = *resource->memory->reservation;
++ }
++ if (resource->memory->swap != NULL) {
++ oci_spec->linux->resources->memory->swap = *resource->memory->swap;
++ }
++ if (resource->memory->kernel != NULL) {
++ oci_spec->linux->resources->memory->kernel = *resource->memory->kernel;
++ }
++ if (resource->memory->kernel_tcp != NULL) {
++ oci_spec->linux->resources->memory->kernel_tcp = *resource->memory->kernel_tcp;
++ }
++ if (resource->memory->swappiness != NULL) {
++ oci_spec->linux->resources->memory->swappiness = *resource->memory->swappiness;
++ }
++ if (resource->memory->disable_oom_killer != NULL) {
++ oci_spec->linux->resources->memory->disable_oom_killer = *resource->memory->disable_oom_killer;
++ }
++}
++
++static int nri_adjust_hugepage_resource(nri_linux_resources *resource, oci_runtime_spec *oci_spec)
++{
++ size_t i;
++ if (resource->hugepage_limits != NULL) {
++ for (i = 0; i < resource->hugepage_limits_len; i++) {
++ nri_hugepage_limit *limit = resource->hugepage_limits[i];
++ if (limit->page_size != NULL) {
++ if (spec_add_linux_resources_hugepage_limit(oci_spec, limit->page_size, limit->limit) != 0) {
++ ERROR("Failed to add hugepage limit");
++ return -1;
++ }
++ }
++ }
++ }
++ return 0;
++}
++
++static int nri_adjust_unified_resource(nri_linux_resources *resource, oci_runtime_spec *oci_spec)
++{
++ size_t i;
++ if (resource->unified != NULL) {
++ for (i = 0; i < resource->unified->len; i++) {
++ if (append_json_map_string_string(oci_spec->linux->resources->unified, resource->unified->keys[i],
++ resource->unified->values[i]) != 0) {
++ ERROR("Failed to append unified resource");
++ return -1;
++ }
++ }
++ }
++ return 0;
++}
++
++static int nri_adjust_resources(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ if (adjust->linux == NULL || adjust->linux->resources == NULL) {
++ return 0;
++ }
++
++ nri_linux_resources *resource = adjust->linux->resources;
++
++ nri_adjust_memory_resource(resource, oci_spec);
++ nri_adjust_cpu_memory(resource, oci_spec);
++
++ if (nri_adjust_hugepage_resource(resource, oci_spec) != 0) {
++ ERROR("Failed to adjust hugepage resource");
++ return -1;
++ }
++
++ if (nri_adjust_unified_resource(resource, oci_spec) != 0) {
++ ERROR("Failed to adjust unified resource");
++ return -1;
++ }
++
++ return 0;
++}
++
++static int nri_adjust_mounts(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ if (adjust->mounts == NULL || adjust->mounts_len == 0) {
++ return 0;
++ }
++
++ size_t i;
++ for (i = 0; i < adjust->mounts_len; i++) {
++ nri_mount *mount = adjust->mounts[i];
++ defs_mount *oci_mount = nri_mount_to_oci(mount);
++ if (oci_mount == NULL) {
++ ERROR("Failed to convert nri mount to oci mount");
++ return -1;
++ }
++ if (spec_add_mount(oci_spec, oci_mount) != 0) {
++ ERROR("Failed to add mount");
++ free_defs_mount(oci_mount);
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++static int nri_adjust_rlimit(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ if (adjust->rlimits == NULL || adjust->rlimits_len == 0) {
++ return 0;
++ }
++
++ size_t i;
++ for (i = 0; i < adjust->rlimits_len; i++) {
++ nri_posix_rlimit *rlimit = adjust->rlimits[i];
++ if (rlimit->type == NULL) {
++ ERROR("Invalid rlimit type");
++ return -1;
++ }
++ if (spec_add_linux_resources_rlimit(oci_spec, rlimit->type, rlimit->soft, rlimit->hard) != 0) {
++ ERROR("Failed to add rlimit");
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++// todo: we do not support it blockio_class
++static int nri_adjust_blockio_class(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ if (adjust->linux == NULL || adjust->linux->resources->blockio_class == NULL) {
++ return 0;
++ }
++
++ return 0;
++}
++
++int nri_adjust_oci_spec(const nri_container_adjustment *adjust, oci_runtime_spec *oci_spec)
++{
++ if (oci_spec == NULL || adjust == NULL) {
++ ERROR("Invalid input arguments");
++ return -1;
++ }
++
++ if (nri_adjust_annotation(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust annotation in oci spec");
++ return -1;
++ }
++
++ if (nri_adjust_env(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust env in oci spec");
++ return -1;
++ }
++
++ if (nri_adjust_hooks(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust hooks in oci spec");
++ return -1;
++ }
++
++ if (nri_adjust_devices(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust devices in oci spec");
++ return -1;
++ }
++
++ if (nri_adjust_cgroup_path(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust cgroup path in oci spec");
++ return -1;
++ }
++
++ if (nri_adjust_resources(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust resources in oci spec");
++ return -1;
++ }
++
++ if (nri_adjust_blockio_class(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust blockio class in oci spec");
++ return -1;
++ }
++
++ // iSuald is not support IntelRdt
++ if (nri_adjust_mounts(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust mount in oci spec");
++ return -1;
++ }
++
++ if (nri_adjust_rlimit(adjust, oci_spec) != 0) {
++ ERROR("Failed to do nri adjust rlimit in oci spec");
++ return -1;
++ }
++
++ __isula_auto_sysinfo_t sysinfo_t *sysinfo = NULL;
++
++ sysinfo = get_sys_info(true);
++ if (sysinfo == NULL) {
++ ERROR("Failed to get system info");
++ return -1;
++ }
++
++ if (verify_container_settings(oci_spec, sysinfo) != 0) {
++ ERROR("Failed to verify oci runtime spec settings after adjust by nri");
++ return -1;
++ }
++
++ return 0;
++}
+\ No newline at end of file
+diff --git a/src/daemon/common/nri/nri_utils.c b/src/daemon/common/nri/nri_utils.c
+new file mode 100644
+index 00000000..51054e32
+--- /dev/null
++++ b/src/daemon/common/nri/nri_utils.c
+@@ -0,0 +1,520 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: zhongtao
++ * Create: 2024-07-17
++ * Description: provide nri utils functions
++ *********************************************************************************/
++
++#include "nri_utils.h"
++
++#include <isula_libutils/log.h>
++
++#include "utils.h"
++
++static bool copy_nri_hugepage_limit(const nri_hugepage_limit* src, nri_hugepage_limit** dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ *dest = (nri_hugepage_limit *)util_common_calloc_s(sizeof(nri_hugepage_limit));
++ if (*dest == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ (*dest)->limit = src->limit;
++ (*dest)->page_size = util_strdup_s(src->page_size);
++ return true;
++}
++
++static bool copy_nri_hook(const nri_hook *src, nri_hook **dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ *dest = (nri_hook *)util_common_calloc_s(sizeof(nri_hook));
++ if (dest == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (*dest)->args = util_copy_array_by_len(src->args, src->args_len);
++ (*dest)->args_len = src->args_len;
++ (*dest)->env = util_copy_array_by_len(src->env, src->env_len);
++ (*dest)->env_len = src->env_len;
++ (*dest)->path = util_strdup_s(src->path);
++ return true;
++}
++
++static bool copy_nri_linux_device_cgroup(const nri_linux_device_cgroup *src, nri_linux_device_cgroup **dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ *dest = (nri_linux_device_cgroup *)util_common_calloc_s(sizeof(nri_linux_device_cgroup));
++ if (dest == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (*dest)->allow = src->allow;
++ (*dest)->type = util_strdup_s(src->type);
++ (*dest)->major = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->major == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (*dest)->minor = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->minor == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (*dest)->access = util_strdup_s(src->access);
++ return true;
++}
++
++static bool copy_nri_linux_cpu(const nri_linux_cpu *src, nri_linux_cpu **dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ (*dest) = (nri_linux_cpu *)util_common_calloc_s(sizeof(nri_linux_cpu));
++ if ((*dest) == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (*dest)->cpus = util_strdup_s(src->cpus);
++ (*dest)->mems = util_strdup_s(src->mems);
++ if (src->period != NULL) {
++ (*dest)->period = (uint64_t *)util_common_calloc_s(sizeof(uint64_t));
++ if ((*dest)->period == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->period = *src->period;
++ }
++
++ if (src->quota != NULL) {
++ (*dest)->quota = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->quota == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->quota = *src->quota;
++ }
++
++ if (src->realtime_period != NULL) {
++ (*dest)->realtime_period = (uint64_t *)util_common_calloc_s(sizeof(uint64_t));
++ if ((*dest)->realtime_period == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->realtime_period = *src->realtime_period;
++ }
++
++ if (src->realtime_runtime != NULL) {
++ (*dest)->realtime_runtime = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->realtime_runtime == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->realtime_runtime = *src->realtime_runtime;
++ }
++
++ if (src->shares != NULL) {
++ (*dest)->shares = (uint64_t *)util_common_calloc_s(sizeof(uint64_t));
++ if ((*dest)->shares == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->shares = *src->shares;
++ }
++
++ return true;
++}
++
++static bool copy_nri_linux_memory(const nri_linux_memory *src, nri_linux_memory **dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++ *dest = (nri_linux_memory *)util_common_calloc_s(sizeof(nri_linux_memory));
++ if (dest == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ if (src->limit != NULL) {
++ (*dest)->limit = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->limit == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->limit = *src->limit;
++ }
++
++ if (src->reservation != NULL) {
++ (*dest)->reservation = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->reservation == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->reservation = *src->reservation;
++ }
++
++ if (src->swap != NULL) {
++ (*dest)->swap = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->swap == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->swap = *src->swap;
++ }
++
++ if (src->kernel != NULL) {
++ (*dest)->kernel = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->kernel == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->kernel = *src->kernel;
++ }
++
++
++ if (src->kernel_tcp != NULL) {
++ (*dest)->kernel_tcp = (int64_t *)util_common_calloc_s(sizeof(int64_t));
++ if ((*dest)->kernel_tcp == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->kernel_tcp = *src->kernel_tcp;
++ }
++
++ if (src->swappiness != NULL) {
++ (*dest)->swappiness = (uint64_t *)util_common_calloc_s(sizeof(uint64_t));
++ if ((*dest)->swappiness == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->swappiness = *src->swappiness;
++ }
++
++ if (src->disable_oom_killer != NULL) {
++ (*dest)->disable_oom_killer = (uint8_t *)util_common_calloc_s(sizeof(uint8_t));
++ if ((*dest)->disable_oom_killer == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->disable_oom_killer = *src->disable_oom_killer;
++ }
++
++ if (src->use_hierarchy != NULL) {
++ (*dest)->use_hierarchy = (uint8_t *)util_common_calloc_s(sizeof(uint8_t));
++ if ((*dest)->use_hierarchy == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ *(*dest)->use_hierarchy = *src->use_hierarchy;
++ }
++ return true;
++}
++
++bool is_marked_for_removal(const char* key, char **out)
++{
++ if (key == NULL || out == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ if (!util_has_prefix(key, "-")) {
++ *out = (char*)key;
++ return false;
++ }
++
++ *out = util_sub_string(key, 1, strlen(key) - 1);
++ if (*out == NULL) {
++ ERROR("Failed to sub string");
++ return false;
++ }
++
++ return true;
++}
++
++bool copy_nri_mount(const nri_mount *src, nri_mount **dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++ *dest = (nri_mount *)util_common_calloc_s(sizeof(nri_mount));
++ if (dest == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (*dest)->destination = util_strdup_s(src->destination);
++ (*dest)->options = util_copy_array_by_len(src->options, src->options_len);
++ (*dest)->options_len = src->options_len;
++ (*dest)->source = util_strdup_s(src->source);
++ (*dest)->type = util_strdup_s(src->type);
++ return true;
++}
++
++bool copy_nri_key_value(const nri_key_value *src, nri_key_value **dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++ *dest = (nri_key_value *)util_common_calloc_s(sizeof(nri_key_value));
++ if (dest == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (*dest)->key = util_strdup_s(src->key);
++ (*dest)->value = util_strdup_s(src->value);
++ return true;
++}
++
++bool copy_nri_posix_rlimit(const nri_posix_rlimit *src, nri_posix_rlimit **dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++ *dest = (nri_posix_rlimit *)util_common_calloc_s(sizeof(nri_posix_rlimit));
++ if (dest == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (*dest)->hard = src->hard;
++ (*dest)->soft = src->soft;
++ (*dest)->type = util_strdup_s(src->type);
++ return true;
++}
++
++bool copy_nri_linux_resources(const nri_linux_resources *src, nri_linux_resources **dest)
++{
++ if (src == NULL || dest == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ *dest = (nri_linux_resources *)util_common_calloc_s(sizeof(nri_linux_resources));
++ if (*dest == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ if (!init_nri_linux_resources(dest)) {
++ ERROR("Failed to init dest nri linux resources");
++ goto free_out;
++ }
++
++ if (!copy_nri_linux_cpu(src->cpu, &(*dest)->cpu)) {
++ ERROR("Failed to copy nri_linux_cpu");
++ goto free_out;
++ }
++
++ if (!copy_nri_linux_memory(src->memory, &(*dest)->memory)) {
++ ERROR("Failed to copy nri_linux_memory");
++ goto free_out;
++ }
++
++ (*dest)->blockio_class = util_strdup_s(src->blockio_class);
++ (*dest)->rdt_class = util_strdup_s(src->rdt_class);
++
++ if (src->hugepage_limits_len > 0) {
++ (*dest)->hugepage_limits = (nri_hugepage_limit**)util_smart_calloc_s(sizeof(nri_hugepage_limit*),
++ src->hugepage_limits_len);
++ for (size_t i = 0; i < src->hugepage_limits_len; ++i) {
++ if (!copy_nri_hugepage_limit(src->hugepage_limits[i], &((*dest)->hugepage_limits[i]))) {
++ ERROR("Failed to copy nri_hugepage_limit");
++ goto free_out;
++ }
++ }
++ }
++
++ if (src->devices_len > 0) {
++ (*dest)->devices = (nri_linux_device_cgroup**)util_smart_calloc_s(sizeof(nri_linux_device_cgroup*), src->devices_len);
++ for (size_t i = 0; i < src->devices_len; ++i) {
++ if (!copy_nri_linux_device_cgroup(src->devices[i], &((*dest)->devices[i]))) {
++ ERROR("Failed to copy nri_linux_device_cgroup");
++ goto free_out;
++ }
++ }
++ }
++
++ if (dup_json_map_string_string(src->unified, (*dest)->unified)) {
++ ERROR("Failed to copy json_map_string_string");
++ goto free_out;
++ }
++
++ return true;
++
++free_out:
++ free_nri_linux_resources(*dest);
++ return false;
++}
++
++bool merge_nri_hooks(nri_hook **targetHooks, size_t targetSize, const nri_hook **sourceHooks,
++ size_t sourceLen)
++{
++ size_t oldSize = targetSize * sizeof(nri_hook *);
++ size_t newSize = oldSize + sourceLen * sizeof(nri_hook *);
++
++ if (sourceHooks == NULL || targetHooks == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ if (util_mem_realloc((void**)&targetHooks, newSize, (void**)&targetHooks, oldSize) != 0) {
++ ERROR("Failed to realloc and assign hook array");
++ return false;
++ }
++
++ for (size_t i = 0; i < sourceLen; i++) {
++ if (!copy_nri_hook(sourceHooks[i], &targetHooks[targetSize++])) {
++ ERROR("Failed to copy hook");
++ return false;
++ }
++ }
++
++ return true;
++}
++
++bool init_nri_container_adjust(nri_container_adjustment **adjust)
++{
++ if (adjust == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ *adjust = (nri_container_adjustment *)util_common_calloc_s(sizeof(nri_container_adjustment));
++ if (*adjust == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ (*adjust)->annotations = (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string));
++ if ((*adjust)->annotations == NULL) {
++ goto free_out;
++ }
++
++ (*adjust)->env = (nri_key_value **)util_common_calloc_s(sizeof(nri_key_value *));
++ if ((*adjust)->env == NULL) {
++ goto free_out;
++ }
++ (*adjust)->env_len = 0;
++
++ (*adjust)->hooks = (nri_hooks *)util_common_calloc_s(sizeof(nri_hooks));
++ if ((*adjust)->hooks == NULL) {
++ goto free_out;
++ }
++
++ (*adjust)->linux = (nri_linux_container_adjustment *)util_common_calloc_s(sizeof(nri_linux_container_adjustment));
++ if ((*adjust)->linux == NULL) {
++ goto free_out;
++ }
++
++ (*adjust)->linux->resources = (nri_linux_resources *)util_common_calloc_s(sizeof(nri_linux_resources));
++ if ((*adjust)->linux->resources == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ (*adjust)->mounts = (nri_mount **)util_common_calloc_s(sizeof(nri_mount *));
++ if ((*adjust)->mounts == NULL) {
++ goto free_out;
++ }
++ (*adjust)->mounts_len = 0;
++
++ (*adjust)->rlimits = (nri_posix_rlimit **)util_common_calloc_s(sizeof(nri_posix_rlimit *));
++ if ((*adjust)->rlimits == NULL) {
++ goto free_out;
++ }
++ (*adjust)->rlimits_len = 0;
++
++ return true;
++
++free_out:
++ ERROR("Out of memory");
++ free_nri_container_adjustment(*adjust);
++ return false;
++}
++
++bool init_nri_container_update(nri_container_update **update, const char *id, uint8_t ignore_failure)
++{
++ if (update == NULL || id == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ *update = (nri_container_update *)util_common_calloc_s(sizeof(nri_container_update));
++ if (*update == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ (*update)->container_id = util_strdup_s(id);
++ (*update)->linux = (nri_linux_container_update *)util_common_calloc_s(sizeof(nri_linux_container_update));
++ if ((*update)->linux == NULL) {
++ goto free_out;
++ }
++
++ (*update)->ignore_failure = ignore_failure;
++ return true;
++
++free_out:
++ ERROR("Out of memory");
++ free_nri_container_update(*update);
++ return false;
++}
++
++bool init_nri_linux_resources(nri_linux_resources **resources)
++{
++ if (resources == NULL) {
++ ERROR("Invalid input arguments");
++ return false;
++ }
++
++ *resources = (nri_linux_resources *)util_common_calloc_s(sizeof(nri_linux_resources));
++ if (*resources == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++
++ (*resources)->cpu = (nri_linux_cpu *)util_common_calloc_s(sizeof(nri_linux_cpu));
++ if ((*resources)->cpu == NULL) {
++ goto free_out;
++ }
++
++ (*resources)->memory = (nri_linux_memory *)util_common_calloc_s(sizeof(nri_linux_memory));
++ if ((*resources)->memory == NULL) {
++ goto free_out;
++ }
++
++ (*resources)->unified = (json_map_string_string *)util_common_calloc_s(sizeof(json_map_string_string));
++ if ((*resources)->unified == NULL) {
++ goto free_out;
++ }
++ return true;
++
++free_out:
++ ERROR("Out of memory");
++ free_nri_linux_resources(*resources);
++ return false;
++}
+\ No newline at end of file
+diff --git a/src/daemon/common/nri/nri_utils.h b/src/daemon/common/nri/nri_utils.h
+index 3aa50ae4..7bf54a71 100644
+--- a/src/daemon/common/nri/nri_utils.h
++++ b/src/daemon/common/nri/nri_utils.h
+@@ -51,14 +51,13 @@ typedef enum {
+
+ bool copy_nri_mount(const nri_mount *src, nri_mount **dest);
+ bool copy_nri_key_value(const nri_key_value *src, nri_key_value **dest);
+-bool copy_nri_hook(const nri_hook *src, nri_hook **dest);
+ bool copy_nri_posix_rlimit(const nri_posix_rlimit *src, nri_posix_rlimit **dest);
+ bool copy_nri_linux_resources(const nri_linux_resources *src, nri_linux_resources **dest);
+-bool copy_nri_linux_cpu(const nri_linux_cpu *src, nri_linux_cpu **dest);
+
+ bool is_marked_for_removal(const char* key, char **out);
+
+-bool realloc_and_copy_nri_hooks(nri_hook **targetHooks, size_t targetSize, const nri_hook **sourceHooks, size_t sourceLen);
++bool merge_nri_hooks(nri_hook **targetHooks, size_t targetSize, const nri_hook **sourceHooks,
++ size_t sourceLen);
+
+ bool init_nri_container_adjust(nri_container_adjustment **adjust);
+ bool init_nri_container_update(nri_container_update **update, const char *id, uint8_t ignore_failure);
+diff --git a/src/daemon/config/isulad_config.c b/src/daemon/config/isulad_config.c
+index d7b54498..9ba1c8a0 100644
+--- a/src/daemon/config/isulad_config.c
++++ b/src/daemon/config/isulad_config.c
+@@ -456,6 +456,175 @@ out:
+ (void)isulad_server_conf_unlock();
+ return path;
+ }
++
++#ifdef ENABLE_NRI
++bool conf_get_nri_support(void)
++{
++ bool nri_support = false;
++ struct service_arguments *conf = NULL;
++
++ if (isulad_server_conf_rdlock() != 0) {
++ return false;
++ }
++
++ conf = conf_get_server_conf();
++ if (conf == NULL || conf->json_confs == NULL) {
++ goto out;
++ }
++
++ nri_support = conf->json_confs->nri_support;
++
++out:
++ (void)isulad_server_conf_unlock();
++ return nri_support;
++}
++
++bool conf_get_nri_external_support(void)
++{
++ bool nri_external_support = false;
++ struct service_arguments *conf = NULL;
++
++ if (isulad_server_conf_rdlock() != 0) {
++ return false;
++ }
++
++ conf = conf_get_server_conf();
++ if (conf == NULL || conf->json_confs == NULL) {
++ goto out;
++ }
++
++ nri_external_support = conf->json_confs->disable_connections;
++
++out:
++ (void)isulad_server_conf_unlock();
++ return !nri_external_support;
++}
++
++char *conf_get_nri_plugin_config_path(void)
++{
++ char *path = NULL;
++ struct service_arguments *conf = NULL;
++
++ if (isulad_server_conf_rdlock() != 0) {
++ return NULL;
++ }
++
++ conf = conf_get_server_conf();
++ if (conf == NULL || conf->json_confs == NULL || conf->json_confs->plugin_config_path == NULL) {
++ path = util_strdup_s(DEFAULT_PLUGIN_CONFIG_PATH);
++ goto out;
++ }
++
++ path = util_strdup_s(conf->json_confs->plugin_config_path);
++
++out:
++ (void)isulad_server_conf_unlock();
++ return path;
++}
++
++char *conf_get_nri_plugin_path(void)
++{
++ char *path = NULL;
++ struct service_arguments *conf = NULL;
++
++ if (isulad_server_conf_rdlock() != 0) {
++ return NULL;
++ }
++
++ conf = conf_get_server_conf();
++ if (conf == NULL || conf->json_confs == NULL) {
++ goto out;
++ }
++
++ if (conf->json_confs->plugin_path == NULL) {
++ path = util_strdup_s(DEFAULT_PLUGIN_PATH);
++ goto out;
++ }
++
++ path = util_strdup_s(conf->json_confs->plugin_path);
++
++out:
++ (void)isulad_server_conf_unlock();
++ return path;
++}
++
++char *conf_get_socket_path(void)
++{
++ char *path = NULL;
++ struct service_arguments *conf = NULL;
++
++ if (isulad_server_conf_rdlock() != 0) {
++ return NULL;
++ }
++
++ conf = conf_get_server_conf();
++ if (conf == NULL || conf->json_confs == NULL) {
++ goto out;
++ }
++
++ if (conf->json_confs->nri_socket_path == NULL) {
++ path = util_strdup_s(DEFAULT_SOCKET_PATH);
++ goto out;
++ }
++
++ path = util_strdup_s(conf->json_confs->nri_socket_path);
++
++out:
++ (void)isulad_server_conf_unlock();
++ return path;
++}
++
++uint64_t conf_get_nri_plugin_registration_timeout(void)
++{
++ uint64_t timeout = false;
++ struct service_arguments *conf = NULL;
++
++ if (isulad_server_conf_rdlock() != 0) {
++ return false;
++ }
++
++ conf = conf_get_server_conf();
++ if (conf == NULL || conf->json_confs == NULL) {
++ goto out;
++ }
++
++ if (conf->json_confs->plugin_registration_timeout == 0) {
++ timeout = DEFAULT_PLUGIN_REGISTRY_TIMEOUT;
++ goto out;
++ }
++
++ timeout = conf->json_confs->plugin_registration_timeout;
++
++out:
++ (void)isulad_server_conf_unlock();
++ return timeout;
++}
++uint64_t conf_get_nri_plugin_requst_timeout(void)
++{
++ uint64_t timeout = false;
++ struct service_arguments *conf = NULL;
++
++ if (isulad_server_conf_rdlock() != 0) {
++ return false;
++ }
++
++ conf = conf_get_server_conf();
++ if (conf == NULL || conf->json_confs == NULL) {
++ goto out;
++ }
++
++ if (conf->json_confs->plugin_requst_timeout == 0) {
++ timeout = DEFAULT_PLUGIN_REQUST_TIMEOUT;
++ goto out;
++ }
++
++ timeout = conf->json_confs->plugin_requst_timeout;
++
++out:
++ (void)isulad_server_conf_unlock();
++ return timeout;
++}
++#endif
+ #endif
+
+ /* conf get isulad rootdir */
+@@ -1762,6 +1931,15 @@ int merge_json_confs_into_global(struct service_arguments *args)
+ tmp_json_confs->cri_sandboxers = NULL;
+ #endif
+ args->json_confs->enable_cri_v1 = tmp_json_confs->enable_cri_v1;
++#ifdef ENABLE_NRI
++ args->json_confs->nri_support = tmp_json_confs->nri_support;
++ args->json_confs->disable_connections = tmp_json_confs->disable_connections;
++ override_string_value(&args->json_confs->plugin_config_path, &tmp_json_confs->plugin_config_path);
++ override_string_value(&args->json_confs->plugin_path, &tmp_json_confs->plugin_path);
++ args->json_confs->plugin_registration_timeout = tmp_json_confs->plugin_registration_timeout;
++ args->json_confs->plugin_requst_timeout = tmp_json_confs->plugin_requst_timeout;
++ override_string_value(&args->json_confs->nri_socket_path, &tmp_json_confs->nri_socket_path);
++#endif
+ args->json_confs->enable_pod_events = tmp_json_confs->enable_pod_events;
+ #endif
+
+diff --git a/src/daemon/modules/api/specs_api.h b/src/daemon/modules/api/specs_api.h
+index 6a1cd776..d5ea0c7c 100644
+--- a/src/daemon/modules/api/specs_api.h
++++ b/src/daemon/modules/api/specs_api.h
+@@ -76,6 +76,11 @@ int spec_add_linux_resources_hugepage_limit(oci_runtime_spec *oci_spec, const ch
+ int spec_add_linux_resources_rlimit(oci_runtime_spec *oci_spec, const char *type, uint64_t hard, uint64_t soft);
+ #endif /* ENABLE_NRI */
+
++int make_sure_oci_spec_annotations(oci_runtime_spec *oci_spec);
++int make_sure_oci_spec_linux_resources_cpu(oci_runtime_spec *oci_spec);
++int make_sure_oci_spec_linux_resources_mem(oci_runtime_spec *oci_spec);
++int make_sure_oci_spec_hooks(oci_runtime_spec *oci_spec);
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff --git a/src/daemon/modules/spec/specs.c b/src/daemon/modules/spec/specs.c
+index 1fd9e5a8..002431d8 100644
+--- a/src/daemon/modules/spec/specs.c
++++ b/src/daemon/modules/spec/specs.c
+@@ -87,8 +87,11 @@ struct readonly_default_oci_spec {
+
+ static struct readonly_default_oci_spec g_rdspec;
+
+-static int make_sure_oci_spec_annotations(oci_runtime_spec *oci_spec)
++int make_sure_oci_spec_annotations(oci_runtime_spec *oci_spec)
+ {
++ if (oci_spec == NULL) {
++ return -1;
++ }
+ if (oci_spec->annotations == NULL) {
+ oci_spec->annotations = util_common_calloc_s(sizeof(json_map_string_string));
+ if (oci_spec->annotations == NULL) {
+@@ -464,10 +467,14 @@ out:
+ return ret;
+ }
+
+-static int make_sure_oci_spec_linux_resources_cpu(oci_runtime_spec *oci_spec)
++int make_sure_oci_spec_linux_resources_cpu(oci_runtime_spec *oci_spec)
+ {
+ int ret = 0;
+
++ if (oci_spec == NULL) {
++ return -1;
++ }
++
+ ret = make_sure_oci_spec_linux_resources(oci_spec);
+ if (ret < 0) {
+ return -1;
+@@ -589,10 +596,14 @@ out:
+ return ret;
+ }
+
+-static int make_sure_oci_spec_linux_resources_mem(oci_runtime_spec *oci_spec)
++int make_sure_oci_spec_linux_resources_mem(oci_runtime_spec *oci_spec)
+ {
+ int ret = 0;
+
++ if (oci_spec == NULL) {
++ return -1;
++ }
++
+ ret = make_sure_oci_spec_linux_resources(oci_spec);
+ if (ret < 0) {
+ return -1;
+@@ -731,8 +742,11 @@ out:
+ return ret;
+ }
+
+-static int make_sure_oci_spec_hooks(oci_runtime_spec *oci_spec)
++int make_sure_oci_spec_hooks(oci_runtime_spec *oci_spec)
+ {
++ if (oci_spec == NULL) {
++ return -1;
++ }
+ if (oci_spec->hooks == NULL) {
+ oci_spec->hooks = util_common_calloc_s(sizeof(oci_runtime_spec_hooks));
+ if (oci_spec->hooks == NULL) {
+@@ -2827,6 +2841,11 @@ int spec_add_linux_resources_hugepage_limit(oci_runtime_spec *oci_spec, const ch
+ int ret = 0;
+ defs_resources_hugepage_limits_element *hugepage_limit = NULL;
+
++ if (oci_spec == NULL || page_size == NULL) {
++ ERROR("Invalid arguments");
++ return -1;
++ }
++
+ ret = make_sure_oci_spec_linux_resources(oci_spec);
+ if (ret < 0) {
+ return -1;
+@@ -2859,6 +2878,11 @@ int spec_add_linux_resources_rlimit(oci_runtime_spec *oci_spec, const char *type
+ int ret = 0;
+ defs_process_rlimits_element *rlimit = NULL;
+
++ if (oci_spec == NULL || type == NULL) {
++ ERROR("Invalid arguments");
++ return -1;
++ }
++
+ ret = make_sure_oci_spec_linux_resources(oci_spec);
+ if (ret < 0) {
+ return -1;
+diff --git a/src/daemon/nri/nri_adaption.h b/src/daemon/nri/nri_adaption.h
+index 7f0640df..874662cf 100644
+--- a/src/daemon/nri/nri_adaption.h
++++ b/src/daemon/nri/nri_adaption.h
+@@ -46,7 +46,6 @@ public:
+
+ auto GetSockpath(std::vector<std::string> &paths) -> bool;
+
+- // Stop plugins.
+ auto StopPlugins() -> bool;
+
+ void RemoveClosedPlugins();
+@@ -58,19 +57,23 @@ public:
+ auto RunPodSandbox(std::shared_ptr<const sandbox::Sandbox> sandbox, Errors &error) ->bool;
+ auto StopPodSandbox(std::shared_ptr<const sandbox::Sandbox> sandbox, Errors &error) ->bool;
+ auto RemovePodSandbox(std::shared_ptr<const sandbox::Sandbox> sandbox, Errors &error) ->bool;
+- auto CreateContainer(std::shared_ptr<const sandbox::Sandbox> sandbox, const std::string &conId, const runtime::v1::ContainerConfig &containerConfig, nri_container_adjustment **adjust, Errors &error) -> bool;
+- auto PostCreateContainer(const std::string &conId, Errors &error) ->bool;
+- auto UndoCreateContainer(std::shared_ptr<const sandbox::Sandbox> sandbox, const std::string &conId, Errors &error) -> bool;
+- auto StartContainer(const std::string &conId, Errors &error) ->bool;
+- auto PostStartContainer(const std::string &conId, Errors &error) ->bool;
+- auto UpdateContainer(const std::string &conId, Errors &error) ->bool;
+- auto PostUpdateContainer(const std::string &conId, Errors &error) ->bool;
+- auto StopContainer(const std::string &conId, Errors &error) ->bool;
+- auto RemoveContainer(const std::string &conId, Errors &error) ->bool;
+- auto StateChange(nri_state_change_event *evt, Errors &error) ->bool;
+- auto updateContainers(const nri_update_containers_request *req, nri_update_containers_response **resp) ->bool;
++ auto CreateContainer(std::shared_ptr<const sandbox::Sandbox> sandbox, const std::string &conId,
++ const runtime::v1::ContainerConfig &containerConfig, nri_container_adjustment **adjust,
++ Errors &error) -> bool;
++ auto PostCreateContainer(const std::string &conId, Errors &error) -> bool;
++ auto UndoCreateContainer(std::shared_ptr<const sandbox::Sandbox> sandbox, const std::string &conId,
++ Errors &error) -> bool;
++ auto StartContainer(const std::string &conId, Errors &error) -> bool;
++ auto PostStartContainer(const std::string &conId, Errors &error) -> bool;
++ auto UpdateContainer(const std::string &conId, Errors &error) -> bool;
++ auto PostUpdateContainer(const std::string &conId, Errors &error) -> bool;
++ auto StopContainer(const std::string &conId, Errors &error) -> bool;
++ auto RemoveContainer(const std::string &conId, Errors &error) -> bool;
++ auto StateChange(nri_state_change_event *evt, Errors &error) -> bool;
++ auto updateContainers(const nri_update_containers_request *req, nri_update_containers_response **resp) -> bool;
+
+ auto NewExternalPlugin(int fd) -> bool;
++
+ private:
+ NRIAdaptation() = default;
+ NRIAdaptation(const NRIAdaptation &other) = delete;
+@@ -86,18 +89,25 @@ private:
+ auto SortPlugins() -> bool;
+ void GetClosedPlugins(std::vector<std::string> &closedPlugin);
+
+- auto IsSupport() -> bool;
++ auto ApplyUpdates(const std::vector<nri_container_update *> &update, std::vector<nri_container_update *> &failed,
++ bool getFailed, Errors &error) -> bool;
+
+- auto ApplyUpdates(const std::vector<nri_container_update *> &update, std::vector<nri_container_update *> &failed, bool getFailed,
+- Errors &error) -> bool;
++ auto IsSupport() -> bool;
+
+- auto NRIPodSandbox(const std::shared_ptr<const sandbox::Sandbox> &sandbox, Errors& error) -> std::unique_ptr<CStructWrapper<nri_pod_sandbox>>;
+- auto NRIContainerByConConfig(const std::shared_ptr<const sandbox::Sandbox> &sandbox, const runtime::v1::ContainerConfig &containerConfig, Errors& error) -> std::unique_ptr<CStructWrapper<nri_container>>;
+- auto NRIContainerByID(const std::string &id, Errors& error) -> std::unique_ptr<CStructWrapper<nri_container>>;
++ auto NRIPodSandbox(const std::shared_ptr<const sandbox::Sandbox> &sandbox,
++ Errors &error) -> std::unique_ptr<CStructWrapper<nri_pod_sandbox>>;
++ auto NRIContainerByConConfig(const std::shared_ptr<const sandbox::Sandbox> &sandbox,
++ const runtime::v1::ContainerConfig &containerConfig, Errors &error) -> std::unique_ptr<CStructWrapper<nri_container>>;
++ auto NRIContainerByID(const std::string &id, Errors &error) -> std::unique_ptr<CStructWrapper<nri_container>>;
+
+ auto GetNRIPluginConfigPath(void) -> std::string;
+ auto GetNRIPluginPath(void) -> std::string;
+ auto GetNRISockPath(void) -> std::string;
++
++ void PluginsStateChange(nri_state_change_event *evt);
++ bool PluginsCreateContainer(nri_create_container_request *req, const std::string &conId, pluginResult &result);
++ bool PluginsUpdateContainer(nri_update_container_request *req, const std::string &conId, pluginResult &result);
++
+ private:
+ RWMutex m_mutex;
+ static std::atomic<NRIAdaptation *> m_instance;
+diff --git a/src/daemon/nri/nri_helpers.cc b/src/daemon/nri/nri_helpers.cc
+new file mode 100644
+index 00000000..ff9d67c1
+--- /dev/null
++++ b/src/daemon/nri/nri_helpers.cc
+@@ -0,0 +1,93 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: zhongtao
++ * Create: 2024-07-13
++ * Description: provide nri helpers functions
++ *********************************************************************************/
++
++#include "nri_helpers.h"
++
++#include <isula_libutils/log.h>
++
++#include "utils.h"
++#include "isulad_config.h"
++
++namespace NRIHelpers {
++std::string MarkForRemoval(const std::string &key)
++{
++ return "-" + key;
++}
++
++auto GetPluginConfig(std::string &idx, std::string &name, std::string &config) -> bool
++{
++ __isula_auto_free char *plugin_path = NULL;
++
++ plugin_path = conf_get_nri_plugin_config_path();
++ if (plugin_path == NULL) {
++ return false;
++ }
++ std::string compleName = idx + "-" + name;
++ std::vector<std::string> dropIns = {
++ std::string(plugin_path) + "/" + compleName + ".conf",
++ std::string(plugin_path) + "/" + name + ".conf"
++ };
++
++ for (const std::string &path : dropIns) {
++ char buf[MAX_BUFFER_SIZE + 1] = { 0 };
++ __isula_auto_close int fd = util_open(path.c_str(), O_RDONLY, 0);
++ if (fd < 0) {
++ ERROR("Failed to open '%s'", path.c_str());
++ return false;
++ }
++ int len = util_read_nointr(fd, buf, sizeof(buf) - 1);
++ if (len < 0) {
++ SYSERROR("Failed to read nri plugin config : %s", path.c_str());
++ return false;
++ }
++ config = std::string(buf);
++ return true;
++ }
++ return true;
++}
++
++void GenerateRandomExternalName(std::string &ret)
++{
++ __isula_auto_free char *external_name = NULL;
++
++ external_name = (char *)util_smart_calloc_s(sizeof(char), (CONTAINER_ID_MAX_LEN + 1));
++ if (external_name == NULL) {
++ ERROR("Out of memory");
++ return;
++ }
++
++ if (util_generate_random_str(external_name, (size_t)CONTAINER_ID_MAX_LEN)) {
++ ERROR("Generate exec suffix failed");
++ return;
++ }
++
++ ret = std::string(external_name);
++}
++
++bool CheckPluginIndex(const std::string &idx)
++{
++ if (idx.length() != 2) {
++ ERROR("Invalid plugin index \"%s\", must be 2 digits", idx.c_str());
++ return false;
++ }
++
++ if (!std::isdigit(idx[0]) || !std::isdigit(idx[1])) {
++ ERROR("Invalid plugin index \"%s\", (not [0-9][0-9])", idx.c_str());
++ return false;
++ }
++
++ return true;
++}
++}// namespace NRIHelpers
+\ No newline at end of file
+diff --git a/src/daemon/nri/nri_helpers.h b/src/daemon/nri/nri_helpers.h
+index 06ee8419..1a2f488e 100644
+--- a/src/daemon/nri/nri_helpers.h
++++ b/src/daemon/nri/nri_helpers.h
+@@ -37,7 +37,7 @@ std::string MarkForRemoval(const std::string &key);
+
+ auto GetPluginConfig(std::string &idx, std::string &name, std::string &config) -> bool;
+
+-std::string GenerateRandomExternalName(void);
++void GenerateRandomExternalName(std::string &ret);
+
+ bool CheckPluginIndex(const std::string &idx);
+
+diff --git a/src/utils/cpputils/transform.cc b/src/utils/cpputils/transform.cc
+index 51c154fb..ba8c1f7a 100644
+--- a/src/utils/cpputils/transform.cc
++++ b/src/utils/cpputils/transform.cc
+@@ -97,7 +97,7 @@ auto RepeatedPtrFieldToCharArray(const google::protobuf::RepeatedPtrField<std::s
+ if (result == nullptr) {
+ return nullptr;
+ }
+- size_t i {};
++ size_t i = 0;
+ for (const auto &it : ptrs) {
+ result[i++] = util_strdup_s(it.c_str());
+ }
+--
+2.25.1
+