diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b95fdae5b5..4f68487045 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -11,14 +11,14 @@ jobs: build-sysdig-linux: runs-on: ubuntu-24.04${{ matrix.platform == 'arm64' && '-arm' || '' }} container: - image: ubuntu:22.04 + image: ubuntu:24.04 strategy: matrix: platform: - amd64 - arm64 env: - ZIG_VERSION: 0.14.0-dev.3259+0779e847f + ZIG_VERSION: 0.14.1 steps: - name: Checkout Sysdig @@ -32,8 +32,6 @@ jobs: cp -v scripts/zig-c++ /usr/bin/ apt update && \ apt install -y --no-install-recommends \ - autoconf \ - automake \ build-essential \ ca-certificates \ clang \ @@ -42,6 +40,7 @@ jobs: git \ libelf-dev \ libtool \ + linux-tools-$(uname -r) \ llvm \ ninja-build \ pkg-config \ @@ -55,10 +54,10 @@ jobs: make install && \ cd ../.. && \ rm -fr bpftool && \ - curl -LO https://ziglang.org/builds/zig-linux-"$(uname -m)"-"${ZIG_VERSION}".tar.xz && \ - tar -xaf zig-linux-"$(uname -m)"-"${ZIG_VERSION}".tar.xz && \ - rm -v zig-linux-"$(uname -m)"-"${ZIG_VERSION}".tar.xz && \ - cd zig-linux-"$(uname -m)"-"${ZIG_VERSION}" && \ + curl -LO "https://ziglang.org/download/${ZIG_VERSION}/zig-$(uname -m)-linux-${ZIG_VERSION}.tar.xz" && \ + tar -xaf "zig-$(uname -m)-linux-${ZIG_VERSION}.tar.xz" && \ + rm -v "zig-$(uname -m)-linux-${ZIG_VERSION}.tar.xz" && \ + cd zig-* && \ cp -v zig /usr/bin && \ find lib -exec cp --parents {} /usr/ \; && \ cd .. && \ @@ -129,9 +128,13 @@ jobs: steps: - name: Checkout Sysdig uses: actions/checkout@v4 + - name: Install NSIS + if: matrix.os == 'windows-latest' + run: | + choco install nsis -y - name: Build run: | - cmake -Wno-dev -S . -B build + cmake -Wno-dev -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -S . -B build cmake --build build --target package --config Release - name: Upload Artifacts uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release-draft.yaml b/.github/workflows/release-draft.yaml index 263e2a18c7..3b65462164 100644 --- a/.github/workflows/release-draft.yaml +++ b/.github/workflows/release-draft.yaml @@ -28,7 +28,7 @@ jobs: release_arch: aarch64 env: - ZIG_VERSION: 0.14.0-dev.3259+0779e847f + ZIG_VERSION: 0.14.1 steps: - name: Checkout Sysdig @@ -42,8 +42,6 @@ jobs: cp -v scripts/zig-c++ /usr/bin/ apt update && \ apt install -y --no-install-recommends \ - autoconf \ - automake \ build-essential \ ca-certificates \ clang \ @@ -52,6 +50,7 @@ jobs: git \ libelf-dev \ libtool \ + linux-tools-$(uname -r) \ llvm \ ninja-build \ pkg-config \ @@ -65,15 +64,16 @@ jobs: make install && \ cd ../.. && \ rm -fr bpftool && \ - curl -LO https://ziglang.org/builds/zig-linux-"$(uname -m)"-"${ZIG_VERSION}".tar.xz && \ - tar -xaf zig-linux-"$(uname -m)"-"${ZIG_VERSION}".tar.xz && \ - rm -v zig-linux-"$(uname -m)"-"${ZIG_VERSION}".tar.xz && \ - cd zig-linux-"$(uname -m)"-"${ZIG_VERSION}" && \ + curl -LO "https://ziglang.org/download/${ZIG_VERSION}/zig-$(uname -m)-linux-${ZIG_VERSION}.tar.xz" && \ + tar -xaf "zig-$(uname -m)-linux-${ZIG_VERSION}.tar.xz" && \ + rm -v "zig-$(uname -m)-linux-${ZIG_VERSION}.tar.xz" && \ + cd zig-* && \ cp -v zig /usr/bin && \ find lib -exec cp --parents {} /usr/ \; && \ cd .. && \ rm -fr zig* + - name: Build Sysdig env: CC: zig-cc diff --git a/CMakeLists.txt b/CMakeLists.txt index b1cbd02ccd..218f758d4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,11 +33,10 @@ if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.txt) "The following wiki page has more information on manually building sysdig: http://bit.ly/1oJ84UI") endif() -cmake_minimum_required(VERSION 3.5.1) +cmake_minimum_required(VERSION 3.28) project(sysdig) -option(MINIMAL_BUILD "Produce a minimal sysdig binary with only the essential features (no eBPF probe driver, no kubernetes, no mesos, no marathon and no container metadata)" OFF) option(MUSL_OPTIMIZED_BUILD "Enable if you want a musl optimized build" OFF) option(USE_BUNDLED_DEPS "Enable bundled dependencies instead of using the system ones" ON) @@ -71,14 +70,6 @@ add_definitions(-DCHISEL_TOOL_LIBRARY_NAME="${CHISEL_TOOL_LIBRARY_NAME}") option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags") -if(APPLE) - set(MINIMAL_BUILD ON) -endif() - -if(MINIMAL_BUILD) - set(MINIMAL_BUILD_FLAGS "-DMINIMAL_BUILD") -endif() - if(MUSL_OPTIMIZED_BUILD) set(SYSDIG_MUSL_FLAGS "-static -Os") endif() @@ -86,7 +77,7 @@ endif() if(NOT WIN32) set(SYSDIG_DEBUG_FLAGS "-D_DEBUG") - set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${MINIMAL_BUILD_FLAGS} ${SYSDIG_MUSL_FLAGS}") + set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${SYSDIG_MUSL_FLAGS}") if(BUILD_WARNINGS_AS_ERRORS) set(CMAKE_SUPPRESSED_WARNINGS "-Wno-unused-parameter -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits -Wno-implicit-fallthrough -Wno-format-truncation") @@ -122,9 +113,7 @@ if(NOT WIN32) endif() else() - set(MINIMAL_BUILD ON) - - set(SYSDIG_FLAGS_WIN "-D_CRT_SECURE_NO_WARNINGS -DWIN32 -DMINIMAL_BUILD /EHsc /W3 /Zi") + set(SYSDIG_FLAGS_WIN "-D_CRT_SECURE_NO_WARNINGS -DWIN32 /EHsc /W3 /Zi") if(CMAKE_VERSION VERSION_LESS 3.15.0) set(SYSDIG_FLAGS_WIN_DEBUG "/MTd /Od") @@ -144,7 +133,7 @@ else() set(CMAKE_CXX_FLAGS_RELEASE "${SYSDIG_FLAGS_WIN_RELEASE}") endif() -# Modern BPF is not supported on not Linux systems and in MINIMAL_BUILD +# Modern BPF is not supported on not Linux systems if(CMAKE_SYSTEM_NAME MATCHES "Linux") option(BUILD_SYSDIG_MODERN_BPF "Build modern BPF support for Sysdig" ON) if(BUILD_SYSDIG_MODERN_BPF) @@ -165,11 +154,16 @@ if(MSVC OR WIN32) _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR NOMINMAX ) + + # Set MSVC runtime library for Windows builds (CMake 3.15+) + # This ensures consistent runtime linkage across all targets and dependencies + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() include(falcosecurity-libs) include(yaml-cpp) include(nlohmann-json) +include(container_plugin) if(CMAKE_SYSTEM_NAME MATCHES "Linux") if(NOT DEFINED DRIVER_VERSION) diff --git a/cmake/modules/container_plugin.cmake b/cmake/modules/container_plugin.cmake new file mode 100644 index 0000000000..f9384bfaf0 --- /dev/null +++ b/cmake/modules/container_plugin.cmake @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2025 The Falco 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. +# + +include(ExternalProject) + +string(TOLOWER ${CMAKE_HOST_SYSTEM_NAME} PLUGINS_SYSTEM_NAME) + +set(CONTAINER_VERSION "0.4.1") + +if(UNIX AND NOT APPLE) + + set(CONTAINER_LIBRARY + "${CMAKE_BINARY_DIR}/container_plugin-prefix/src/container_plugin/libcontainer.so" + ) + if(${CMAKE_HOST_SYSTEM_PROCESSOR} STREQUAL "x86_64") + set(CONTAINER_HASH "2ca0390f8b44bb4d0ec4c7f030dfb82af349897d00276393b6cb29281e14588e") + else() # arm64 + set(CONTAINER_HASH "aa69ae222fb3947d9eac3756e06d5006964e1544130d3ebff398a18462fd0b12") + endif() + + if(NOT TARGET container_plugin) + message(STATUS "Fetching container plugin ${CONTAINER_VERSION} in '${CONTAINER_LIBRARY}'") + ExternalProject_Add( + container_plugin + URL "https://download.falco.org/plugins/stable/container-${CONTAINER_VERSION}-${PLUGINS_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz" + URL_HASH "SHA256=${CONTAINER_HASH}" + BUILD_BYPRODUCTS "${CONTAINER_LIBRARY}" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + ) + + install( + FILES "${CONTAINER_LIBRARY}" + DESTINATION local/share/sysdig/plugins + COMPONENT "${SYSDIG_COMPONENT_NAME}" + ) + endif() +else() + + # Determine the correct library extension for the platform + if(APPLE) + set(CONTAINER_LIB_EXT "dylib") + elseif(WIN32) + set(CONTAINER_LIB_EXT "dll") + else() + set(CONTAINER_LIB_EXT "so") + endif() + + # On Windows, shared libraries don't have the "lib" prefix + # and multi-config generators place outputs in config subdirectories + if(WIN32) + set(CONTAINER_LIBRARY + "${CMAKE_BINARY_DIR}/container_plugin-prefix/src/container_plugin/plugins/container/${CMAKE_BUILD_TYPE}/container.${CONTAINER_LIB_EXT}" + ) + else() + set(CONTAINER_LIBRARY + "${CMAKE_BINARY_DIR}/container_plugin-prefix/src/container_plugin/plugins/container/libcontainer.${CONTAINER_LIB_EXT}" + ) + endif() + if(NOT TARGET container_plugin) + message(STATUS "Fetching container plugin source ${CONTAINER_VERSION} in '${CONTAINER_LIBRARY}'") + ExternalProject_Add( + container_plugin + URL "https://github.com/falcosecurity/plugins/archive/refs/tags/plugins/container/v${CONTAINER_VERSION}.tar.gz" + URL_HASH "SHA256=7adbd1062533dbd3f6d18e77abe44f63dd80cf40ebb7755d0a1bdb8298888ac4" + SOURCE_SUBDIR plugins/container + BUILD_IN_SOURCE 1 + BUILD_BYPRODUCTS "${CONTAINER_LIBRARY}" + CONFIGURE_COMMAND + ${CMAKE_COMMAND} . -DENABLE_ASYNC=OFF -G "${CMAKE_GENERATOR}" + BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE} + INSTALL_COMMAND "" + ) + + install( + FILES "${CONTAINER_LIBRARY}" + DESTINATION share/plugins + COMPONENT "${SYSDIG_COMPONENT_NAME}" + ) + endif() + +endif() diff --git a/cmake/modules/driver.cmake b/cmake/modules/driver.cmake index 9b9bc24c9d..e5c9e01edc 100644 --- a/cmake/modules/driver.cmake +++ b/cmake/modules/driver.cmake @@ -31,8 +31,8 @@ else() # In case you want to test against another driver version (or branch, or commit) just pass the variable - # ie., `cmake -DDRIVER_VERSION=dev ..` if(NOT DRIVER_VERSION) - set(DRIVER_VERSION "8.0.0+driver") - set(DRIVER_CHECKSUM "SHA256=f35990d6a1087a908fe94e1390027b9580d4636032c0f2b80bf945219474fd6b") + set(DRIVER_VERSION "8.1.0+driver") + set(DRIVER_CHECKSUM "SHA256=182e6787bf86249a846a3baeb4dcd31578b76d4a13efa16ce3f44d66b18a77a6") endif() # cd /path/to/build && cmake /path/to/source diff --git a/cmake/modules/falcosecurity-libs.cmake b/cmake/modules/falcosecurity-libs.cmake index c4db6037af..67eb84b182 100644 --- a/cmake/modules/falcosecurity-libs.cmake +++ b/cmake/modules/falcosecurity-libs.cmake @@ -47,8 +47,8 @@ else() # In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable - # ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..` if(NOT FALCOSECURITY_LIBS_VERSION) - set(FALCOSECURITY_LIBS_VERSION "0.20.0") - set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=4ae6ddb42a1012bacd88c63abdaa7bd27ca0143c4721338a22c45597e63bc99d") + set(FALCOSECURITY_LIBS_VERSION "0.21.0") + set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=9e977001dd42586df42a5dc7e7a948c297124865a233402e44bdec68839d322a") endif() # cd /path/to/build && cmake /path/to/source diff --git a/userspace/chisel/chisel.cpp b/userspace/chisel/chisel.cpp index 33952bc1bb..96521632d5 100644 --- a/userspace/chisel/chisel.cpp +++ b/userspace/chisel/chisel.cpp @@ -60,11 +60,6 @@ using namespace std; extern vector* g_chisel_dirs; extern sinsp_evttables g_infotables; -// todo(jasondellaluce): this list is static and prevents chisels from using -// plugin-defined extraction fields. The right way would be to have a filtercheck -// list owned by each chisel itself and populate depending on the loaded plugins. -static sinsp_filter_check_list s_filterlist; - /////////////////////////////////////////////////////////////////////////////// // For Lua debugging /////////////////////////////////////////////////////////////////////////////// @@ -167,12 +162,13 @@ const static struct luaL_Reg ll_evt [] = /////////////////////////////////////////////////////////////////////////////// // chiselinfo implementation /////////////////////////////////////////////////////////////////////////////// -chiselinfo::chiselinfo(sinsp* inspector) +chiselinfo::chiselinfo(sinsp* inspector, std::shared_ptr filter_check_list) { m_filter = NULL; m_formatter = NULL; m_dumper = NULL; m_inspector = inspector; + m_filter_check_list = filter_check_list; m_has_nextrun_args = false; m_end_capture = false; @@ -208,8 +204,8 @@ void chiselinfo::init(string filterstr, string formatterstr) void chiselinfo::set_filter(string filterstr) { - - sinsp_filter_compiler compiler(m_inspector, filterstr); + auto filter_factory = std::make_shared(m_inspector, *m_filter_check_list); + sinsp_filter_compiler compiler(filter_factory, filterstr); if(m_filter) { delete m_filter; @@ -232,11 +228,11 @@ void chiselinfo::set_formatter(string formatterstr) if(formatterstr == "" || formatterstr == "default") { - m_formatter = new sinsp_evt_formatter(m_inspector, DEFAULT_OUTPUT_STR, s_filterlist); + m_formatter = new sinsp_evt_formatter(m_inspector, DEFAULT_OUTPUT_STR, *m_filter_check_list); } else { - m_formatter = new sinsp_evt_formatter(m_inspector, formatterstr, s_filterlist); + m_formatter = new sinsp_evt_formatter(m_inspector, formatterstr, *m_filter_check_list); } } @@ -255,7 +251,7 @@ void chiselinfo::set_callback_precise_interval(uint64_t interval) /////////////////////////////////////////////////////////////////////////////// // chisel implementation /////////////////////////////////////////////////////////////////////////////// -sinsp_chisel::sinsp_chisel(sinsp* inspector, string filename, bool is_file) +sinsp_chisel::sinsp_chisel(sinsp* inspector, std::string filename, bool is_file) { m_inspector = inspector; m_ls = NULL; @@ -1224,7 +1220,7 @@ void sinsp_chisel::load(string cmdstr, bool is_file) // // Allocate the chisel context for the script // - m_lua_cinfo = new chiselinfo(m_inspector); + m_lua_cinfo = new chiselinfo(m_inspector, m_filter_check_list); // // Set the context globals @@ -1449,6 +1445,12 @@ void sinsp_chisel::set_args(vector> args) #endif } + +void sinsp_chisel::set_filter_list(std::shared_ptr filter_list) +{ + m_filter_check_list = std::move(filter_list); +} + void sinsp_chisel::on_init() { // diff --git a/userspace/chisel/chisel.h b/userspace/chisel/chisel.h index a7632db7d8..9d7dac5370 100644 --- a/userspace/chisel/chisel.h +++ b/userspace/chisel/chisel.h @@ -111,7 +111,7 @@ class chisel_metric class chiselinfo { public: - chiselinfo(sinsp* inspector); + chiselinfo(sinsp* inspector, std::shared_ptr filter_check_list); void init(std::string filterstr, std::string formatterstr); void set_filter(std::string filterstr); void set_formatter(std::string formatterstr); @@ -129,9 +129,10 @@ class chiselinfo private: sinsp* m_inspector; + std::shared_ptr m_filter_check_list; }; -class SINSP_PUBLIC sinsp_chisel +class sinsp_chisel { public: sinsp_chisel(sinsp* inspector, std::string filename, bool is_file = true); @@ -153,6 +154,7 @@ class SINSP_PUBLIC sinsp_chisel bool run(sinsp_evt* evt); void do_timeout(sinsp_evt* evt); void do_end_of_sample(); + void set_filter_list(std::shared_ptr filter_list); void on_init(); void on_capture_start(); void on_capture_end(); @@ -178,6 +180,7 @@ class SINSP_PUBLIC sinsp_chisel std::string m_description; std::vector m_argvals; std::string m_filename; + std::shared_ptr m_filter_check_list; lua_State* m_ls; chisel_desc m_lua_script_info; bool m_lua_has_handle_evt; diff --git a/userspace/chisel/chisel_api.cpp b/userspace/chisel/chisel_api.cpp index 09bb7cb56b..94a91b69f1 100644 --- a/userspace/chisel/chisel_api.cpp +++ b/userspace/chisel/chisel_api.cpp @@ -43,9 +43,6 @@ extern "C" { #endif #include -#include -#include -#include #ifdef _WIN32 #include #else @@ -61,11 +58,6 @@ extern vector* g_chisel_dirs; extern sinsp_evttables g_infotables; void lua_stackdump(lua_State *L); -// todo(jasondellaluce): this list is static and prevents chisels from using -// plugin-defined extraction fields. The right way would be to have a filtercheck -// list owned by each chisel itself and populate depending on the loaded plugins. -static sinsp_filter_check_list s_filterlist; - /////////////////////////////////////////////////////////////////////////////// // Lua callbacks /////////////////////////////////////////////////////////////////////////////// @@ -326,7 +318,7 @@ int lua_cbacks::request_field(lua_State *ls) throw sinsp_exception("chisel error"); } - auto chk = s_filterlist.new_filter_check_from_fldname(fld, + auto chk = ch->m_filter_check_list->new_filter_check_from_fldname(fld, inspector, false).release(); @@ -746,7 +738,8 @@ int lua_cbacks::get_thread_table_int(lua_State *ls, bool include_fds, bool bareb { try { - compiler = std::make_unique(ch->m_inspector, filterstr); + auto filter_factory = std::make_shared(ch->m_inspector, *ch->m_filter_check_list); + compiler = std::make_unique(filter_factory, filterstr); filter = compiler->compile(); } catch(const sinsp_exception& e) @@ -842,10 +835,10 @@ int lua_cbacks::get_thread_table_int(lua_State *ls, bool include_fds, bool bareb lua_pushnumber(ls, (uint32_t)tinfo.m_fdlimit); lua_settable(ls, -3); lua_pushliteral(ls, "uid"); - lua_pushnumber(ls, (uint32_t)tinfo.m_uid); + lua_pushnumber(ls, (uint32_t)tinfo.get_user()->uid); lua_settable(ls, -3); lua_pushliteral(ls, "gid"); - lua_pushnumber(ls, (uint32_t)tinfo.m_gid); + lua_pushnumber(ls, (uint32_t)tinfo.get_group()->gid); lua_settable(ls, -3); lua_pushliteral(ls, "nchilds"); lua_pushnumber(ls, (uint32_t)tinfo.get_num_not_leader_threads()); @@ -1109,6 +1102,26 @@ int lua_cbacks::get_thread_table_barebone_nofds(lua_State *ls) return get_thread_table_int(ls, false, true); } +enum container_type +{ + CT_DOCKER = 0, + CT_LXC = 1, + CT_LIBVIRT_LXC = 2, + CT_MESOS = 3, // deprecated + CT_RKT = 4, // deprecated + CT_CUSTOM = 5, + CT_CRI = 6, + CT_CONTAINERD = 7, + CT_CRIO = 8, + CT_BPM = 9, + CT_STATIC = 10, + CT_PODMAN = 11, + + // Default value, may be changed if necessary + CT_HOST = 0xfffe, + CT_UNKNOWN = 0xffff +}; + int lua_cbacks::get_container_table(lua_State *ls) { #ifndef _WIN32 @@ -1130,71 +1143,85 @@ int lua_cbacks::get_container_table(lua_State *ls) // // Retrieve the container list // - const sinsp_container_manager::map_ptr_t ctable = ch->m_inspector->m_container_manager.get_containers(); + const auto ctable = ch->m_inspector->m_thread_manager + ->get_table(sinsp_thread_manager::s_containers_table_name); lua_newtable(ls); // // Go through the list // - j = 0; - for(auto it = ctable->begin(); it != ctable->end(); ++it) - { - lua_newtable(ls); - lua_pushliteral(ls, "id"); - lua_pushstring(ls, it->second->m_id.c_str()); - lua_settable(ls, -3); - lua_pushliteral(ls, "name"); - lua_pushstring(ls, it->second->m_name.c_str()); - lua_settable(ls, -3); - lua_pushliteral(ls, "image"); - lua_pushstring(ls, it->second->m_image.c_str()); - lua_settable(ls, -3); + if(ctable != nullptr) { + auto fld_id = ctable->get_field("container_id"); + auto fld_name = ctable->get_field("name"); + auto fld_image = ctable->get_field("image"); + auto fld_type = ctable->get_field("type"); + auto it = [&](sinsp_table_entry& e) -> bool { + std::string id, name, image; + int type; + e.read_field(fld_id, id); + e.read_field(fld_name, name); + e.read_field(fld_image, image); + e.read_field(fld_type, type); - lua_pushliteral(ls, "type"); - switch (it->second->m_type) - { - case CT_DOCKER: - lua_pushstring(ls, "docker"); - break; - case CT_LXC: - lua_pushstring(ls, "lxc"); - break; - case CT_LIBVIRT_LXC: - lua_pushstring(ls, "libvirt_lxc"); - break; - case CT_MESOS: - lua_pushstring(ls, "mesos"); - break; - case CT_RKT: - lua_pushstring(ls, "rkt"); - break; - case CT_CRI: - lua_pushstring(ls, "cri"); - break; - case CT_CONTAINERD: - lua_pushstring(ls, "containerd"); - break; - case CT_CRIO: - lua_pushstring(ls, "cri-o"); - break; - case CT_BPM: - lua_pushstring(ls, "bpm"); - break; - case CT_PODMAN: - lua_pushstring(ls, "podman"); - break; - default: - ASSERT(false); - lua_pushstring(ls, "unknown"); - break; - } - lua_settable(ls, -3); + lua_newtable(ls); + lua_pushliteral(ls, "id"); + lua_pushstring(ls, id.c_str()); + lua_settable(ls, -3); + lua_pushliteral(ls, "name"); + lua_pushstring(ls, name.c_str()); + lua_settable(ls, -3); + lua_pushliteral(ls, "image"); + lua_pushstring(ls, image.c_str()); + lua_settable(ls, -3); - // - // Set the key for this entry - // - lua_rawseti(ls,-2, (uint32_t)++j); + lua_pushliteral(ls, "type"); + switch (type) + { + case container_type::CT_DOCKER: + lua_pushstring(ls, "docker"); + break; + case container_type::CT_LXC: + lua_pushstring(ls, "lxc"); + break; + case container_type::CT_LIBVIRT_LXC: + lua_pushstring(ls, "libvirt_lxc"); + break; + case container_type::CT_MESOS: + lua_pushstring(ls, "mesos"); + break; + case container_type::CT_RKT: + lua_pushstring(ls, "rkt"); + break; + case container_type::CT_CRI: + lua_pushstring(ls, "cri"); + break; + case container_type::CT_CONTAINERD: + lua_pushstring(ls, "containerd"); + break; + case container_type::CT_CRIO: + lua_pushstring(ls, "cri-o"); + break; + case container_type::CT_BPM: + lua_pushstring(ls, "bpm"); + break; + case container_type::CT_PODMAN: + lua_pushstring(ls, "podman"); + break; + default: + ASSERT(false); + lua_pushstring(ls, "unknown"); + break; + } + lua_settable(ls, -3); + + // + // Set the key for this entry + // + lua_rawseti(ls,-2, (uint32_t)++j); + return true; + }; + ctable->foreach_entry(it); } #endif @@ -1211,7 +1238,7 @@ int lua_cbacks::is_print_container_data(lua_State *ls) ASSERT(ch); ASSERT(ch->m_lua_cinfo); - lua_pushboolean(ls, ch->m_inspector->is_print_container_data()); + lua_pushboolean(ls, true); return 1; } diff --git a/userspace/chisel/chisel_table.cpp b/userspace/chisel/chisel_table.cpp index ede9690495..0c84d054b7 100644 --- a/userspace/chisel/chisel_table.cpp +++ b/userspace/chisel/chisel_table.cpp @@ -23,8 +23,6 @@ draios/sysdig project. */ -#include - #include #include @@ -32,11 +30,6 @@ using namespace std; extern sinsp_evttables g_infotables; -// todo(jasondellaluce): this list is static and prevents chisels from using -// plugin-defined extraction fields. The right way would be to have a filtercheck -// list owned by each chisel itself and populate depending on the loaded plugins. -static sinsp_filter_check_list s_filterlist; - // // // Table sorter functor @@ -81,10 +74,11 @@ struct table_row_cmp bool m_ascending; }; -chisel_table::chisel_table(sinsp* inspector, tabletype type, uint64_t refresh_interval_ns, +chisel_table::chisel_table(sinsp* inspector, std::shared_ptr filter_list, tabletype type, uint64_t refresh_interval_ns, chisel_table::output_type output_type, uint32_t json_first_row, uint32_t json_last_row) { m_inspector = inspector; + m_filter_check_list = filter_list; m_type = type; m_is_key_present = false; m_is_groupby_key_present = false; @@ -163,7 +157,8 @@ void chisel_table::configure(vector* entries, const str ////////////////////////////////////////////////////////////////////////////////////// if(filter != "") { - sinsp_filter_compiler compiler(m_inspector, filter); + auto filter_factory = std::make_shared(m_inspector, *m_filter_check_list); + sinsp_filter_compiler compiler(filter_factory, filter); m_filter = compiler.compile().release(); } @@ -174,7 +169,7 @@ void chisel_table::configure(vector* entries, const str for(auto vit : *entries) { - auto chk = s_filterlist.new_filter_check_from_fldname(vit.get_field(m_view_depth), + auto chk = m_filter_check_list->new_filter_check_from_fldname(vit.get_field(m_view_depth), m_inspector, false).release(); @@ -216,7 +211,7 @@ void chisel_table::configure(vector* entries, const str } else { - auto chk = s_filterlist.new_filter_check_from_fldname("util.cnt", + auto chk = m_filter_check_list->new_filter_check_from_fldname("util.cnt", m_inspector, false).release(); diff --git a/userspace/chisel/chisel_table.h b/userspace/chisel/chisel_table.h index 56163f2a69..eac617b8de 100644 --- a/userspace/chisel/chisel_table.h +++ b/userspace/chisel/chisel_table.h @@ -266,7 +266,7 @@ class chisel_table chisel_field_aggregation m_merge_aggregation; }; - chisel_table(sinsp* inspector, tabletype type, + chisel_table(sinsp* inspector, std::shared_ptr filter_list, tabletype type, uint64_t refresh_interval_ns, chisel_table::output_type output_type, uint32_t json_first_row, uint32_t json_last_row); ~chisel_table(); @@ -345,6 +345,7 @@ class chisel_table void print_json(std::vector* sample_data, uint64_t time_delta); sinsp* m_inspector; + std::shared_ptr m_filter_check_list; std::unordered_map* m_table; std::unordered_map m_premerge_table; std::unordered_map m_merge_table; diff --git a/userspace/chisel/chisel_viewinfo.cpp b/userspace/chisel/chisel_viewinfo.cpp index ec09da36b3..f665a76a6f 100644 --- a/userspace/chisel/chisel_viewinfo.cpp +++ b/userspace/chisel/chisel_viewinfo.cpp @@ -22,7 +22,6 @@ falcosecurity/libs project, has been reintroduced to the draios/sysdig project. */ -#include #include #include diff --git a/userspace/sinspui/cursescomponents.cpp b/userspace/sinspui/cursescomponents.cpp index e8dfbfcd32..0759c7fcf9 100644 --- a/userspace/sinspui/cursescomponents.cpp +++ b/userspace/sinspui/cursescomponents.cpp @@ -47,16 +47,11 @@ using namespace std; extern bool g_filterchecks_force_raw_times; -// todo(jasondellaluce): this list is static and prevents from using -// plugin-defined extraction fields. The right way would be to have a filtercheck -// list owned by each component and populate depending on the loaded plugins. -// this is not something that we plan on supporting for now. -static sinsp_filter_check_list s_filterlist; - /////////////////////////////////////////////////////////////////////////////// // spy_text_renderer implementation /////////////////////////////////////////////////////////////////////////////// spy_text_renderer::spy_text_renderer(sinsp* inspector, + std::shared_ptr filter_check_list, sinsp_cursesui* parent, int32_t viz_type, sysdig_output_type sotype, @@ -65,6 +60,7 @@ spy_text_renderer::spy_text_renderer(sinsp* inspector, { m_formatter = NULL; m_inspector = inspector; + m_filter_check_list = filter_check_list; m_viz_type = viz_type; m_linecnt = 0; @@ -79,13 +75,13 @@ spy_text_renderer::spy_text_renderer(sinsp* inspector, { m_formatter = new sinsp_evt_formatter(m_inspector, "*(latency=%evt.latency.human) (fd=%fd.name) %evt.num %evt.time %evt.cpu %container.name (%container.id) %proc.name (%thread.tid:%thread.vtid) %evt.dir %evt.type %evt.info", - s_filterlist); + *m_filter_check_list); } else { m_formatter = new sinsp_evt_formatter(m_inspector, "*(latency=%evt.latency.human) (fd=%fd.name) %evt.num %evt.time %evt.cpu %proc.name %thread.tid %evt.dir %evt.type %evt.info", - s_filterlist); + *m_filter_check_list); } } else @@ -94,11 +90,11 @@ spy_text_renderer::spy_text_renderer(sinsp* inspector, { m_formatter = new sinsp_evt_formatter(m_inspector, "*%evt.num %evt.time %evt.cpu %container.name (%container.id) %proc.name (%thread.tid:%thread.vtid) %evt.dir %evt.type %evt.info", - s_filterlist); + *m_filter_check_list); } else { - m_formatter = new sinsp_evt_formatter(m_inspector, DEFAULT_OUTPUT_STR, s_filterlist); + m_formatter = new sinsp_evt_formatter(m_inspector, DEFAULT_OUTPUT_STR, *m_filter_check_list); } } } @@ -737,7 +733,7 @@ chisel_table_action curses_table_sidemenu::handle_input(int ch) /////////////////////////////////////////////////////////////////////////////// // curses_textbox implementation /////////////////////////////////////////////////////////////////////////////// -curses_textbox::curses_textbox(sinsp* inspector, sinsp_cursesui* parent, int32_t viz_type, spy_text_renderer::sysdig_output_type sotype) +curses_textbox::curses_textbox(sinsp* inspector, std::shared_ptr filter_check_list, sinsp_cursesui* parent, int32_t viz_type, spy_text_renderer::sysdig_output_type sotype) { ASSERT(inspector != NULL); ASSERT(parent != NULL); @@ -748,6 +744,7 @@ curses_textbox::curses_textbox(sinsp* inspector, sinsp_cursesui* parent, int32_t m_filter = NULL; m_text_renderer = NULL; m_inspector = inspector; + m_filter_check_list = filter_check_list; n_prints = 0; m_paused = false; m_sidemenu = NULL; @@ -766,8 +763,9 @@ curses_textbox::curses_textbox(sinsp* inspector, sinsp_cursesui* parent, int32_t config.m_scroll_on_append = true; config.m_bounding_box = true; - m_text_renderer = new spy_text_renderer(inspector, - parent, + m_text_renderer = new spy_text_renderer(inspector, + m_filter_check_list, + parent, viz_type, sotype, m_parent->m_print_containers, @@ -854,8 +852,12 @@ curses_textbox::~curses_textbox() void curses_textbox::set_filter(string filter) { - sinsp_filter_compiler compiler(m_inspector, filter); - m_filter = compiler.compile(); + if(filter != "") + { + auto filter_factory = std::make_shared(m_inspector, *m_filter_check_list); + sinsp_filter_compiler compiler(filter_factory, filter); + m_filter = compiler.compile(); + } } void curses_textbox::print_no_data() @@ -925,7 +927,20 @@ void curses_textbox::process_event_spy(sinsp_evt* evt, int32_t next_res) { wattrset(m_win, m_parent->m_colors[sinsp_cursesui::LED_COLOR]); - m_ctext->printf(" [%s]", m_inspector->m_container_manager.get_container_name(m_tinfo).c_str()); + const auto ctable = m_inspector->m_thread_manager + ->get_table(sinsp_thread_manager::s_containers_table_name); + + std::string container_name = "host"; + if(!m_tinfo->get_container_id().empty()) + { + if(ctable != nullptr) { + auto fld_name = ctable->get_field("name"); + + auto container_info = ctable->get_entry(m_tinfo->get_container_id()); + container_info.read_field(fld_name, container_name); + } + } + m_ctext->printf(" [%s]", container_name.c_str()); if(eflags & EF_READS_FROM_FD) { diff --git a/userspace/sinspui/cursescomponents.h b/userspace/sinspui/cursescomponents.h index a0858a711d..5a9edb7aee 100644 --- a/userspace/sinspui/cursescomponents.h +++ b/userspace/sinspui/cursescomponents.h @@ -57,7 +57,8 @@ class spy_text_renderer }; spy_text_renderer(sinsp* inspector, - sinsp_cursesui* parent, + std::shared_ptr filter_check_list, + sinsp_cursesui* parent, int32_t viz_type, sysdig_output_type sotype, bool print_containers, @@ -67,6 +68,7 @@ class spy_text_renderer sinsp_evt_formatter* m_formatter; sinsp* m_inspector; + std::shared_ptr m_filter_check_list; int32_t m_viz_type; uint64_t m_linecnt; }; @@ -186,7 +188,7 @@ class curses_textbox : public sinsp_chart, public search_caller_interface { public: - curses_textbox(sinsp* inspector, sinsp_cursesui* parent, int32_t viz_type, spy_text_renderer::sysdig_output_type sotype); + curses_textbox(sinsp* inspector, std::shared_ptr filter_check_list, sinsp_cursesui* parent, int32_t viz_type, spy_text_renderer::sysdig_output_type sotype); ~curses_textbox(); void render(); void set_filter(std::string filter); @@ -214,6 +216,7 @@ public sinsp_chart, public search_caller_interface ctext* m_ctext; sinsp_cursesui* m_parent; sinsp* m_inspector; + std::shared_ptr m_filter_check_list; std::unique_ptr m_filter; uint32_t n_prints; bool m_paused; diff --git a/userspace/sinspui/cursesui.cpp b/userspace/sinspui/cursesui.cpp index 9a1fb7b79c..e9743b4a93 100644 --- a/userspace/sinspui/cursesui.cpp +++ b/userspace/sinspui/cursesui.cpp @@ -63,7 +63,8 @@ int do_sleep(DWORD usec) /////////////////////////////////////////////////////////////////////////////// // json_spy_renderer implementation /////////////////////////////////////////////////////////////////////////////// -json_spy_renderer::json_spy_renderer(sinsp* inspector, +json_spy_renderer::json_spy_renderer(sinsp* inspector, + std::shared_ptr filter_check_list, sinsp_cursesui* parent, int32_t viz_type, spy_text_renderer::sysdig_output_type sotype, @@ -71,11 +72,13 @@ json_spy_renderer::json_spy_renderer(sinsp* inspector, sinsp_evt::param_fmt text_fmt) { m_inspector = inspector; + m_filter_check_list = filter_check_list; m_filter = NULL; m_root = Json::Value(Json::arrayValue); m_linecnt = 0; - m_json_spy_renderer = new spy_text_renderer(inspector, + m_json_spy_renderer = new spy_text_renderer(inspector, + m_filter_check_list, parent, viz_type, sotype, @@ -92,7 +95,8 @@ void json_spy_renderer::set_filter(string filter) { if(filter != "") { - sinsp_filter_compiler compiler(m_inspector, filter); + auto filter_factory = std::make_shared(m_inspector, *m_filter_check_list); + sinsp_filter_compiler compiler(filter_factory, filter); m_filter = compiler.compile(); } } @@ -152,15 +156,21 @@ void json_spy_renderer::process_event_spy(sinsp_evt* evt, int32_t next_res) line["p"] = tinfo->m_comm; - if(!tinfo->m_container_id.empty()) + if(!tinfo->get_container_id().empty()) { - const sinsp_container_info::ptr_t container_info = - m_inspector->m_container_manager.get_container(tinfo->m_container_id); - if(container_info) - { - if(!container_info->m_name.empty()) + const auto ctable = m_inspector->m_thread_manager + ->get_table(sinsp_thread_manager::s_containers_table_name); + + if(ctable != nullptr) { + auto fld_name = ctable->get_field("name"); + std::string container_name; + + auto container_info = ctable->get_entry(tinfo->get_container_id()); + container_info.read_field(fld_name, container_name); + + if(!container_name.empty()) { - line["c"] = container_info->m_name; + line["c"] = container_name; } } } @@ -234,6 +244,7 @@ uint64_t json_spy_renderer::get_count() // sinsp_cursesui implementation /////////////////////////////////////////////////////////////////////////////// sinsp_cursesui::sinsp_cursesui(sinsp* inspector, + std::shared_ptr filter_list, sinsp_opener* source_opener, string cmdline_capture_filter, uint64_t refresh_interval_ns, @@ -245,6 +256,7 @@ sinsp_cursesui::sinsp_cursesui(sinsp* inspector, sinsp_evt::param_fmt json_spy_text_fmt) { m_inspector = inspector; + m_filter_check_list = filter_list; m_source_opener = source_opener; m_selected_view = 0; m_prev_selected_view = 0; @@ -580,13 +592,13 @@ void sinsp_cursesui::start(bool is_drilldown, bool is_spy_switch) if(wi->m_type == chisel_view_info::T_TABLE) { ty = chisel_table::TT_TABLE; - m_datatable = new chisel_table(m_inspector, ty, m_refresh_interval_ns, + m_datatable = new chisel_table(m_inspector, m_filter_check_list, ty, m_refresh_interval_ns, m_output_type, m_json_first_row, m_json_last_row); } else if(wi->m_type == chisel_view_info::T_LIST) { ty = chisel_table::TT_LIST; - m_datatable = new chisel_table(m_inspector, ty, m_refresh_interval_ns, + m_datatable = new chisel_table(m_inspector, m_filter_check_list, ty, m_refresh_interval_ns, m_output_type, m_json_first_row, m_json_last_row); } else if(wi->m_type == chisel_view_info::T_SPECTRO) @@ -598,12 +610,12 @@ void sinsp_cursesui::start(bool is_drilldown, bool is_spy_switch) // if(m_refresh_interval_ns == 2000000000) { - m_datatable = new chisel_table(m_inspector, ty, m_refresh_interval_ns / 4, + m_datatable = new chisel_table(m_inspector, m_filter_check_list, ty, m_refresh_interval_ns / 4, m_output_type, m_json_first_row, m_json_last_row); } else { - m_datatable = new chisel_table(m_inspector, ty, m_refresh_interval_ns, + m_datatable = new chisel_table(m_inspector, m_filter_check_list, ty, m_refresh_interval_ns, m_output_type, m_json_first_row, m_json_last_row); } } @@ -643,6 +655,7 @@ void sinsp_cursesui::start(bool is_drilldown, bool is_spy_switch) if(m_output_type == chisel_table::OT_JSON) { m_json_spy_renderer= new json_spy_renderer(m_inspector, + m_filter_check_list, this, m_selected_view, spy_text_renderer::OT_NORMAL, @@ -654,7 +667,7 @@ void sinsp_cursesui::start(bool is_drilldown, bool is_spy_switch) #ifndef NOCURSESUI else { - m_spy_box = new curses_textbox(m_inspector, this, m_selected_view, dig_otype); + m_spy_box = new curses_textbox(m_inspector, m_filter_check_list, this, m_selected_view, dig_otype); m_spy_box->reset(); m_chart = m_spy_box; m_spy_box->set_filter(m_complete_filter); @@ -2270,7 +2283,9 @@ chisel_table_action sinsp_cursesui::handle_textbox_input(int ch) { if(*str != "") { - sinsp_filter_compiler compiler(m_inspector, *str); + // TODO(therealbobo): use a populated filter check list + auto filter_factory = std::make_shared(m_inspector, *m_filter_check_list); + sinsp_filter_compiler compiler(filter_factory, *str); std::unique_ptr f; try diff --git a/userspace/sinspui/cursesui.h b/userspace/sinspui/cursesui.h index 3a81d9bd78..023d387741 100644 --- a/userspace/sinspui/cursesui.h +++ b/userspace/sinspui/cursesui.h @@ -331,7 +331,8 @@ class sinsp_mouse_to_key_list class json_spy_renderer { public: - json_spy_renderer(sinsp* inspector, + json_spy_renderer(sinsp* inspector, + std::shared_ptr filter_check_list, sinsp_cursesui* parent, int32_t viz_type, spy_text_renderer::sysdig_output_type sotype, @@ -350,6 +351,7 @@ class json_spy_renderer spy_text_renderer* m_json_spy_renderer; sinsp* m_inspector; + std::shared_ptr m_filter_check_list; Json::Value m_root; std::unique_ptr m_filter; uint64_t m_linecnt; @@ -432,7 +434,7 @@ class sinsp_cursesui LAST_COLORELEMENT }; - sinsp_cursesui(sinsp* inspector, sinsp_opener* source_opener, + sinsp_cursesui(sinsp* inspector, std::shared_ptr filter_list, sinsp_opener* source_opener, std::string cmdline_capture_filter, uint64_t refresh_interval_ns, bool print_containers, chisel_table::output_type output_type, bool is_mousedrag_available, int32_t json_first_row, int32_t json_last_row, int32_t sorting_col, @@ -756,6 +758,7 @@ class sinsp_cursesui bool m_offline_replay; uint64_t m_refresh_interval_ns; sinsp* m_inspector; + std::shared_ptr m_filter_check_list; uint32_t m_view_depth; bool m_is_mousedrag_available; @@ -829,4 +832,3 @@ class sinsp_cursesui sinsp_evt::param_fmt m_json_spy_text_fmt; uint64_t m_n_progress_reports; }; - diff --git a/userspace/sysdig/csysdig.cpp b/userspace/sysdig/csysdig.cpp index 8994183032..7bd5ca7519 100644 --- a/userspace/sysdig/csysdig.cpp +++ b/userspace/sysdig/csysdig.cpp @@ -26,9 +26,9 @@ limitations under the License. #include #include #include -#include #include +#include "plugin_manager.h" #ifdef HAS_CAPTURE #ifndef WIN32 #include "driver_config.h" @@ -126,13 +126,6 @@ static void usage() " 1:2. The modern BPF probe allows you to choose different mappings, for\n" " example, 1:1 would mean a syscall buffer for each CPU.\n" #endif -#ifdef HAS_CAPTURE -" --cri Path to CRI socket for container metadata\n" -" Use the specified socket to fetch data from a CRI-compatible runtime\n" -"\n" -" --cri-timeout \n" -" Wait at most milliseconds for response from CRI\n" -#endif " -d , --delay=\n" " Set the delay between updates, in milliseconds. This works\n" " similarly to the -d option in top.\n" @@ -149,28 +142,6 @@ static void usage() " better with terminals like putty. Try to use this flag if you experience\n" " terminal issues like the mouse not working.\n" " -h, --help Print this page\n" -#ifndef MINIMAL_BUILD -" -k , --k8s-api=\n" -" [DEPRECATED] Enable Kubernetes support by connecting to the API server\n" -" specified as argument. E.g. \"http://admin:password@127.0.0.1:8080\".\n" -" The API server can also be specified via the environment variable\n" -" SYSDIG_K8S_API.\n" -" --node-name=\n" -" [DEPRECATED] The node name is used as a filter when requesting metadata of pods\n" -" to the API server; if empty, no filter is set\n" -" -K | :[:], --k8s-api-cert= | :[:]\n" -" [DEPRECATED] Use the provided files names to authenticate user and (optionally) verify the K8S API\n" -" server identity.\n" -" Each entry must specify full (absolute, or relative to the current directory) path\n" -" to the respective file.\n" -" Private key password is optional (needed only if key is password protected).\n" -" CA certificate is optional. For all files, only PEM file format is supported. \n" -" Specifying CA certificate only is obsoleted - when single entry is provided \n" -" for this option, it will be interpreted as the name of a file containing bearer token.\n" -" Note that the format of this command-line option prohibits use of files whose names contain\n" -" ':' or '#' characters in the file name.\n" -" Option can also be provided via the environment variable SYSDIG_K8S_API_CERT.\n" -#endif // MINIMAL_BUILD " -l, --list List all the fields that can be used in views.\n" " --large-environment\n" " Support environments larger than 4KiB\n" @@ -197,14 +168,6 @@ static void usage() " Capture the first bytes of each I/O buffer.\n" " By default, the first 80 bytes are captured. Use this\n" " option with caution, it can generate huge trace files.\n" -" -T, --force-tracers-capture\n" -" [DEPRECATED] Tell the driver to make sure full buffers are captured from\n" -" /dev/null, to make sure that tracers are completely\n" -" captured. Note that sysdig will enable extended /dev/null\n" -" capture by itself after detecting that tracers are written\n" -" there, but that could result in the truncation of some\n" -" tracers at the beginning of the capture. This option allows\n" -" preventing that.\n" " -v , --view=\n" " Run the view with the given ID when csysdig starts.\n" " View IDs can be found in the view documentation pages in\n" @@ -389,26 +352,19 @@ sysdig_init_res csysdig_init(int argc, char **argv) int32_t json_last_row = 0; int32_t sorting_col = -1; bool list_views = false; -#ifdef HAS_CAPTURE - std::string cri_socket_path; -#endif #ifndef _WIN32 chisel_table::output_type output_type = chisel_table::OT_CURSES; #else chisel_table::output_type output_type = chisel_table::OT_JSON; #endif -#ifndef MINIMAL_BUILD - bool k8s = false; - bool mesos = false; -#endif // MINIMAL_BUILD - bool tracers = false; bool terminal_with_mouse = false; bool force_term_compat = false; sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL; plugin_utils plugins; bool list_plugins = false; sinsp_opener opener; + std::shared_ptr filter_list; static struct option long_options[] = { @@ -416,10 +372,6 @@ sysdig_init_res csysdig_init(int argc, char **argv) {"bpf", optional_argument, 0, 'B' }, #ifdef HAS_MODERN_BPF {"cpus-for-each-buffer", required_argument, 0, 0 }, -#endif -#ifdef HAS_CAPTURE - {"cri", required_argument, 0, 0 }, - {"cri-timeout", required_argument, 0, 0 }, #endif {"delay", required_argument, 0, 'd' }, {"exclude-users", no_argument, 0, 'E' }, @@ -430,9 +382,6 @@ sysdig_init_res csysdig_init(int argc, char **argv) {"large-environment", no_argument, 0, 0 }, {"list", optional_argument, 0, 'l' }, {"list-views", no_argument, 0, 0}, -#ifndef MINIMAL_BUILD - {"mesos-api", required_argument, 0, 'm'}, -#endif // MINIMAL_BUILD #ifdef HAS_MODERN_BPF {"modern-bpf", no_argument, 0, 0 }, #endif @@ -444,7 +393,6 @@ sysdig_init_res csysdig_init(int argc, char **argv) {"raw", no_argument, 0, 0 }, {"snaplen", required_argument, 0, 's' }, {"logfile", required_argument, 0, 0 }, - {"force-tracers-capture", required_argument, 0, 'T'}, {"force-term-compat", no_argument, 0, 0}, {"sortingcol", required_argument, 0, 0 }, {"to", required_argument, 0, 0 }, @@ -467,11 +415,14 @@ sysdig_init_res csysdig_init(int argc, char **argv) plugins.add_directory(SYSDIG_PLUGINS_DIR); plugins.read_plugins_from_dirs(inspector); + // Load container plugin (if available) + plugins.load_container_plugin_if_available(inspector); + // // Parse the args // while((op = getopt_long(argc, argv, - "AB::d:Ehk:K:jlm:n:p:Rr:s:Tv:X", long_options, &long_index)) != -1) + "AB::d:Ehk:K:jlm:n:p:Rr:s:v:X", long_options, &long_index)) != -1) { switch(op) { @@ -523,32 +474,12 @@ sysdig_init_res csysdig_init(int argc, char **argv) usage(); delete inspector; return sysdig_init_res(EXIT_SUCCESS); -#ifndef MINIMAL_BUILD - case 'k': - //TODO(therealbobo): remove this on 0.36.0 - k8s = true; - break; - case 'N': - //TODO(therealbobo): remove this on 0.36.0 - k8s = true; - break; - case 'K': - //TODO(therealbobo): remove this on 0.36.0 - k8s = true; - break; -#endif // MINIMAL_BUILD case 'j': output_type = chisel_table::OT_JSON; break; case 'l': list_flds = true; break; -#ifndef MINIMAL_BUILD - case 'm': - //TODO(therealbobo): remove this on 0.36.0 - mesos = true; - break; -#endif // MINIMAL_BUILD case 'n': try { @@ -569,7 +500,6 @@ sysdig_init_res csysdig_init(int argc, char **argv) case 'p': if(std::string(optarg) == "c" || std::string(optarg) == "container") { - inspector->set_print_container_data(true); print_containers = true; } @@ -583,10 +513,6 @@ sysdig_init_res csysdig_init(int argc, char **argv) case 's': snaplen = atoi(optarg); break; - case 'T': - //TODO(therealbobo): remove this on 0.36.0 - tracers = true; - break; case 'v': display_view = optarg; break; @@ -628,18 +554,6 @@ sysdig_init_res csysdig_init(int argc, char **argv) { opener.bpf.cpus_for_each_syscall_buffer = sinsp_numparser::parsed16(optarg); } -#endif -#ifdef HAS_CAPTURE -#ifndef MINIMAL_BUILD - else if(optname == "cri") - { - cri_socket_path = optarg; - } - else if(optname == "cri-timeout") - { - inspector->set_cri_timeout(sinsp_numparser::parsed64(optarg)); - } -#endif // MINIMAL_BUILD #endif else if(optname == "logfile") { @@ -699,13 +613,6 @@ sysdig_init_res csysdig_init(int argc, char **argv) return sysdig_init_res(EXIT_SUCCESS); } -#ifdef HAS_CAPTURE - if(!cri_socket_path.empty()) - { - inspector->set_cri_socket_path(cri_socket_path); - } -#endif - std::string filter; // @@ -734,6 +641,19 @@ sysdig_init_res csysdig_init(int argc, char **argv) } } + // TODO(therealbobo): add plugins filterchecks + filter_list = std::make_shared(); + plugins.init_loaded_plugins(inspector, filter_list.get()); + + for (auto plugin : inspector->m_plugin_manager->plugins()) + { + if (plugin->caps() & CAP_EXTRACTION) + { + // todo(therealbobo): manage field name conflicts + filter_list->add_filter_check(sinsp_plugin::new_filtercheck(plugin)); + } + } + if(!opener.bpf.enabled) { const char *probe = getenv("SYSDIG_BPF_PROBE"); @@ -895,6 +815,7 @@ sysdig_init_res csysdig_init(int argc, char **argv) // Initialize the UI // sinsp_cursesui ui(inspector, + filter_list, &opener, (filter.size() != 0)? filter : "", refresh_interval_ns, @@ -962,36 +883,6 @@ sysdig_init_res csysdig_init(int argc, char **argv) inspector->set_snaplen(snaplen); } -#ifndef MINIMAL_BUILD - // - // run k8s, if required - // - if (k8s || getenv("SYSDIG_K8S_API") != NULL || - getenv("SYSDIG_K8S_API_CERT") != NULL) - { - throw sinsp_exception(std::string("the k8s client is deprecated!")); - res.m_res = EXIT_FAILURE; - goto exit; - } - - // - // run mesos, if required - // - if(mesos || getenv("SYSDIG_MESOS_API") != NULL) - { - throw sinsp_exception(std::string("the mesos client is deprecated!")); - res.m_res = EXIT_FAILURE; - goto exit; - } -#endif // MINIMAL_BUILD - - if(tracers) - { - throw sinsp_exception(std::string("tracers are deprecated!")); - res.m_res = EXIT_FAILURE; - goto exit; - } - if(output_type == chisel_table::OT_JSON) { printf("{\"slices\": [\n"); diff --git a/userspace/sysdig/sysdig.cpp b/userspace/sysdig/sysdig.cpp index 3728bc7462..f414cb8c19 100644 --- a/userspace/sysdig/sysdig.cpp +++ b/userspace/sysdig/sysdig.cpp @@ -27,7 +27,6 @@ limitations under the License. #include #include #include -#include #include #include @@ -154,15 +153,6 @@ static void usage() " starting at 0 and continuing upward. The units of file_size\n" " are millions of bytes (10^6, not 2^20). Use the -W flag to\n" " determine how many files will be saved to disk.\n" -#ifdef HAS_CAPTURE -#ifndef MINIMAL_BUILD -" --cri Path to CRI socket for container metadata\n" -" Use the specified socket to fetch data from a CRI-compatible runtime\n" -"\n" -" --cri-timeout \n" -" Wait at most milliseconds for response from CRI\n" -#endif // MINIMAL_BUILD -#endif // HAS_CAPTURE " -d, --displayflt Make the given filter a display one\n" " Setting this option causes the events to be filtered\n" " after being parsed by the state system. Events are\n" @@ -247,28 +237,6 @@ static void usage() #endif " -j, --json Emit output as json, data buffer encoding will depend from the\n" " print format selected.\n" -#ifndef MINIMAL_BUILD -" -k , --k8s-api=\n" -" [DEPRECATED] Enable Kubernetes support by connecting to the API server\n" -" specified as argument. E.g. \"http://admin:password@127.0.0.1:8080\".\n" -" The API server can also be specified via the environment variable\n" -" SYSDIG_K8S_API.\n" -" --node-name=\n" -" [DEPRECATED] The node name is used as a filter when requesting metadata of pods\n" -" to the API server; if empty, no filter is set\n" -" -K | :[:], --k8s-api-cert= | :[:]\n" -" [DEPRECATED] Use the provided files names to authenticate user and (optionally) verify the K8S API\n" -" server identity.\n" -" Each entry must specify full (absolute, or relative to the current directory) path\n" -" to the respective file.\n" -" Private key password is optional (needed only if key is password protected).\n" -" CA certificate is optional. For all files, only PEM file format is supported. \n" -" Specifying CA certificate only is obsoleted - when single entry is provided \n" -" for this option, it will be interpreted as the name of a file containing bearer token.\n" -" Note that the format of this command-line option prohibits use of files whose names contain\n" -" ':' or '#' characters in the file name.\n" -" Option can also be provided via the environment variable SYSDIG_K8S_API_CERT.\n" -#endif // MINIMAL_BUILD " -L, --list-events List the events that the engine supports\n" " -l, --list List the fields that can be used for filtering and output\n" " formatting. Use -lv to get additional information for each\n" @@ -338,14 +306,6 @@ static void usage() " epoch, r for relative time from the beginning of the\n" " capture, d for delta between event enter and exit, and\n" " D for delta from the previous event.\n" -" -T, --force-tracers-capture\n" -" [DEPRECATED] Tell the driver to make sure full buffers are captured from\n" -" /dev/null, to make sure that tracers are completely\n" -" captured. Note that sysdig will enable extended /dev/null\n" -" capture by itself after detecting that tracers are written\n" -" there, but that could result in the truncation of some\n" -" tracers at the beginning of the capture. This option allows\n" -" preventing that.\n" " --unbuffered Turn off output buffering. This causes every single line\n" " emitted by sysdig to be flushed, which generates higher CPU\n" " usage but is useful when piping sysdig's output into another\n" @@ -1039,15 +999,7 @@ sysdig_init_res sysdig_init(int argc, char **argv) bool filter_proclist_flag = false; std::string cname; std::vector summary_table; -#ifndef MINIMAL_BUILD - bool k8s = false; - bool mesos = false; -#endif // MINIMAL_BUILD - bool tracers = false; std::set suppress_comms; -#ifdef HAS_CAPTURE - std::string cri_socket_path; -#endif plugin_utils plugins; bool list_plugins = false; std::string plugin_config_file = ""; @@ -1074,10 +1026,6 @@ sysdig_init_res sysdig_init(int argc, char **argv) #endif #ifdef HAS_MODERN_BPF {"cpus-for-each-buffer", required_argument, 0, 0 }, -#endif -#ifdef HAS_CAPTURE - {"cri", required_argument, 0, 0 }, - {"cri-timeout", required_argument, 0, 0 }, #endif {"displayflt", no_argument, 0, 'd' }, {"debug", no_argument, 0, 'D'}, @@ -1118,9 +1066,7 @@ sysdig_init_res sysdig_init(int argc, char **argv) {"snaplen", required_argument, 0, 's' }, {"summary", no_argument, 0, 'S' }, {"suppress-comm", required_argument, 0, 'U' }, - {"udig", required_argument, 0, 'u' }, {"timetype", required_argument, 0, 't' }, - {"force-tracers-capture", required_argument, 0, 'T'}, {"unbuffered", no_argument, 0, 0 }, {"verbose", no_argument, 0, 'v' }, {"version", no_argument, 0, 0 }, @@ -1147,17 +1093,17 @@ sysdig_init_res sysdig_init(int argc, char **argv) plugins.add_directory(SYSDIG_PLUGINS_DIR); plugins.read_plugins_from_dirs(inspector.get()); + // Load container plugin (if available) + plugins.load_container_plugin_if_available(inspector.get()); + // // Parse the args // - while((op = getopt_long(argc, argv, - "AbB::c:" - "C:" - "dDEe:F" - "g:G:" - "hH:I:i:jk:K:lLm:M:n:Pp:qRr:Ss:t:TU:uv" - "W:" - "w:xXz", long_options, &long_index)) != -1) + while ( + (op = getopt_long(argc, argv, + "AbB::c:C:dDEe:Fg:G:" + "hH:I:i:jlLm:M:n:Pp:qRr:Ss:t:U:vW:w:xXz", + long_options, &long_index)) != -1) { switch(op) { @@ -1200,8 +1146,20 @@ sysdig_init_res sysdig_init(int argc, char **argv) return sysdig_init_res(EXIT_SUCCESS); } + // TODO(therealbobo): add plugins filterchecks + auto filter_list = std::make_shared(); + + for (auto plugin : inspector->m_plugin_manager->plugins()) + { + if (plugin->caps() & CAP_EXTRACTION) + { + // todo(therealbobo): manage field name conflicts + filter_list->add_filter_check(sinsp_plugin::new_filtercheck(plugin)); + } + } + auto tmp_filter_factory = std::make_shared(inspector.get(), *filter_list.get()); sinsp_chisel* ch = new sinsp_chisel(inspector.get(), chisel); - parse_chisel_args(ch, filter_factory, optind, argc, argv, &n_filterargs); + parse_chisel_args(ch, tmp_filter_factory, optind, argc, argv, &n_filterargs); g_chisels.push_back(ch); } #endif @@ -1324,20 +1282,6 @@ sysdig_init_res sysdig_init(int argc, char **argv) // jflag = true; break; -#ifndef MINIMAL_BUILD - case 'k': - //TODO(therealbobo): remove this on 0.36.0 - k8s = true; - break; - case 'N': - //TODO(therealbobo): remove this on 0.36.0 - k8s = true; - break; - case 'K': - //TODO(therealbobo): remove this on 0.36.0 - k8s = true; - break; -#endif // MINIMAL_BUILD case 'h': usage(); return sysdig_init_res(EXIT_SUCCESS); @@ -1352,11 +1296,6 @@ sysdig_init_res sysdig_init(int argc, char **argv) // todo(jasondellaluce): support CLI for printing in markdown too print_supported_events(inspector.get(), false); return sysdig_init_res(EXIT_SUCCESS); -#ifndef MINIMAL_BUILD - case 'm': - mesos = true; - break; -#endif // MINIMAL_BUILD case 'M': duration_to_tot = atoi(optarg); if(duration_to_tot <= 0) @@ -1396,32 +1335,14 @@ sysdig_init_res sysdig_init(int argc, char **argv) else if(std::string(optarg) == "c" || std::string(optarg) == "container") { output_format = "*%evt.num %evt.outputtime %evt.cpu %container.name (%container.id) %proc.name (%thread.tid:%thread.vtid) %evt.dir %evt.type %evt.info"; - - // This enables chisels to determine if they should print container information - if(inspector != NULL) - { - inspector->set_print_container_data(true); - } } else if(std::string(optarg) == "k" || std::string(optarg) == "kubernetes") { output_format = "*%evt.num %evt.outputtime %evt.cpu %k8s.pod.name (%container.id) %proc.name (%thread.tid:%thread.vtid) %evt.dir %evt.type %evt.info"; - - // This enables chisels to determine if they should print container information - if(inspector != NULL) - { - inspector->set_print_container_data(true); - } } else if(std::string(optarg) == "m" || std::string(optarg) == "mesos") { output_format = "*%evt.num %evt.outputtime %evt.cpu %mesos.task.name (%container.id) %proc.name (%thread.tid:%thread.vtid) %evt.dir %evt.type %evt.info"; - - // This enables chisels to determine if they should print container information - if(inspector != NULL) - { - inspector->set_print_container_data(true); - } } else { @@ -1470,17 +1391,9 @@ sysdig_init_res sysdig_init(int argc, char **argv) } } break; - case 'T': - //TODO(therealbobo): remove this on 0.36.0 - tracers = true; - break; case 'U': suppress_comms.insert(std::string(optarg)); break; - case 'u': - //TODO(therealbobo): remove this on 0.36.0 - opener.udig.enabled = true; - break; case 'v': verbose = true; break; @@ -1576,14 +1489,6 @@ sysdig_init_res sysdig_init(int argc, char **argv) { opener.bpf.cpus_for_each_syscall_buffer = sinsp_numparser::parsed16(optarg); } -#endif -#ifdef HAS_CAPTURE - else if (optname == "cri") { - cri_socket_path = optarg; - } - else if (optname == "cri-timeout") { - inspector->set_cri_timeout(sinsp_numparser::parsed64(optarg)); - } #endif else if (optname == "unbuffered") { unbuf_flag = true; @@ -1715,7 +1620,7 @@ sysdig_init_res sysdig_init(int argc, char **argv) // all plugins have been loaded and configured so now we initialize them plugins.init_loaded_plugins(inspector.get(), filter_list.get()); - + if (list_plugins) { plugins.print_plugin_info_list(inspector.get()); @@ -1727,13 +1632,6 @@ sysdig_init_res sysdig_init(int argc, char **argv) return sysdig_init_res(EXIT_SUCCESS); } -#ifdef HAS_CAPTURE - if(!cri_socket_path.empty()) - { - inspector->set_cri_socket_path(cri_socket_path); - } -#endif - if (opener.plugin.enabled) { opener.plugin.name = plugins.input_plugin_name(); @@ -1799,6 +1697,22 @@ sysdig_init_res sysdig_init(int argc, char **argv) goto exit; } + for (auto &ch : g_chisels) + { + auto filter_list = std::make_shared(); + + for (auto plugin : inspector->m_plugin_manager->plugins()) + { + if (plugin->caps() & CAP_EXTRACTION) + { + // todo(therealbobo): manage field name conflicts + filter_list->add_filter_check(sinsp_plugin::new_filtercheck(plugin)); + } + } + auto tmp_filter_factory = std::make_shared(inspector.get(), *filter_list.get()); + ch->set_filter_list(filter_list); + } + std::string filter; // @@ -1984,42 +1898,6 @@ sysdig_init_res sysdig_init(int argc, char **argv) // chisels_on_capture_start(); -#ifndef MINIMAL_BUILD - // - // run k8s, if required - // - if (k8s || getenv("SYSDIG_K8S_API") != NULL || - getenv("SYSDIG_K8S_API_CERT") != NULL) - { - throw sinsp_exception(std::string("the k8s client is deprecated!")); - res.m_res = EXIT_FAILURE; - goto exit; - } - - // - // run mesos, if required - // - if(mesos || getenv("SYSDIG_MESOS_API") != NULL) - { - throw sinsp_exception(std::string("the mesos client is deprecated!")); - res.m_res = EXIT_FAILURE; - goto exit; - } -#endif - if(opener.udig.enabled) - { - throw sinsp_exception(std::string("the udig engine is deprecated!")); - res.m_res = EXIT_FAILURE; - goto exit; - } - - if(tracers) - { - throw sinsp_exception(std::string("tracers are deprecated!")); - res.m_res = EXIT_FAILURE; - goto exit; - } - #ifndef _WIN32 // Sysdig does not accept user input during the inspect loop // If the user stops the program with Ctrl-C disabling input would prevent the echoed ^C diff --git a/userspace/sysdig/utils/plugin_utils.cpp b/userspace/sysdig/utils/plugin_utils.cpp index 357c2d5390..1a43cf15f3 100644 --- a/userspace/sysdig/utils/plugin_utils.cpp +++ b/userspace/sysdig/utils/plugin_utils.cpp @@ -20,10 +20,10 @@ limitations under the License. #include "common.h" #include "plugin_utils.h" -#include - #include #include +#include +#include #include #include @@ -139,7 +139,7 @@ void plugin_utils::plugin_entry::init(sinsp *inspector, filter_check_list* flist } if (plugin->caps() & CAP_EXTRACTION) { - // todo(jasondellaluce): manage field name conflicts + // todo(therealbobo): manage field name conflicts flist->add_filter_check(sinsp_plugin::new_filtercheck(plugin)); } inited = true; @@ -646,3 +646,52 @@ std::vector> plugin_utils::get_filterchecks( } return list; } + +bool plugin_utils::load_container_plugin_if_available(sinsp *inspector) +{ + // Check if container plugin exists in any of the plugin directories + std::string soname = SHAREDOBJ_PREFIX "container" SHAREDOBJ_EXT; + bool plugin_exists = false; + + iterate_plugins_dirs(m_dirs, [&soname, &plugin_exists] (const std::filesystem::path file) -> bool { + auto filename = file.filename().generic_string(); + if (filename == soname) + { + plugin_exists = true; + return true; // break-out + } + return false; + }); + + if (!plugin_exists) + { + fprintf(stderr, "Warning: container plugin (%s) not found in plugin directories. Container metadata will not be available.\n", soname.c_str()); + fprintf(stderr, " This is expected if you're running sysdig standalone (not installed via package manager).\n"); + return false; + } + + try + { + // Load container configuration from file or use default + std::string container_config = R"({"hooks":["create","start"],"engines":{"docker":{"enabled":true,"sockets":["/var/run/docker.sock"]},"podman":{"enabled":true,"sockets":["/run/podman/podman.sock","/run/user/1000/podman/podman.sock"]},"containerd":{"enabled":false,"sockets":["/run/containerd/containerd.sock"]},"cri":{"enabled":true,"sockets":["/run/crio/crio.sock", "/run/containerd/containerd.sock"]},"lxc":{"enabled":false},"libvirt_lxc":{"enabled":false},"bpm":{"enabled":false}}})"; + auto container_config_file = "/etc/sysdig/container.json"; + if (std::filesystem::exists(container_config_file)) + { + std::ifstream file(container_config_file); + std::stringstream buffer; + buffer << file.rdbuf(); + container_config = buffer.str(); + } + + // Load and configure the plugin + load_plugin(inspector, "container"); + config_plugin(inspector, "container", container_config); + return true; + } + catch (const sinsp_exception& e) + { + fprintf(stderr, "Warning: failed to load container plugin: %s\n", e.what()); + fprintf(stderr, " Container metadata will not be available.\n"); + return false; + } +} diff --git a/userspace/sysdig/utils/plugin_utils.h b/userspace/sysdig/utils/plugin_utils.h index 27187b30fa..3cc94ae252 100644 --- a/userspace/sysdig/utils/plugin_utils.h +++ b/userspace/sysdig/utils/plugin_utils.h @@ -39,6 +39,9 @@ class plugin_utils void config_plugin(sinsp *inspector, const std::string& name, const std::string& conf); + // Load container plugin if available, with graceful fallback + bool load_container_plugin_if_available(sinsp *inspector); + void select_input_plugin(sinsp *inspector, filter_check_list* flist, const std::string& name, const std::string& params); void clear_input_plugin(); diff --git a/userspace/sysdig/utils/sinsp_opener.cpp b/userspace/sysdig/utils/sinsp_opener.cpp index 4f1440404d..8c54d20c67 100644 --- a/userspace/sysdig/utils/sinsp_opener.cpp +++ b/userspace/sysdig/utils/sinsp_opener.cpp @@ -103,7 +103,7 @@ void sinsp_opener::open(sinsp* inspector) const inspector->set_get_procs_cpu_from_driver(true); return; } - + // default to kernel module if no other option is specified try {