Skip to content

Commit

Permalink
Merge branch 'agent-release-0-93-0' into agent-master-3
Browse files Browse the repository at this point in the history
mstemm committed Nov 5, 2019

Unverified

This user has not yet uploaded their public signing key.
2 parents 286ea18 + 3de8620 commit 7c8d4e8
Showing 5 changed files with 223 additions and 106 deletions.
2 changes: 2 additions & 0 deletions userspace/libsinsp/container.cpp
Original file line number Diff line number Diff line change
@@ -19,7 +19,9 @@ limitations under the License.

#include <algorithm>

#if defined(HAS_CAPTURE)
#include "container_engine/cri.h"
#endif
#include "container_engine/docker.h"
#include "container_engine/rkt.h"
#include "container_engine/libvirt_lxc.h"
92 changes: 32 additions & 60 deletions userspace/libsinsp/container_engine/cri.cpp
Original file line number Diff line number Diff line change
@@ -31,7 +31,6 @@ limitations under the License.
#include "cgroup_limits.h"
#include "runc.h"
#include "container_engine/mesos.h"
#include "grpc_channel_registry.h"
#include <cri.h>
#include "sinsp.h"
#include "sinsp_int.h"
@@ -71,29 +70,23 @@ bool cri_async_source::parse_containerd(const runtime::v1alpha2::ContainerStatus
return false;
}

parse_cri_env(root, container);
parse_cri_json_image(root, container);
parse_cri_runtime_spec(root, container);
m_cri->parse_cri_env(root, container);
m_cri->parse_cri_json_image(root, container);
m_cri->parse_cri_runtime_spec(root, container);

if(root.isMember("sandboxID") && root["sandboxID"].isString())
{
const auto pod_sandbox_id = root["sandboxID"].asString();
container.m_container_ip = ntohl(get_pod_sandbox_ip(pod_sandbox_id));
container.m_container_ip = ntohl(m_cri->get_pod_sandbox_ip(pod_sandbox_id));
}

return true;
}

