Skip to content

Commit

Permalink
feat(libsinsp/container_engine/containerd): support image digest retr…
Browse files Browse the repository at this point in the history
…ival

Signed-off-by: Roberto Scolaro <[email protected]>
  • Loading branch information
therealbobo committed Dec 17, 2024
1 parent ca6858f commit 3c6b970
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 36 deletions.
37 changes: 33 additions & 4 deletions userspace/libsinsp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -257,17 +257,45 @@ function(prepare_containerd_grpc)
${CMAKE_CURRENT_SOURCE_DIR}/container_engine/containerd/containers.proto
${DEST}/containers.proto COPYONLY
)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/container_engine/containerd/images.proto ${DEST}/images.proto
COPYONLY
)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/container_engine/containerd/descriptor.proto
${DEST}/descriptor.proto COPYONLY
)
add_custom_command(
OUTPUT ${DEST}/containers.grpc.pb.cc ${DEST}/containers.grpc.pb.h ${DEST}/containers.pb.cc
OUTPUT ${DEST}/containers.grpc.pb.cc
${DEST}/containers.grpc.pb.h
${DEST}/containers.pb.cc
${DEST}/containers.pb.h
${DEST}/images.grpc.pb.cc
${DEST}/images.grpc.pb.h
${DEST}/images.pb.cc
${DEST}/images.pb.h
${DEST}/descriptor.grpc.pb.cc
${DEST}/descriptor.grpc.pb.h
${DEST}/descriptor.pb.cc
${DEST}/descriptor.pb.h
COMMENT "Generate containerd grpc code"
DEPENDS
COMMAND ${PROTOC} -I ${DEST} --cpp_out=${DEST} ${DEST}/containers.proto
COMMAND ${PROTOC} -I ${DEST} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${DEST}/containers.proto
COMMAND ${PROTOC} -I ${DEST} --cpp_out=${DEST} ${DEST}/descriptor.proto
COMMAND ${PROTOC} -I ${DEST} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${DEST}/descriptor.proto
COMMAND ${PROTOC} -I ${DEST} --cpp_out=${DEST} ${DEST}/images.proto
COMMAND ${PROTOC} -I ${DEST} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${DEST}/images.proto
WORKING_DIRECTORY ${DEST}
)
add_library(containerd_interface STATIC ${DEST}/containers.pb.cc ${DEST}/containers.grpc.pb.cc)
add_library(
containerd_interface STATIC
${DEST}/containers.pb.cc ${DEST}/containers.grpc.pb.cc ${DEST}/descriptor.pb.cc
${DEST}/descriptor.grpc.pb.cc ${DEST}/images.pb.cc ${DEST}/images.grpc.pb.cc
)
target_include_directories(containerd_interface PUBLIC $<BUILD_INTERFACE:${DEST}>)
target_link_libraries(
containerd_interface
Expand All @@ -281,7 +309,8 @@ function(prepare_containerd_grpc)
)
add_dependencies(containerd_interface grpc)
install(
FILES ${DEST}/containers.grpc.pb.h ${DEST}/containers.pb.h
FILES ${DEST}/containers.grpc.pb.h ${DEST}/containers.pb.h ${DEST}/descriptor.grpc.pb.h
${DEST}/descriptor.pb.h ${DEST}/images.grpc.pb.h ${DEST}/images.pb.h
DESTINATION
"${CMAKE_INSTALL_INCLUDEDIR}/${LIBS_PACKAGE_NAME}/libsinsp/container_engine/containerd"
COMPONENT "scap"
Expand Down Expand Up @@ -318,7 +347,7 @@ if(NOT WIN32)
prepare_containerd_grpc()

target_link_libraries(sinsp PUBLIC cri_v1alpha2 cri_v1)
target_link_libraries(sinsp PUBLIC containerd_interface)
target_link_libraries(sinsp PRIVATE containerd_interface)

if(NOT MUSL_OPTIMIZED_BUILD)
find_library(LIB_ANL anl)
Expand Down
112 changes: 86 additions & 26 deletions userspace/libsinsp/container_engine/containerd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,19 @@ constexpr const std::string_view CONTAINERD_SOCKETS[] = {
};

bool containerd_async_source::is_ok() {
return m_stub != nullptr;
return m_container_stub != nullptr && m_image_stub != nullptr;
}

static inline void setup_grpc_client_context(grpc::ClientContext &context) {
auto deadline = std::chrono::system_clock::now() +
std::chrono::milliseconds(libsinsp::cri::cri_settings::get_cri_timeout());

context.set_deadline(deadline);

// The `default` namesapce is the default one of containerd
// and the one used by host-containers in bottlerocket.
// This is mandatory to query the containers.
context.AddMetadata("containerd-namespace", "default");
}

containerd_async_source::containerd_async_source(const std::string &socket_path,
Expand All @@ -47,30 +59,50 @@ containerd_async_source::containerd_async_source(const std::string &socket_path,
std::shared_ptr<grpc::Channel> channel =
libsinsp::grpc_channel_registry::get_channel("unix://" + socket_path, &args);

m_stub = ContainerdService::Containers::NewStub(channel);
// Check the status of the container stub.
{
grpc::ClientContext context;
setup_grpc_client_context(context);

ContainerdService::ListContainersRequest req;
ContainerdService::ListContainersResponse resp;
m_container_stub = ContainerdContainerService::Containers::NewStub(channel);

grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() +
std::chrono::milliseconds(libsinsp::cri::cri_settings::get_cri_timeout());
context.set_deadline(deadline);
ContainerdContainerService::ListContainersRequest req;
ContainerdContainerService::ListContainersResponse resp;

// The `default` namesapce is the default one of containerd
// and the one used by host-containers in bottlerocket.
// This is mandatory to query the containers.
context.AddMetadata("containerd-namespace", "default");
grpc::Status status = m_stub->List(&context, req, &resp);
grpc::Status status = m_container_stub->List(&context, req, &resp);

if(!status.ok()) {
libsinsp_logger()->format(sinsp_logger::SEV_NOTICE,
"containerd (%s): containerd runtime returned an error after "
"trying to list containerd: %s",
socket_path.c_str(),
status.error_message().c_str());
m_stub.reset(nullptr);
return;
if(!status.ok()) {
libsinsp_logger()->format(sinsp_logger::SEV_NOTICE,
"containerd (%s): containerd runtime returned an error after "
"trying to list containers: %s",
socket_path.c_str(),
status.error_message().c_str());
m_container_stub.reset(nullptr);
return;
}
}

// Check the status of the image stub.
{
grpc::ClientContext context;
setup_grpc_client_context(context);

m_image_stub = ContainerdImageService::Images::NewStub(channel);

ContainerdImageService::ListImagesRequest req;
ContainerdImageService::ListImagesResponse resp;

grpc::Status status = m_image_stub->List(&context, req, &resp);

if(!status.ok()) {
libsinsp_logger()->format(sinsp_logger::SEV_NOTICE,
"containerd (%s): containerd runtime returned an error after "
"trying to list images: %s",
socket_path.c_str(),
status.error_message().c_str());
m_image_stub.reset(nullptr);
return;
}
}
}

Expand All @@ -81,8 +113,8 @@ containerd_async_source::~containerd_async_source() {

grpc::Status containerd_async_source::list_container_resp(
const std::string &container_id,
ContainerdService::ListContainersResponse &resp) {
ContainerdService::ListContainersRequest req;
ContainerdContainerService::ListContainersResponse &resp) {
ContainerdContainerService::ListContainersRequest req;

// To match the container using a truncated containerd id
// we need to use a match filter (~=).
Expand All @@ -92,7 +124,21 @@ grpc::Status containerd_async_source::list_container_resp(
auto deadline = std::chrono::system_clock::now() +
std::chrono::milliseconds(libsinsp::cri::cri_settings::get_cri_timeout());
context.set_deadline(deadline);
return m_stub->List(&context, req, &resp);
return m_container_stub->List(&context, req, &resp);
}

grpc::Status containerd_async_source::get_image_resp(
const std::string &image_name,
ContainerdImageService::GetImageResponse &resp) {
ContainerdImageService::GetImageRequest req;

req.set_name(image_name);
grpc::ClientContext context;
context.AddMetadata("containerd-namespace", "default");
auto deadline = std::chrono::system_clock::now() +
std::chrono::milliseconds(libsinsp::cri::cri_settings::get_cri_timeout());
context.set_deadline(deadline);
return m_image_stub->Get(&context, req, &resp);
}

libsinsp::container_engine::containerd::containerd(container_cache_interface &cache):
Expand Down Expand Up @@ -132,7 +178,7 @@ bool containerd_async_source::parse(const containerd_lookup_request &request,

// given the truncated container id, the full container id needs to be retrivied from
// containerd.
ContainerdService::ListContainersResponse resp;
ContainerdContainerService::ListContainersResponse resp;
grpc::Status status = list_container_resp(container_id, resp);

if(!status.ok()) {
Expand Down Expand Up @@ -174,9 +220,23 @@ bool containerd_async_source::parse(const containerd_lookup_request &request,
// and the first part is the repo
container.m_imagerepo = raw_image_splits[0].substr(0, raw_image_splits[0].rfind("/"));
container.m_imagetag = raw_image_splits[1];
container.m_imagedigest = "";
container.m_type = CT_CONTAINERD;

// Retrieve the image digest.
ContainerdImageService::GetImageResponse img_resp;
status = get_image_resp(containers[0].image(), img_resp);

if(!status.ok()) {
libsinsp_logger()->format(sinsp_logger::SEV_DEBUG,
"containerd (%s): GetImageResponse status error message: (%s)",
container.m_id.c_str(),
status.error_message().c_str());

// Don't exit given that we have part of the needed information.
}

container.m_imagedigest = img_resp.image().target().digest();

// Retrieve the labels.
for(const auto &pair : containers[0].labels()) {
if(pair.second.length() <= sinsp_container_info::m_container_label_max_length) {
Expand Down
13 changes: 9 additions & 4 deletions userspace/libsinsp/container_engine/containerd.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ class sinsp_container_info;
class sinsp_threadinfo;

#include <libsinsp/container_engine/containerd/containers.grpc.pb.h>
#include <libsinsp/container_engine/containerd/images.grpc.pb.h>
#include <libsinsp/container_engine/container_async_source.h>
#include <libsinsp/container_engine/container_engine_base.h>
#include <libsinsp/container_engine/sinsp_container_type.h>

namespace ContainerdService = containerd::services::containers::v1;
namespace ContainerdContainerService = containerd::services::containers::v1;
namespace ContainerdImageService = containerd::services::images::v1;

namespace libsinsp {
namespace container_engine {
Expand Down Expand Up @@ -80,7 +82,6 @@ class containerd_async_source : public container_async_source<containerd_lookup_
container_cache_interface* cache);
virtual ~containerd_async_source();

// TODO probably remove
bool is_ok();

private:
Expand All @@ -94,9 +95,13 @@ class containerd_async_source : public container_async_source<containerd_lookup_
std::string container_id(const key_type& key) const override { return key.container_id; }

grpc::Status list_container_resp(const std::string& container_id,
ContainerdService::ListContainersResponse& resp);
ContainerdContainerService::ListContainersResponse& resp);

std::unique_ptr<ContainerdService::Containers::Stub> m_stub;
grpc::Status get_image_resp(const std::string& image_name,
ContainerdImageService::GetImageResponse& resp);

std::unique_ptr<ContainerdContainerService::Containers::Stub> m_container_stub;
std::unique_ptr<ContainerdImageService::Images::Stub> m_image_stub;
std::string m_socket_path;
};

Expand Down
33 changes: 33 additions & 0 deletions userspace/libsinsp/container_engine/containerd/descriptor.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
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;

option go_package = "github.com/containerd/containerd/api/types;types";

// Descriptor describes a blob in a content store.
//
// This descriptor can be used to reference content from an
// oci descriptor found in a manifest.
// See https://godoc.org/github.com/opencontainers/image-spec/specs-go/v1#Descriptor
message Descriptor {
string media_type = 1;
string digest = 2;
int64 size = 3;
map<string, string> annotations = 5;
}
Loading

0 comments on commit 3c6b970

Please sign in to comment.