summaryrefslogtreecommitdiff
path: root/0151-sandbox-sandbox-api-update.patch
diff options
context:
space:
mode:
Diffstat (limited to '0151-sandbox-sandbox-api-update.patch')
-rw-r--r--0151-sandbox-sandbox-api-update.patch1600
1 files changed, 1600 insertions, 0 deletions
diff --git a/0151-sandbox-sandbox-api-update.patch b/0151-sandbox-sandbox-api-update.patch
new file mode 100644
index 0000000..f925ccc
--- /dev/null
+++ b/0151-sandbox-sandbox-api-update.patch
@@ -0,0 +1,1600 @@
+From b994e99a4188bef549e5fa1f944eb3546be43201 Mon Sep 17 00:00:00 2001
+From: liuxu <liuxu156@huawei.com>
+Date: Wed, 18 Sep 2024 11:40:15 +0800
+Subject: [PATCH 151/156] sandbox:sandbox api update
+
+Signed-off-by: liuxu <liuxu156@huawei.com>
+---
+ cmake/protoc.cmake | 1 +
+ src/api/services/sandbox/sandbox.proto | 107 +++---
+ .../sandbox/sandbox/types/metrics.proto | 30 ++
+ .../sandbox/sandbox/types/platform.proto | 3 +-
+ .../sandbox/sandbox/types/sandbox.proto | 15 +-
+ src/daemon/sandbox/controller/controller.h | 12 +-
+ .../sandboxer/client/grpc_sandboxer_client.cc | 111 ++----
+ .../sandboxer/client/grpc_sandboxer_client.h | 18 +-
+ .../sandboxer/sandboxer_controller.cc | 19 +-
+ .../sandboxer/sandboxer_controller.h | 9 +-
+ .../controller/shim/shim_controller.cc | 11 +-
+ .../sandbox/controller/shim/shim_controller.h | 9 +-
+ src/daemon/sandbox/sandbox.cc | 221 +++++++++++-
+ src/daemon/sandbox/sandbox.h | 24 ++
+ src/daemon/sandbox/sandbox_ops.cc | 333 ++++++++++++++----
+ src/daemon/sandbox/sandbox_task.cc | 99 ++++++
+ src/daemon/sandbox/sandbox_task.h | 48 +++
+ 17 files changed, 808 insertions(+), 262 deletions(-)
+ create mode 100644 src/api/services/sandbox/sandbox/types/metrics.proto
+ create mode 100644 src/daemon/sandbox/sandbox_task.cc
+ create mode 100644 src/daemon/sandbox/sandbox_task.h
+
+diff --git a/cmake/protoc.cmake b/cmake/protoc.cmake
+index 6e2d1b84..6343fe3e 100644
+--- a/cmake/protoc.cmake
++++ b/cmake/protoc.cmake
+@@ -72,6 +72,7 @@ if (ENABLE_CRI_API_V1 AND ENABLE_SANDBOXER)
+ PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/sandbox.proto)
+ PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/mount.proto)
+ PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/platform.proto)
++ PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/metrics.proto)
+ PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox.proto)
+ PROTOC_GRPC_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox.proto)
+ endif()
+diff --git a/src/api/services/sandbox/sandbox.proto b/src/api/services/sandbox/sandbox.proto
+index 87c7e27c..dcc78444 100644
+--- a/src/api/services/sandbox/sandbox.proto
++++ b/src/api/services/sandbox/sandbox.proto
+@@ -31,6 +31,7 @@ import "google/protobuf/timestamp.proto";
+ import "sandbox/types/sandbox.proto";
+ import "sandbox/types/mount.proto";
+ import "sandbox/types/platform.proto";
++import "sandbox/types/metrics.proto";
+
+ option go_package = "github.com/containerd/containerd/api/services/sandbox/v1;sandbox";
+
+@@ -89,21 +90,22 @@ service Controller {
+ rpc Create(ControllerCreateRequest) returns (ControllerCreateResponse);
+ rpc Start(ControllerStartRequest) returns (ControllerStartResponse);
+ rpc Platform(ControllerPlatformRequest) returns (ControllerPlatformResponse);
+- rpc Prepare(PrepareRequest) returns (PrepareResponse);
+- rpc Purge(PurgeRequest) returns (PurgeResponse);
+- rpc UpdateResources(UpdateResourcesRequest) returns (UpdateResourcesResponse);
+ rpc Stop(ControllerStopRequest) returns (ControllerStopResponse);
+ rpc Wait(ControllerWaitRequest) returns (ControllerWaitResponse);
+ rpc Status(ControllerStatusRequest) returns (ControllerStatusResponse);
+ rpc Shutdown(ControllerShutdownRequest) returns (ControllerShutdownResponse);
++ rpc Metrics(ControllerMetricsRequest) returns (ControllerMetricsResponse);
++ rpc Update(ControllerUpdateRequest) returns (ControllerUpdateResponse);
+ }
+
+ message ControllerCreateRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
+- repeated containerd.types.Mount rootfs = 3;
+- google.protobuf.Any options = 4;
+- string netns_path = 5;
++ string sandbox_id = 1;
++ repeated containerd.types.Mount rootfs = 2;
++ google.protobuf.Any options = 3;
++ string netns_path = 4;
++ map<string, string> annotations = 5;
++ containerd.types.Sandbox sandbox = 6;
++ string sandboxer = 10;
+ }
+
+ message ControllerCreateResponse {
+@@ -111,8 +113,8 @@ message ControllerCreateResponse {
+ }
+
+ message ControllerStartRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
++ string sandbox_id = 1;
++ string sandboxer = 10;
+ }
+
+ message ControllerStartResponse {
+@@ -120,12 +122,16 @@ message ControllerStartResponse {
+ uint32 pid = 2;
+ google.protobuf.Timestamp created_at = 3;
+ map<string, string> labels = 4;
+- string task_address = 5;
++ // Address of the sandbox for containerd to connect,
++ // for calling Task or other APIs serving in the sandbox.
++ // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://<vsock cid>:<port>.
++ string address = 5;
++ uint32 version = 6;
+ }
+
+ message ControllerPlatformRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
++ string sandbox_id = 1;
++ string sandboxer = 10;
+ }
+
+ message ControllerPlatformResponse {
+@@ -133,16 +139,16 @@ message ControllerPlatformResponse {
+ }
+
+ message ControllerStopRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
+- uint32 timeout_secs = 3;
++ string sandbox_id = 1;
++ uint32 timeout_secs = 2;
++ string sandboxer = 10;
+ }
+
+ message ControllerStopResponse {}
+
+ message ControllerWaitRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
++ string sandbox_id = 1;
++ string sandboxer = 10;
+ }
+
+ message ControllerWaitResponse {
+@@ -151,61 +157,48 @@ message ControllerWaitResponse {
+ }
+
+ message ControllerStatusRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
+- bool verbose = 3;
++ string sandbox_id = 1;
++ bool verbose = 2;
++ string sandboxer = 10;
+ }
+
+ message ControllerStatusResponse {
+ string sandbox_id = 1;
+ uint32 pid = 2;
+ string state = 3;
+- string task_address = 4;
+- map<string, string> info = 5;
+- google.protobuf.Timestamp created_at = 6;
+- google.protobuf.Timestamp exited_at = 7;
+- google.protobuf.Any extra = 8;
++ map<string, string> info = 4;
++ google.protobuf.Timestamp created_at = 5;
++ google.protobuf.Timestamp exited_at = 6;
++ google.protobuf.Any extra = 7;
++ // Address of the sandbox for containerd to connect,
++ // for calling Task or other APIs serving in the sandbox.
++ // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://<vsock cid>:<port>.
++ string address = 8;
++ uint32 version = 9;
+ }
+
+ message ControllerShutdownRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
++ string sandbox_id = 1;
++ string sandboxer = 10;
+ }
+
+ message ControllerShutdownResponse {}
+
+-message PrepareRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
+- string container_id = 3;
+- string exec_id = 4;
+- google.protobuf.Any spec = 5;
+- repeated containerd.types.Mount rootfs = 6;
+- string stdin = 7;
+- string stdout = 8;
+- string stderr = 9;
+- bool terminal = 10;
+-}
+-
+-message PrepareResponse {
+- string bundle = 1;
++message ControllerMetricsRequest {
++ string sandbox_id = 1;
++ string sandboxer = 10;
+ }
+
+-message PurgeRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
+- string container_id = 3;
+- string exec_id = 4;
++message ControllerMetricsResponse {
++ types.Metric metrics = 1;
+ }
+
+-message PurgeResponse {}
+-
+-message UpdateResourcesRequest {
+- string sandboxer = 1;
+- string sandbox_id = 2;
+- string container_id = 3;
+- google.protobuf.Any resources = 4;
+- map<string, string> annotations = 5;
++message ControllerUpdateRequest {
++ string sandbox_id = 1;
++ string sandboxer = 2;
++ containerd.types.Sandbox sandbox = 3;
++ repeated string fields = 4;
+ }
+
+-message UpdateResourcesResponse {}
++message ControllerUpdateResponse {
++}
+\ No newline at end of file
+diff --git a/src/api/services/sandbox/sandbox/types/metrics.proto b/src/api/services/sandbox/sandbox/types/metrics.proto
+new file mode 100644
+index 00000000..61185939
+--- /dev/null
++++ b/src/api/services/sandbox/sandbox/types/metrics.proto
+@@ -0,0 +1,30 @@
++/*
++ Copyright The containerd Authors.
++
++ Licensed under the Apache License, Version 2.0 (the "License");
++ you may not use this file except in compliance with the License.
++ You may obtain a copy of the License at
++
++ http://www.apache.org/licenses/LICENSE-2.0
++
++ Unless required by applicable law or agreed to in writing, software
++ distributed under the License is distributed on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ See the License for the specific language governing permissions and
++ limitations under the License.
++*/
++
++syntax = "proto3";
++
++package containerd.types;
++
++import "google/protobuf/any.proto";
++import "google/protobuf/timestamp.proto";
++
++option go_package = "github.com/containerd/containerd/api/types;types";
++
++message Metric {
++ google.protobuf.Timestamp timestamp = 1;
++ string id = 2;
++ google.protobuf.Any data = 3;
++}
+\ No newline at end of file
+diff --git a/src/api/services/sandbox/sandbox/types/platform.proto b/src/api/services/sandbox/sandbox/types/platform.proto
+index b6088251..102e6e2b 100644
+--- a/src/api/services/sandbox/sandbox/types/platform.proto
++++ b/src/api/services/sandbox/sandbox/types/platform.proto
+@@ -26,4 +26,5 @@ message Platform {
+ string os = 1;
+ string architecture = 2;
+ string variant = 3;
+-}
++ string os_version = 4;
++}
+\ No newline at end of file
+diff --git a/src/api/services/sandbox/sandbox/types/sandbox.proto b/src/api/services/sandbox/sandbox/types/sandbox.proto
+index 7b9d196b..6fe08d40 100644
+--- a/src/api/services/sandbox/sandbox/types/sandbox.proto
++++ b/src/api/services/sandbox/sandbox/types/sandbox.proto
+@@ -40,14 +40,15 @@ message Sandbox {
+ // Spec is sandbox configuration (kin of OCI runtime spec), spec's data will be written to a config.json file in the
+ // bundle directory (similary to OCI spec).
+ google.protobuf.Any spec = 3;
+- // Sandboxer is the name of the sandbox controller who manages the sandbox.
+- string sandboxer = 4;
+ // Labels provides an area to include arbitrary data on containers.
+- map<string, string> labels = 5;
++ map<string, string> labels = 4;
+ // CreatedAt is the time the container was first created.
+- google.protobuf.Timestamp created_at = 6;
++ google.protobuf.Timestamp created_at = 5;
+ // UpdatedAt is the last time the container was mutated.
+- google.protobuf.Timestamp updated_at = 7;
++ google.protobuf.Timestamp updated_at = 6;
+ // Extensions allow clients to provide optional blobs that can be handled by runtime.
+- map<string, google.protobuf.Any> extensions = 8;
+-}
++ map<string, google.protobuf.Any> extensions = 7;
++ // Sandboxer is the name of the sandbox controller who manages the sandbox.
++ string sandboxer = 10;
++
++}
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/controller/controller.h b/src/daemon/sandbox/controller/controller.h
+index 9ad45855..60d2dee5 100644
+--- a/src/daemon/sandbox/controller/controller.h
++++ b/src/daemon/sandbox/controller/controller.h
+@@ -24,6 +24,7 @@
+
+ #include "errors.h"
+ #include "api_v1.pb.h"
++#include "sandbox.pb.h"
+
+ namespace sandbox {
+
+@@ -65,6 +66,7 @@ struct ControllerSandboxInfo {
+ uint32_t pid;
+ uint64_t createdAt;
+ std::string taskAddress;
++ std::string version;
+ google::protobuf::Map<std::string, std::string> labels;
+ };
+
+@@ -78,6 +80,7 @@ struct ControllerSandboxStatus {
+ uint32_t pid;
+ std::string state;
+ std::string taskAddress;
++ std::string version;
+ google::protobuf::Map<std::string, std::string> info;
+ uint64_t createdAt;
+ uint64_t exitedAt;
+@@ -123,11 +126,10 @@ public:
+ Errors &error) = 0;
+ virtual std::unique_ptr<ControllerSandboxInfo> Start(const std::string &sandboxId, Errors &error) = 0 ;
+ virtual std::unique_ptr<ControllerPlatformInfo> Platform(const std::string &sandboxId, Errors &error) = 0;
+- virtual std::string Prepare(const std::string &sandboxId,
+- const ControllerPrepareParams &params,
+- Errors &error) = 0;
+- virtual bool Purge(const std::string &sandboxId, const std::string &containerId,
+- const std::string &execId, Errors &error) = 0;
++ virtual bool Prepare(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields, Errors &error) = 0;
++ virtual bool Purge(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields, Errors &error) = 0;
+ virtual bool UpdateResources(const std::string &sandboxId,
+ const ControllerUpdateResourcesParams &params,
+ Errors &error) = 0;
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc
+index 11c2b014..e042ad45 100644
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc
++++ b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc
+@@ -74,6 +74,7 @@ auto SandboxerClient::InitCreateRequest(containerd::services::sandbox::v1::Contr
+ }
+ }
+ request.set_netns_path(params.netNSPath);
++ // The arg sandbox is useless for now
+ return true;
+ }
+
+@@ -117,7 +118,8 @@ void SandboxerClient::StartResponseToSandboxInfo(const containerd::services::san
+ sandboxInfo.id = response.sandbox_id();
+ sandboxInfo.pid = response.pid();
+ sandboxInfo.createdAt = TimestampToNanos(response.created_at());
+- sandboxInfo.taskAddress = response.task_address();
++ sandboxInfo.taskAddress = response.address();
++ sandboxInfo.version = response.version();
+ sandboxInfo.labels = response.labels();
+ }
+
+@@ -144,53 +146,27 @@ auto SandboxerClient::Start(const std::string &sandboxId, ControllerSandboxInfo
+ return true;
+ }
+
+-auto SandboxerClient::InitPrepareRequest(containerd::services::sandbox::v1::PrepareRequest &request,
+- const std::string &sandboxId, const ControllerPrepareParams &params) -> bool
++void SandboxerClient::InitUpdateRequest(containerd::services::sandbox::v1::ControllerUpdateRequest &request,
++ containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields)
+ {
+- if (params.spec == nullptr) {
+- ERROR("Sandboxer controller prepare request failed, spec is null");
+- return false;
+- }
+- request.mutable_spec()->set_value(*(params.spec));
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+- request.set_container_id(params.containerId);
+- request.set_exec_id(params.execId);
+- for (const auto &entry : params.rootfs) {
+- if (entry != nullptr) {
+- Mount* mount = request.add_rootfs();
+- InitMountInfo(*mount, *entry);
+- }
+- }
+- if (params.streamInfo != nullptr) {
+- request.set_stdin(params.streamInfo->stdin);
+- request.set_stdout(params.streamInfo->stdout);
+- request.set_stderr(params.streamInfo->stderr);
+- request.set_terminal(params.streamInfo->terminal);
+- } else {
+- request.set_stdin("");
+- request.set_stdout("");
+- request.set_stderr("");
+- request.set_terminal(false);
+- }
+-
+- return true;
++ request.set_sandbox_id(apiSandbox.sandbox_id());
++ request.set_sandboxer(apiSandbox.sandboxer());
++ *(request.mutable_sandbox()) = apiSandbox;
++ *(request.mutable_fields()) = {fields.begin(), fields.end()};
+ }
+
+-auto SandboxerClient::Prepare(const std::string &sandboxId, const ControllerPrepareParams &params, std::string &bundle,
+- Errors &error) -> bool
++auto SandboxerClient::Prepare(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields, Errors &error) -> bool
+ {
+ grpc::ClientContext context;
+- containerd::services::sandbox::v1::PrepareRequest request;
+- containerd::services::sandbox::v1::PrepareResponse response;
++ containerd::services::sandbox::v1::ControllerUpdateRequest request;
++ containerd::services::sandbox::v1::ControllerUpdateResponse response;
+ grpc::Status status;
+
+- if (!InitPrepareRequest(request, sandboxId, params)) {
+- error.SetError("Failed to init prepare request for sandboxer prepare request, sandbox id: " + sandboxId);
+- return false;
+- }
++ InitUpdateRequest(request, apiSandbox, fields);
+
+- status = m_stub->Prepare(&context, request, &response);
++ status = m_stub->Update(&context, request, &response);
+ if (!status.ok()) {
+ error.SetError(status.error_message());
+ ERROR("Sandboxer controller prepare request failed, error_code: %d: %s", status.error_code(),
+@@ -198,25 +174,20 @@ auto SandboxerClient::Prepare(const std::string &sandboxId, const ControllerPrep
+ return false;
+ }
+
+- bundle = response.bundle();
+-
+ return true;
+ }
+
+-auto SandboxerClient::Purge(const std::string &sandboxId, const std::string &containerId,
+- const std::string &execId, Errors &error) -> bool
++auto SandboxerClient::Purge(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields, Errors &error) -> bool
+ {
+ grpc::ClientContext context;
+- containerd::services::sandbox::v1::PurgeRequest request;
+- containerd::services::sandbox::v1::PurgeResponse response;
++ containerd::services::sandbox::v1::ControllerUpdateRequest request;
++ containerd::services::sandbox::v1::ControllerUpdateResponse response;
+ grpc::Status status;
+
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+- request.set_container_id(containerId);
+- request.set_exec_id(execId);
++ InitUpdateRequest(request, apiSandbox, fields);
+
+- status = m_stub->Purge(&context, request, &response);
++ status = m_stub->Update(&context, request, &response);
+ if (!status.ok()) {
+ error.SetError(status.error_message());
+ ERROR("Sandboxer controller purge request failed, error_code: %d: %s", status.error_code(),
+@@ -227,44 +198,9 @@ auto SandboxerClient::Purge(const std::string &sandboxId, const std::string &con
+ return true;
+ }
+
+-auto SandboxerClient::InitUpdateResourcesRequest(containerd::services::sandbox::v1::UpdateResourcesRequest &request,
+- const std::string &sandboxId,
+- const ControllerUpdateResourcesParams &params) -> bool
+-{
+- if (params.resources == nullptr) {
+- ERROR("Sandboxer controller update resources request failed, resources is null");
+- return false;
+- }
+- request.mutable_resources()->set_value(*(params.resources));
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+- request.set_container_id(params.containerId);
+- request.mutable_annotations()->insert(params.annotations.begin(), params.annotations.end());
+- return true;
+-}
+-
+ auto SandboxerClient::UpdateResources(const std::string &sandboxId, const ControllerUpdateResourcesParams &params,
+ Errors &error) -> bool
+ {
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::UpdateResourcesRequest request;
+- containerd::services::sandbox::v1::UpdateResourcesResponse response;
+- grpc::Status status;
+-
+- if (!InitUpdateResourcesRequest(request, sandboxId, params)) {
+- error.SetError("Failed to init update-resources request for sandboxer update-resources request, sandbox id: " +
+- sandboxId);
+- return false;
+- }
+-
+- status = m_stub->UpdateResources(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller update resources request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+ return true;
+ }
+
+@@ -331,7 +267,8 @@ void SandboxerClient::StatusResponseToSandboxStatus(const containerd::services::
+ sandboxStatus.id = response.sandbox_id();
+ sandboxStatus.pid = response.pid();
+ sandboxStatus.state = response.state();
+- sandboxStatus.taskAddress = response.task_address();
++ sandboxStatus.taskAddress = response.address();
++ sandboxStatus.version = response.version();
+ sandboxStatus.info.insert(response.info().begin(), response.info().end());
+ sandboxStatus.createdAt = TimestampToNanos(response.created_at());
+ sandboxStatus.exitedAt = TimestampToNanos(response.exited_at());
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h
+index accca16b..eeb5d7f2 100644
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h
++++ b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h
+@@ -48,11 +48,11 @@ public:
+
+ auto Platform(const std::string &sandboxId, ControllerPlatformInfo &platformInfo, Errors &error) -> bool;
+
+- auto Prepare(const std::string &sandboxId, const ControllerPrepareParams &params, std::string &bundle,
+- Errors &error) -> bool;
++ auto Prepare(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields, Errors &error) -> bool;
+
+- auto Purge(const std::string &sandboxId, const std::string &containerId,
+- const std::string &execId, Errors &error) -> bool;
++ auto Purge(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields, Errors &error) -> bool;
+
+ auto UpdateResources(const std::string &sandboxId, const ControllerUpdateResourcesParams &params,
+ Errors &error) -> bool;
+@@ -72,11 +72,11 @@ private:
+ const ControllerCreateParams &params) -> bool;
+ void StartResponseToSandboxInfo(const containerd::services::sandbox::v1::ControllerStartResponse &response,
+ ControllerSandboxInfo &sandboxInfo);
+- auto InitPrepareRequest(containerd::services::sandbox::v1::PrepareRequest &request,
+- const std::string &sandboxId, const ControllerPrepareParams &params) -> bool;
+- auto InitUpdateResourcesRequest(containerd::services::sandbox::v1::UpdateResourcesRequest &request,
+- const std::string &sandboxId,
+- const ControllerUpdateResourcesParams &params) -> bool;
++ void InitUpdateRequest(containerd::services::sandbox::v1::ControllerUpdateRequest &request,
++ containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields);
++ // auto InitUpdateResourcesRequest(containerd::services::sandbox::v1::UpdateResourcesRequest &request,
++ // const std::string &sandboxId,
++ // const ControllerUpdateResourcesParams &params) -> bool;
+ void PlatformResponseToPlatformInfo(const containerd::services::sandbox::v1::ControllerPlatformResponse &response,
+ ControllerPlatformInfo &platformInfo);
+ void StatusResponseToSandboxStatus(const containerd::services::sandbox::v1::ControllerStatusResponse &response,
+diff --git a/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.cc b/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.cc
+index d35f1118..70cab015 100644
+--- a/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.cc
++++ b/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.cc
+@@ -61,21 +61,18 @@ std::unique_ptr<ControllerPlatformInfo> SandboxerController::Platform(const std:
+ return platformInfo;
+ }
+
+-std::string SandboxerController::Prepare(const std::string &sandboxId,
+- const ControllerPrepareParams &params,
+- Errors &error)
++bool SandboxerController::Prepare(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields,
++ Errors &error)
+ {
+- std::string bundle;
+- if (!m_client->Prepare(sandboxId, params, bundle, error)) {
+- return "";
+- }
+- return bundle;
++ return m_client->Prepare(apiSandbox, fields, error);
+ }
+
+-bool SandboxerController::Purge(const std::string &sandboxId, const std::string &containerId,
+- const std::string &execId, Errors &error)
++bool SandboxerController::Purge(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields,
++ Errors &error)
+ {
+- return m_client->Purge(sandboxId, containerId, execId, error);
++ return m_client->Purge(apiSandbox, fields, error);
+ }
+
+ bool SandboxerController::UpdateResources(const std::string &sandboxId,
+diff --git a/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.h b/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.h
+index ff66d3d8..8cb7fe7c 100644
+--- a/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.h
++++ b/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.h
+@@ -37,11 +37,10 @@ public:
+ Errors &error) override;
+ std::unique_ptr<ControllerSandboxInfo> Start(const std::string &sandboxId, Errors &error) override;
+ std::unique_ptr<ControllerPlatformInfo> Platform(const std::string &sandboxId, Errors &error) override;
+- std::string Prepare(const std::string &sandboxId,
+- const ControllerPrepareParams &params,
+- Errors &error) override;
+- bool Purge(const std::string &sandboxId, const std::string &containerId,
+- const std::string &execId, Errors &error) override;
++ bool Prepare(containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields,
++ Errors &error) override;
++ bool Purge(containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields,
++ Errors &error) override;
+ bool UpdateResources(const std::string &sandboxId,
+ const ControllerUpdateResourcesParams &params,
+ Errors &error) override;
+diff --git a/src/daemon/sandbox/controller/shim/shim_controller.cc b/src/daemon/sandbox/controller/shim/shim_controller.cc
+index ce09c076..14c99168 100644
+--- a/src/daemon/sandbox/controller/shim/shim_controller.cc
++++ b/src/daemon/sandbox/controller/shim/shim_controller.cc
+@@ -340,15 +340,14 @@ std::unique_ptr<ControllerPlatformInfo> ShimController::Platform(const std::stri
+ return nullptr;
+ }
+
+-std::string ShimController::Prepare(const std::string &sandboxId,
+- const ControllerPrepareParams &params,
+- Errors &error)
++bool ShimController::Prepare(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields, Errors &error)
+ {
+- return std::string("");
++ return true;
+ }
+
+-bool ShimController::Purge(const std::string &sandboxId, const std::string &containerId,
+- const std::string &execId, Errors &error)
++bool ShimController::Purge(containerd::types::Sandbox &apiSandbox,
++ std::vector<std::string> &fields, Errors &error)
+ {
+ return true;
+ }
+diff --git a/src/daemon/sandbox/controller/shim/shim_controller.h b/src/daemon/sandbox/controller/shim/shim_controller.h
+index 5d097bac..1985ddc0 100644
+--- a/src/daemon/sandbox/controller/shim/shim_controller.h
++++ b/src/daemon/sandbox/controller/shim/shim_controller.h
+@@ -45,11 +45,10 @@ public:
+ Errors &error) override;
+ std::unique_ptr<ControllerSandboxInfo> Start(const std::string &sandboxId, Errors &error) override;
+ std::unique_ptr<ControllerPlatformInfo> Platform(const std::string &sandboxId, Errors &error) override;
+- std::string Prepare(const std::string &sandboxId,
+- const ControllerPrepareParams &params,
+- Errors &error) override;
+- bool Purge(const std::string &sandboxId, const std::string &containerId,
+- const std::string &execId, Errors &error) override;
++ bool Prepare(containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields,
++ Errors &error) override;
++ bool Purge(containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields,
++ Errors &error) override;
+ bool UpdateResources(const std::string &sandboxId,
+ const ControllerUpdateResourcesParams &params,
+ Errors &error) override;
+diff --git a/src/daemon/sandbox/sandbox.cc b/src/daemon/sandbox/sandbox.cc
+index dec082bc..97b77f22 100644
+--- a/src/daemon/sandbox/sandbox.cc
++++ b/src/daemon/sandbox/sandbox.cc
+@@ -494,6 +494,7 @@ auto Sandbox::Load(Errors &error) -> bool
+ }
+
+ LoadNetworkSetting();
++ LoadSandboxTasks();
+
+ // When the sandbox status acquisition fails or wait fails, the sandbox status is set to not ready,
+ // and the user decides whether to delete the sandbox.
+@@ -698,6 +699,7 @@ auto Sandbox::Start(Errors &error) -> bool
+ m_state.pid = info->pid;
+ m_state.createdAt = info->createdAt;
+ m_taskAddress = info->taskAddress;
++ m_version = info->version;
+ m_state.status = SANDBOX_STATUS_RUNNING;
+
+ if (!SaveState(error)) {
+@@ -814,7 +816,7 @@ void Sandbox::Status(runtime::v1::PodSandboxStatus &status)
+
+ auto Sandbox::GenerateSandboxStateJson(sandbox_state *state) -> std::string
+ {
+- __isula_auto_free parser_error error;
++ __isula_auto_free parser_error error = NULL;
+ std::string ret;
+ __isula_auto_free char *state_json = NULL;
+ state_json = sandbox_state_generate_json(state, NULL, &(error));
+@@ -874,7 +876,7 @@ auto Sandbox::SaveNetworkSetting(Errors &error) -> bool
+
+ auto Sandbox::GenerateSandboxMetadataJson(sandbox_metadata *metadata) -> std::string
+ {
+- __isula_auto_free parser_error error;
++ __isula_auto_free parser_error error = NULL;
+ std::string ret;
+ __isula_auto_free char *metadata_json = NULL;
+ metadata_json = sandbox_metadata_generate_json(metadata, NULL, &(error));
+@@ -1096,6 +1098,11 @@ auto Sandbox::GetNetworkSettingsPath() -> std::string
+ return m_rootdir + std::string("/") + NETWORK_SETTINGS_JSON;
+ }
+
++auto Sandbox::GetTasksJsonPath() -> std::string
++{
++ return m_rootdir + std::string("/") + SANDBOX_TASKS_JSON;
++}
++
+ void Sandbox::FillSandboxMetadata(sandbox_metadata* metadata, Errors &error)
+ {
+ std::string jsonStr;
+@@ -1116,4 +1123,214 @@ void Sandbox::FillSandboxMetadata(sandbox_metadata* metadata, Errors &error)
+
+ metadata->sandbox_config_json = util_strdup_s(jsonStr.c_str());
+ }
++
++auto Sandbox::AddTaskById(const char *task_id, sandbox_task *task) -> bool
++{
++
++ std::string taskId = std::string(task_id);
++ auto iter = m_tasks.find(taskId);
++
++ if (iter != m_tasks.end()) {
++ ERROR("Failed to add exits sandbox task %s for sandbox: %s",
++ task_id, m_id.c_str());
++ return false;
++ }
++ m_tasks[taskId] = std::make_shared<SandboxTask>(task);
++ return true;
++}
++
++auto Sandbox::ReadSandboxTasksJson() -> sandbox_tasks *
++{
++ const std::string path = GetTasksJsonPath();
++ __isula_auto_free parser_error err = nullptr;
++ sandbox_tasks *tasksArray = nullptr;
++
++ ReadGuard<RWMutex> lock(m_tasksMutex);
++ tasksArray = sandbox_tasks_parse_file(path.c_str(), nullptr, &err);
++ if (tasksArray == nullptr) {
++ WARN("Failed to read %s tasks json: %s", path.c_str(), err);
++ }
++ return tasksArray;
++}
++
++auto Sandbox::WriteSandboxTasksJson(std::string &tasks_json) -> bool
++{
++ int nret = 0;
++ const std::string path = GetTasksJsonPath();
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++ nret = util_atomic_write_file(path.c_str(), tasks_json.c_str(), tasks_json.size(), CONFIG_FILE_MODE, false);
++ if (nret != 0) {
++ SYSERROR("Failed to write file %s", path.c_str());
++ }
++ return nret == 0;
++}
++
++auto Sandbox::DeleteSandboxTasksJson() -> bool
++{
++ int get_err = 0;
++ const std::string path = GetTasksJsonPath();
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++ if (util_fileself_exists(path.c_str()) &&
++ !util_force_remove_file(path.c_str(), &get_err)) {
++ errno = get_err;
++ SYSERROR("Failed to remove file %s", path.c_str());
++ return false;
++ }
++
++ return true;
++}
++
++void Sandbox::AddSandboxTasksByArray(sandbox_tasks *tasksArray)
++{
++ size_t i;
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++ for (i = 0; i < tasksArray->tasks_len; i++) {
++ if (!AddTaskById(tasksArray->tasks[i]->task_id, tasksArray->tasks[i])) {
++ return;
++ }
++ tasksArray->tasks[i] = nullptr;
++ }
++ tasksArray->tasks_len = 0;
++}
++
++void Sandbox::LoadSandboxTasks()
++{
++ sandbox_tasks *tasksArray = nullptr;
++
++ tasksArray = ReadSandboxTasksJson();
++ if (tasksArray == nullptr) {
++ return;
++ }
++
++ AddSandboxTasksByArray(tasksArray);
++
++ free_sandbox_tasks(tasksArray);
++}
++
++auto Sandbox::SaveSandboxTasks() -> bool
++{
++ std::string tasks_json;
++
++ if (m_tasks.empty()) {
++ return DeleteSandboxTasksJson();
++ }
++
++ tasks_json = GetAnySandboxTasks();
++ if (tasks_json.empty()) {
++ ERROR("Failed to get sandbox tasks json for sandbox: '%s'", m_id.c_str());
++ return false;
++ }
++
++ return WriteSandboxTasksJson(tasks_json);
++}
++
++auto Sandbox::AddSandboxTasks(sandbox_task *task) -> bool
++{
++ if (task == nullptr) {
++ return true;
++ }
++ if (task->task_id == nullptr) {
++ return false;
++ }
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++
++ return AddTaskById(task->task_id, task);
++}
++
++auto Sandbox::GetAnySandboxTasks() -> std::string
++{
++ __isula_auto_free parser_error err = nullptr;
++ sandbox_tasks tasksArray = { 0 };
++ size_t i = 0;
++ __isula_auto_free char *tasks_json = nullptr;
++
++ tasksArray.tasks = (sandbox_task **)util_smart_calloc_s(sizeof(sandbox_task *), m_tasks.size());
++ if (tasksArray.tasks == nullptr) {
++ SYSERROR("Out of memory.");
++ return std::string("");
++ }
++
++ ReadGuard<RWMutex> lock(m_tasksMutex);
++ for (auto const& [_, val] : m_tasks) {
++ /*
++ * We ignore that the processes are modified
++ * when we generate tasks json string.
++ * Because no matter whether a process is deleted or added,
++ * the Update of sandbox api will be called eventually.
++ *
++ * And we ignore that the task is freed after we do GetTask().
++ * Because the only way to free task is DeleteSandboxTasks()
++ * which needs write lock of m_tasksMutex.
++ */
++ tasksArray.tasks[i] = val->GetTask();
++ i++;
++ }
++ tasksArray.tasks_len = m_tasks.size();
++
++ tasks_json = sandbox_tasks_generate_json(&tasksArray, nullptr, &(err));
++ if (tasks_json == nullptr || strlen(tasks_json) == 0) {
++ ERROR("Failed to get sandbox tasks json for sandbox: '%s'", m_id.c_str());
++ free(tasksArray.tasks);
++ return std::string("");
++ }
++
++ free(tasksArray.tasks);
++ return std::string(tasks_json);
++}
++
++void Sandbox::DeleteSandboxTasks(const char *containerId)
++{
++ if (containerId == nullptr) {
++ return;
++ }
++
++ std::string taskId = std::string(containerId);
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++ auto iter = m_tasks.find(taskId);
++ if (iter == m_tasks.end()) {
++ return;
++ }
++ m_tasks.erase(iter);
++}
++
++auto Sandbox::AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool
++{
++ if (containerId == nullptr || processes == nullptr) {
++ ERROR("Empty args.");
++ return false;
++ }
++
++ std::string taskId = std::string(containerId);
++
++ ReadGuard<RWMutex> lock(m_tasksMutex);
++ auto iter = m_tasks.find(taskId);
++ if (iter == m_tasks.end()) {
++ SYSERROR("Failed to find container %s", containerId);
++ return false;
++ }
++
++ return iter->second->AddSandboxTasksProcess(processes);
++}
++
++void Sandbox::DeleteSandboxTasksProcess(const char *containerId, const char *execId)
++{
++ if (containerId == nullptr || execId == nullptr) {
++ return;
++ }
++
++ std::string taskId = std::string(containerId);
++
++ ReadGuard<RWMutex> lock(m_tasksMutex);
++ auto iter = m_tasks.find(taskId);
++ if (iter == m_tasks.end()) {
++ return;
++ }
++ iter->second->DeleteSandboxTasksProcess(execId);
++}
++
+ }
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/sandbox.h b/src/daemon/sandbox/sandbox.h
+index 42fbee2a..437b6113 100644
+--- a/src/daemon/sandbox/sandbox.h
++++ b/src/daemon/sandbox/sandbox.h
+@@ -30,12 +30,14 @@
+ #include "controller_manager.h"
+ #include "cstruct_wrapper.h"
+ #include "read_write_lock.h"
++#include "sandbox_task.h"
+
+ namespace sandbox {
+
+ const std::string SANDBOX_METADATA_JSON = "sandbox_metadata.json";
+ const std::string SANDBOX_STATE_JSON = "sandbox_state.json";
+ const std::string NETWORK_SETTINGS_JSON = "network_settings.json";
++const std::string SANDBOX_TASKS_JSON = "sandbox_tasks.json";
+
+ // Keep consistent with the default values set in containerd and cri-o.
+ const uint32_t DEFAULT_STOP_TIMEOUT = 10;
+@@ -138,6 +140,15 @@ public:
+ auto Remove(Errors &error) -> bool;
+ void Status(runtime::v1::PodSandboxStatus &status);
+
++ // for sandbox api update
++ void LoadSandboxTasks();
++ auto SaveSandboxTasks() -> bool;
++ auto AddSandboxTasks(sandbox_task *task) -> bool;
++ auto GetAnySandboxTasks() -> std::string;
++ void DeleteSandboxTasks(const char *containerId);
++ auto AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool;
++ void DeleteSandboxTasksProcess(const char *containerId, const char *execId);
++
+ private:
+ auto SaveState(Errors &error) -> bool;
+ auto SaveMetadata(Errors &error) -> bool;
+@@ -161,6 +172,7 @@ private:
+ auto GetMetadataJsonPath() -> std::string;
+ auto GetStatePath() -> std::string;
+ auto GetNetworkSettingsPath() -> std::string;
++ auto GetTasksJsonPath() -> std::string;
+
+ void FillSandboxState(sandbox_state *state);
+ void FillSandboxMetadata(sandbox_metadata* metadata, Errors &error);
+@@ -177,6 +189,12 @@ private:
+
+ void updateSelinuxLabels(std::string &selinuxLabels);
+
++ auto AddTaskById(const char *task_id, sandbox_task *task) -> bool;
++ auto ReadSandboxTasksJson() -> sandbox_tasks *;
++ auto WriteSandboxTasksJson(std::string &tasks_json) -> bool;
++ auto DeleteSandboxTasksJson() -> bool;
++ void AddSandboxTasksByArray(sandbox_tasks *tasksArray);
++
+ private:
+ // Since the cri module will operate concurrently on the sandbox instance,
+ // use m_mutex to ensure the correctness of the sandbox instance
+@@ -191,6 +209,7 @@ private:
+ std::string m_rootdir;
+ std::string m_statedir;
+ std::string m_taskAddress;
++ uint32_t m_version;
+ StatsInfo m_statsInfo;
+ // Store network information in the sandbox, which is convenient for the cri module to obtain
+ // and update the network settings of the pause container in the shim-controller.
+@@ -211,6 +230,11 @@ private:
+ // vsock ports
+ std::mutex m_vsockPortsMutex;
+ std::set<uint32_t> m_vsockPorts;
++
++ // use m_tasksMutex to ensure the correctness of the tasks
++ RWMutex m_tasksMutex;
++ // for sandbox api update, containerId --> tasks
++ std::map<std::string, std::shared_ptr<SandboxTask>> m_tasks;
+ };
+
+ } // namespace sandbox
+diff --git a/src/daemon/sandbox/sandbox_ops.cc b/src/daemon/sandbox/sandbox_ops.cc
+index 22cfea95..96e541a4 100644
+--- a/src/daemon/sandbox/sandbox_ops.cc
++++ b/src/daemon/sandbox/sandbox_ops.cc
+@@ -16,11 +16,18 @@
+
+ #include <isula_libutils/auto_cleanup.h>
+ #include <isula_libutils/log.h>
++#include <google/protobuf/util/time_util.h>
+
+ #include "controller_manager.h"
+ #include "sandbox_manager.h"
++#include "sandbox.h"
+ #include "namespace.h"
+ #include "utils.h"
++#include "utils_timestamp.h"
++
++const std::string SANDBOX_EXTENSIONS_TASKS = "extensions.tasks";
++const std::string SANDBOX_TASKS_KEY = "tasks";
++const std::string SANDBOX_TASKS_TYPEURL = "github.com/containerd/containerd/Tasks";
+
+ static inline bool validate_sandbox_info(const container_sandbox_info *sandbox)
+ {
+@@ -28,106 +35,166 @@ static inline bool validate_sandbox_info(const container_sandbox_info *sandbox)
+ sandbox->id != NULL);
+ }
+
+-static int generate_ctrl_rootfs(sandbox::ControllerPrepareParams &params,
++static int generate_ctrl_rootfs(sandbox_task *task,
+ const container_config_v2_common_config *config)
+ {
++ size_t len = 1;
+ if (nullptr == config->base_fs) {
+ ERROR("Container %s has no base fs", config->id);
+ return -1;
+ }
+
+ // TODO: rootfs's options left to be configured
+- std::unique_ptr<sandbox::ControllerMountInfo> mount_info(new sandbox::ControllerMountInfo());
+- mount_info->type = MOUNT_TYPE_BIND;
+- mount_info->source = config->base_fs;
+- params.rootfs.push_back(std::move(mount_info));
++ task->rootfs = (sandbox_mount **)util_smart_calloc_s(sizeof(sandbox_mount *), len);
++ if (task->rootfs == nullptr) {
++ ERROR("Out of memory.");
++ return -1;
++ }
++ task->rootfs[0] = (sandbox_mount *)util_common_calloc_s(sizeof(sandbox_mount));
++ if (task->rootfs[0] == nullptr) {
++ ERROR("Out of memory.");
++ return -1;
++ }
++ task->rootfs_len = len;
++ task->rootfs[0]->type = util_strdup_s(MOUNT_TYPE_BIND);
++ task->rootfs[0]->source = util_strdup_s(config->base_fs);
+
+ return 0;
+ }
+
+-static int do_sandbox_prepare(const container_config_v2_common_config *config,
+- const char *exec_id, const char *oci_spec,
+- const char * console_fifos[], bool tty)
++static int do_sandbox_prepare(std::shared_ptr<sandbox::Sandbox> &sandbox, containerd::types::Sandbox &apiSandbox)
+ {
+ Errors err;
+- sandbox::ControllerPrepareParams params;
+- std::unique_ptr<sandbox::ControllerStreamInfo> stream_info(new sandbox::ControllerStreamInfo());
+- const container_sandbox_info *sandbox_info = nullptr;
+-
+- if (nullptr == config || nullptr == config->id) {
+- ERROR("Invalid parameter: config");
+- return -1;
+- }
++ std::vector<std::string> fields;
++
++ fields.push_back(SANDBOX_EXTENSIONS_TASKS);
+
+- sandbox_info = config->sandbox_info;
+- if (false == validate_sandbox_info(sandbox_info)) {
+- ERROR("Invalid parameter: sandbox");
++ auto controller = sandbox::ControllerManager::GetInstance()->GetController(sandbox->GetSandboxer());
++ if (nullptr == controller) {
++ ERROR("Invalid sandboxer name: %s", sandbox->GetSandboxer().c_str());
+ return -1;
+ }
+
+- if (nullptr == console_fifos) {
+- ERROR("Invlaid parameter: console_fifos");
++ if (!controller->Prepare(apiSandbox, fields, err)) {
++ ERROR("Failed to prepare in container controller prepare: %s", err.GetCMessage());
+ return -1;
+ }
+
+- params.containerId = config->id;
+- params.execId = (nullptr == exec_id) ? "" : exec_id;
+- params.spec = std::unique_ptr<std::string>(new std::string(oci_spec));
+-
+- if (generate_ctrl_rootfs(params, config) != 0) {
+- ERROR("Invalid rootfs");
+- return -1;
+- }
++ return 0;
++}
+
+- stream_info->stdin = (nullptr == console_fifos[0]) ? "" : console_fifos[0];
+- stream_info->stdout = (nullptr == console_fifos[1]) ? "" : console_fifos[1];
+- stream_info->stderr = (nullptr == console_fifos[2]) ? "" : console_fifos[2];
+- stream_info->terminal = tty;
+- params.streamInfo = std::move(stream_info);
++static int do_sandbox_purge(std::shared_ptr<sandbox::Sandbox> &sandbox, containerd::types::Sandbox &apiSandbox)
++{
++ Errors err;
++ std::vector<std::string> fields;
++
++ fields.push_back(SANDBOX_EXTENSIONS_TASKS);
+
+- auto controller = sandbox::ControllerManager::GetInstance()->GetController(sandbox_info->sandboxer);
++ auto controller = sandbox::ControllerManager::GetInstance()->GetController(sandbox->GetSandboxer());
+ if (nullptr == controller) {
+- ERROR("Invalid sandboxer name: %s", sandbox_info->sandboxer);
++ ERROR("Invalid sandboxer name: %s", sandbox->GetSandboxer().c_str());
+ return -1;
+ }
+
+- std::string bundle = controller->Prepare(sandbox_info->id, params, err);
+- if (err.NotEmpty()) {
+- ERROR("Failed to prepare in container controller prepare: %s", err.GetCMessage());
++ if (!controller->Purge(apiSandbox, fields, err)) {
++ ERROR("Failed to purge: %s", err.GetCMessage());
+ return -1;
+ }
+
+ return 0;
+ }
+
+-static int do_sandbox_purge(const container_config_v2_common_config *config,
+- const char *exec_id)
++static oci_runtime_spec *clone_oci_runtime_spec(const oci_runtime_spec *oci_spec)
+ {
+- Errors err;
+- const container_sandbox_info *sandbox_info = nullptr;
++ __isula_auto_free char *json_str = nullptr;
++ __isula_auto_free parser_error err = nullptr;
++ oci_runtime_spec *ret = nullptr;
++
++ json_str = oci_runtime_spec_generate_json(oci_spec, nullptr, &err);
++ if (json_str == nullptr) {
++ ERROR("Failed to generate spec json: %s", err);
++ return nullptr;
++ }
++ ret = oci_runtime_spec_parse_data(json_str, nullptr, &err);
++ if (ret == nullptr) {
++ ERROR("Failed to generate spec: %s", err);
++ }
++ return ret;
++}
++
++static defs_process *clone_defs_process(defs_process *process_spec)
++{
++ __isula_auto_free char *json_str = nullptr;
++ __isula_auto_free parser_error err = nullptr;
++ defs_process *ret = nullptr;
++
++ json_str = defs_process_generate_json(process_spec, nullptr, &err);
++ if (json_str == nullptr) {
++ ERROR("Failed to generate process spec json: %s", err);
++ return nullptr;
++ }
++ ret = defs_process_parse_data(json_str, nullptr, &err);
++ if (ret == nullptr) {
++ ERROR("Failed to generate process spec: %s", err);
++ }
++ return ret;
++}
+
++static std::shared_ptr<sandbox::Sandbox> get_prepare_sandbox(const container_config_v2_common_config *config)
++{
+ if (nullptr == config || nullptr == config->id) {
+ ERROR("Invalid parameter: config");
+- return -1;
++ return nullptr;
+ }
+
+- sandbox_info = config->sandbox_info;
++ auto sandbox_info = config->sandbox_info;
+ if (false == validate_sandbox_info(sandbox_info)) {
+ ERROR("Invalid parameter: sandbox");
+- return -1;
++ return nullptr;
+ }
+
+- auto controller = sandbox::ControllerManager::GetInstance()->GetController(sandbox_info->sandboxer);
+- if (nullptr == controller) {
+- ERROR("Invalid sandboxer name: %s", sandbox_info->sandboxer);
+- return -1;
++ auto sandbox = sandbox::SandboxManager::GetInstance()->GetSandbox(sandbox_info->id);
++ if (nullptr == sandbox) {
++ ERROR("Sandbox not found");
++ return nullptr;
+ }
++ return sandbox;
++}
+
+- if (!controller->Purge(sandbox_info->id, config->id,
+- (nullptr == exec_id) ? "" : exec_id, err)) {
+- ERROR("Failed to purge: %s", err.GetCMessage());
++static int init_prepare_api_sandbox(std::shared_ptr<sandbox::Sandbox> sandbox, const char *containerId,
++ containerd::types::Sandbox &apiSandbox)
++{
++ google::protobuf::Map<std::string, std::string> *labels = apiSandbox.mutable_labels();
++ google::protobuf::Map<std::string, google::protobuf::Any> *extensions = apiSandbox.mutable_extensions();
++ google::protobuf::Any any;
++ auto created_at = new (std::nothrow) google::protobuf::Timestamp;
++ auto updated_at = new (std::nothrow) google::protobuf::Timestamp;
++
++ apiSandbox.set_sandbox_id(sandbox->GetId());
++ apiSandbox.mutable_runtime()->set_name(sandbox->GetRuntime());
++ // TODO how get options
++ // apiSandbox.mutable_runtime()->set_options(sandbox->GetRuntime());
++ // Just ignore spec
++ (*labels)[std::string("name")] = sandbox->GetName();
++
++ *created_at = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(
++ sandbox->GetCreatedAt());
++ apiSandbox.set_allocated_created_at(created_at);
++ *updated_at = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(util_get_now_time_nanos());
++ apiSandbox.set_allocated_updated_at(updated_at);
++
++ auto any_type_url = any.mutable_type_url();
++ *any_type_url = SANDBOX_TASKS_TYPEURL;
++ auto any_value = any.mutable_value();
++ *any_value = sandbox->GetAnySandboxTasks();
++ if ((*any_value).empty()) {
++ ERROR("Failed to get any sandbox tasks");
+ return -1;
+ }
++ DEBUG("Get any sandbox tasks %s", (*any_value).c_str());
++ (*extensions)[SANDBOX_TASKS_KEY] = any;
++
++ apiSandbox.set_sandboxer(sandbox->GetSandboxer());
+
+ return 0;
+ }
+@@ -136,45 +203,177 @@ int sandbox_prepare_container(const container_config_v2_common_config *config,
+ const oci_runtime_spec *oci_spec,
+ const char * console_fifos[], bool tty)
+ {
+- __isula_auto_free char *json_oci_spec = nullptr;
+- __isula_auto_free parser_error err = nullptr;
++ sandbox_task *task = nullptr;
++ containerd::types::Sandbox apiSandbox;
++ int ret = -1;
+
+ INFO("Prepare container for sandbox");
+
+- json_oci_spec = oci_runtime_spec_generate_json(oci_spec, nullptr, &err);
+- if (nullptr == json_oci_spec) {
+- ERROR("Failed to generate container spec json: %s", err);
++ if (nullptr == console_fifos) {
++ ERROR("Invlaid parameter: console_fifos");
++ return -1;
++ }
++
++ auto sandbox = get_prepare_sandbox(config);
++ if (sandbox == nullptr) {
++ ERROR("Sandbox not found");
++ return -1;
++ }
++
++ task = (sandbox_task *)util_common_calloc_s(sizeof(sandbox_task));
++ if (task == nullptr) {
++ ERROR("Out of memory.");
+ return -1;
+ }
+- return do_sandbox_prepare(config, nullptr, json_oci_spec, console_fifos, tty);
++ task->task_id = util_strdup_s(config->id);
++ task->spec = clone_oci_runtime_spec(oci_spec);
++ if (task->spec == nullptr) {
++ ERROR("Out of memory.");
++ goto free_out;
++ }
++ if (generate_ctrl_rootfs(task, config) != 0) {
++ ERROR("Invalid rootfs");
++ goto free_out;
++ }
++ task->stdin = util_strdup_s((nullptr == console_fifos[0]) ? "" : console_fifos[0]);
++ task->stdout = util_strdup_s((nullptr == console_fifos[1]) ? "" : console_fifos[1]);
++ task->stderr = util_strdup_s((nullptr == console_fifos[2]) ? "" : console_fifos[2]);
++
++ if (!sandbox->AddSandboxTasks(task)) {
++ ERROR("Failed to add sandbox %s task.", config->id);
++ goto free_out;
++ }
++ task = nullptr;
++ ret = init_prepare_api_sandbox(sandbox, config->id, apiSandbox);
++ if (ret != 0) {
++ ERROR("Failed to init %s api sandbox.", config->id);
++ goto del_out;
++ }
++ ret = do_sandbox_prepare(sandbox, apiSandbox);
++
++del_out:
++ if (ret != 0) {
++ sandbox->DeleteSandboxTasks(config->id);
++ }
++ if (!sandbox->SaveSandboxTasks()) {
++ ERROR("Failed to Save %s sandbox tasks.", config->id);
++ ret = -1;
++ }
++free_out:
++ free_sandbox_task(task);
++ return ret;
+ }
+
+ int sandbox_prepare_exec(const container_config_v2_common_config *config,
+ const char *exec_id, defs_process *process_spec,
+ const char * console_fifos[], bool tty)
+ {
+- __isula_auto_free char *json_process = nullptr;
+- __isula_auto_free parser_error err = nullptr;
++ sandbox_process *process = nullptr;
++ containerd::types::Sandbox apiSandbox;
++ int ret = -1;
+
+ INFO("Prepare exec for container in sandbox");
+
+- json_process = defs_process_generate_json(process_spec, nullptr, &err);
+- if (nullptr == json_process) {
+- ERROR("Failed to generate process spec json: %s", err);
++ if (nullptr == console_fifos) {
++ ERROR("Invlaid parameter: console_fifos");
+ return -1;
+ }
+
+- return do_sandbox_prepare(config, exec_id, json_process, console_fifos, tty);
++ auto sandbox = get_prepare_sandbox(config);
++ if (sandbox == nullptr) {
++ ERROR("Sandbox not found");
++ return -1;
++ }
++
++ process = (sandbox_process *)util_common_calloc_s(sizeof(sandbox_process));
++ if (process == nullptr) {
++ ERROR("Out of memory.");
++ return -1;
++ }
++ process->exec_id = util_strdup_s(exec_id);
++ process->spec = clone_defs_process(process_spec);
++ if (process->spec == nullptr) {
++ ERROR("Out of memory.");
++ goto free_out;
++ }
++ process->stdin = util_strdup_s((nullptr == console_fifos[0]) ? "" : console_fifos[0]);
++ process->stdout = util_strdup_s((nullptr == console_fifos[1]) ? "" : console_fifos[1]);
++ process->stderr = util_strdup_s((nullptr == console_fifos[2]) ? "" : console_fifos[2]);
++
++ if (!sandbox->AddSandboxTasksProcess(config->id, process)) {
++ ERROR("Failed to add sandbox %s process.", config->id);
++ goto free_out;
++ }
++ process = nullptr;
++ ret = init_prepare_api_sandbox(sandbox, config->id, apiSandbox);
++ if (ret != 0) {
++ ERROR("Failed to init %s api sandbox.", config->id);
++ goto del_out;
++ }
++ ret = do_sandbox_prepare(sandbox, apiSandbox);
++
++del_out:
++ if (ret != 0) {
++ sandbox->DeleteSandboxTasksProcess(config->id, exec_id);
++ }
++ if (!sandbox->SaveSandboxTasks()) {
++ ERROR("Failed to Save %s sandbox tasks.", config->id);
++ ret = -1;
++ }
++free_out:
++ free_sandbox_process(process);
++ return ret;
+ }
+
+ int sandbox_purge_container(const container_config_v2_common_config *config)
+ {
+- return do_sandbox_purge(config, nullptr);
++ containerd::types::Sandbox apiSandbox;
++
++ INFO("Purge container for sandbox");
++
++ auto sandbox = get_prepare_sandbox(config);
++ if (sandbox == nullptr) {
++ ERROR("Sandbox not found");
++ return -1;
++ }
++
++ sandbox->DeleteSandboxTasks(config->id);
++ if (!sandbox->SaveSandboxTasks()) {
++ ERROR("Failed to Save %s sandbox tasks.", config->id);
++ return -1;
++ }
++
++ if (init_prepare_api_sandbox(sandbox, config->id, apiSandbox) != 0) {
++ ERROR("Failed to init %s api sandbox.", config->id);
++ return -1;
++ }
++ return do_sandbox_purge(sandbox, apiSandbox);
+ }
+
+ int sandbox_purge_exec(const container_config_v2_common_config *config, const char *exec_id)
+ {
+- return do_sandbox_purge(config, exec_id);
++ containerd::types::Sandbox apiSandbox;
++
++ INFO("Purge exec for container in sandbox");
++
++ auto sandbox = get_prepare_sandbox(config);
++ if (sandbox == nullptr) {
++ ERROR("Sandbox not found");
++ return -1;
++ }
++
++ sandbox->DeleteSandboxTasksProcess(config->id, exec_id);
++ if (!sandbox->SaveSandboxTasks()) {
++ ERROR("Failed to Save %s sandbox tasks.", config->id);
++ return -1;
++ }
++
++ if (init_prepare_api_sandbox(sandbox, config->id, apiSandbox) != 0) {
++ ERROR("Failed to init %s api sandbox.", exec_id);
++ return -1;
++ }
++
++ return do_sandbox_purge(sandbox, apiSandbox);
+ }
+
+ int sandbox_on_sandbox_exit(const char *sandbox_id, int exit_code)
+diff --git a/src/daemon/sandbox/sandbox_task.cc b/src/daemon/sandbox/sandbox_task.cc
+new file mode 100644
+index 00000000..b1efc340
+--- /dev/null
++++ b/src/daemon/sandbox/sandbox_task.cc
+@@ -0,0 +1,99 @@
++/******************************************************************************
++ * 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: liuxu
++ * Create: 2024-10-22
++ * Description: provide sandbox class definition
++ *********************************************************************************/
++#include "sandbox_task.h"
++
++#include <mutex>
++
++#include <isula_libutils/log.h>
++
++#include "utils.h"
++#include "errors.h"
++
++namespace sandbox {
++
++SandboxTask::SandboxTask(sandbox_task *task): m_task(task)
++{
++}
++
++SandboxTask::~SandboxTask()
++{
++ free_sandbox_task(m_task);
++ m_task = nullptr;
++}
++
++auto SandboxTask::GetTask() -> sandbox_task *
++{
++ ReadGuard<RWMutex> lock(m_taskMutex);
++ return m_task;
++}
++
++auto SandboxTask::AddSandboxTasksProcess(sandbox_process *processes) -> bool
++{
++ if (processes == nullptr) {
++ ERROR("Empty args.");
++ return false;
++ }
++
++ WriteGuard<RWMutex> lock(m_taskMutex);
++ if (util_mem_realloc((void **)(&m_task->processes),
++ (m_task->processes_len + 1) * sizeof(sandbox_process *),
++ (void *)m_task->processes,
++ m_task->processes_len * sizeof(sandbox_process *)) != 0) {
++ ERROR("Out of memory");
++ return false;
++ }
++ m_task->processes[m_task->processes_len] = processes;
++ m_task->processes_len++;
++
++ return true;
++}
++
++auto SandboxTask::FindProcessByID(const char *execId) -> int
++{
++ int i;
++ int processes_len = m_task->processes_len;
++
++ if (m_task->processes == nullptr) {
++ return -1;
++ }
++
++ for (i = 0; i < processes_len; i++) {
++ if (strcmp(m_task->processes[i]->exec_id, execId) == 0) {
++ return i;
++ }
++ }
++ return -1;
++}
++
++void SandboxTask::DeleteSandboxTasksProcess(const char *execId)
++{
++ if (execId == nullptr) {
++ return;
++ }
++
++ int idx;
++
++ WriteGuard<RWMutex> lock(m_taskMutex);
++ idx = FindProcessByID(execId);
++ if (idx < 0) {
++ return;
++ }
++ free_sandbox_process(m_task->processes[idx]);
++ (void)memcpy((void **)&m_task->processes[idx], (void **)&m_task->processes[idx + 1],
++ (m_task->processes_len - idx - 1) * sizeof(void *));
++ m_task->processes_len--;
++}
++
++}
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/sandbox_task.h b/src/daemon/sandbox/sandbox_task.h
+new file mode 100644
+index 00000000..1bd0ce58
+--- /dev/null
++++ b/src/daemon/sandbox/sandbox_task.h
+@@ -0,0 +1,48 @@
++/******************************************************************************
++ * 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: liuxu
++ * Create: 2024-10-22
++ * Description: provide sandbox class definition
++ *********************************************************************************/
++
++#ifndef DAEMON_SANDBOX_SANDBOX_TASK_H
++#define DAEMON_SANDBOX_SANDBOX_TASK_H
++
++#include <string>
++#include <mutex>
++
++#include <isula_libutils/sandbox_tasks.h>
++
++#include "api_v1.grpc.pb.h"
++#include "errors.h"
++#include "read_write_lock.h"
++
++namespace sandbox {
++
++class SandboxTask : public std::enable_shared_from_this<SandboxTask> {
++public:
++ SandboxTask(sandbox_task *task);
++ ~SandboxTask();
++
++ auto GetTask() -> sandbox_task *;
++ auto AddSandboxTasksProcess(sandbox_process *processes) -> bool;
++ void DeleteSandboxTasksProcess(const char *execId);
++
++private:
++ auto FindProcessByID(const char *execId) -> int;
++private:
++ // Do not modify m_task concurrently.
++ RWMutex m_taskMutex;
++ sandbox_task *m_task;
++};
++} // namespace sandbox
++
++#endif // DAEMON_SANDBOX_SANDBOX_TASK_H
+\ No newline at end of file
+--
+2.34.1
+