bool cri_async_source::parse_cri(sinsp_container_info& container, const libsinsp::cgroup_limits::cgroup_limits_key& key)
{
runtime::v1alpha2::ContainerStatusRequest req;
runtime::v1alpha2::ContainerStatusResponse resp;
req.set_container_id(container.m_id);
req.set_verbose(true);
grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(s_cri_timeout);
context.set_deadline(deadline);
grpc::Status status = s_cri->ContainerStatus(&context, req, &resp);
grpc::Status status = m_cri->get_container_status(container.m_id, resp);

g_logger.format(sinsp_logger::SEV_DEBUG,
"cri (%s): Status from ContainerStatus: (%s)",
@@ -102,7 +95,7 @@ bool cri_async_source::parse_cri(sinsp_container_info& container, const libsinsp

if(!status.ok())
{
if(is_pod_sandbox(container.m_id))
if(m_cri->is_pod_sandbox(container.m_id))
{
container.m_is_pod_sandbox = true;
return true;
@@ -126,8 +119,8 @@ bool cri_async_source::parse_cri(sinsp_container_info& container, const libsinsp
container.m_labels[pair.first] = pair.second;
}

parse_cri_image(resp_container, container);
parse_cri_mounts(resp_container, container);
m_cri->parse_cri_image(resp_container, container);
m_cri->parse_cri_mounts(resp_container, container);

if(parse_containerd(resp, container))
{
@@ -145,8 +138,8 @@ bool cri_async_source::parse_cri(sinsp_container_info& container, const libsinsp

if(s_cri_extra_queries)
{
container.m_container_ip = get_container_ip(container.m_id);
container.m_imageid = get_container_image_id(resp_container.image_ref());
container.m_container_ip = m_cri->get_container_ip(container.m_id);
container.m_imageid = m_cri->get_container_image_id(resp_container.image_ref());
}

return true;
@@ -165,7 +158,7 @@ void cri_async_source::run_impl()
sinsp_container_info res;

res.m_lookup_state = sinsp_container_lookup_state::SUCCESSFUL;
res.m_type = s_cri_runtime_type;
res.m_type = m_cri->get_cri_runtime_type();
res.m_id = key.m_container_id;

if(!parse_cri(res, key))
@@ -189,7 +182,7 @@ bool cri_async_source::lookup_sync(const libsinsp::cgroup_limits::cgroup_limits_
sinsp_container_info& value)
{
value.m_lookup_state = sinsp_container_lookup_state::SUCCESSFUL;
value.m_type = s_cri_runtime_type;
value.m_type = m_cri->get_cri_runtime_type();
value.m_id = key.m_container_id;

if(!parse_cri(value, key))
@@ -205,7 +198,7 @@ bool cri_async_source::lookup_sync(const libsinsp::cgroup_limits::cgroup_limits_

cri::cri()
{
if(s_cri || s_cri_unix_socket_path.empty()) {
if(s_cri_unix_socket_path.empty()) {
return;
}

@@ -215,30 +208,11 @@ cri::cri()
return;
}

std::shared_ptr<grpc::Channel> channel = libsinsp::grpc_channel_registry::get_channel("unix://" + cri_path);
s_cri = runtime::v1alpha2::RuntimeService::NewStub(channel);
s_cri_image = runtime::v1alpha2::ImageService::NewStub(channel);

runtime::v1alpha2::VersionRequest vreq;
runtime::v1alpha2::VersionResponse vresp;

vreq.set_version("v1alpha2");
grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(s_cri_timeout);
context.set_deadline(deadline);
grpc::Status status = s_cri->Version(&context, vreq, &vresp);

if (!status.ok())
m_cri = std::unique_ptr<libsinsp::cri::cri_interface>(new libsinsp::cri::cri_interface(cri_path));
if(!m_cri->is_ok())
{
g_logger.format(sinsp_logger::SEV_NOTICE, "cri: CRI runtime returned an error after version check at %s: %s",
s_cri_unix_socket_path.c_str(), status.error_message().c_str());
s_cri.reset(nullptr);
s_cri_unix_socket_path = "";
return;
m_cri.reset(nullptr);
}

g_logger.format(sinsp_logger::SEV_INFO, "cri: CRI runtime: %s %s", vresp.runtime_name().c_str(), vresp.runtime_version().c_str());
s_cri_runtime_type = get_cri_runtime_type(vresp.runtime_name());
}

void cri::cleanup()
@@ -247,8 +221,6 @@ void cri::cleanup()
{
m_async_source->quiesce();
}
s_cri.reset(nullptr);
s_cri_image.reset(nullptr);
s_cri_extra_queries = true;
}

@@ -286,14 +258,26 @@ bool cri::resolve(sinsp_container_manager* manager, sinsp_threadinfo* tinfo, boo
}
tinfo->m_container_id = container_id;

if(!manager->should_lookup(container_id, s_cri_runtime_type))
if(!m_cri)
{
// This isn't an error in the case where the
// configured unix domain socket doesn't exist. In
// that case, s_cri isn't initialized at all. Hence,
// the DEBUG.
g_logger.format(sinsp_logger::SEV_DEBUG,
"cri (%s): Could not parse cri (no s_cri object)",
container_id.c_str());
return false;
}

if(!manager->should_lookup(container_id, m_cri->get_cri_runtime_type()))
{
return true;
}

auto container = std::make_shared<sinsp_container_info>();
container->m_id = container_id;
container->m_type = s_cri_runtime_type;
container->m_type = m_cri->get_cri_runtime_type();
if (mesos::set_mesos_task_id(*container, tinfo))
{
g_logger.format(sinsp_logger::SEV_DEBUG,
@@ -307,18 +291,6 @@ bool cri::resolve(sinsp_container_manager* manager, sinsp_threadinfo* tinfo, boo
"cri (%s): Performing lookup",
container_id.c_str());

if(!s_cri)
{
// This isn't an error in the case where the
// configured unix domain socket doesn't exist. In
// that case, s_cri isn't initialized at all. Hence,
// the DEBUG.
g_logger.format(sinsp_logger::SEV_DEBUG,
"cri (%s): Could not parse cri (no s_cri object)",
container_id.c_str());
return false;
}

container->m_lookup_state = sinsp_container_lookup_state::SUCCESSFUL;
libsinsp::cgroup_limits::cgroup_limits_key key(
container->m_id,
@@ -328,11 +300,11 @@ bool cri::resolve(sinsp_container_manager* manager, sinsp_threadinfo* tinfo, boo

if(!m_async_source)
{
auto async_source = new cri_async_source(manager, s_cri_timeout);
auto async_source = new cri_async_source(manager, m_cri.get(), s_cri_timeout);
m_async_source = std::unique_ptr<cri_async_source>(async_source);
}

manager->set_lookup_status(container_id, s_cri_runtime_type, sinsp_container_lookup_state::STARTED);
manager->set_lookup_status(container_id, m_cri->get_cri_runtime_type(), sinsp_container_lookup_state::STARTED);
auto cb = [manager](const libsinsp::cgroup_limits::cgroup_limits_key& key, const sinsp_container_info &res)
{
g_logger.format(sinsp_logger::SEV_DEBUG,
8 changes: 6 additions & 2 deletions userspace/libsinsp/container_engine/cri.h
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ class sinsp_threadinfo;
#include "cgroup_limits.h"
#include "container_engine/container_engine.h"
#include "container_info.h"
#include <cri.h>

namespace runtime {
namespace v1alpha2 {
@@ -52,9 +53,10 @@ class cri_async_source : public sysdig::async_key_value_source<
sinsp_container_info>
{
public:
explicit cri_async_source(sinsp_container_manager* manager, uint64_t ttl_ms) :
explicit cri_async_source(sinsp_container_manager* manager, ::libsinsp::cri::cri_interface* cri, uint64_t ttl_ms) :
async_key_value_source(NO_WAIT_LOOKUP, ttl_ms),
m_container_manager(manager)
m_container_manager(manager),
m_cri(cri)
{
}

@@ -71,6 +73,7 @@ class cri_async_source : public sysdig::async_key_value_source<
void run_impl() override;

sinsp_container_manager* m_container_manager;
::libsinsp::cri::cri_interface *m_cri;
};

class cri : public resolver
@@ -88,6 +91,7 @@ class cri : public resolver

private:
std::unique_ptr<cri_async_source> m_async_source;
std::unique_ptr<::libsinsp::cri::cri_interface> m_cri;
};
}
}
87 changes: 63 additions & 24 deletions userspace/libsinsp/cri.cpp
Original file line number Diff line number Diff line change
@@ -20,11 +20,7 @@ limitations under the License.
#include "cri.h"

#include <chrono>
#ifdef GRPC_INCLUDE_IS_GRPCPP
# include <grpcpp/grpcpp.h>
#else
# include <grpc++/grpc++.h>
#endif
#include "grpc_channel_registry.h"

#include "sinsp.h"
#include "sinsp_int.h"
@@ -40,27 +36,70 @@ bool pod_uses_host_netns(const runtime::v1alpha2::PodSandboxStatusResponse& resp
namespace libsinsp {
namespace cri {
std::string s_cri_unix_socket_path = "/run/containerd/containerd.sock";
std::unique_ptr <runtime::v1alpha2::RuntimeService::Stub> s_cri = nullptr;
std::unique_ptr <runtime::v1alpha2::ImageService::Stub> s_cri_image = nullptr;
int64_t s_cri_timeout = 1000;
sinsp_container_type s_cri_runtime_type = CT_CRI;
bool s_cri_extra_queries = true;

sinsp_container_type get_cri_runtime_type(const std::string &runtime_name)
cri_interface::cri_interface(const std::string& cri_path)
{
std::shared_ptr<grpc::Channel> channel = libsinsp::grpc_channel_registry::get_channel("unix://" + cri_path);

m_cri = runtime::v1alpha2::RuntimeService::NewStub(channel);

runtime::v1alpha2::VersionRequest vreq;
runtime::v1alpha2::VersionResponse vresp;

vreq.set_version("v1alpha2");
grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(s_cri_timeout);
context.set_deadline(deadline);
grpc::Status status = m_cri->Version(&context, vreq, &vresp);

if (!status.ok())
{
g_logger.format(sinsp_logger::SEV_NOTICE, "cri: CRI runtime returned an error after version check at %s: %s",
s_cri_unix_socket_path.c_str(), status.error_message().c_str());
m_cri.reset(nullptr);
s_cri_unix_socket_path = "";
return;
}

g_logger.format(sinsp_logger::SEV_INFO, "cri: CRI runtime: %s %s", vresp.runtime_name().c_str(), vresp.runtime_version().c_str());

m_cri_image = runtime::v1alpha2::ImageService::NewStub(channel);

const std::string& runtime_name = vresp.runtime_name();
if(runtime_name == "containerd")
{
return CT_CONTAINERD;
m_cri_runtime_type = CT_CONTAINERD;
} else if(runtime_name == "cri-o")
{
return CT_CRIO;
m_cri_runtime_type = CT_CRIO;
} else
{
return CT_CRI;
m_cri_runtime_type = CT_CRI;
}

s_cri_runtime_type = m_cri_runtime_type;
}

sinsp_container_type cri_interface::get_cri_runtime_type() const
{
return m_cri_runtime_type;
}

grpc::Status cri_interface::get_container_status(const std::string& container_id, runtime::v1alpha2::ContainerStatusResponse& resp)
{
runtime::v1alpha2::ContainerStatusRequest req;
req.set_container_id(container_id);
req.set_verbose(true);
grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(s_cri_timeout);
context.set_deadline(deadline);
return m_cri->ContainerStatus(&context, req, &resp);
}

bool parse_cri_image(const runtime::v1alpha2::ContainerStatus &status, sinsp_container_info &container)
bool cri_interface::parse_cri_image(const runtime::v1alpha2::ContainerStatus &status, sinsp_container_info &container)
{
// image_ref may be one of two forms:
// host/image@sha256:digest
@@ -102,7 +141,7 @@ bool parse_cri_image(const runtime::v1alpha2::ContainerStatus &status, sinsp_con
return true;
}

bool parse_cri_mounts(const runtime::v1alpha2::ContainerStatus &status, sinsp_container_info &container)
bool cri_interface::parse_cri_mounts(const runtime::v1alpha2::ContainerStatus &status, sinsp_container_info &container)
{
for(const auto &mount : status.mounts())
{
@@ -183,7 +222,7 @@ bool set_numeric_64(const Json::Value &dict, const std::string &key, int64_t &va
return true;
}

bool parse_cri_env(const Json::Value &info, sinsp_container_info &container)
bool cri_interface::parse_cri_env(const Json::Value &info, sinsp_container_info &container)
{
const Json::Value *envs;
if(!walk_down_json(info, &envs, "config", "envs") || !envs->isArray())
@@ -208,7 +247,7 @@ bool parse_cri_env(const Json::Value &info, sinsp_container_info &container)
return true;
}

bool parse_cri_json_image(const Json::Value &info, sinsp_container_info &container)
bool cri_interface::parse_cri_json_image(const Json::Value &info, sinsp_container_info &container)
{
const Json::Value *image;
if(!walk_down_json(info, &image, "config", "image", "image") || !image->isString())
@@ -229,7 +268,7 @@ bool parse_cri_json_image(const Json::Value &info, sinsp_container_info &contain
return true;
}

bool parse_cri_runtime_spec(const Json::Value &info, sinsp_container_info &container)
bool cri_interface::parse_cri_runtime_spec(const Json::Value &info, sinsp_container_info &container)
{
const Json::Value *linux = nullptr;
if(!walk_down_json(info, &linux, "runtimeSpec", "linux") || !linux->isObject())
@@ -262,7 +301,7 @@ bool parse_cri_runtime_spec(const Json::Value &info, sinsp_container_info &conta
return true;
}

bool is_pod_sandbox(const std::string &container_id)
bool cri_interface::is_pod_sandbox(const std::string &container_id)
{
runtime::v1alpha2::PodSandboxStatusRequest req;
runtime::v1alpha2::PodSandboxStatusResponse resp;
@@ -271,12 +310,12 @@ bool is_pod_sandbox(const std::string &container_id)
grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(s_cri_timeout);
context.set_deadline(deadline);
grpc::Status status = s_cri->PodSandboxStatus(&context, req, &resp);
grpc::Status status = m_cri->PodSandboxStatus(&context, req, &resp);

return status.ok();
}

uint32_t get_pod_sandbox_ip(const std::string &pod_sandbox_id)
uint32_t cri_interface::get_pod_sandbox_ip(const std::string &pod_sandbox_id)
{
runtime::v1alpha2::PodSandboxStatusRequest req;
runtime::v1alpha2::PodSandboxStatusResponse resp;
@@ -285,7 +324,7 @@ uint32_t get_pod_sandbox_ip(const std::string &pod_sandbox_id)
grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(s_cri_timeout);
context.set_deadline(deadline);
grpc::Status status = s_cri->PodSandboxStatus(&context, req, &resp);
grpc::Status status = m_cri->PodSandboxStatus(&context, req, &resp);

if(!status.ok())
{
@@ -314,7 +353,7 @@ uint32_t get_pod_sandbox_ip(const std::string &pod_sandbox_id)
}
}

uint32_t get_container_ip(const std::string &container_id)
uint32_t cri_interface::get_container_ip(const std::string &container_id)
{
runtime::v1alpha2::ListContainersRequest req;
runtime::v1alpha2::ListContainersResponse resp;
@@ -323,7 +362,7 @@ uint32_t get_container_ip(const std::string &container_id)
grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(s_cri_timeout);
context.set_deadline(deadline);
grpc::Status lstatus = s_cri->ListContainers(&context, req, &resp);
grpc::Status lstatus = m_cri->ListContainers(&context, req, &resp);

switch(resp.containers_size())
{
@@ -343,7 +382,7 @@ uint32_t get_container_ip(const std::string &container_id)
return 0;
}

std::string get_container_image_id(const std::string &image_ref)
std::string cri_interface::get_container_image_id(const std::string &image_ref)
{
runtime::v1alpha2::ListImagesRequest req;
runtime::v1alpha2::ListImagesResponse resp;
@@ -353,7 +392,7 @@ std::string get_container_image_id(const std::string &image_ref)
grpc::ClientContext context;
auto deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(s_cri_timeout);
context.set_deadline(deadline);
grpc::Status status = s_cri_image->ListImages(&context, req, &resp);
grpc::Status status = m_cri_image->ListImages(&context, req, &resp);

switch(resp.images_size())
{
140 changes: 120 additions & 20 deletions userspace/libsinsp/cri.h
Original file line number Diff line number Diff line change
@@ -27,33 +27,133 @@ limitations under the License.

#include "container_info.h"

#ifdef GRPC_INCLUDE_IS_GRPCPP
# include <grpcpp/grpcpp.h>
#else
# include <grpc++/grpc++.h>
#endif

namespace libsinsp {
namespace cri {

// these shouldn't be globals but we still need references to *the* CRI runtime
extern std::string s_cri_unix_socket_path;
extern std::unique_ptr<runtime::v1alpha2::RuntimeService::Stub> s_cri;
extern std::unique_ptr<runtime::v1alpha2::ImageService::Stub> s_cri_image;
extern int64_t s_cri_timeout;
extern sinsp_container_type s_cri_runtime_type;
extern bool s_cri_extra_queries;

sinsp_container_type get_cri_runtime_type(const std::string &runtime_name);

bool parse_cri_image(const runtime::v1alpha2::ContainerStatus &status, sinsp_container_info &container);

bool parse_cri_mounts(const runtime::v1alpha2::ContainerStatus &status, sinsp_container_info &container);

bool parse_cri_env(const Json::Value &info, sinsp_container_info &container);

bool parse_cri_json_image(const Json::Value &info, sinsp_container_info &container);

bool parse_cri_runtime_spec(const Json::Value &info, sinsp_container_info &container);

bool is_pod_sandbox(const std::string &container_id);

uint32_t get_pod_sandbox_ip(const std::string &pod_sandbox_id);

uint32_t get_container_ip(const std::string &container_id);
class cri_interface
{
public:
cri_interface(const std::string& cri_path);

/**
* @brief did we manage to connect to CRI and get the runtime name/version?
* @return true if successfully connected to CRI
*/
bool is_ok() const
{
return m_cri != nullptr;
}

/**
* @brief get the detected CRI runtime type
* @return one of CT_CRIO, CT_CONTAINERD, CT_CRI (for other CRI runtimes)
* corresponding to the CRI runtime type detected
*/
sinsp_container_type get_cri_runtime_type() const;

/**
* @brief thin wrapper around CRI gRPC ContainerStatus call
* @param container_id container ID
* @param resp reference to the response (if the RPC is successful, it will be filled out)
* @return status of the gRPC call
*/
grpc::Status get_container_status(const std::string& container_id, runtime::v1alpha2::ContainerStatusResponse& resp);

/**
* @brief fill out container image information based on CRI response
* @param status `status` field of the ContainerStatusResponse
* @param container the container info to fill out
* @return true if successful
*/
bool parse_cri_image(const runtime::v1alpha2::ContainerStatus &status, sinsp_container_info &container);

/**
* @brief fill out container mount information based on CRI response
* @param status `status` field of the ContainerStatusResponse
* @param container the container info to fill out
* @return true if successful
*/
bool parse_cri_mounts(const runtime::v1alpha2::ContainerStatus &status, sinsp_container_info &container);

/**
* @brief fill out container environment variables based on CRI response
* @param info the `info` key of the `info` field of the ContainerStatusResponse
* @param container the container info to fill out
* @return true if successful
*
* Note: only containerd exposes this data
*/
bool parse_cri_env(const Json::Value &info, sinsp_container_info &container);

/**
* @brief fill out extra image info based on CRI response
* @param info the `info` key of the `info` field of the ContainerStatusResponse
* @param container the container info to fill out
* @return true if successful
*
* Note: only containerd exposes this data
*/
bool parse_cri_json_image(const Json::Value &info, sinsp_container_info &container);

/**
* @brief fill out extra container info (e.g. resource limits) based on CRI response
* @param info the `info` key of the `info` field of the ContainerStatusResponse
* @param container the container info to fill out
* @return true if successful
*
* Note: only containerd exposes this data
*/
bool parse_cri_runtime_spec(const Json::Value &info, sinsp_container_info &container);

/**
* @brief check if the passed container ID is a pod sandbox (pause container)
* @param container_id the container ID to check
* @return true if it's a pod sandbox
*/
bool is_pod_sandbox(const std::string &container_id);

/**
* @brief get pod IP address
* @param pod_sandbox_id container ID of the pod sandbox
* @return the IP address if possible, 0 otherwise (e.g. when the pod uses host netns)
*/
uint32_t get_pod_sandbox_ip(const std::string &pod_sandbox_id);

/**
* @brief get container IP address
* @param container_id the container ID
* @return the IP address if possible, 0 otherwise (e.g. when the pod uses host netns)
*
* This method first finds the pod ID, then gets the IP address
* of the pod sandbox container
*/
uint32_t get_container_ip(const std::string &container_id);

/**
* @brief get image id info from CRI
* @param image_ref the image ref from container metadata
* @return image id if found, empty string otherwise
*/
std::string get_container_image_id(const std::string &image_ref);

private:

std::unique_ptr<runtime::v1alpha2::RuntimeService::Stub> m_cri;
std::unique_ptr<runtime::v1alpha2::ImageService::Stub> m_cri_image;
sinsp_container_type m_cri_runtime_type;
};

std::string get_container_image_id(const std::string &image_ref);
}
}

0 comments on commit 7c8d4e8

Please sign in to comment.