diff options
Diffstat (limited to '0151-sandbox-sandbox-api-update.patch')
-rw-r--r-- | 0151-sandbox-sandbox-api-update.patch | 1600 |
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 ¶ms, +- 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 ¶ms, + 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 ¶ms) -> 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 ¶ms, 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 ¶ms) -> 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 ¶ms, + 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 ¶ms, 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 ¶ms, + Errors &error) -> bool; +@@ -72,11 +72,11 @@ private: + const ControllerCreateParams ¶ms) -> 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 ¶ms) -> bool; +- auto InitUpdateResourcesRequest(containerd::services::sandbox::v1::UpdateResourcesRequest &request, +- const std::string &sandboxId, +- const ControllerUpdateResourcesParams ¶ms) -> 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 ¶ms) -> 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 ¶ms, +- 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 ¶ms, +- 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 ¶ms, + 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 ¶ms, +- 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 ¶ms, +- 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 ¶ms, + 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 ¶ms, ++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 + |