From b994e99a4188bef549e5fa1f944eb3546be43201 Mon Sep 17 00:00:00 2001 From: liuxu Date: Wed, 18 Sep 2024 11:40:15 +0800 Subject: [PATCH 151/156] sandbox:sandbox api update Signed-off-by: liuxu --- 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 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 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://:. + 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 info = 5; - google.protobuf.Timestamp created_at = 6; - google.protobuf.Timestamp exited_at = 7; - google.protobuf.Any extra = 8; + map 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://:. + 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 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 labels = 5; + map 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 extensions = 8; -} + map 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 labels; }; @@ -78,6 +80,7 @@ struct ControllerSandboxStatus { uint32_t pid; std::string state; std::string taskAddress; + std::string version; google::protobuf::Map info; uint64_t createdAt; uint64_t exitedAt; @@ -123,11 +126,10 @@ public: Errors &error) = 0; virtual std::unique_ptr Start(const std::string &sandboxId, Errors &error) = 0 ; virtual std::unique_ptr 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 &fields, Errors &error) = 0; + virtual bool Purge(containerd::types::Sandbox &apiSandbox, + std::vector &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 &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 &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 &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 &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 &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 &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 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 &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 &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 Start(const std::string &sandboxId, Errors &error) override; std::unique_ptr 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 &fields, + Errors &error) override; + bool Purge(containerd::types::Sandbox &apiSandbox, std::vector &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 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 &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 &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 Start(const std::string &sandboxId, Errors &error) override; std::unique_ptr 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 &fields, + Errors &error) override; + bool Purge(containerd::types::Sandbox &apiSandbox, std::vector &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(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 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 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 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 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 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 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 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 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 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 m_vsockPorts; + + // use m_tasksMutex to ensure the correctness of the tasks + RWMutex m_tasksMutex; + // for sandbox api update, containerId --> tasks + std::map> 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 #include +#include #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 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, containerd::types::Sandbox &apiSandbox) { Errors err; - sandbox::ControllerPrepareParams params; - std::unique_ptr 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 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(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, containerd::types::Sandbox &apiSandbox) +{ + Errors err; + std::vector 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 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, const char *containerId, + containerd::types::Sandbox &apiSandbox) +{ + google::protobuf::Map *labels = apiSandbox.mutable_labels(); + google::protobuf::Map *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 + +#include + +#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 lock(m_taskMutex); + return m_task; +} + +auto SandboxTask::AddSandboxTasksProcess(sandbox_process *processes) -> bool +{ + if (processes == nullptr) { + ERROR("Empty args."); + return false; + } + + WriteGuard 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 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 +#include + +#include + +#include "api_v1.grpc.pb.h" +#include "errors.h" +#include "read_write_lock.h" + +namespace sandbox { + +class SandboxTask : public std::enable_shared_from_this { +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