代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/iSulad 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 745497bdc5c5192709ecc7b3edc91a5170f5b30e Mon Sep 17 00:00:00 2001
From: jikai <jikai11@huawei.com>
Date: Fri, 29 Mar 2024 09:33:38 +0000
Subject: [PATCH 40/69] add support for GetContainerEvents
Signed-off-by: jikai <jikai11@huawei.com>
---
src/daemon/CMakeLists.txt | 3 +
src/daemon/common/cri/v1/v1_cri_helpers.cc | 205 +++++++++++++++
src/daemon/common/cri/v1/v1_cri_helpers.h | 5 +
.../{entry => common}/cri/v1/v1_naming.cc | 0
.../{entry => common}/cri/v1/v1_naming.h | 0
src/daemon/config/isulad_config.c | 1 +
.../entry/connect/grpc/cri/cri_service.cc | 3 +-
.../entry/connect/grpc/cri/cri_service.h | 1 +
.../cri/v1/cri_v1_runtime_runtime_service.cc | 147 ++++++++++-
.../cri/v1/cri_v1_runtime_runtime_service.h | 11 +-
src/daemon/entry/connect/grpc/grpc_service.cc | 6 +-
.../v1/v1_cri_container_manager_service.cc | 203 +--------------
.../cri/v1/v1_cri_container_manager_service.h | 13 -
.../v1/v1_cri_pod_sandbox_manager_service.cc | 92 ++++++-
.../v1/v1_cri_pod_sandbox_manager_service.h | 10 +-
.../entry/cri/v1/v1_cri_runtime_service.h | 4 +-
.../cri/v1/v1_cri_runtime_service_impl.cc | 10 +-
.../cri/v1/v1_cri_runtime_service_impl.h | 7 +-
src/daemon/executor/container_cb/execution.c | 25 ++
.../executor/container_cb/execution_create.c | 12 +
src/daemon/mailbox/CMakeLists.txt | 11 +
src/daemon/mailbox/mailbox.c | 167 +++++++++++++
src/daemon/mailbox/mailbox.h | 82 ++++++
src/daemon/mailbox/mailbox_message.c | 94 +++++++
src/daemon/mailbox/mailbox_message.h | 50 ++++
src/daemon/mailbox/message_queue.c | 234 ++++++++++++++++++
src/daemon/mailbox/message_queue.h | 57 +++++
src/daemon/mailbox/message_subscriber.c | 85 +++++++
src/daemon/mailbox/message_subscriber.h | 41 +++
src/daemon/modules/api/container_api.h | 5 +
.../modules/container/supervisor/supervisor.c | 18 ++
src/daemon/sandbox/sandbox.cc | 9 +
src/utils/cutils/blocking_queue.c | 185 ++++++++++++++
src/utils/cutils/blocking_queue.h | 66 +++++
test/mocks/mailbox_mock.cc | 30 +++
test/mocks/mailbox_mock.h | 30 +++
test/sandbox/controller/shim/CMakeLists.txt | 1 +
test/sandbox/sandbox/CMakeLists.txt | 2 +
38 files changed, 1681 insertions(+), 244 deletions(-)
rename src/daemon/{entry => common}/cri/v1/v1_naming.cc (100%)
rename src/daemon/{entry => common}/cri/v1/v1_naming.h (100%)
create mode 100644 src/daemon/mailbox/CMakeLists.txt
create mode 100644 src/daemon/mailbox/mailbox.c
create mode 100644 src/daemon/mailbox/mailbox.h
create mode 100644 src/daemon/mailbox/mailbox_message.c
create mode 100644 src/daemon/mailbox/mailbox_message.h
create mode 100644 src/daemon/mailbox/message_queue.c
create mode 100644 src/daemon/mailbox/message_queue.h
create mode 100644 src/daemon/mailbox/message_subscriber.c
create mode 100644 src/daemon/mailbox/message_subscriber.h
create mode 100644 src/utils/cutils/blocking_queue.c
create mode 100644 src/utils/cutils/blocking_queue.h
create mode 100644 test/mocks/mailbox_mock.cc
create mode 100644 test/mocks/mailbox_mock.h
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index d5280c88..29af3dca 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -3,6 +3,7 @@
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} daemon_top_srcs)
add_subdirectory(executor)
add_subdirectory(entry)
+add_subdirectory(mailbox)
add_subdirectory(modules)
add_subdirectory(config)
add_subdirectory(common)
@@ -11,6 +12,7 @@ set(local_daemon_srcs
${daemon_top_srcs}
${EXECUTOR_SRCS}
${ENTRY_SRCS}
+ ${MAILBOX_SRCS}
${MODULES_SRCS}
${CONFIG_SRCS}
${DAEMON_COMMON_SRCS}
@@ -20,6 +22,7 @@ set(local_daemon_incs
${CMAKE_CURRENT_SOURCE_DIR}
${EXECUTOR_INCS}
${ENTRY_INCS}
+ ${MAILBOX_INCS}
${MODULES_INCS}
${CONFIG_INCS}
${DAEMON_COMMON_INCS}
diff --git a/src/daemon/common/cri/v1/v1_cri_helpers.cc b/src/daemon/common/cri/v1/v1_cri_helpers.cc
index c57301ce..a3488894 100644
--- a/src/daemon/common/cri/v1/v1_cri_helpers.cc
+++ b/src/daemon/common/cri/v1/v1_cri_helpers.cc
@@ -32,6 +32,7 @@
#include "service_container_api.h"
#include "isulad_config.h"
#include "sha256.h"
+#include "v1_naming.h"
namespace CRIHelpersV1 {
@@ -458,4 +459,208 @@ void ApplySandboxSecurityContextToHostConfig(const runtime::v1::LinuxSandboxSecu
}
}
+void PackContainerImageToStatus(
+ container_inspect *inspect, std::unique_ptr<runtime::v1::ContainerStatus> &contStatus, Errors &error)
+{
+ if (inspect->config == nullptr) {
+ return;
+ }
+
+ if (inspect->config->image != nullptr) {
+ contStatus->mutable_image()->set_image(inspect->config->image);
+ }
+
+ contStatus->set_image_ref(CRIHelpers::ToPullableImageID(inspect->config->image, inspect->config->image_ref));
+}
+
+void UpdateBaseStatusFromInspect(
+ container_inspect *inspect, int64_t &createdAt, int64_t &startedAt, int64_t &finishedAt,
+ std::unique_ptr<runtime::v1::ContainerStatus> &contStatus)
+{
+ runtime::v1::ContainerState state { runtime::v1::CONTAINER_UNKNOWN };
+ std::string reason;
+ std::string message;
+ int32_t exitCode { 0 };
+
+ if (inspect->state == nullptr) {
+ goto pack_status;
+ }
+
+ if (inspect->state->running) {
+ // Container is running
+ state = runtime::v1::CONTAINER_RUNNING;
+ } else {
+ // Container is not running.
+ if (finishedAt != 0) { // Case 1
+ state = runtime::v1::CONTAINER_EXITED;
+ if (inspect->state->exit_code == 0) {
+ reason = "Completed";
+ } else {
+ reason = "Error";
+ }
+ } else if (inspect->state->exit_code != 0) { // Case 2
+ state = runtime::v1::CONTAINER_EXITED;
+ finishedAt = createdAt;
+ startedAt = createdAt;
+ reason = "ContainerCannotRun";
+ } else { // Case 3
+ state = runtime::v1::CONTAINER_CREATED;
+ }
+ if (inspect->state->error != nullptr) {
+ message = inspect->state->error;
+ }
+ exitCode = (int32_t)inspect->state->exit_code;
+ }
+
+pack_status:
+ contStatus->set_exit_code(exitCode);
+ contStatus->set_state(state);
+ contStatus->set_created_at(createdAt);
+ contStatus->set_started_at(startedAt);
+ contStatus->set_finished_at(finishedAt);
+ contStatus->set_reason(reason);
+ contStatus->set_message(message);
+}
+
+void PackLabelsToStatus(container_inspect *inspect,
+ std::unique_ptr<runtime::v1::ContainerStatus> &contStatus)
+{
+ if (inspect->config == nullptr || inspect->config->labels == nullptr) {
+ return;
+ }
+ CRIHelpers::ExtractLabels(inspect->config->labels, *contStatus->mutable_labels());
+ CRIHelpers::ExtractAnnotations(inspect->config->annotations, *contStatus->mutable_annotations());
+ for (size_t i = 0; i < inspect->config->labels->len; i++) {
+ if (strcmp(inspect->config->labels->keys[i], CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str()) == 0) {
+ contStatus->set_log_path(inspect->config->labels->values[i]);
+ break;
+ }
+ }
+}
+
+void ConvertMountsToStatus(container_inspect *inspect,
+ std::unique_ptr<runtime::v1::ContainerStatus> &contStatus)
+{
+ for (size_t i = 0; i < inspect->mounts_len; i++) {
+ runtime::v1::Mount *mount = contStatus->add_mounts();
+ mount->set_host_path(inspect->mounts[i]->source);
+ mount->set_container_path(inspect->mounts[i]->destination);
+ mount->set_readonly(!inspect->mounts[i]->rw);
+ if (inspect->mounts[i]->propagation == nullptr || strcmp(inspect->mounts[i]->propagation, "rprivate") == 0) {
+ mount->set_propagation(runtime::v1::PROPAGATION_PRIVATE);
+ } else if (strcmp(inspect->mounts[i]->propagation, "rslave") == 0) {
+ mount->set_propagation(runtime::v1::PROPAGATION_HOST_TO_CONTAINER);
+ } else if (strcmp(inspect->mounts[i]->propagation, "rshared") == 0) {
+ mount->set_propagation(runtime::v1::PROPAGATION_BIDIRECTIONAL);
+ }
+ // Note: Can't set SeLinuxRelabel
+ }
+}
+
+void ConvertResourcesToStatus(container_inspect *inspect,
+ std::unique_ptr<runtime::v1::ContainerStatus> &contStatus)
+{
+ if (inspect->resources == nullptr) {
+ return;
+ }
+ runtime::v1::LinuxContainerResources *resources = contStatus->mutable_resources()->mutable_linux();
+ if (inspect->resources->cpu_shares != 0) {
+ resources->set_cpu_shares(inspect->resources->cpu_shares);
+ }
+ if (inspect->resources->cpu_period != 0) {
+ resources->set_cpu_period(inspect->resources->cpu_period);
+ }
+ if (inspect->resources->cpu_quota != 0) {
+ resources->set_cpu_quota(inspect->resources->cpu_quota);
+ }
+ if (inspect->resources->memory != 0) {
+ resources->set_memory_limit_in_bytes(inspect->resources->memory);
+ }
+ if (inspect->resources->memory_swap != 0) {
+ resources->set_memory_swap_limit_in_bytes(inspect->resources->memory_swap);
+ }
+ for (size_t i = 0; i < inspect->resources->hugetlbs_len; i++) {
+ runtime::v1::HugepageLimit *hugepage = resources->add_hugepage_limits();
+ hugepage->set_page_size(inspect->resources->hugetlbs[i]->page_size);
+ hugepage->set_limit(inspect->resources->hugetlbs[i]->limit);
+ }
+ if (inspect->resources->unified != nullptr) {
+ for (size_t i = 0; i < inspect->resources->unified->len; i++) {
+ auto &resUnified = *(resources->mutable_unified());
+ resUnified[inspect->resources->unified->keys[i]] = inspect->resources->unified->values[i];
+ }
+ }
+}
+
+void ContainerStatusToGRPC(container_inspect *inspect,
+ std::unique_ptr<runtime::v1::ContainerStatus> &contStatus,
+ Errors &error)
+{
+ if (inspect->id != nullptr) {
+ contStatus->set_id(inspect->id);
+ }
+
+ int64_t createdAt {};
+ int64_t startedAt {};
+ int64_t finishedAt {};
+ CRIHelpers::GetContainerTimeStamps(inspect, &createdAt, &startedAt, &finishedAt, error);
+ if (error.NotEmpty()) {
+ return;
+ }
+ contStatus->set_created_at(createdAt);
+ contStatus->set_started_at(startedAt);
+ contStatus->set_finished_at(finishedAt);
+
+ PackContainerImageToStatus(inspect, contStatus, error);
+ UpdateBaseStatusFromInspect(inspect, createdAt, startedAt, finishedAt, contStatus);
+ PackLabelsToStatus(inspect, contStatus);
+ CRINamingV1::ParseContainerName(contStatus->annotations(), contStatus->mutable_metadata(), error);
+ if (error.NotEmpty()) {
+ return;
+ }
+ ConvertMountsToStatus(inspect, contStatus);
+ ConvertResourcesToStatus(inspect, contStatus);
+}
+
+std::unique_ptr<runtime::v1::ContainerStatus> GetContainerStatus(service_executor_t *m_cb, const std::string &containerID, Errors &error)
+{
+ if (m_cb == nullptr) {
+ error.SetError("Invalid input arguments: empty service executor");
+ return nullptr;
+ }
+
+ if (containerID.empty()) {
+ error.SetError("Empty container id");
+ return nullptr;
+ }
+
+ std::string realContainerID = CRIHelpers::GetRealContainerOrSandboxID(m_cb, containerID, false, error);
+ if (error.NotEmpty()) {
+ ERROR("Failed to find container id %s: %s", containerID.c_str(), error.GetCMessage());
+ error.Errorf("Failed to find container id %s: %s", containerID.c_str(), error.GetCMessage());
+ return nullptr;
+ }
+
+ container_inspect *inspect = CRIHelpers::InspectContainer(realContainerID, error, false);
+ if (error.NotEmpty()) {
+ return nullptr;
+ }
+ if (inspect == nullptr) {
+ error.SetError("Get null inspect");
+ return nullptr;
+ }
+ using ContainerStatusPtr = std::unique_ptr<runtime::v1::ContainerStatus>;
+ ContainerStatusPtr contStatus(new (std::nothrow) runtime::v1::ContainerStatus);
+ if (contStatus == nullptr) {
+ error.SetError("Out of memory");
+ free_container_inspect(inspect);
+ return nullptr;
+ }
+
+ ContainerStatusToGRPC(inspect, contStatus, error);
+
+ free_container_inspect(inspect);
+ return contStatus;
+}
+
} // v1 namespace CRIHelpers
diff --git a/src/daemon/common/cri/v1/v1_cri_helpers.h b/src/daemon/common/cri/v1/v1_cri_helpers.h
index b6e6aec6..1578c428 100644
--- a/src/daemon/common/cri/v1/v1_cri_helpers.h
+++ b/src/daemon/common/cri/v1/v1_cri_helpers.h
@@ -27,6 +27,8 @@
#include "checkpoint_handler.h"
#include "constants.h"
#include "errors.h"
+#include "callback.h"
+#include "cstruct_wrapper.h"
namespace CRIHelpersV1 {
@@ -78,6 +80,9 @@ std::string CRISandboxerConvert(const std::string &runtime);
void ApplySandboxSecurityContextToHostConfig(const runtime::v1::LinuxSandboxSecurityContext &context, host_config *hc,
Errors &error);
+auto GetContainerStatus(service_executor_t *m_cb, const std::string &containerID, Errors &error)
+-> std::unique_ptr<runtime::v1::ContainerStatus>;
+
}; // namespace CRIHelpers
#endif // DAEMON_ENTRY_CRI_V1ALPHA_CRI_HELPERS_H
diff --git a/src/daemon/entry/cri/v1/v1_naming.cc b/src/daemon/common/cri/v1/v1_naming.cc
similarity index 100%
rename from src/daemon/entry/cri/v1/v1_naming.cc
rename to src/daemon/common/cri/v1/v1_naming.cc
diff --git a/src/daemon/entry/cri/v1/v1_naming.h b/src/daemon/common/cri/v1/v1_naming.h
similarity index 100%
rename from src/daemon/entry/cri/v1/v1_naming.h
rename to src/daemon/common/cri/v1/v1_naming.h
diff --git a/src/daemon/config/isulad_config.c b/src/daemon/config/isulad_config.c
index 8179558e..778ff921 100644
--- a/src/daemon/config/isulad_config.c
+++ b/src/daemon/config/isulad_config.c
@@ -1760,6 +1760,7 @@ int merge_json_confs_into_global(struct service_arguments *args)
args->json_confs->cri_sandboxers = tmp_json_confs->cri_sandboxers;
tmp_json_confs->cri_sandboxers = NULL;
args->json_confs->enable_cri_v1 = tmp_json_confs->enable_cri_v1;
+ args->json_confs->enable_pod_events = tmp_json_confs->enable_pod_events;
#endif
args->json_confs->systemd_cgroup = tmp_json_confs->systemd_cgroup;
diff --git a/src/daemon/entry/connect/grpc/cri/cri_service.cc b/src/daemon/entry/connect/grpc/cri/cri_service.cc
index c1986c44..d10a60b5 100644
--- a/src/daemon/entry/connect/grpc/cri/cri_service.cc
+++ b/src/daemon/entry/connect/grpc/cri/cri_service.cc
@@ -89,8 +89,9 @@ int CRIService::Init(const isulad_daemon_configs *config)
#ifdef ENABLE_CRI_API_V1
m_enableCRIV1 = config->enable_cri_v1;
+ m_enablePodEvents = config->enable_pod_events;
if (m_enableCRIV1) {
- m_runtimeV1RuntimeService.Init(m_podSandboxImage, m_pluginManager, err);
+ m_runtimeV1RuntimeService.Init(m_podSandboxImage, m_pluginManager, m_enablePodEvents, err);
if (err.NotEmpty()) {
ERROR("Init CRI v1 runtime service failed: %s", err.GetCMessage());
return -1;
diff --git a/src/daemon/entry/connect/grpc/cri/cri_service.h b/src/daemon/entry/connect/grpc/cri/cri_service.h
index 77b2eb72..041c7c63 100644
--- a/src/daemon/entry/connect/grpc/cri/cri_service.h
+++ b/src/daemon/entry/connect/grpc/cri/cri_service.h
@@ -56,6 +56,7 @@ private:
std::string m_podSandboxImage;
std::shared_ptr<Network::PluginManager> m_pluginManager;
bool m_enableCRIV1;
+ bool m_enablePodEvents;
};
}
diff --git a/src/daemon/entry/connect/grpc/cri/v1/cri_v1_runtime_runtime_service.cc b/src/daemon/entry/connect/grpc/cri/v1/cri_v1_runtime_runtime_service.cc
index 76e393f3..bc5ab591 100644
--- a/src/daemon/entry/connect/grpc/cri/v1/cri_v1_runtime_runtime_service.cc
+++ b/src/daemon/entry/connect/grpc/cri/v1/cri_v1_runtime_runtime_service.cc
@@ -22,11 +22,37 @@
#include "callback.h"
#include "network_plugin.h"
#include "v1_cri_runtime_service_impl.h"
+#include "mailbox.h"
+#include "mailbox_message.h"
using namespace CRIV1;
+static void *cri_container_topic_handler(void *context, void *arg)
+{
+ if (context == nullptr || arg == nullptr) {
+ ERROR("Invalid input arguments");
+ return nullptr;
+ }
+
+ auto v1runtimeService = static_cast<RuntimeV1RuntimeServiceImpl *>(context);
+ auto msg = static_cast<cri_container_message_t *>(arg);
+ return v1runtimeService->GenerateCRIContainerEvent(msg->container_id, msg->sandbox_id,
+ static_cast<runtime::v1::ContainerEventType>(msg->type));
+}
+
+static void cri_container_topic_release(void *arg)
+{
+ if (arg == nullptr) {
+ return;
+ }
+
+ auto resp = static_cast<runtime::v1::ContainerEventResponse *>(arg);
+ delete resp;
+}
+
void RuntimeV1RuntimeServiceImpl::Init(std::string &podSandboxImage,
- std::shared_ptr<Network::PluginManager> networkPlugin, Errors &err)
+ std::shared_ptr<Network::PluginManager> networkPlugin,
+ bool enablePodEvents, Errors &err)
{
// Assembly implementation for CRIRuntimeServiceImpl
service_executor_t *cb = get_service_executor();
@@ -36,7 +62,18 @@ void RuntimeV1RuntimeServiceImpl::Init(std::string &podSandboxImage,
return;
}
- m_rService = std::unique_ptr<CRIV1::CRIRuntimeService>(new CRIRuntimeServiceImpl(podSandboxImage, cb, networkPlugin));
+ if (enablePodEvents) {
+ if (mailbox_register_topic_handler(MAILBOX_TOPIC_CRI_CONTAINER, cri_container_topic_handler,
+ this, cri_container_topic_release, true) != 0) {
+ ERROR("Failed to register container topic handler");
+ err.SetError("Failed to register container topic handler");
+ return;
+ }
+ m_enablePodEvents = enablePodEvents;
+ }
+
+
+ m_rService = std::unique_ptr<CRIV1::CRIRuntimeService>(new CRIRuntimeServiceImpl(podSandboxImage, cb, networkPlugin, m_enablePodEvents));
}
void RuntimeV1RuntimeServiceImpl::Wait()
@@ -45,6 +82,54 @@ void RuntimeV1RuntimeServiceImpl::Wait()
void RuntimeV1RuntimeServiceImpl::Shutdown()
{
+ mailbox_unregister_topic_handler(MAILBOX_TOPIC_CRI_CONTAINER);
+}
+
+auto RuntimeV1RuntimeServiceImpl::GenerateCRIContainerEvent(const char *container_id, const char *sandbox_id,
+ runtime::v1::ContainerEventType type) -> runtime::v1::ContainerEventResponse *
+{
+ if (container_id == nullptr || sandbox_id == nullptr) {
+ ERROR("Invalid input arguments");
+ return nullptr;
+ }
+
+ if (type < runtime::v1::ContainerEventType::CONTAINER_CREATED_EVENT ||
+ type > runtime::v1::ContainerEventType::CONTAINER_DELETED_EVENT) {
+ ERROR("Invalid container event type %d", type);
+ return nullptr;
+ }
+
+ std::string containerID(container_id), sandboxID(sandbox_id);
+ Errors error;
+ runtime::v1::ContainerEventResponse *response = new (std::nothrow) runtime::v1::ContainerEventResponse();
+ if (response == nullptr) {
+ ERROR("Out of memory");
+ return nullptr;
+ }
+
+ runtime::v1::PodSandboxStatusResponse *statusReply = new (std::nothrow) runtime::v1::PodSandboxStatusResponse();
+ if (statusReply == nullptr) {
+ ERROR("Out of memory");
+ delete response;
+ return nullptr;
+ }
+
+ m_rService->PodSandboxStatus(sandboxID, statusReply, error);
+ if (!error.Empty()) {
+ WARN("Object: CRI, Type: Failed to status pod:%s due to %s", sandboxID.c_str(),
+ error.GetMessage().c_str());
+ } else {
+ *(response->mutable_pod_sandbox_status()) = *(statusReply->mutable_status());
+ for (auto &containerStatus : statusReply->containers_statuses()) {
+ *(response->add_containers_statuses()) = containerStatus;
+ }
+ }
+
+ response->set_container_event_type((runtime::v1::ContainerEventType)type);
+ response->set_container_id(containerID);
+ response->set_created_at(util_get_now_time_nanos());
+
+ return response;
}
grpc::Status RuntimeV1RuntimeServiceImpl::Version(grpc::ServerContext *context,
@@ -398,14 +483,12 @@ grpc::Status RuntimeV1RuntimeServiceImpl::PodSandboxStatus(grpc::ServerContext *
INFO("Event: {Object: CRI, Type: Status Pod: %s}", request->pod_sandbox_id().c_str());
- std::unique_ptr<runtime::v1::PodSandboxStatus> podStatus;
- podStatus = m_rService->PodSandboxStatus(request->pod_sandbox_id(), error);
- if (!error.Empty() || !podStatus) {
+ m_rService->PodSandboxStatus(request->pod_sandbox_id(), reply, error);
+ if (!error.Empty()) {
ERROR("Object: CRI, Type: Failed to status pod:%s due to %s", request->pod_sandbox_id().c_str(),
error.GetMessage().c_str());
return grpc::Status(grpc::StatusCode::UNKNOWN, error.GetMessage());
}
- *(reply->mutable_status()) = *podStatus;
INFO("Event: {Object: CRI, Type: Statused Pod: %s}", request->pod_sandbox_id().c_str());
@@ -657,3 +740,55 @@ RuntimeV1RuntimeServiceImpl::RuntimeConfig(grpc::ServerContext *context,
return grpc::Status::OK;
}
+
+grpc::Status RuntimeV1RuntimeServiceImpl::GetContainerEvents(grpc::ServerContext *context,
+ const runtime::v1::GetEventsRequest *request,
+ grpc::ServerWriter<runtime::v1::ContainerEventResponse> *writer)
+{
+ Errors error;
+
+ if (context == nullptr || request == nullptr || writer == nullptr) {
+ ERROR("Invalid input arguments");
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Invalid input arguments");
+ }
+
+ if (!m_enablePodEvents) {
+ ERROR("Pod events is not enabled");
+ return grpc::Status(grpc::StatusCode::UNIMPLEMENTED, "Pod events is not enabled");
+ }
+
+ INFO("Event: {Object: CRI, Type: Getting Container Events}");
+
+ __isula_auto_subscriber auto sub = mailbox_subscribe(MAILBOX_TOPIC_CRI_CONTAINER);
+ if (sub == nullptr) {
+ ERROR("Object: CRI, Type: Failed to subscribe container events");
+ return grpc::Status(grpc::StatusCode::UNKNOWN, "Failed to subscribe container events");
+ }
+
+ for (;;) {
+ __isula_auto_mailbox_message mailbox_message *msg = NULL;
+ int ret = message_subscriber_pop(sub, &msg);
+ if (ret == 0) {
+ if (msg == nullptr) {
+ // nullptr response indicates eventqueue being shutdown, not need to unscribe now
+ return grpc::Status(grpc::StatusCode::UNKNOWN, "Event queue is shutdown");
+ }
+ auto *response = static_cast<runtime::v1::ContainerEventResponse *>(msg->data);
+ if (!writer->Write(*response)) {
+ break;
+ }
+ } else if (ret != ETIMEDOUT) {
+ ERROR("Failed to pop message from subscriber");
+ break;
+ }
+ if (context->IsCancelled()) {
+ INFO("Object: CRI, Type: GetContainerEvents is cancelled");
+ break;
+ }
+ }
+
+ mailbox_unsubscribe(MAILBOX_TOPIC_CRI_CONTAINER, sub);
+ INFO("Event: {Object: CRI, Type: Got Container Events}");
+
+ return grpc::Status::OK;
+}
diff --git a/src/daemon/entry/connect/grpc/cri/v1/cri_v1_runtime_runtime_service.h b/src/daemon/entry/connect/grpc/cri/v1/cri_v1_runtime_runtime_service.h
index 52cc6b99..842d1811 100644
--- a/src/daemon/entry/connect/grpc/cri/v1/cri_v1_runtime_runtime_service.h
+++ b/src/daemon/entry/connect/grpc/cri/v1/cri_v1_runtime_runtime_service.h
@@ -26,9 +26,13 @@
// Implement of runtime RuntimeService
class RuntimeV1RuntimeServiceImpl : public runtime::v1::RuntimeService::Service {
public:
- void Init(std::string &podSandboxImage, std::shared_ptr<Network::PluginManager> networkPlugin, Errors &err);
+ void Init(std::string &podSandboxImage, std::shared_ptr<Network::PluginManager> networkPlugin,
+ bool enablePodEvents, Errors &err);
void Wait();
void Shutdown();
+ auto GenerateCRIContainerEvent(const char *container_id, const char *sandbox_id, runtime::v1::ContainerEventType type)
+ -> runtime::v1::ContainerEventResponse *;
+
grpc::Status Version(grpc::ServerContext *context, const runtime::v1::VersionRequest *request,
runtime::v1::VersionResponse *reply) override;
@@ -105,8 +109,13 @@ public:
const runtime::v1::RuntimeConfigRequest *request,
runtime::v1::RuntimeConfigResponse *reply) override;
+ grpc::Status GetContainerEvents(grpc::ServerContext *context,
+ const runtime::v1::GetEventsRequest *request,
+ grpc::ServerWriter<runtime::v1::ContainerEventResponse> *writer) override;
+
private:
std::unique_ptr<CRIV1::CRIRuntimeService> m_rService;
+ bool m_enablePodEvents;
};
#endif // DAEMON_ENTRY_CONNECT_GRPC_CRI_V1_RUNTIME_RUNTIME_SERVICE_H
diff --git a/src/daemon/entry/connect/grpc/grpc_service.cc b/src/daemon/entry/connect/grpc/grpc_service.cc
index 61e284f3..1d8de922 100644
--- a/src/daemon/entry/connect/grpc/grpc_service.cc
+++ b/src/daemon/entry/connect/grpc/grpc_service.cc
@@ -108,11 +108,11 @@ public:
void Shutdown(void)
{
- m_server->Shutdown();
-
- // call CRI to shutdown stream server
+ // call CRI to shutdown stream server, shutdown cri first to notify events thread to exit
m_criService.Shutdown();
+ m_server->Shutdown();
+
// Shutdown daemon, this operation should remove socket file.
for (const auto &address : m_socketPath) {
if (address.find(UNIX_SOCKET_PREFIX) == 0) {
diff --git a/src/daemon/entry/cri/v1/v1_cri_container_manager_service.cc b/src/daemon/entry/cri/v1/v1_cri_container_manager_service.cc
index cac5c0ba..e86dafae 100644
--- a/src/daemon/entry/cri/v1/v1_cri_container_manager_service.cc
+++ b/src/daemon/entry/cri/v1/v1_cri_container_manager_service.cc
@@ -1007,208 +1007,9 @@ cleanup:
return contStats;
}
-void ContainerManagerService::PackContainerImageToStatus(
- container_inspect *inspect, std::unique_ptr<runtime::v1::ContainerStatus> &contStatus, Errors &error)
+std::unique_ptr<runtime::v1::ContainerStatus> ContainerManagerService::ContainerStatus(const std::string &containerID, Errors &error)
{
- if (inspect->config == nullptr) {
- return;
- }
-
- if (inspect->config->image != nullptr) {
- contStatus->mutable_image()->set_image(inspect->config->image);
- }
-
- contStatus->set_image_ref(CRIHelpers::ToPullableImageID(inspect->config->image, inspect->config->image_ref));
- return;
-}
-
-void ContainerManagerService::UpdateBaseStatusFromInspect(
- container_inspect *inspect, int64_t &createdAt, int64_t &startedAt, int64_t &finishedAt,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus)
-{
- runtime::v1::ContainerState state { runtime::v1::CONTAINER_UNKNOWN };
- std::string reason;
- std::string message;
- int32_t exitCode { 0 };
-
- if (inspect->state == nullptr) {
- goto pack_status;
- }
-
- if (inspect->state->running) {
- // Container is running
- state = runtime::v1::CONTAINER_RUNNING;
- } else {
- // Container is not running.
- if (finishedAt != 0) { // Case 1
- state = runtime::v1::CONTAINER_EXITED;
- if (inspect->state->exit_code == 0) {
- reason = "Completed";
- } else {
- reason = "Error";
- }
- } else if (inspect->state->exit_code != 0) { // Case 2
- state = runtime::v1::CONTAINER_EXITED;
- finishedAt = createdAt;
- startedAt = createdAt;
- reason = "ContainerCannotRun";
- } else { // Case 3
- state = runtime::v1::CONTAINER_CREATED;
- }
- if (inspect->state->oom_killed) {
- reason = "OOMKilled";
- }
- if (inspect->state->error != nullptr) {
- message = inspect->state->error;
- }
- exitCode = (int32_t)inspect->state->exit_code;
- }
-
-pack_status:
- contStatus->set_exit_code(exitCode);
- contStatus->set_state(state);
- contStatus->set_created_at(createdAt);
- contStatus->set_started_at(startedAt);
- contStatus->set_finished_at(finishedAt);
- contStatus->set_reason(reason);
- contStatus->set_message(message);
-}
-
-void ContainerManagerService::PackLabelsToStatus(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus)
-{
- if (inspect->config == nullptr || inspect->config->labels == nullptr) {
- return;
- }
- CRIHelpers::ExtractLabels(inspect->config->labels, *contStatus->mutable_labels());
- CRIHelpers::ExtractAnnotations(inspect->config->annotations, *contStatus->mutable_annotations());
- for (size_t i = 0; i < inspect->config->labels->len; i++) {
- if (strcmp(inspect->config->labels->keys[i], CRIHelpers::Constants::CONTAINER_LOGPATH_LABEL_KEY.c_str()) == 0) {
- contStatus->set_log_path(inspect->config->labels->values[i]);
- break;
- }
- }
-}
-
-void ContainerManagerService::ConvertMountsToStatus(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus)
-{
- for (size_t i = 0; i < inspect->mounts_len; i++) {
- runtime::v1::Mount *mount = contStatus->add_mounts();
- mount->set_host_path(inspect->mounts[i]->source);
- mount->set_container_path(inspect->mounts[i]->destination);
- mount->set_readonly(!inspect->mounts[i]->rw);
- if (inspect->mounts[i]->propagation == nullptr || strcmp(inspect->mounts[i]->propagation, "rprivate") == 0) {
- mount->set_propagation(runtime::v1::PROPAGATION_PRIVATE);
- } else if (strcmp(inspect->mounts[i]->propagation, "rslave") == 0) {
- mount->set_propagation(runtime::v1::PROPAGATION_HOST_TO_CONTAINER);
- } else if (strcmp(inspect->mounts[i]->propagation, "rshared") == 0) {
- mount->set_propagation(runtime::v1::PROPAGATION_BIDIRECTIONAL);
- }
- // Note: Can't set SeLinuxRelabel
- }
-}
-
-void ContainerManagerService::ConvertResourcesToStatus(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus)
-{
- if (inspect->resources == nullptr) {
- return;
- }
- runtime::v1::LinuxContainerResources *resources = contStatus->mutable_resources()->mutable_linux();
- if (inspect->resources->cpu_shares != 0) {
- resources->set_cpu_shares(inspect->resources->cpu_shares);
- }
- if (inspect->resources->cpu_period != 0) {
- resources->set_cpu_period(inspect->resources->cpu_period);
- }
- if (inspect->resources->cpu_quota != 0) {
- resources->set_cpu_quota(inspect->resources->cpu_quota);
- }
- if (inspect->resources->memory != 0) {
- resources->set_memory_limit_in_bytes(inspect->resources->memory);
- }
- if (inspect->resources->memory_swap != 0) {
- resources->set_memory_swap_limit_in_bytes(inspect->resources->memory_swap);
- }
- for (size_t i = 0; i < inspect->resources->hugetlbs_len; i++) {
- runtime::v1::HugepageLimit *hugepage = resources->add_hugepage_limits();
- hugepage->set_page_size(inspect->resources->hugetlbs[i]->page_size);
- hugepage->set_limit(inspect->resources->hugetlbs[i]->limit);
- }
- if (inspect->resources->unified != nullptr) {
- for (size_t i = 0; i < inspect->resources->unified->len; i++) {
- auto &resUnified = *(resources->mutable_unified());
- resUnified[inspect->resources->unified->keys[i]] = inspect->resources->unified->values[i];
- }
- }
-}
-
-void ContainerManagerService::ContainerStatusToGRPC(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus,
- Errors &error)
-{
- if (inspect->id != nullptr) {
- contStatus->set_id(inspect->id);
- }
-
- int64_t createdAt {};
- int64_t startedAt {};
- int64_t finishedAt {};
- CRIHelpers::GetContainerTimeStamps(inspect, &createdAt, &startedAt, &finishedAt, error);
- if (error.NotEmpty()) {
- return;
- }
- contStatus->set_created_at(createdAt);
- contStatus->set_started_at(startedAt);
- contStatus->set_finished_at(finishedAt);
-
- PackContainerImageToStatus(inspect, contStatus, error);
- UpdateBaseStatusFromInspect(inspect, createdAt, startedAt, finishedAt, contStatus);
- PackLabelsToStatus(inspect, contStatus);
- CRINamingV1::ParseContainerName(contStatus->annotations(), contStatus->mutable_metadata(), error);
- if (error.NotEmpty()) {
- return;
- }
- ConvertMountsToStatus(inspect, contStatus);
- ConvertResourcesToStatus(inspect, contStatus);
-}
-
-std::unique_ptr<runtime::v1::ContainerStatus>
-ContainerManagerService::ContainerStatus(const std::string &containerID, Errors &error)
-{
- if (containerID.empty()) {
- error.SetError("Empty container id");
- return nullptr;
- }
-
- std::string realContainerID = CRIHelpers::GetRealContainerOrSandboxID(m_cb, containerID, false, error);
- if (error.NotEmpty()) {
- ERROR("Failed to find container id %s: %s", containerID.c_str(), error.GetCMessage());
- error.Errorf("Failed to find container id %s: %s", containerID.c_str(), error.GetCMessage());
- return nullptr;
- }
-
- container_inspect *inspect = CRIHelpers::InspectContainer(realContainerID, error, false);
- if (error.NotEmpty()) {
- return nullptr;
- }
- if (inspect == nullptr) {
- error.SetError("Get null inspect");
- return nullptr;
- }
- using ContainerStatusPtr = std::unique_ptr<runtime::v1::ContainerStatus>;
- ContainerStatusPtr contStatus(new (std::nothrow) runtime::v1::ContainerStatus);
- if (contStatus == nullptr) {
- error.SetError("Out of memory");
- free_container_inspect(inspect);
- return nullptr;
- }
-
- ContainerStatusToGRPC(inspect, contStatus, error);
-
- free_container_inspect(inspect);
- return contStatus;
+ return CRIHelpersV1::GetContainerStatus(m_cb, containerID, error);
}
void ContainerManagerService::UpdateContainerResources(const std::string &containerID,
diff --git a/src/daemon/entry/cri/v1/v1_cri_container_manager_service.h b/src/daemon/entry/cri/v1/v1_cri_container_manager_service.h
index 4e772bda..50f5ed69 100644
--- a/src/daemon/entry/cri/v1/v1_cri_container_manager_service.h
+++ b/src/daemon/entry/cri/v1/v1_cri_container_manager_service.h
@@ -111,19 +111,6 @@ private:
std::unique_ptr<runtime::v1::ContainerStats> &container);
void SetFsUsage(const imagetool_fs_info *fs_usage, int64_t timestamp,
std::unique_ptr<runtime::v1::ContainerStats> &container);
- void ContainerStatusToGRPC(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus, Errors &error);
- void PackContainerImageToStatus(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus, Errors &error);
- void UpdateBaseStatusFromInspect(container_inspect *inspect, int64_t &createdAt, int64_t &startedAt,
- int64_t &finishedAt,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus);
- void PackLabelsToStatus(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus);
- void ConvertMountsToStatus(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus);
- void ConvertResourcesToStatus(container_inspect *inspect,
- std::unique_ptr<runtime::v1::ContainerStatus> &contStatus);
void ExecSyncFromGRPC(const std::string &containerID, const google::protobuf::RepeatedPtrField<std::string> &cmd,
int64_t timeout, container_exec_request **request, Errors &error);
auto ValidateExecRequest(const runtime::v1::ExecRequest &req, Errors &error) -> int;
diff --git a/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.cc b/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.cc
index f125e714..4291d8a0 100644
--- a/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.cc
+++ b/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.cc
@@ -36,6 +36,7 @@
#include "sandbox_manager.h"
#include "transform.h"
#include "isulad_config.h"
+#include "mailbox.h"
namespace CRIV1 {
void PodSandboxManagerService::PrepareSandboxData(const runtime::v1::PodSandboxConfig &config,
@@ -302,6 +303,7 @@ auto PodSandboxManagerService::RunPodSandbox(const runtime::v1::PodSandboxConfig
std::string jsonCheckpoint;
std::string network_setting_json;
runtime::v1::PodSandboxConfig copyConfig = config;
+ cri_container_message_t msg = { 0 };
// Step 1: Parepare sandbox name, runtime and networkMode
PrepareSandboxData(config, runtimeHandler, sandboxName, runtimeInfo, networkMode, error);
@@ -372,6 +374,11 @@ auto PodSandboxManagerService::RunPodSandbox(const runtime::v1::PodSandboxConfig
goto cleanup_network;
}
+ msg.container_id = sandbox->GetId().c_str();
+ msg.sandbox_id = sandbox->GetId().c_str();
+ msg.type = CRI_CONTAINER_MESSAGE_TYPE_CREATED;
+ mailbox_publish(MAILBOX_TOPIC_CRI_CONTAINER, &msg);
+
// Step 10: Save network settings json to disk
// Update network settings before start sandbox since sandbox container will use the sandbox key
if (namespace_is_cni(networkMode.c_str())) {
@@ -391,6 +398,9 @@ auto PodSandboxManagerService::RunPodSandbox(const runtime::v1::PodSandboxConfig
return response_id;
}
+ msg.type = CRI_CONTAINER_MESSAGE_TYPE_STARTED;
+ mailbox_publish(MAILBOX_TOPIC_CRI_CONTAINER, &msg);
+
return sandbox->GetId();
cleanup_network:
@@ -700,6 +710,13 @@ void PodSandboxManagerService::RemovePodSandbox(const std::string &podSandboxID,
ERROR("Failed to delete sandbox %s: %s", podSandboxID.c_str(), error.GetCMessage());
}
+ if (error.Empty()) {
+ cri_container_message_t msg = { 0 };
+ msg.container_id = sandbox->GetId().c_str();
+ msg.sandbox_id = sandbox->GetId().c_str();
+ msg.type = CRI_CONTAINER_MESSAGE_TYPE_DELETED;
+ mailbox_publish(MAILBOX_TOPIC_CRI_CONTAINER, &msg);
+ }
}
auto PodSandboxManagerService::SharesHostNetwork(const container_inspect *inspect) -> runtime::v1::NamespaceMode
@@ -800,10 +817,29 @@ void PodSandboxManagerService::SetSandboxStatusNetwork(std::shared_ptr<sandbox::
}
}
-std::unique_ptr<runtime::v1::PodSandboxStatus>
-PodSandboxManagerService::PodSandboxStatus(const std::string &podSandboxID, Errors &error)
+void PodSandboxManagerService::GetContainerStatuses(const std::string &podSandboxID,
+ std::vector<std::unique_ptr<runtime::v1::ContainerStatus>> &containerStatuses,
+ std::vector<std::string> &errors) {
+ auto list_response_wrapper = GetContainerListResponse(podSandboxID, errors);
+ if (list_response_wrapper == nullptr) {
+ return;
+ }
+
+ auto list_response = list_response_wrapper->get();
+ // Remove all containers in the sandbox.
+ for (size_t i = 0; i < list_response->containers_len; i++) {
+ Errors stError;
+ containerStatuses.push_back(CRIHelpersV1::GetContainerStatus(m_cb, list_response->containers[i]->id, stError));
+ if (stError.NotEmpty()) {
+ ERROR("Error get container status: %s: %s", list_response->containers[i]->id, stError.GetCMessage());
+ errors.push_back(stError.GetMessage());
+ }
+ }
+}
+
+std::unique_ptr<runtime::v1::PodSandboxStatus> PodSandboxManagerService::GetPodSandboxStatus(const std::string &podSandboxID, Errors &error)
{
- std::unique_ptr<runtime::v1::PodSandboxStatus> podStatus(new runtime::v1::PodSandboxStatus);
+ std::unique_ptr<runtime::v1::PodSandboxStatus> podStatus(new (std::nothrow) runtime::v1::PodSandboxStatus);
if (podStatus == nullptr) {
ERROR("Out of memory");
error.SetError("Out of memory");
@@ -831,6 +867,50 @@ PodSandboxManagerService::PodSandboxStatus(const std::string &podSandboxID, Erro
return podStatus;
}
+void PodSandboxManagerService::PodSandboxStatus(const std::string &podSandboxID,
+ runtime::v1::PodSandboxStatusResponse *reply, Errors &error)
+{
+ if (reply == nullptr) {
+ ERROR("Invalid NULL reply");
+ error.SetError("Invalid NULL reply");
+ return;
+ }
+
+
+ auto podStatus = GetPodSandboxStatus(podSandboxID, error);
+ if (error.NotEmpty()) {
+ ERROR("Failed to get pod sandbox status: %s", error.GetCMessage());
+ return;
+ }
+
+ auto sandbox = sandbox::SandboxManager::GetInstance()->GetSandbox(podSandboxID);
+ if (sandbox == nullptr) {
+ ERROR("Failed to find sandbox id %s", podSandboxID.c_str());
+ error.Errorf("Failed to find sandbox id %s", podSandboxID.c_str());
+ return;
+ }
+
+ *(reply->mutable_status()) = *podStatus;
+
+
+ if (!m_enablePodEvents) {
+ return;
+ }
+
+ std::vector<std::unique_ptr<runtime::v1::ContainerStatus>> containerStatuses;
+ std::vector<std::string> errors;
+ GetContainerStatuses(sandbox->GetId(), containerStatuses, errors);
+ if (errors.size() != 0) {
+ error.SetAggregate(errors);
+ return;
+ }
+
+ for (auto &containerStatus : containerStatuses) {
+ *(reply->add_containers_statuses()) = *containerStatus;
+ }
+ return;
+}
+
void PodSandboxManagerService::ListPodSandbox(const runtime::v1::PodSandboxFilter &filter,
std::vector<std::unique_ptr<runtime::v1::PodSandbox>> &pods,
Errors &error)
@@ -944,7 +1024,7 @@ void PodSandboxManagerService::GetPodSandboxNetworkMetrics(const std::string &ne
void PodSandboxManagerService::PackagePodSandboxStatsAttributes(
const std::string &id, std::unique_ptr<runtime::v1::PodSandboxStats> &podStatsPtr, Errors &error)
{
- auto status = PodSandboxStatus(id, error);
+ auto status = GetPodSandboxStatus(id, error);
if (error.NotEmpty()) {
return;
}
@@ -1111,8 +1191,8 @@ auto PodSandboxManagerService::PodSandboxStats(const std::string &podSandboxID,
auto &config = sandbox->GetSandboxConfig();
auto oldStatsRec = sandbox->GetStatsInfo();
- auto status = PodSandboxStatus(sandbox->GetId(), tmpErr);
- if (error.NotEmpty()) {
+ auto status = GetPodSandboxStatus(sandbox->GetId(), tmpErr);
+ if (tmpErr.NotEmpty()) {
ERROR("Failed to get podsandbox %s status: %s", sandbox->GetId().c_str(), tmpErr.GetCMessage());
error.Errorf("Failed to get podsandbox %s status", sandbox->GetId().c_str());
return nullptr;
diff --git a/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.h b/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.h
index c3d98b8c..3872c4c9 100644
--- a/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.h
+++ b/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.h
@@ -38,10 +38,11 @@ namespace CRIV1 {
class PodSandboxManagerService {
public:
PodSandboxManagerService(const std::string &podSandboxImage, service_executor_t *cb,
- std::shared_ptr<Network::PluginManager> pluginManager)
+ std::shared_ptr<Network::PluginManager> pluginManager, bool enablePodEvents)
: m_podSandboxImage(podSandboxImage)
, m_cb(cb)
, m_pluginManager(pluginManager)
+ , m_enablePodEvents(enablePodEvents)
{
}
PodSandboxManagerService(const PodSandboxManagerService &) = delete;
@@ -55,8 +56,7 @@ public:
void RemovePodSandbox(const std::string &podSandboxID, Errors &error);
- auto PodSandboxStatus(const std::string &podSandboxID, Errors &error)
- -> std::unique_ptr<runtime::v1::PodSandboxStatus>;
+ void PodSandboxStatus(const std::string &podSandboxID, runtime::v1::PodSandboxStatusResponse *reply, Errors &error);
void ListPodSandbox(const runtime::v1::PodSandboxFilter &filter,
std::vector<std::unique_ptr<runtime::v1::PodSandbox>> &pods, Errors &error);
@@ -129,6 +129,9 @@ private:
std::vector<std::string> &podSandboxIDs, Errors &error);
void ApplySandboxLinuxOptions(const runtime::v1::LinuxPodSandboxConfig &lc, host_config *hc,
container_config *custom_config, Errors &error);
+ auto GetPodSandboxStatus(const std::string &podSandboxID, Errors &error) -> std::unique_ptr<runtime::v1::PodSandboxStatus>;
+ void GetContainerStatuses(const std::string &podSandboxID, std::vector<std::unique_ptr<runtime::v1::ContainerStatus>> &containerStatuses,
+ std::vector<std::string> &errors);
private:
std::string m_podSandboxImage;
@@ -136,6 +139,7 @@ private:
std::map<std::string, bool> m_networkReady;
service_executor_t *m_cb { nullptr };
std::shared_ptr<Network::PluginManager> m_pluginManager { nullptr };
+ bool m_enablePodEvents;
};
} // namespace CRI
diff --git a/src/daemon/entry/cri/v1/v1_cri_runtime_service.h b/src/daemon/entry/cri/v1/v1_cri_runtime_service.h
index 839f6724..4521e3df 100644
--- a/src/daemon/entry/cri/v1/v1_cri_runtime_service.h
+++ b/src/daemon/entry/cri/v1/v1_cri_runtime_service.h
@@ -70,8 +70,8 @@ public:
virtual void RemovePodSandbox(const std::string &podSandboxID, Errors &error) = 0;
- virtual auto PodSandboxStatus(const std::string &podSandboxID,
- Errors &error) -> std::unique_ptr<runtime::v1::PodSandboxStatus> = 0;
+ virtual void PodSandboxStatus(const std::string &podSandboxID, runtime::v1::PodSandboxStatusResponse *reply,
+ Errors &error) = 0;
virtual void ListPodSandbox(const runtime::v1::PodSandboxFilter &filter,
std::vector<std::unique_ptr<runtime::v1::PodSandbox>> &pods, Errors &error) = 0;
diff --git a/src/daemon/entry/cri/v1/v1_cri_runtime_service_impl.cc b/src/daemon/entry/cri/v1/v1_cri_runtime_service_impl.cc
index aa5ae516..7b40e29d 100644
--- a/src/daemon/entry/cri/v1/v1_cri_runtime_service_impl.cc
+++ b/src/daemon/entry/cri/v1/v1_cri_runtime_service_impl.cc
@@ -19,11 +19,12 @@
namespace CRIV1 {
CRIRuntimeServiceImpl::CRIRuntimeServiceImpl(const std::string &podSandboxImage, service_executor_t *cb,
- std::shared_ptr<Network::PluginManager> pluginManager)
+ std::shared_ptr<Network::PluginManager> pluginManager, bool enablePodEvents)
: m_runtimeVersioner(new RuntimeVersionerService(cb))
, m_containerManager(new ContainerManagerService(cb))
- , m_podSandboxManager(new PodSandboxManagerService(podSandboxImage, cb, pluginManager))
+ , m_podSandboxManager(new PodSandboxManagerService(podSandboxImage, cb, pluginManager, enablePodEvents))
, m_runtimeManager(new RuntimeManagerService(cb, pluginManager))
+ , m_enablePodEvents(enablePodEvents)
{
}
@@ -124,10 +125,9 @@ void CRIRuntimeServiceImpl::RemovePodSandbox(const std::string &podSandboxID, Er
m_podSandboxManager->RemovePodSandbox(podSandboxID, error);
}
-auto CRIRuntimeServiceImpl::PodSandboxStatus(const std::string &podSandboxID, Errors &error)
--> std::unique_ptr<runtime::v1::PodSandboxStatus>
+void CRIRuntimeServiceImpl::PodSandboxStatus(const std::string &podSandboxID, runtime::v1::PodSandboxStatusResponse *reply, Errors &error)
{
- return m_podSandboxManager->PodSandboxStatus(podSandboxID, error);
+ m_podSandboxManager->PodSandboxStatus(podSandboxID, reply, error);
}
void CRIRuntimeServiceImpl::ListPodSandbox(const runtime::v1::PodSandboxFilter &filter,
diff --git a/src/daemon/entry/cri/v1/v1_cri_runtime_service_impl.h b/src/daemon/entry/cri/v1/v1_cri_runtime_service_impl.h
index 0a25749f..6ae59bfa 100644
--- a/src/daemon/entry/cri/v1/v1_cri_runtime_service_impl.h
+++ b/src/daemon/entry/cri/v1/v1_cri_runtime_service_impl.h
@@ -26,7 +26,8 @@ namespace CRIV1 {
class CRIRuntimeServiceImpl : public CRIRuntimeService {
public:
CRIRuntimeServiceImpl(const std::string &podSandboxImage, service_executor_t *cb,
- std::shared_ptr<Network::PluginManager> pluginManager);
+ std::shared_ptr<Network::PluginManager> pluginManager,
+ bool enablePodEvents);
CRIRuntimeServiceImpl(const CRIRuntimeServiceImpl &) = delete;
auto operator=(const CRIRuntimeServiceImpl &) -> CRIRuntimeServiceImpl & = delete;
virtual ~CRIRuntimeServiceImpl() = default;
@@ -72,8 +73,7 @@ public:
void RemovePodSandbox(const std::string &podSandboxID, Errors &error) override;
- auto PodSandboxStatus(const std::string &podSandboxID, Errors &error)
- -> std::unique_ptr<runtime::v1::PodSandboxStatus> override;
+ void PodSandboxStatus(const std::string &podSandboxID, runtime::v1::PodSandboxStatusResponse *reply, Errors &error) override;
void ListPodSandbox(const runtime::v1::PodSandboxFilter &filter,
std::vector<std::unique_ptr<runtime::v1::PodSandbox>> &pods, Errors &error) override;
@@ -103,6 +103,7 @@ protected:
private:
std::string m_podSandboxImage;
std::shared_ptr<Network::PluginManager> m_pluginManager { nullptr };
+ bool m_enablePodEvents;
};
} // namespace CRIV1
#endif // DAEMON_ENTRY_CRI_V1_CRI_RUNTIME_SERVICE_IMPL_H
diff --git a/src/daemon/executor/container_cb/execution.c b/src/daemon/executor/container_cb/execution.c
index 88c6b354..e5c96628 100644
--- a/src/daemon/executor/container_cb/execution.c
+++ b/src/daemon/executor/container_cb/execution.c
@@ -62,6 +62,7 @@
#include "event_type.h"
#include "utils_timestamp.h"
#include "utils_verify.h"
+#include "mailbox.h"
#ifdef ENABLE_NATIVE_NETWORK
#include "service_network_api.h"
@@ -542,6 +543,9 @@ static int container_start_cb(const container_start_request *request, container_
container_t *cont = NULL;
int sync_fd = -1;
pthread_t thread_id = 0;
+#ifdef ENABLE_CRI_API_V1
+ cri_container_message_t message;
+#endif
DAEMON_CLEAR_ERRMSG();
@@ -596,6 +600,15 @@ static int container_start_cb(const container_start_request *request, container_
EVENT("Event: {Object: %s, Type: Running}", id);
(void)isulad_monitor_send_container_event(id, START, -1, 0, NULL, NULL);
+#ifdef ENABLE_CRI_API_V1
+ if (is_container_in_sandbox(cont->common_config->sandbox_info)) {
+ message.container_id = id;
+ message.sandbox_id = cont->common_config->sandbox_info->id;
+ message.type = CRI_CONTAINER_MESSAGE_TYPE_STARTED;
+ mailbox_publish(MAILBOX_TOPIC_CRI_CONTAINER, &message);
+ }
+#endif
+
pack_response:
handle_start_io_thread_by_cc(cc, sync_fd, thread_id);
delete_daemon_fifos(fifopath, (const char **)fifos);
@@ -1009,6 +1022,9 @@ static int container_delete_cb(const container_delete_request *request, containe
char *name = NULL;
char *id = NULL;
container_t *cont = NULL;
+#ifdef ENABLE_CRI_API_V1
+ cri_container_message_t message;
+#endif
DAEMON_CLEAR_ERRMSG();
if (request == NULL || response == NULL) {
@@ -1063,6 +1079,15 @@ static int container_delete_cb(const container_delete_request *request, containe
EVENT("Event: {Object: %s, Type: Deleted}", id);
+#ifdef ENABLE_CRI_API_V1
+ if (is_container_in_sandbox(cont->common_config->sandbox_info)) {
+ message.container_id = cont->common_config->id;
+ message.sandbox_id = cont->common_config->sandbox_info->id;
+ message.type = CRI_CONTAINER_MESSAGE_TYPE_DELETED;
+ mailbox_publish(MAILBOX_TOPIC_CRI_CONTAINER, &message);
+ }
+#endif
+
pack_response:
pack_delete_response(*response, cc, id);
container_unref(cont);
diff --git a/src/daemon/executor/container_cb/execution_create.c b/src/daemon/executor/container_cb/execution_create.c
index e00afb68..a9102226 100644
--- a/src/daemon/executor/container_cb/execution_create.c
+++ b/src/daemon/executor/container_cb/execution_create.c
@@ -62,6 +62,7 @@
#include "opt_log.h"
#include "runtime_api.h"
#include "id_name_manager.h"
+#include "mailbox.h"
#ifdef ENABLE_CRI_API_V1
static bool validate_sandbox_info(const container_sandbox_info *sandbox)
@@ -1389,6 +1390,9 @@ int container_create_cb(const container_create_request *request, container_creat
bool skip_id_name_manage = false;
bool skip_sandbox_key_manage = false;
__isula_auto_sysinfo_t sysinfo_t *sysinfo = NULL;
+#ifdef ENABLE_CRI_API_V1
+ cri_container_message_t message;
+#endif
DAEMON_CLEAR_ERRMSG();
@@ -1572,6 +1576,14 @@ int container_create_cb(const container_create_request *request, container_creat
EVENT("Event: {Object: %s, Type: Created %s}", id, name);
(void)isulad_monitor_send_container_event(id, CREATE, -1, 0, NULL, NULL);
+#ifdef ENABLE_CRI_API_V1
+ if (is_container_in_sandbox(request->sandbox)) {
+ message.container_id = id;
+ message.sandbox_id = request->sandbox->id;
+ message.type = CRI_CONTAINER_MESSAGE_TYPE_CREATED;
+ mailbox_publish(MAILBOX_TOPIC_CRI_CONTAINER, &message);
+ }
+#endif
goto pack_response;
umount_channel:
diff --git a/src/daemon/mailbox/CMakeLists.txt b/src/daemon/mailbox/CMakeLists.txt
new file mode 100644
index 00000000..984f9acb
--- /dev/null
+++ b/src/daemon/mailbox/CMakeLists.txt
@@ -0,0 +1,11 @@
+# get current directory sources files
+aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} mailbox_top_srcs)
+
+set(MAILBOX_SRCS
+ ${mailbox_top_srcs}
+ PARENT_SCOPE
+ )
+set(MAILBOX_INCS
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PARENT_SCOPE
+ )
\ No newline at end of file
diff --git a/src/daemon/mailbox/mailbox.c b/src/daemon/mailbox/mailbox.c
new file mode 100644
index 00000000..732b91b9
--- /dev/null
+++ b/src/daemon/mailbox/mailbox.c
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide common event definition
+ ******************************************************************************/
+
+#include "mailbox.h"
+
+#include <isula_libutils/log.h>
+
+#include "message_queue.h"
+#include "mailbox_message.h"
+#include "message_subscriber.h"
+
+mailbox_topic_handler_t mailbox_topic_handlers[MAILBOX_TOPIC_MAX] = { 0 };
+
+static bool mailbox_topic_valid(mailbox_topic topic) {
+ return topic > MAILBOX_TOPIC_INVALID && topic < MAILBOX_TOPIC_MAX;
+}
+
+static bool mailbox_should_publish(mailbox_topic topic)
+{
+ if (!mailbox_topic_valid(topic)) {
+ ERROR("Invalid topic %d", topic);
+ return false;
+ }
+
+ if (!mailbox_topic_handlers[topic].registered) {
+ return false;
+ }
+
+ if (mailbox_topic_handlers[topic].queue == NULL) {
+ return true;
+ }
+
+ // for async queues, only publish if anyone subscribe
+ return message_queue_have_subscribers(mailbox_topic_handlers[topic].queue);
+}
+
+// only register once when iSulad start, no need to free the queue
+int mailbox_register_topic_handler(mailbox_topic topic, message_generator_t generator, void *context,
+ message_release_t release, bool async)
+{
+ if (!mailbox_topic_valid(topic)) {
+ ERROR("Invalid topic %d", topic);
+ return -1;
+ }
+
+ if (generator == NULL) {
+ ERROR("Invalid generator for topic %d", topic);
+ return -1;
+ }
+
+ mailbox_topic_handlers[topic].generator = generator;
+ mailbox_topic_handlers[topic].context = context;
+ mailbox_topic_handlers[topic].release = release;
+ if (async) {
+ mailbox_topic_handlers[topic].queue = message_queue_create(release);
+ if (mailbox_topic_handlers[topic].queue == NULL) {
+ ERROR("Failed to create message queue for topic %d", topic);
+ return -1;
+ }
+ }
+ mailbox_topic_handlers[topic].registered = true;
+ return 0;
+}
+
+// unregister only when iSulad shutdown, no need to free the queue
+void mailbox_unregister_topic_handler(mailbox_topic topic)
+{
+ if (!mailbox_topic_valid(topic)) {
+ ERROR("Invalid topic %d", topic);
+ return;
+ }
+
+ if (mailbox_topic_handlers[topic].queue != NULL) {
+ message_queue_shutdown(mailbox_topic_handlers[topic].queue);
+ }
+ mailbox_topic_handlers[topic].registered = false;
+}
+
+void mailbox_publish(mailbox_topic topic, void *data)
+{
+ if (!mailbox_should_publish(topic)) {
+ return;
+ }
+
+ message_generator_t generator = mailbox_topic_handlers[topic].generator;
+ void *context = mailbox_topic_handlers[topic].context;
+ message_release_t release = mailbox_topic_handlers[topic].release;
+ message_queue *queue = mailbox_topic_handlers[topic].queue;
+
+ if (generator == NULL) {
+ ERROR("No handler for topic %d", topic);
+ return;
+ }
+
+ void *middle = generator(context, data);
+ if (middle == NULL) {
+ return;
+ }
+
+ if (queue != NULL) {
+ mailbox_message *msg = mailbox_message_create(middle, release);
+ if (msg == NULL) {
+ ERROR("Failed to create mailbox message");
+ if (release) {
+ release(middle);
+ }
+ return;
+ }
+ if (message_queue_publish(queue, msg) != 0) {
+ ERROR("Failed to publish event");
+ mailbox_message_unref(msg);
+ return;
+ }
+ }
+}
+
+message_subscriber *mailbox_subscribe(mailbox_topic topic)
+{
+ if (!mailbox_topic_valid(topic)) {
+ ERROR("Invalid topic %d", topic);
+ return NULL;
+ }
+
+ if (!mailbox_topic_handlers[topic].registered) {
+ ERROR("Handler for topic %d not registered", topic);
+ return NULL;
+ }
+
+ if (mailbox_topic_handlers[topic].queue != NULL) {
+ return message_queue_subscribe(mailbox_topic_handlers[topic].queue,
+ mailbox_topic_handlers[topic].release);
+ }
+
+ // For sync queues, there is no need to subscribe, just return
+ return NULL;
+}
+
+void mailbox_unsubscribe(mailbox_topic topic, message_subscriber *sub)
+{
+ if (!mailbox_topic_valid(topic)) {
+ ERROR("Invalid topic %d", topic);
+ return;
+ }
+
+ if (!mailbox_topic_handlers[topic].registered) {
+ ERROR("Handler for topic %d not registered", topic);
+ return;
+ }
+
+ if (mailbox_topic_handlers[topic].queue != NULL) {
+ return message_queue_unsubscribe(mailbox_topic_handlers[topic].queue, sub);
+ }
+
+ return;
+}
diff --git a/src/daemon/mailbox/mailbox.h b/src/daemon/mailbox/mailbox.h
new file mode 100644
index 00000000..1dc2e934
--- /dev/null
+++ b/src/daemon/mailbox/mailbox.h
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide common event definition
+ ******************************************************************************/
+
+#ifndef DAEMON_MAILBOX_MAILBOX_H
+#define DAEMON_MAILBOX_MAILBOX_H
+
+#include "daemon_arguments.h"
+#include "blocking_queue.h"
+#include "message_queue.h"
+#include "message_subscriber.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+typedef enum {
+ MAILBOX_TOPIC_INVALID = -1,
+ MAILBOX_TOPIC_CRI_CONTAINER,
+ MAILBOX_TOPIC_MAX
+} mailbox_topic;
+
+// for async message, it generates a true message to publish
+// for sync message, it is the callback function to handle the data to publish
+typedef void *(*message_generator_t)(void *, void *);
+// release function of message generated by generator, if any
+typedef void (*message_release_t)(void *);
+
+typedef struct {
+ // to generate a message
+ message_generator_t generator;
+ // context of handler
+ void *context;
+ // release function of message, if any
+ message_release_t release;
+ // message queue
+ message_queue *queue;
+ // if registered
+ bool registered;
+} mailbox_topic_handler_t;
+
+typedef enum {
+ CRI_CONTAINER_MESSAGE_TYPE_INVALID = -1,
+ CRI_CONTAINER_MESSAGE_TYPE_CREATED,
+ CRI_CONTAINER_MESSAGE_TYPE_STARTED,
+ CRI_CONTAINER_MESSAGE_TYPE_STOPPED,
+ CRI_CONTAINER_MESSAGE_TYPE_DELETED,
+ CRI_CONTAINER_MESSAGE_TYPE_MAX
+} cri_container_message_type;
+
+typedef struct {
+ const char *container_id;
+ const char *sandbox_id;
+ cri_container_message_type type;
+} cri_container_message_t;
+
+int mailbox_register_topic_handler(mailbox_topic topic, message_generator_t handle, void *context,
+ message_release_t release, bool async);
+
+void mailbox_unregister_topic_handler(mailbox_topic topic);
+
+void mailbox_publish(mailbox_topic topic, void *data);
+
+message_subscriber *mailbox_subscribe(mailbox_topic topic);
+
+void mailbox_unsubscribe(mailbox_topic, message_subscriber *sub);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/daemon/mailbox/mailbox_message.c b/src/daemon/mailbox/mailbox_message.c
new file mode 100644
index 00000000..b16a1bdd
--- /dev/null
+++ b/src/daemon/mailbox/mailbox_message.c
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide mailbox message definition
+ ******************************************************************************/
+
+#include "mailbox_message.h"
+
+#include <isula_libutils/log.h>
+
+#include "utils.h"
+
+// Once the create succeeds, the ownership is transferred to the mailbox_message.
+mailbox_message *mailbox_message_create(void *data, void (*destroy)(void *)) {
+ __isula_auto_free mailbox_message *msg = NULL;
+ msg = util_common_calloc_s(sizeof(mailbox_message));
+ if (msg == NULL) {
+ ERROR("Out of memory");
+ return NULL;
+ }
+
+ msg->data = data;
+ msg->destroy = destroy;
+ msg->ref_count = 1;
+
+ if (pthread_mutex_init(&msg->lock, NULL) != 0) {
+ ERROR("Failed to init mutex");
+ return NULL;
+ }
+
+ return isula_transfer_ptr(msg);
+}
+
+int mailbox_message_ref(mailbox_message *dest) {
+ __isula_auto_pm_unlock pthread_mutex_t *lock = NULL;
+ if (dest == NULL) {
+ ERROR("Invalid mailbox_message");
+ return -1;
+ }
+
+ if (pthread_mutex_lock(&dest->lock) != 0) {
+ ERROR("Failed to lock mutex");
+ return -1;
+ }
+ lock = &dest->lock;
+
+ if (dest->ref_count == INT_MAX) {
+ ERROR("Reference count overflow");
+ return -1;
+ }
+
+ dest->ref_count++;
+
+ return 0;
+}
+
+void mailbox_message_unref(mailbox_message *dest) {
+ __isula_auto_pm_unlock pthread_mutex_t *lock = NULL;
+ if (dest == NULL) {
+ return;
+ }
+
+ if (pthread_mutex_lock(&dest->lock) != 0) {
+ ERROR("Failed to lock mutex");
+ return;
+ }
+ lock = &dest->lock;
+
+ if (dest->ref_count == 0) {
+ ERROR("Reference count underflow, should not reach here");
+ return;
+ }
+
+ dest->ref_count--;
+ if (dest->ref_count == 0) {
+ if (dest->destroy) {
+ dest->destroy(dest->data);
+ }
+ lock = NULL;
+ (void)pthread_mutex_unlock(&dest->lock);
+ (void)pthread_mutex_destroy(&dest->lock);
+ free(dest);
+ }
+ return;
+}
diff --git a/src/daemon/mailbox/mailbox_message.h b/src/daemon/mailbox/mailbox_message.h
new file mode 100644
index 00000000..39e40b70
--- /dev/null
+++ b/src/daemon/mailbox/mailbox_message.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide ref counted ptr definition
+ ******************************************************************************/
+
+#ifndef DAEMON_MAILBOX_MAILBOX_MESSAGE_H
+#define DAEMON_MAILBOX_MAILBOX_MESSAGE_H
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#include <isula_libutils/auto_cleanup.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mailbox_message {
+ void *data;
+ size_t ref_count;
+ pthread_mutex_t lock;
+ void (*destroy)(void *);
+} mailbox_message;
+
+mailbox_message *mailbox_message_create(void *ptr, void (*destroy)(void *));
+
+int mailbox_message_ref(mailbox_message *p);
+
+void mailbox_message_unref(mailbox_message *p);
+
+// define auto free function callback for mailbox_message
+define_auto_cleanup_callback(mailbox_message_unref, mailbox_message);
+// define auto free macro for char *
+#define __isula_auto_mailbox_message auto_cleanup_tag(mailbox_message_unref)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/daemon/mailbox/message_queue.c b/src/daemon/mailbox/message_queue.c
new file mode 100644
index 00000000..7fe044f2
--- /dev/null
+++ b/src/daemon/mailbox/message_queue.c
@@ -0,0 +1,234 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide message queue definition
+ ******************************************************************************/
+
+#include "message_queue.h"
+
+#include <sys/prctl.h>
+#include <isula_libutils/log.h>
+
+#include "utils.h"
+
+// default set subscriber timeout to 1000ms, maybe could be configured later
+const int64_t subscribe_timeout = 1000;
+
+static void message_queue_subscriber_free(void *key, void *val)
+{
+ return;
+}
+
+static void *message_queue_thread(void *arg)
+{
+ int ret = 0;
+
+ ret = pthread_detach(pthread_self());
+ if (ret != 0) {
+ CRIT("Set thread detach fail");
+ return NULL;
+ }
+
+ prctl(PR_SET_NAME, "Message Queue");
+
+ message_queue *mq = (message_queue *)arg;
+ if (mq == NULL) {
+ ERROR("Invalid argument");
+ return NULL;
+ }
+
+ for (;;) {
+ void *data = NULL;
+ if (blocking_queue_pop(mq->messages, &data) != 0) {
+ ERROR("Fail to get message, message queue thread exit");
+ break;
+ }
+
+ __isula_auto_mailbox_message mailbox_message *msg = (mailbox_message *)data;
+ // an empty msg indicates shutdown
+ if (pthread_rwlock_rdlock(&mq->rwlock) != 0) {
+ ERROR("Failed to lock rwlock");
+ continue;
+ }
+
+ bool should_shutdown = (msg == NULL);
+ map_itor *itor = map_itor_new(mq->subscribers);
+ if (itor == NULL) {
+ ERROR("Out of memory");
+ if (pthread_rwlock_unlock(&mq->rwlock) != 0) {
+ ERROR("Failed to lock rwlock");
+ }
+ break;
+ }
+
+ for (; map_itor_valid(itor); map_itor_next(itor)) {
+ void *sub = map_itor_key(itor);
+ if (should_shutdown) {
+ message_subscriber_shutdown(sub);
+ } else {
+ if (message_subscriber_push(sub, msg) != 0) {
+ ERROR("Failed to push event to subscriber");
+ }
+ }
+ }
+ map_itor_free(itor);
+
+ if (pthread_rwlock_unlock(&mq->rwlock) != 0) {
+ ERROR("Failed to unlock rwlock");
+ }
+
+ // if msg is NULL, it is a shutdown signal
+ if (should_shutdown) {
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+message_queue *message_queue_create(void (*release)(void *))
+{
+ __isula_auto_free message_queue *mq = NULL;
+ __isula_auto_blocking_queue blocking_queue *bq = NULL;
+ pthread_t message_queue_tid;
+ mq = util_common_calloc_s(sizeof(message_queue));
+ if (mq == NULL) {
+ ERROR("Out of memory");
+ return NULL;
+ }
+
+ bq = blocking_queue_create(BLOCKING_QUEUE_NO_TIMEOUT, release);
+ if (bq == NULL) {
+ ERROR("Failed to create events queue");
+ return NULL;
+ }
+
+ mq->subscribers = map_new(MAP_PTR_INT, MAP_DEFAULT_CMP_FUNC, message_queue_subscriber_free);
+ if (mq->subscribers == NULL) {
+ ERROR("Failed to create subscribers map");
+ return NULL;
+ }
+
+ if (pthread_rwlock_init(&mq->rwlock, NULL) != 0) {
+ ERROR("Failed to init rwlock");
+ map_free(mq->subscribers);
+ return NULL;
+ }
+
+ if (pthread_create(&message_queue_tid, NULL, message_queue_thread, mq) != 0) {
+ ERROR("Failed to create message queue thread");
+ pthread_rwlock_destroy(&mq->rwlock);
+ map_free(mq->subscribers);
+ return NULL;
+ }
+
+ mq->messages = isula_transfer_ptr(bq);
+ return isula_transfer_ptr(mq);
+}
+
+// message queue should be global value, it will be destroyed when daemon exit
+void message_queue_shutdown(message_queue *mq)
+{
+ if (mq == NULL) {
+ return;
+ }
+
+ blocking_queue_clear(mq->messages);
+
+ // push a nullptr to notify the thread to exit
+ if (blocking_queue_push(mq->messages, NULL) != 0) {
+ ERROR("Failed to push nullptr to message queue");
+ }
+}
+
+message_subscriber *message_queue_subscribe(message_queue *mq, void (*release)(void *))
+{
+ __isula_auto_subscriber message_subscriber *sub = NULL;
+ __isula_auto_prw_unlock pthread_rwlock_t *lock = NULL;
+ int val = 0;
+ if (mq == NULL) {
+ ERROR("Invalid argument");
+ return NULL;
+ }
+
+ sub = message_subscriber_create(subscribe_timeout, release);
+ if (sub == NULL) {
+ ERROR("Failed to create subscriber");
+ return NULL;
+ }
+
+ if (pthread_rwlock_wrlock(&mq->rwlock) != 0) {
+ ERROR("Failed to lock rwlock");
+ return NULL;
+ }
+ lock = &mq->rwlock;
+
+ if (map_insert(mq->subscribers, sub, (void *)&val) == false) {
+ ERROR("Failed to insert subscriber");
+ return NULL;
+ }
+
+ return isula_transfer_ptr(sub);
+}
+
+void message_queue_unsubscribe(message_queue *mq, message_subscriber *sub)
+{
+ __isula_auto_prw_unlock pthread_rwlock_t *lock = NULL;
+ if (mq == NULL) {
+ ERROR("Invalid argument");
+ return;
+ }
+
+ if (pthread_rwlock_wrlock(&mq->rwlock) != 0) {
+ ERROR("Failed to lock rwlock");
+ return;
+ }
+ lock = &mq->rwlock;
+
+ if (map_remove(mq->subscribers, sub) == false) {
+ ERROR("Failed to remove subscriber");
+ return;
+ }
+
+ return;
+}
+
+int message_queue_publish(message_queue *mq, mailbox_message *msg)
+{
+ if (mq == NULL || msg == NULL) {
+ ERROR("Invalid argument");
+ return -1;
+ }
+
+ if (blocking_queue_push(mq->messages, msg) != 0) {
+ ERROR("Failed to push message");
+ return -1;
+ }
+ return 0;
+}
+
+bool message_queue_have_subscribers(message_queue *mq)
+{
+ __isula_auto_prw_unlock pthread_rwlock_t *lock = NULL;
+ if (mq == NULL) {
+ ERROR("Invalid argument");
+ return false;
+ }
+
+ if (pthread_rwlock_wrlock(&mq->rwlock) != 0) {
+ ERROR("Failed to lock rwlock");
+ return false;
+ }
+ lock = &mq->rwlock;
+
+ return map_size(mq->subscribers) > 0;
+}
diff --git a/src/daemon/mailbox/message_queue.h b/src/daemon/mailbox/message_queue.h
new file mode 100644
index 00000000..7905840f
--- /dev/null
+++ b/src/daemon/mailbox/message_queue.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide message queue definition
+ ******************************************************************************/
+
+#ifndef DAEMON_MESSAGE_MESSAGE_QUEUE_H
+#define DAEMON_MESSAGE_MESSAGE_QUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <pthread.h>
+
+#include "blocking_queue.h"
+#include "mailbox_message.h"
+#include "map.h"
+#include "message_subscriber.h"
+
+typedef struct message_queue {
+ blocking_queue *messages;
+
+ // lock for set of subscribers
+ pthread_rwlock_t rwlock;
+
+ map_t *subscribers;
+
+ int64_t sub_timeout;
+} message_queue;
+
+message_queue *message_queue_create(void (*release)(void *));
+
+void message_queue_shutdown(message_queue *mq);
+
+message_subscriber *message_queue_subscribe(message_queue *mq, void (*release)(void *));
+
+void message_queue_unsubscribe(message_queue *mq, message_subscriber *sub);
+
+int message_queue_publish(message_queue *mq, mailbox_message *msg);
+
+bool message_queue_have_subscribers(message_queue *mq);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/daemon/mailbox/message_subscriber.c b/src/daemon/mailbox/message_subscriber.c
new file mode 100644
index 00000000..8ef3cb58
--- /dev/null
+++ b/src/daemon/mailbox/message_subscriber.c
@@ -0,0 +1,85 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide message subscriber definition
+ ******************************************************************************/
+
+#include "message_subscriber.h"
+
+#include <isula_libutils/log.h>
+
+#include "utils.h"
+
+message_subscriber *message_subscriber_create(int64_t timeout, void (*release)(void *))
+{
+ message_subscriber *sub = (message_subscriber *)util_common_calloc_s(sizeof(message_subscriber));
+ if (sub == NULL) {
+ ERROR("Out of memory");
+ return NULL;
+ }
+ sub->queue = blocking_queue_create(timeout, release);
+ if (sub->queue == NULL) {
+ ERROR("Failed to create blocking queue");
+ free(sub);
+ return NULL;
+ }
+ return sub;
+}
+
+int message_subscriber_push(message_subscriber *sub, mailbox_message *msg)
+{
+ if (sub == NULL || msg == NULL) {
+ ERROR("Invalid argument");
+ return -1;
+ }
+
+ if (mailbox_message_ref(msg) != 0) {
+ ERROR("Failed to get message");
+ return -1;
+ }
+
+ if (blocking_queue_push(sub->queue, msg) != 0) {
+ ERROR("Failed to push message to queue");
+ mailbox_message_unref(msg);
+ return -1;
+ }
+
+ return 0;
+}
+
+int message_subscriber_pop(message_subscriber *sub, mailbox_message **msg)
+{
+ if (sub == NULL) {
+ ERROR("Invalid argument");
+ return -1;
+ }
+ return blocking_queue_pop(sub->queue, (void **)msg);
+}
+
+void message_subscriber_shutdown(message_subscriber *sub)
+{
+ if (sub == NULL) {
+ return;
+ }
+
+ blocking_queue_clear(sub->queue);
+ (void)blocking_queue_push(sub->queue, NULL);
+}
+
+void message_subscriber_destroy(message_subscriber *sub)
+{
+ if (sub == NULL) {
+ return;
+ }
+ blocking_queue_destroy(sub->queue);
+ free(sub);
+}
diff --git a/src/daemon/mailbox/message_subscriber.h b/src/daemon/mailbox/message_subscriber.h
new file mode 100644
index 00000000..de4574d9
--- /dev/null
+++ b/src/daemon/mailbox/message_subscriber.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide message subscriber definition
+ ******************************************************************************/
+
+#ifndef SRC_DAEMON_MAILBOX_MESSAGE_SUBSCRIBER_H
+#define SRC_DAEMON_MAILBOX_MESSAGE_SUBSCRIBER_H
+
+#include "blocking_queue.h"
+#include "mailbox_message.h"
+
+typedef struct {
+ blocking_queue *queue;
+} message_subscriber;
+
+message_subscriber *message_subscriber_create(int64_t timeout, void (*release)(void *));
+
+void message_subscriber_shutdown(message_subscriber *sub);
+
+void message_subscriber_destroy(message_subscriber *sub);
+
+int message_subscriber_push(message_subscriber *sub, mailbox_message *msg);
+
+int message_subscriber_pop(message_subscriber *sub, mailbox_message **msg);
+
+// define auto free function callback for blocking queue
+define_auto_cleanup_callback(message_subscriber_destroy, message_subscriber);
+// define auto free macro for blocking queue
+#define __isula_auto_subscriber auto_cleanup_tag(message_subscriber_destroy)
+
+#endif
diff --git a/src/daemon/modules/api/container_api.h b/src/daemon/modules/api/container_api.h
index 830fd696..55c59980 100644
--- a/src/daemon/modules/api/container_api.h
+++ b/src/daemon/modules/api/container_api.h
@@ -289,6 +289,11 @@ static inline bool is_sandbox_container(container_sandbox_info *sandbox)
{
return sandbox != NULL && sandbox->is_sandbox_container;
}
+
+static inline bool is_container_in_sandbox(container_sandbox_info *sandbox)
+{
+ return sandbox != NULL && !sandbox->is_sandbox_container;
+}
#endif
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/src/daemon/modules/container/supervisor/supervisor.c b/src/daemon/modules/container/supervisor/supervisor.c
index 1b7da383..83d46268 100644
--- a/src/daemon/modules/container/supervisor/supervisor.c
+++ b/src/daemon/modules/container/supervisor/supervisor.c
@@ -38,6 +38,7 @@
#include "container_api.h"
#include "event_type.h"
#include "utils_file.h"
+#include "mailbox.h"
#ifdef ENABLE_CRI_API_V1
#include "sandbox_ops.h"
#endif
@@ -51,6 +52,7 @@ struct supervisor_handler_data {
int fd;
int exit_code;
char *name;
+ char *sandbox_name;
char *runtime;
bool is_sandbox_container;
pid_ppid_info_t pid_info;
@@ -152,6 +154,9 @@ static void supervisor_handler_data_free(struct supervisor_handler_data *data)
free(data->name);
data->name = NULL;
+ free(data->sandbox_name);
+ data->sandbox_name = NULL;
+
free(data->runtime);
data->runtime = NULL;
@@ -172,6 +177,9 @@ static void *clean_resources_thread(void *arg)
pid_t pid = data->pid_info.pid;
int retry_count = 0;
int max_retry = 10;
+#ifdef ENABLE_CRI_API_V1
+ cri_container_message_t msg;
+#endif
ret = pthread_detach(pthread_self());
if (ret != 0) {
@@ -218,6 +226,13 @@ retry:
(void)isulad_monitor_send_container_event(name, STOPPED, (int)pid, data->exit_code, NULL, NULL);
#ifdef ENABLE_CRI_API_V1
+ if (data->sandbox_name) {
+ msg.container_id = name;
+ msg.sandbox_id = data->sandbox_name;
+ msg.type = CRI_CONTAINER_MESSAGE_TYPE_STOPPED;
+ mailbox_publish(MAILBOX_TOPIC_CRI_CONTAINER, &msg);
+ }
+
if (data->is_sandbox_container) {
if (sandbox_on_sandbox_exit(name, data->exit_code) < 0) {
ERROR("Failed to handle sandbox %s exit", name);
@@ -329,6 +344,9 @@ int container_supervisor_add_exit_monitor(int fd, const char *exit_fifo, const p
data->runtime = util_strdup_s(cont->runtime);
#ifdef ENABLE_CRI_API_V1
data->is_sandbox_container = is_sandbox_container(cont->common_config->sandbox_info);
+ if (is_container_in_sandbox(cont->common_config->sandbox_info)) {
+ data->sandbox_name = util_strdup_s(cont->common_config->sandbox_info->id);
+ }
#endif
data->pid_info.pid = pid_info->pid;
data->pid_info.start_time = pid_info->start_time;
diff --git a/src/daemon/sandbox/sandbox.cc b/src/daemon/sandbox/sandbox.cc
index 7b6496ed..c70116c1 100644
--- a/src/daemon/sandbox/sandbox.cc
+++ b/src/daemon/sandbox/sandbox.cc
@@ -37,6 +37,7 @@
#include "cxxutils.h"
#include "controller_manager.h"
#include "utils_timestamp.h"
+#include "mailbox.h"
#define SANDBOX_READY_STATE_STR "SANDBOX_READY"
#define SANDBOX_NOTREADY_STATE_STR "SANDBOX_NOTREADY"
@@ -527,6 +528,14 @@ void Sandbox::OnSandboxExit(const ControllerExitInfo &exitInfo)
if (!SaveState(error)) {
ERROR("Failed to save sandbox state, %s", m_id.c_str());
}
+
+ if (error.Empty()) {
+ cri_container_message_t msg = { 0 };
+ msg.container_id = GetId().c_str();
+ msg.sandbox_id = GetId().c_str();
+ msg.type = CRI_CONTAINER_MESSAGE_TYPE_STOPPED;
+ mailbox_publish(MAILBOX_TOPIC_CRI_CONTAINER, &msg);
+ }
}
auto Sandbox::UpdateStatus(Errors &error) -> bool
diff --git a/src/utils/cutils/blocking_queue.c b/src/utils/cutils/blocking_queue.c
new file mode 100644
index 00000000..7c9c5f50
--- /dev/null
+++ b/src/utils/cutils/blocking_queue.c
@@ -0,0 +1,185 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide blocking queue definition
+ ******************************************************************************/
+
+#include "blocking_queue.h"
+
+#include <pthread.h>
+#include <time.h>
+#include <isula_libutils/log.h>
+
+#include "utils.h"
+#include "utils_timestamp.h"
+
+// create blocking queue with timeout(ms), if timeout < 0, then with no timeout
+blocking_queue *blocking_queue_create(int64_t timeout, void (*release)(void *))
+{
+ __isula_auto_free blocking_queue *queue = NULL;
+ __isula_auto_free blocking_node *node = NULL;
+ queue = (blocking_queue *)util_common_calloc_s(sizeof(blocking_queue));
+ if (queue == NULL) {
+ ERROR("Out of memory");
+ return NULL;
+ }
+ node = (blocking_node *)util_common_calloc_s(sizeof(blocking_node));
+ if (node == NULL) {
+ ERROR("Out of memory");
+ return NULL;
+ }
+
+ if (pthread_mutex_init(&queue->lock, NULL) != 0) {
+ ERROR("Failed to init mutex");
+ return NULL;
+ }
+
+ if (pthread_cond_init(&queue->not_empty, NULL) != 0) {
+ ERROR("Failed to init cond");
+ (void)pthread_mutex_destroy(&queue->lock);
+ return NULL;
+ }
+
+ queue->head = node;
+ queue->tail = node;
+ node = NULL;
+ queue->release = release;
+
+ if (timeout >= 0) {
+ queue->timeout.tv_sec = timeout / (Time_Second / Time_Milli);
+ queue->timeout.tv_nsec = (timeout % (Time_Second / Time_Milli) ) * Time_Milli;
+ } else {
+ queue->timeout.tv_sec = -1;
+ }
+
+ return isula_transfer_ptr(queue);
+}
+
+int blocking_queue_push(blocking_queue *queue, void *data)
+{
+ __isula_auto_free blocking_node *new_node = NULL;
+ __isula_auto_pm_unlock pthread_mutex_t *lock = NULL;
+ if (queue == NULL) {
+ ERROR("Invalid NULL arguments");
+ return -1;
+ }
+
+ new_node = (blocking_node *)util_common_calloc_s(sizeof(blocking_node));
+ if (new_node == NULL) {
+ ERROR("Out of memory");
+ return -1;
+ }
+ new_node->data = data;
+ new_node->next = NULL;
+
+ if (pthread_mutex_lock(&queue->lock) != 0) {
+ ERROR("Failed to lock mutex");
+ return -1;
+ }
+ lock = &queue->lock;
+
+ queue->tail->next = new_node;
+ queue->tail = new_node;
+ new_node = NULL;
+
+ if (pthread_cond_broadcast(&queue->not_empty) != 0) {
+ ERROR("Failed to broadcast cond");
+ }
+
+ return 0;
+}
+
+int blocking_queue_pop(blocking_queue *queue, void **data) {
+ if (queue == NULL || data == NULL) {
+ ERROR("Invalid NULL arguments");
+ return -1;
+ }
+
+ __isula_auto_pm_unlock pthread_mutex_t *lock = NULL;
+ if (pthread_mutex_lock(&queue->lock) != 0) {
+ ERROR("Failed to lock mutex");
+ return -1;
+ }
+ lock = &queue->lock;
+
+ while (queue->head->next == NULL) {
+ if (queue->timeout.tv_sec >= 0) {
+ int ret = pthread_cond_timedwait(&queue->not_empty, &queue->lock, &queue->timeout);
+ if (ret != 0) {
+ if (ret != ETIMEDOUT) {
+ ERROR("Failed to wait cond");
+ }
+ return ret;
+ }
+ } else {
+ int ret = pthread_cond_wait(&queue->not_empty, &queue->lock);
+ if (ret != 0) {
+ ERROR("Failed to wait cond");
+ return ret;
+ }
+ }
+ }
+
+ blocking_node *old_head = queue->head;
+ blocking_node *new_head = old_head->next;
+ *data = new_head->data;
+ queue->head = new_head;
+
+ free(old_head);
+ return 0;
+}
+
+void blocking_queue_clear(blocking_queue *queue)
+{
+ if (queue == NULL) {
+ return;
+ }
+
+ __isula_auto_pm_unlock pthread_mutex_t *lock = NULL;
+ // clear all nodes in queue
+ if (queue == NULL) {
+ ERROR("Invalid NULL arguments");
+ return;
+ }
+
+ if (pthread_mutex_lock(&queue->lock) != 0) {
+ ERROR("Failed to lock mutex");
+ return;
+ }
+ lock = &queue->lock;
+
+ while (queue->head->next != NULL) {
+ blocking_node *old_head = queue->head;
+ blocking_node *new_head = old_head->next;
+ if (queue->release) {
+ queue->release(old_head->data);
+ }
+ free(old_head);
+ queue->head = new_head;
+ }
+}
+
+// ensure there is no other thread executing enqueue or dequeue operation
+void blocking_queue_destroy(blocking_queue *queue)
+{
+ if (queue == NULL) {
+ return;
+ }
+
+ blocking_queue_clear(queue);
+
+ (void)pthread_mutex_destroy(&queue->lock);
+
+ (void)pthread_cond_destroy(&queue->not_empty);
+
+ free(queue);
+}
diff --git a/src/utils/cutils/blocking_queue.h b/src/utils/cutils/blocking_queue.h
new file mode 100644
index 00000000..1c52a9d3
--- /dev/null
+++ b/src/utils/cutils/blocking_queue.h
@@ -0,0 +1,66 @@
+/******************************************************************************
+ * 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: jikai
+ * Create: 2024-03-25
+ * Description: provide blocking queue definition
+ ******************************************************************************/
+
+#ifndef DAEMON_UTILS_CUTILS_BLOCKING_QUEUE_H
+#define DAEMON_UTILS_CUTILS_BLOCKING_QUEUE_H
+
+#include <pthread.h>
+#include <time.h>
+#include <isula_libutils/auto_cleanup.h>
+
+#include "utils_timestamp.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BLOCKING_QUEUE_NO_TIMEOUT -1
+
+typedef struct blocking_node {
+ void *data;
+ struct blocking_node *next;
+} blocking_node;
+
+typedef struct blocking_queue {
+ blocking_node *head;
+ blocking_node *tail;
+ pthread_mutex_t lock;
+ struct timespec timeout;
+ pthread_cond_t not_empty;
+ void (*release)(void *);
+} blocking_queue;
+
+// create blocking queue with timeout(ms), if timeout < 0, then with no timeout
+blocking_queue *blocking_queue_create(int64_t timeout, void (*release)(void *));
+
+int blocking_queue_push(blocking_queue *queue, void *data);
+
+int blocking_queue_pop(blocking_queue *queue, void **data);
+
+void blocking_queue_clear(blocking_queue *queue);
+
+// ensure there is no other thread executing enqueue or dequeue operation
+void blocking_queue_destroy(blocking_queue *queue);
+
+// define auto free function callback for blocking queue
+define_auto_cleanup_callback(blocking_queue_destroy, blocking_queue);
+// define auto free macro for blocking queue
+#define __isula_auto_blocking_queue auto_cleanup_tag(blocking_queue_destroy)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/test/mocks/mailbox_mock.cc b/test/mocks/mailbox_mock.cc
new file mode 100644
index 00000000..601b804e
--- /dev/null
+++ b/test/mocks/mailbox_mock.cc
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. 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: jikai
+ * Create: 2024-04-02
+ * Description: mailbox mock
+ ******************************************************************************/
+
+#include "mailbox_mock.h"
+
+MockMailbox *g_mailbox_mock = nullptr;
+
+void Mailbox_SetMock(MockMailbox* mock)
+{
+ g_mailbox_mock = mock;
+}
+
+void mailbox_publish(mailbox_topic topic, void *data)
+{
+ if (g_mailbox_mock != nullptr) {
+ g_mailbox_mock->MailboxPublish(topic, data);
+ }
+}
diff --git a/test/mocks/mailbox_mock.h b/test/mocks/mailbox_mock.h
new file mode 100644
index 00000000..ce48f0fc
--- /dev/null
+++ b/test/mocks/mailbox_mock.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. 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: jikai
+ * Create: 2024-04-02
+ * Description: mailbox mock
+ ******************************************************************************/
+
+#ifndef _ISULAD_TEST_MOCKS_MAILBOX_MOCK_H
+#define _ISULAD_TEST_MOCKS_MAILBOX_MOCK_H
+
+#include <gmock/gmock.h>
+#include "mailbox.h"
+
+class MockMailbox {
+public:
+ virtual ~MockMailbox() = default;
+ MOCK_METHOD2(MailboxPublish, void(mailbox_topic topic, void *data));
+};
+
+void Mailbox_SetMock(MockMailbox* mock);
+
+#endif
diff --git a/test/sandbox/controller/shim/CMakeLists.txt b/test/sandbox/controller/shim/CMakeLists.txt
index 6423bb80..26a66e51 100644
--- a/test/sandbox/controller/shim/CMakeLists.txt
+++ b/test/sandbox/controller/shim/CMakeLists.txt
@@ -7,6 +7,7 @@ add_executable(${EXE}
${CMAKE_BINARY_DIR}/grpc/src/api/services/cri/gogo.pb.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/cri/v1/v1_cri_helpers.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/cri/v1/v1_cri_security_context.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/cri/v1/v1_naming.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/cri/checkpoint_handler.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/cri/cri_constants.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/daemon/common/cri/cri_helpers.cc
diff --git a/test/sandbox/sandbox/CMakeLists.txt b/test/sandbox/sandbox/CMakeLists.txt
index 138d4d8d..2a35388f 100644
--- a/test/sandbox/sandbox/CMakeLists.txt
+++ b/test/sandbox/sandbox/CMakeLists.txt
@@ -23,6 +23,7 @@ add_executable(${EXE}
${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/grpc_sandboxer_client_mock.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/controller_stub_mock.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/shim_controller_mock.cc
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../test/mocks/mailbox_mock.cc
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/common/err_msg.c
${CMAKE_CURRENT_SOURCE_DIR}/sandbox_ut.cc)
@@ -33,6 +34,7 @@ target_include_directories(${EXE} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/config
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/entry/cri
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/executor
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/mailbox
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/sandbox/controller
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/sandbox/controller/shim
${CMAKE_CURRENT_SOURCE_DIR}/../../../src/daemon/sandbox/controller/sandboxer
--
2.34.1
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。