diff --git a/collector/collector.cpp b/collector/collector.cpp index 36d4dc1104..51318dd5a9 100644 --- a/collector/collector.cpp +++ b/collector/collector.cpp @@ -31,12 +31,10 @@ extern "C" { #include "CollectorStatsExporter.h" #include "Control.h" #include "Diagnostics.h" -#include "DriverCandidates.h" #include "EventNames.h" #include "FileSystem.h" #include "GRPC.h" #include "GRPCUtil.h" -#include "GetKernelObject.h" #include "GetStatus.h" #include "HostInfo.h" #include "LogLevel.h" diff --git a/collector/lib/CollectionMethod.cpp b/collector/lib/CollectionMethod.cpp index 7553ace008..211f99b75d 100644 --- a/collector/lib/CollectionMethod.cpp +++ b/collector/lib/CollectionMethod.cpp @@ -1,15 +1,26 @@ #include "CollectionMethod.h" +#include + +#include + +#include "Logging.h" + namespace collector { std::ostream& operator<<(std::ostream& os, CollectionMethod method) { + return os << CollectionMethodName(method); +} + +const char* CollectionMethodName(CollectionMethod method) { switch (method) { case CollectionMethod::EBPF: - return os << "ebpf"; + return "ebpf"; case CollectionMethod::CORE_BPF: - return os << "core_bpf"; + return "core_bpf"; default: - return os << "unknown(" << static_cast(method) << ")"; + CLOG(WARNING) << "Unexpected CollectionMethod: " << static_cast(method); + return "unknown"; } } diff --git a/collector/lib/CollectionMethod.h b/collector/lib/CollectionMethod.h index fa4b089cac..1a290a7dc9 100644 --- a/collector/lib/CollectionMethod.h +++ b/collector/lib/CollectionMethod.h @@ -7,11 +7,12 @@ namespace collector { enum class CollectionMethod : uint8_t { EBPF = 0, CORE_BPF, - }; std::ostream& operator<<(std::ostream& os, CollectionMethod method); +const char* CollectionMethodName(CollectionMethod method); + } // namespace collector #endif // COLLECTION_METHOD_H diff --git a/collector/lib/CollectorService.cpp b/collector/lib/CollectorService.cpp index 33ac96387e..4b41300d9d 100644 --- a/collector/lib/CollectorService.cpp +++ b/collector/lib/CollectorService.cpp @@ -1,5 +1,6 @@ #include "CollectorService.h" +#include "CollectionMethod.h" #include "ContainerInfoInspector.h" extern "C" { @@ -14,7 +15,6 @@ extern "C" { #include "Containers.h" #include "Diagnostics.h" #include "GRPCUtil.h" -#include "GetKernelObject.h" #include "GetStatus.h" #include "LogLevel.h" #include "NetworkStatusInspector.h" @@ -138,8 +138,8 @@ void CollectorService::RunForever() { system_inspector_.CleanUp(); } -bool CollectorService::InitKernel(const DriverCandidate& candidate) { - return system_inspector_.InitKernel(config_, candidate); +bool CollectorService::InitKernel() { + return system_inspector_.InitKernel(config_); } bool CollectorService::WaitForGRPCServer() { @@ -150,31 +150,13 @@ bool CollectorService::WaitForGRPCServer() { bool SetupKernelDriver(CollectorService& collector, const std::string& GRPCServer, const CollectorConfig& config) { auto& startup_diagnostics = StartupDiagnostics::GetInstance(); + std::string cm_name(CollectionMethodName(config.GetCollectionMethod())); - std::vector candidates = GetKernelCandidates(config.GetCollectionMethod()); - if (candidates.empty()) { - CLOG(ERROR) << "No kernel candidates available"; - return false; - } - - CLOG(INFO) << "Candidate drivers: "; - for (const auto& candidate : candidates) { - CLOG(INFO) << candidate.GetName(); - } + startup_diagnostics.DriverAvailable(cm_name); - for (const auto& candidate : candidates) { - if (!GetKernelObject(GRPCServer, config.TLSConfiguration(), candidate, config.CurlVerbose())) { - CLOG(WARNING) << "No suitable kernel object downloaded for " << candidate.GetName(); - startup_diagnostics.DriverUnavailable(candidate.GetName()); - continue; - } - - startup_diagnostics.DriverAvailable(candidate.GetName()); - - if (collector.InitKernel(candidate)) { - startup_diagnostics.DriverSuccess(candidate.GetName()); - return true; - } + if (collector.InitKernel()) { + startup_diagnostics.DriverSuccess(cm_name); + return true; } CLOG(ERROR) << "Failed to initialize collector kernel components."; diff --git a/collector/lib/CollectorService.h b/collector/lib/CollectorService.h index 4f909b56ef..f52c644934 100644 --- a/collector/lib/CollectorService.h +++ b/collector/lib/CollectorService.h @@ -3,7 +3,6 @@ #include "CollectorConfig.h" #include "Control.h" -#include "DriverCandidates.h" #include "system-inspector/Service.h" namespace collector { @@ -14,7 +13,7 @@ class CollectorService { void RunForever(); - bool InitKernel(const DriverCandidate& candidate); + bool InitKernel(); private: bool WaitForGRPCServer(); diff --git a/collector/lib/DriverCandidates.cpp b/collector/lib/DriverCandidates.cpp deleted file mode 100644 index d91887d9f3..0000000000 --- a/collector/lib/DriverCandidates.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "DriverCandidates.h" - -#include -#include -#include - -#include "HostInfo.h" -#include "Utility.h" -#include "system-inspector/Service.h" - -namespace collector { - -namespace { - -std::string driverFullName(const std::string& shortName) { - return std::string{system_inspector::Service::kProbeName} + "-" + shortName + ".o"; -} - -// Retrieves the ubuntu backport version from the host kernel's release -// string. If an appropriate backport version is not found, this function -// returns an empty std::optional. -std::optional getUbuntuBackport(HostInfo& host) { - static const char* candidates[] = { - "~16.04", - "~20.04", - }; - - auto kernel = host.GetKernelVersion(); - for (auto candidate : candidates) { - if (kernel.version.find(candidate) != std::string::npos) { - std::string backport = kernel.release + candidate; - std::string name = driverFullName(backport); - return DriverCandidate(std::move(name), CollectionMethod::EBPF); - } - } - - return {}; -} - -// Garden linux uses a special kernel version in order to avoid -// overlapping with Debian. This function returns the appropriate -// name for this candidate while keeping the possibility to use -// the Debian driver if it doesn't exist. -std::optional getGardenLinuxCandidate(HostInfo& host) { - auto kernel = host.GetKernelVersion(); - - std::regex garden_linux_kernel_re(R"(\d+\.\d+\.\d+-\w+)"); - std::smatch match; - - if (!std::regex_search(kernel.version, match, garden_linux_kernel_re)) { - CLOG(WARNING) << "Failed to match the Garden Linux kernel version."; - return {}; - } - - // The Garden Linux specific candidate is of the form - // 5.10.0-9-cloud-amd64-gl-5.10.83-1gardenlinux1 - std::string shortName = kernel.release + "-gl-" + match.str(); - std::string name = driverFullName(shortName); - - return DriverCandidate(name, CollectionMethod::EBPF); -} - -// The kvm driver for minikube uses a custom kernel built from -// mostly vanilla kernel headers and its own configuration defined -// in their repo. However, when using the docker driver, minikube -// runs directly on the host, so we add the kvm kernel as a candidate -// in order to give the chance for collector to use the host driver. -std::optional getMinikubeCandidate(HostInfo& host) { - auto minikube_version = host.GetMinikubeVersion(); - - if (minikube_version.empty()) { - return {}; - } - - auto kernel = host.GetKernelVersion(); - - std::string shortName = kernel.ShortRelease() + "-minikube-" + minikube_version; - std::string name = driverFullName(shortName); - return DriverCandidate(name, CollectionMethod::EBPF); -} - -// Normalizes this host's release string into something collector can use -// to download appropriate kernel objects from the webserver. If the release -// string does not require normalization, it is simply returned. -std::string normalizeReleaseString(HostInfo& host) { - auto kernel = host.GetKernelVersion(); - if (host.IsCOS()) { - std::string release = kernel.release; - // remove the + from the end of the kernel version - if (release[release.size() - 1] == '+') { - release.erase(release.size() - 1); - } - return release + "-" + host.GetBuildID() + "-" + host.GetOSID(); - } - - if (host.IsDockerDesktop()) { - auto smp = kernel.version.find("SMP "); - if (smp == std::string::npos) { - CLOG(FATAL) << "Unable to parse docker desktop kernel version: " - << "'" << kernel.version << "'"; - } - - std::string time_string = kernel.version.substr(smp + 4); - std::tm tm{}; - // Currently assuming that all docker desktop kernels have UTC timestamps - // to simplify parsing for this edge case. std::get_time does not support parsing - // timezone information (%Z) - if (strptime(kernel.version.substr(smp + 4).c_str(), "%a %b %d %H:%M:%S UTC %Y", &tm) == nullptr) { - CLOG(FATAL) << "Failed to parse DockerDesktop kernel timestamp: '" << time_string << "'"; - } - std::stringstream timestamp; - timestamp << std::put_time(&tm, "%Y-%m-%d-%H-%M-%S"); - return kernel.ShortRelease() + "-dockerdesktop-" + timestamp.str(); - } - - return kernel.release; -} - -DriverCandidate getCoreBpfCandidate() { - return DriverCandidate("CO.RE eBPF probe", CollectionMethod::CORE_BPF, false); -} - -DriverCandidate getHostCandidate(HostInfo& host) { - std::string hostCandidate = normalizeReleaseString(host); - std::string hostCandidateFullName = driverFullName(hostCandidate); - - return DriverCandidate(hostCandidateFullName, CollectionMethod::EBPF); -} - -DriverCandidate getUserDriverCandidate(const char* full_name) { - std::filesystem::path driver_file(full_name); - - if (driver_file.is_absolute()) { - return DriverCandidate(driver_file.filename(), CollectionMethod::EBPF, false, driver_file.parent_path()); - } - - return DriverCandidate(driver_file, CollectionMethod::EBPF, false); -} -} // namespace - -std::vector GetKernelCandidates(CollectionMethod cm) { - std::vector candidates; - - const char* kernel_candidates = std::getenv("KERNEL_CANDIDATES"); - if (kernel_candidates && *kernel_candidates) { - std::string_view sview(kernel_candidates); - - for (const auto& candidate_name : SplitStringView(sview)) { - std::string name = driverFullName(candidate_name); - candidates.emplace_back(std::move(name), CollectionMethod::EBPF); - } - - return candidates; - } - - const char* user_driver = std::getenv("COLLECTOR_DRIVER"); - if (user_driver && *user_driver) { - candidates.push_back(getUserDriverCandidate(user_driver)); - } - - if (cm == CollectionMethod::CORE_BPF) { - candidates.push_back(getCoreBpfCandidate()); - } - - HostInfo& host = HostInfo::Instance(); - - if (host.IsUbuntu()) { - auto backport = getUbuntuBackport(host); - if (backport) { - candidates.push_back(std::move(*backport)); - } - } - - if (host.IsGarden()) { - auto garden_candidate = getGardenLinuxCandidate(host); - - if (garden_candidate) { - candidates.push_back(std::move(*garden_candidate)); - } - } - - candidates.push_back(getHostCandidate(host)); - - if (host.IsMinikube()) { - auto minikube_candidate = getMinikubeCandidate(host); - - if (minikube_candidate) { - candidates.push_back(std::move(*minikube_candidate)); - } - } - - return candidates; -} - -} // namespace collector diff --git a/collector/lib/DriverCandidates.h b/collector/lib/DriverCandidates.h deleted file mode 100644 index ded3a2e4ac..0000000000 --- a/collector/lib/DriverCandidates.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _DRIVER_CANDIDATES_H_ -#define _DRIVER_CANDIDATES_H_ - -#include -#include - -#include "CollectionMethod.h" - -namespace collector { - -class DriverCandidate { - public: - DriverCandidate(const std::string& name, CollectionMethod cm, bool downloadable = true, const std::string& path = "/kernel-modules") : name_(name), path_(path), downloadable_(downloadable), collection_method_(cm) { - } - - inline const std::string& GetPath() const { return path_; } - - inline const std::string& GetName() const { return name_; } - - inline bool IsDownloadable() const { return downloadable_; } - - inline CollectionMethod GetCollectionMethod() const { return collection_method_; } - - private: - std::string name_; - std::string path_; - bool downloadable_; - CollectionMethod collection_method_; -}; - -// Get kernel candidates -std::vector GetKernelCandidates(CollectionMethod cm); - -} // namespace collector -#endif // _DRIVER_CANDIDATES_H_ diff --git a/collector/lib/FileDownloader.cpp b/collector/lib/FileDownloader.cpp deleted file mode 100644 index f2233e5f4b..0000000000 --- a/collector/lib/FileDownloader.cpp +++ /dev/null @@ -1,404 +0,0 @@ - -#include "FileDownloader.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "Logging.h" -#include "Utility.h" - -namespace collector { - -namespace { - -size_t HeaderCallback(char* buffer, size_t size, size_t nitems, void* dd) { - auto download_data = static_cast(dd); - size_t buffer_size = size * nitems; - std::string_view data(buffer, buffer_size); - - if (data.substr(0, 5) == "HTTP/") { - size_t error_code_offset = data.find(' '); - - if (error_code_offset == std::string_view::npos) { - download_data->http_status = 500; - download_data->error_msg = Str("Failed extracting HTTP status code (", data.substr(0, 1024), ")"); - return 0; // Force the download to fail explicitly - } - - download_data->http_status = std::stoul(std::string(data.substr(error_code_offset + 1, data.find(' ', error_code_offset + 1)))); - // CLOG(DEBUG) << "Set HTTP status code to '" << download_data->http_status << "'"; - } - - return buffer_size; -} - -size_t WriteFile(void* content, size_t size, size_t nitems, void* dd) { - auto download_data = static_cast(dd); - size_t content_size = size * nitems; - const char* content_bytes = static_cast(content); - - if (download_data->http_status >= 400) { - download_data->error_msg = Str("HTTP Body Response: ", std::string_view(content_bytes, std::min(content_size, 1024UL))); - return 0; // Force the download to fail explicitly - } - - download_data->os->write(content_bytes, content_size); - return content_size; -} - -int DebugCallback(CURL*, curl_infotype type, char* data, size_t size, void*) { - std::string msg(data, size); - msg = rtrim(msg); - - if (type == CURLINFO_TEXT) { - CLOG(DEBUG) << "== Info: " << msg; - return CURLE_OK; - } - - if (!logging::CheckLogLevel(logging::LogLevel::TRACE)) { - // Skip other types of messages if we are not tracing - return CURLE_OK; - } - - std::transform(msg.begin(), msg.end(), msg.begin(), [](char c) -> char { - if (c < 0x20) return '.'; - return (char)c; - }); - - const char* hdr = nullptr; - - if (type == CURLINFO_HEADER_OUT) { - hdr = "-> Send header - "; - } else if (type == CURLINFO_DATA_OUT) { - hdr = "-> Send data - "; - } else if (type == CURLINFO_SSL_DATA_OUT) { - hdr = "-> Send SSL data - "; - } else if (type == CURLINFO_HEADER_IN) { - hdr = "<- Recv header - "; - } else if (type == CURLINFO_DATA_IN) { - hdr = "<- Recv data - "; - } else if (type == CURLINFO_SSL_DATA_IN) { - hdr = "<- Recv SSL data - "; - } - - if (hdr) { - CLOG(DEBUG) << hdr << msg; - } - - return CURLE_OK; -} - -} // namespace - -ConnectTo::ConnectTo(std::string_view host, std::string_view connect_to) : connect_to_(nullptr, curl_slist_free_all) { - auto marker = connect_to.find(':'); - if (marker == std::string_view::npos) { - connect_to_host_ = connect_to; - connect_to_port_ = ""; - } else { - connect_to_host_ = connect_to.substr(0, marker); - connect_to_port_ = connect_to.substr(marker + 1); - } - - marker = host.find(':'); - if (marker == std::string_view::npos) { - host_ = host; - port_ = connect_to_port_; - } else { - host_ = host.substr(0, marker); - port_ = host.substr(marker + 1); - } - - std::string entry{host_ + ":" + port_ + ":" + connect_to_host_ + ":" + connect_to_port_}; - - connect_to_.reset(curl_slist_append(nullptr, entry.c_str())); - if (connect_to_ == nullptr) { - CLOG(WARNING) << "Failed to create connect_to list"; - return; - } -} - -FileDownloader::FileDownloader() : curl_(curl_easy_init()), connect_to_(std::nullopt) { - if (curl_ != nullptr) { - SetDefaultOptions(); - } - - error_.fill('\0'); - retry_ = {.times = 0, .delay = 0, .max_time = std::chrono::seconds(0)}; -} - -FileDownloader::~FileDownloader() { - if (curl_) { - curl_easy_cleanup(curl_); - } - - curl_global_cleanup(); -} - -bool FileDownloader::SetURL(const std::string& url) { - file_path_ = url.substr(url.find_last_of('/') + 1); - - if (!url_.SetURL(url)) { - CLOG(WARNING) << "Unable to set URL '" << url << "'"; - return false; - } - - auto result = curl_easy_setopt(curl_, CURLOPT_URL, url_.GetURL().c_str()); - - if (result != CURLE_OK) { - CLOG(WARNING) << "Unable to set URL '" << url << "' - " << curl_easy_strerror(result); - return false; - } - - return true; -} - -void FileDownloader::IPResolve(FileDownloader::resolve_t version) { - curl_easy_setopt(curl_, CURLOPT_IPRESOLVE, version); -} - -void FileDownloader::SetRetries(unsigned int times, unsigned int delay, unsigned int max_time) { - retry_.times = times; - retry_.delay = delay; - retry_.max_time = std::chrono::seconds(max_time); -} - -bool FileDownloader::SetConnectionTimeout(int timeout) { - auto result = curl_easy_setopt(curl_, CURLOPT_CONNECTTIMEOUT, timeout); - - if (result != CURLE_OK) { - CLOG(WARNING) << "Unable to set connection timeout - " << curl_easy_strerror(result); - return false; - } - - return true; -} - -bool FileDownloader::FollowRedirects(bool follow) { - auto result = curl_easy_setopt(curl_, CURLOPT_FOLLOWLOCATION, follow ? 1L : 0L); - - if (result != CURLE_OK) { - CLOG(WARNING) << "Unable to set value for redirections - " << curl_easy_strerror(result); - return false; - } - return true; -} - -void FileDownloader::OutputFile(const std::string& path) { - output_path_ = path; -} - -void FileDownloader::OutputFile(const char* const path) { - OutputFile(std::string(path)); -} - -bool FileDownloader::CACert(const char* const path) { - if (path == nullptr) { - CLOG(WARNING) << "CA certificate bundle path unset"; - return false; - } - - auto result = curl_easy_setopt(curl_, CURLOPT_CAINFO, path); - - if (result != CURLE_OK) { - CLOG(WARNING) << "Unable to set path to CA certificate bundle - " << curl_easy_strerror(result); - return false; - } - return true; -} - -bool FileDownloader::Cert(const char* const path) { - if (path == nullptr) { - CLOG(WARNING) << "SSL client certificate path unset"; - return false; - } - - auto result = curl_easy_setopt(curl_, CURLOPT_SSLCERT, path); - - if (result != CURLE_OK) { - CLOG(WARNING) << "Unable to set SSL client certificate - " << curl_easy_strerror(result); - return false; - } - return true; -} - -bool FileDownloader::Key(const char* const path) { - if (path == nullptr) { - CLOG(WARNING) << "SSL client key file path unset"; - return false; - } - - auto result = curl_easy_setopt(curl_, CURLOPT_SSLKEY, path); - - if (result != CURLE_OK) { - CLOG(WARNING) << "Unable to set key file - " << curl_easy_strerror(result); - return false; - } - return true; -} - -bool FileDownloader::SetConnectTo(const std::string& host, const std::string& target) { - if (!host.empty() && !target.empty() && host != target) { - connect_to_ = ConnectTo(host, target); - } - return true; -} - -void FileDownloader::SetVerboseMode(bool verbose) { - if (logging::CheckLogLevel(logging::LogLevel::DEBUG) && verbose) { - curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(curl_, CURLOPT_DEBUGFUNCTION, DebugCallback); - } else { - curl_easy_setopt(curl_, CURLOPT_VERBOSE, 0L); - } -} - -std::string FileDownloader::GetEffectiveURL() { - // For the time being, we can only have a single connect_to_ object, - // if it's not set, the download will go to the set URL. - if (!connect_to_) { - return GetURL(); - } - - if (connect_to_->GetPort() != GetPort() || connect_to_->GetHost() != GetHost()) { - return GetURL(); - } - - return GetScheme() + "://" + connect_to_->GetConnectToHost() + ":" + connect_to_->GetConnectToPort() + GetPath(); -} - -void FileDownloader::ResetCURL() { - curl_easy_reset(curl_); - - url_.reset(); - - SetDefaultOptions(); - - connect_to_ = std::nullopt; -} - -bool FileDownloader::IsReady() { - return curl_ != nullptr; -} - -bool FileDownloader::Download() { - if (curl_ == nullptr) { - CLOG(WARNING) << "Attempted to download a file using an uninitialized object"; - return false; - } - - if (output_path_.empty()) { - CLOG(WARNING) << "Attempted to download a file without an output set"; - return false; - } - - if (connect_to_) { - auto result = curl_easy_setopt(curl_, CURLOPT_CONNECT_TO, connect_to_->GetList()); - - if (result != CURLE_OK) { - CLOG(WARNING) << "Unable to set connection host, the download is likely to fail - " << curl_easy_strerror(result); - } - } - - auto start_time = std::chrono::steady_clock::now(); - int failures = 0; - bool encountered_404 = false; - - for (auto max_attempts = retry_.times; max_attempts; max_attempts--) { - std::ofstream of(output_path_, std::ios::trunc | std::ios::binary); - DownloadData download_data = {.http_status = 0, .error_msg = "", .os = &of}; - - if (!of.is_open()) { - CLOG(WARNING) << "Failed to open " << output_path_; - return false; - } - - curl_easy_setopt(curl_, CURLOPT_HEADERDATA, static_cast(&download_data)); - curl_easy_setopt(curl_, CURLOPT_WRITEDATA, static_cast(&download_data)); - - error_.fill('\0'); - auto result = curl_easy_perform(curl_); - - if (result == CURLE_OK) { - return true; - } - - failures++; - - if (download_data.http_status == 404) { - CLOG_IF(!encountered_404, INFO) << "HTTP Request failed with error code 404"; - encountered_404 = true; - } else if (download_data.http_status >= 400) { - CLOG_THROTTLED(WARNING, std::chrono::seconds(10)) - << "Unexpected HTTP request failure (HTTP " << download_data.http_status << ")"; - } - - if (max_attempts == 1) break; - - sleep(retry_.delay); - - auto time_elapsed = std::chrono::duration_cast(std::chrono::steady_clock::now() - start_time); - if (time_elapsed > retry_.max_time) { - CLOG(WARNING) << "Timeout while retrying to download " << file_path_; - return false; - } - } - - CLOG(WARNING) << "Attempted to download " << file_path_ << " " << failures << " time(s)"; - CLOG(WARNING) << "Failed to download from " << file_path_; - - return false; -} - -void FileDownloader::SetDefaultOptions() { - curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, WriteFile); - curl_easy_setopt(curl_, CURLOPT_HEADERFUNCTION, HeaderCallback); - curl_easy_setopt(curl_, CURLOPT_ERRORBUFFER, error_.data()); -} - -bool FileDownloader::URL::SetURL(const std::string& _url) { - std::string_view url{_url}; - auto marker = url.find(':'); - if (marker == std::string_view::npos) { - CLOG(WARNING) << "Invalid URL: " << url; - return false; - } - - auto scheme = url.substr(0, marker); - url.remove_prefix(marker + 1); - if (url.length() < 3 || url[0] != '/' || url[1] != '/') { - CLOG(WARNING) << "Invalid URL: " << url; - return false; - } - - // at this point we have a valid URL (though not strictly conforming to the standard). - scheme_ = scheme; - - url.remove_prefix(2); - marker = url.find('/'); - - if (marker != std::string_view::npos) { - path_ = url.substr(marker); - url.remove_suffix(url.length() - marker); - } else { - path_.clear(); - } - - marker = url.find(':'); - if (marker != std::string_view::npos) { - port_ = url.substr(marker + 1); - url.remove_suffix(url.length() - marker); - } else { - port_.clear(); - } - - hostname_ = url; - return true; -} - -} // namespace collector diff --git a/collector/lib/FileDownloader.h b/collector/lib/FileDownloader.h deleted file mode 100644 index d61ed66d1c..0000000000 --- a/collector/lib/FileDownloader.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef COLLECTOR_FILEDOWNLOADER_H -#define COLLECTOR_FILEDOWNLOADER_H - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace collector { - -struct DownloadData { - unsigned int http_status; - std::string error_msg; - std::ostream* os; -}; - -class ConnectTo { - public: - ConnectTo() : connect_to_(nullptr, curl_slist_free_all) {} - ConnectTo(std::string_view host, std::string_view connect_to); - ConnectTo(ConnectTo&) = delete; - ConnectTo(ConnectTo&&) = default; - ~ConnectTo() = default; - - const curl_slist* GetList() { return connect_to_.get(); }; - - const std::string& GetHost() { return host_; }; - const std::string& GetPort() { return port_; }; - const std::string& GetConnectToHost() { return connect_to_host_; }; - const std::string& GetConnectToPort() { return connect_to_port_; }; - - ConnectTo& operator=(const ConnectTo& other) = delete; - ConnectTo& operator=(ConnectTo&& other) = default; - - private: - std::unique_ptr connect_to_; - std::string host_; - std::string port_; - std::string connect_to_host_; - std::string connect_to_port_; -}; - -/** - * Wrapper aroung libcurl for downloading files. - * See https://curl.se/libcurl/c/libcurl-easy.html for details about specific - * methods - */ -class FileDownloader { - public: - enum resolve_t { - ANY = CURL_IPRESOLVE_WHATEVER, - IPv4 = CURL_IPRESOLVE_V4, - IPv6 = CURL_IPRESOLVE_V6, - }; - - FileDownloader(); - ~FileDownloader(); - - bool SetURL(const std::string& url); - void IPResolve(resolve_t version); - void SetRetries(unsigned int times, unsigned int delay, unsigned int max_time); - bool SetConnectionTimeout(int timeout); - bool FollowRedirects(bool follow); - void OutputFile(const char* const path); - void OutputFile(const std::string& path); - bool CACert(const char* const path); - bool Cert(const char* const path); - bool Key(const char* const path); - bool SetConnectTo(const std::string& host, const std::string& target); - void SetVerboseMode(bool verbose); - - std::string GetURL() { return url_.GetURL(); } - const std::string& GetHost() { return url_.GetHost(); } - const std::string& GetPort() { return url_.GetPort(); } - const std::string& GetScheme() { return url_.GetScheme(); } - const std::string& GetPath() { return url_.GetPath(); } - std::string GetEffectiveURL(); - - void ResetCURL(); - bool IsReady(); - bool Download(); - - private: - CURL* curl_; - std::optional connect_to_; - std::string output_path_; - std::string file_path_; - std::array error_; - struct { - unsigned int times; - unsigned int delay; - std::chrono::seconds max_time; - } retry_; - - class URL { - public: - bool SetURL(const std::string& url); - - std::string GetURL() { - auto url = scheme_ + "://" + hostname_; - if (!port_.empty()) { - url += ":" + port_; - } - return url + path_; - } - const std::string& GetScheme() { return scheme_; }; - const std::string& GetHost() { return hostname_; }; - const std::string& GetPort() { return port_; }; - const std::string& GetPath() { return path_; }; - - void reset() { - scheme_.clear(); - hostname_.clear(); - port_.clear(); - path_.clear(); - } - - private: - std::string scheme_; - std::string hostname_; - std::string port_; - std::string path_; - } url_; - - void SetDefaultOptions(); - std::string GetURLPart(CURLUPart part); -}; - -} // namespace collector - -#endif // COLLECTOR_FILEDOWNLOADER_H diff --git a/collector/lib/GetKernelObject.cpp b/collector/lib/GetKernelObject.cpp deleted file mode 100644 index d3bd89b7da..0000000000 --- a/collector/lib/GetKernelObject.cpp +++ /dev/null @@ -1,246 +0,0 @@ -#include "GetKernelObject.h" - -#include -#include - -extern "C" { -#include -#include -} - -#include - -#include "CollectionMethod.h" -#include "FileDownloader.h" -#include "FileSystem.h" -#include "Logging.h" -#include "Utility.h" -#include "system-inspector/Service.h" - -namespace collector { - -const int kMaxDownloadRetriesTime = 180; -const int kMaxDownloadRetriesInterval = 5; -const int kNumDownloadRetries = kMaxDownloadRetriesTime / kMaxDownloadRetriesInterval; - -bool DownloadKernelObjectFromURL(FileDownloader& downloader, const std::string& base_url, const std::string& kernel_module, const std::string& module_version) { - std::string url(base_url + "/" + module_version + "/" + kernel_module + ".gz"); - -#ifdef COLLECTOR_APPEND_CID - // This extra parameter will be dropped by sensor. - // Its only purpose is to filter alerts coming from our CI. - url += "?cid=collector"; -#endif - - if (!downloader.SetURL(url)) { - return false; - } - - CLOG(INFO) << "Attempting to download kernel object from " << downloader.GetEffectiveURL(); - - if (!downloader.Download()) { - return false; - } - - CLOG(DEBUG) << "Downloaded kernel object from " << url; - - return true; -} - -bool DownloadKernelObjectFromHostname(FileDownloader& downloader, const Json::Value& tls_config, const std::string& hostname, const std::string& kernel_module, const std::string& module_version) { - size_t port_offset = hostname.find(':'); - if (port_offset == std::string::npos) { - CLOG(WARNING) << "Provided hostname must have a valid port"; - return false; - } - - const std::string SNI_hostname(GetSNIHostname()); - if (SNI_hostname.find(':') != std::string::npos) { - CLOG(WARNING) << "SNI hostname must NOT specify a port"; - return false; - } - - if (tls_config.isNull()) { - CLOG(WARNING) << "No TLS configuration provided"; - return false; - } - - if (!downloader.CACert(tls_config["caCertPath"].asCString())) return false; - if (!downloader.Cert(tls_config["clientCertPath"].asCString())) return false; - if (!downloader.Key(tls_config["clientKeyPath"].asCString())) return false; - - std::string server_hostname; - if (hostname.compare(0, port_offset, SNI_hostname) != 0) { - downloader.SetConnectTo(SNI_hostname, hostname); - - const std::string server_port(hostname.substr(port_offset + 1)); - server_hostname = SNI_hostname + ":" + server_port; - } else { - server_hostname = hostname; - } - - // Attempt to download the kernel object from a given hostname server - std::string base_url("https://" + server_hostname + "/kernel-objects"); - if (base_url.empty()) return false; - - return DownloadKernelObjectFromURL(downloader, base_url, kernel_module, module_version); -} - -bool DownloadKernelObject(const std::string& hostname, const Json::Value& tls_config, const std::string& kernel_module, const std::string& compressed_module_path, bool verbose) { - FileDownloader downloader; - if (!downloader.IsReady()) { - CLOG(WARNING) << "Failed to initialize FileDownloader object"; - return false; - } - - std::string module_version(GetModuleVersion()); - if (module_version.empty()) { - CLOG(WARNING) << "/kernel-modules/MODULE_VERSION.txt must exist and not be empty"; - return false; - } - - downloader.IPResolve(FileDownloader::ANY); - downloader.SetRetries(kNumDownloadRetries, kMaxDownloadRetriesInterval, kMaxDownloadRetriesTime); - downloader.SetVerboseMode(verbose); - downloader.OutputFile(compressed_module_path); - if (!downloader.SetConnectionTimeout(2)) return false; - if (!downloader.FollowRedirects(true)) return false; - - if (DownloadKernelObjectFromHostname(downloader, tls_config, hostname, kernel_module, module_version)) { - return true; - } - - std::string base_url(GetModuleDownloadBaseURL()); - if (base_url.empty()) { - return false; - } - - downloader.ResetCURL(); - downloader.IPResolve(FileDownloader::ANY); - downloader.SetRetries(kNumDownloadRetries, kMaxDownloadRetriesInterval, kMaxDownloadRetriesTime); - downloader.SetVerboseMode(verbose); - downloader.OutputFile(compressed_module_path); - if (!downloader.SetConnectionTimeout(2)) return false; - if (!downloader.FollowRedirects(true)) return false; - - if (DownloadKernelObjectFromURL(downloader, base_url, kernel_module, module_version)) { - return true; - } - return false; -} - -std::string Sha256HashStream(std::istream& stream) { - unsigned char hash[SHA256_DIGEST_LENGTH]; - char buffer[4096]; - SHA256_CTX sha256; - char output[65]; - - SHA256_Init(&sha256); - while (stream) { - stream.read(buffer, 4096); - - // The stream must have either read correctly or reached EOF - if (stream.good() || stream.eof()) { - SHA256_Update(&sha256, buffer, stream.gcount()); - } else { - CLOG(WARNING) << "Failed to read stream during hash operation"; - return ""; - } - } - - SHA256_Final(hash, &sha256); - - for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) { - sprintf(output + (i * 2), "%02x", hash[i]); - } - - return std::string{output, 64}; -} - -std::string Sha256HashFile(const std::filesystem::path driver) { - std::ifstream file{driver.string(), std::ios::binary}; - - if (!file.is_open()) { - CLOG(WARNING) << "Failed to open " << driver; - return ""; - } - - return Sha256HashStream(file); -} - -bool GetKernelObject(const std::string& hostname, const Json::Value& tls_config, const DriverCandidate& candidate, bool verbose) { - if (candidate.GetCollectionMethod() == CollectionMethod::CORE_BPF) { - // for now CO.RE bpf probes are embedded in the collector binary, nothing - // to do here. - return true; - } - - std::string expected_path = candidate.GetPath() + "/" + candidate.GetName(); - std::string expected_path_compressed = expected_path + ".gz"; - std::string module_path = candidate.GetCollectionMethod() == CollectionMethod::EBPF ? system_inspector::Service::kProbePath : system_inspector::Service::kModulePath; - struct stat sb; - - // first check for an existing compressed kernel object in the - // kernel-modules directory. - CLOG(DEBUG) << "Checking for existence of " << expected_path_compressed - << " and " << expected_path; - if (stat(expected_path_compressed.c_str(), &sb) == 0) { - CLOG(INFO) << "Found existing compressed kernel object with sha256 hash: " << Sha256HashFile(expected_path_compressed) << "."; - if (!GZFileHandle::DecompressFile(expected_path_compressed, module_path)) { - CLOG(WARNING) << "Failed to decompress " << expected_path_compressed; - // don't delete the local /kernel-modules gzip file because it is on a read-only file system. - return false; - } - } - // then check if we have a decompressed object in the kernel-modules - // directory. If it exists, copy it to modules directory. - else if (stat(expected_path.c_str(), &sb) == 0) { - CLOG(DEBUG) << "Found existing kernel object " << expected_path; - std::ifstream input_file(expected_path, std::ios::binary); - if (!input_file.is_open()) { - CLOG(WARNING) << "Failed to open " << expected_path << " - " << StrError(); - return false; - } - - std::ofstream output_file(module_path, std::ios::binary); - if (!output_file.is_open()) { - CLOG(WARNING) << "Failed to open " << module_path << " - " << StrError(); - return false; - } - - std::copy(std::istreambuf_iterator(input_file), - std::istreambuf_iterator(), - std::ostreambuf_iterator(output_file)); - } - // Otherwise there is no module in local storage, so we should download it. - else if (candidate.IsDownloadable()) { - CLOG(INFO) << "Attempting to download " << candidate.GetName(); - std::string downloadPath = module_path + ".gz"; - if (!DownloadKernelObject(hostname, tls_config, candidate.GetName(), downloadPath, verbose)) { - CLOG(WARNING) << "Unable to download kernel object " << candidate.GetName() << " to " << downloadPath; - return false; - } - - CLOG(INFO) << "Downloaded driver with sha256 hash: " << Sha256HashFile(downloadPath); - - if (!GZFileHandle::DecompressFile(downloadPath, module_path)) { - CLOG(WARNING) << "Failed to decompress downloaded kernel object"; - // If the gzipped file is corrupted, delete it so we don't try to use it - // next time. - TryUnlink(downloadPath.c_str()); - return false; - } - CLOG(INFO) << "Successfully downloaded and decompressed " << module_path; - } else { - CLOG(WARNING) << "Local storage does not contain " << candidate.GetName() << " and the candidate is not downloadable."; - return false; - } - - if (chmod(module_path.c_str(), 0444)) { - CLOG(WARNING) << "Failed to set file permissions for " << module_path << " - " << strerror(errno); - return false; - } - - return true; -} -} // namespace collector diff --git a/collector/lib/GetKernelObject.h b/collector/lib/GetKernelObject.h deleted file mode 100644 index 663c81beaa..0000000000 --- a/collector/lib/GetKernelObject.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef COLLECTOR_GETKERNELOBJECT_H -#define COLLECTOR_GETKERNELOBJECT_H - -#include - -#include - -#include "DriverCandidates.h" - -namespace collector { - -bool GetKernelObject(const std::string& hostname, const Json::Value& tls_config, const DriverCandidate& candidate, bool verbose); - -} // namespace collector -#endif // COLLECTOR_GETKERNELOBJECT_H diff --git a/collector/lib/system-inspector/Service.cpp b/collector/lib/system-inspector/Service.cpp index cdc4b3ba63..dbd191e1a1 100644 --- a/collector/lib/system-inspector/Service.cpp +++ b/collector/lib/system-inspector/Service.cpp @@ -71,7 +71,7 @@ void Service::Init(const CollectorConfig& config, std::shared_ptr)>> ProcessInfoCallbackRef; diff --git a/collector/lib/system-inspector/SystemInspector.h b/collector/lib/system-inspector/SystemInspector.h index bf8c371280..2eea8ee714 100644 --- a/collector/lib/system-inspector/SystemInspector.h +++ b/collector/lib/system-inspector/SystemInspector.h @@ -8,7 +8,6 @@ #include "CollectorConfig.h" #include "ConnTracker.h" #include "Control.h" -#include "DriverCandidates.h" #include "ppm_events_public.h" namespace collector::system_inspector { @@ -46,7 +45,7 @@ class SystemInspector { virtual ~SystemInspector() = default; virtual void Init(const CollectorConfig& config, std::shared_ptr conn_tracker) = 0; - virtual bool InitKernel(const CollectorConfig& config, const DriverCandidate& candidate) = 0; + virtual bool InitKernel(const CollectorConfig& config) = 0; virtual void Start() = 0; virtual void Run(const std::atomic& control) = 0; virtual void CleanUp() = 0; diff --git a/collector/test/DriverCandidatesTest.cpp b/collector/test/DriverCandidatesTest.cpp deleted file mode 100644 index 7d8ff83437..0000000000 --- a/collector/test/DriverCandidatesTest.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#include -#include - -#include "CollectionMethod.h" -#include "DriverCandidates.cpp" -#include "HostInfo.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -using namespace testing; - -namespace collector { - -class MockHostInfoLocal : public HostInfo { - public: - MockHostInfoLocal() = default; - - MOCK_METHOD0(GetOSID, std::string&()); - MOCK_METHOD0(GetBuildID, std::string&()); - MOCK_METHOD0(GetKernelVersion, KernelVersion()); - MOCK_METHOD0(GetMinikubeVersion, std::string()); - MOCK_METHOD0(IsUbuntu, bool()); - MOCK_METHOD0(IsCOS, bool()); - MOCK_METHOD0(IsDockerDesktop, bool()); -}; - -TEST(getGardenLinuxCandidateTest, Garden576_1) { - MockHostInfoLocal host; - std::string release("5.10.0-9-cloud-amd64"); - std::string version("#1 SMP Debian 5.10.83-1gardenlinux1 (2021-12-03)"); - std::string machine("x86_64"); - std::string expected_driver("collector-ebpf-5.10.0-9-cloud-amd64-gl-5.10.83-1gardenlinux1.o"); - std::string expected_path("/kernel-modules"); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - - auto candidate = getGardenLinuxCandidate(host); - - EXPECT_TRUE(candidate); - EXPECT_EQ(candidate->GetName(), expected_driver); - EXPECT_EQ(candidate->GetPath(), expected_path); - EXPECT_EQ(candidate->GetCollectionMethod(), CollectionMethod::EBPF); - EXPECT_TRUE(candidate->IsDownloadable()); -} - -TEST(getGardenLinuxCandidateTest, Garden318) { - MockHostInfoLocal host; - std::string release("5.4.0-6-cloud-amd64"); - std::string version("#1 SMP Debian 5.4.93-1 (2021-02-09)"); - std::string machine("x86_64"); - std::string expected_driver("collector-ebpf-5.4.0-6-cloud-amd64-gl-5.4.93-1.o"); - std::string expected_path("/kernel-modules"); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - - auto candidate = getGardenLinuxCandidate(host); - - EXPECT_TRUE(candidate); - EXPECT_EQ(candidate->GetName(), expected_driver); - EXPECT_EQ(candidate->GetPath(), expected_path); - EXPECT_EQ(candidate->GetCollectionMethod(), CollectionMethod::EBPF); - EXPECT_TRUE(candidate->IsDownloadable()); -} - -TEST(getMinikubeCandidateTest, v1_27_1) { - MockHostInfoLocal host; - std::string release("5.10.57"); - std::string version("#1 SMP Wed Oct 27 22:52:27 UTC 2021 x86_64 GNU/Linux"); - std::string machine("x86_64"); - std::string minikube_version("v1.27.1"); - std::string expected_driver("collector-ebpf-5.10.57-minikube-v1.27.1.o"); - std::string expected_path("/kernel-modules"); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetMinikubeVersion()).WillOnce(Return(minikube_version)); - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - - auto candidate = getMinikubeCandidate(host); - - EXPECT_TRUE(candidate); - EXPECT_EQ(candidate->GetName(), expected_driver); - EXPECT_EQ(candidate->GetPath(), expected_path); - EXPECT_EQ(candidate->GetCollectionMethod(), CollectionMethod::EBPF); - EXPECT_TRUE(candidate->IsDownloadable()); -} - -TEST(getMinikubeCandidateTest, v1_24_0) { - MockHostInfoLocal host; - std::string release("4.19.202"); - std::string version("#1 SMP Wed Oct 27 22:52:27 UTC 2021 x86_64 GNU/Linux"); - std::string machine("x86_64"); - std::string minikube_version("v1.24.0"); - std::string expected_driver("collector-ebpf-4.19.202-minikube-v1.24.0.o"); - std::string expected_path("/kernel-modules"); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetMinikubeVersion()).WillOnce(Return(minikube_version)); - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - - auto candidate = getMinikubeCandidate(host); - - EXPECT_TRUE(candidate); - EXPECT_EQ(candidate->GetName(), expected_driver); - EXPECT_EQ(candidate->GetPath(), expected_path); - EXPECT_EQ(candidate->GetCollectionMethod(), CollectionMethod::EBPF); - EXPECT_TRUE(candidate->IsDownloadable()); -} - -TEST(getMinikubeCandidateTest, NoVersion) { - MockHostInfoLocal host; - std::string release("4.19.202"); - std::string version("#1 SMP Wed Oct 27 22:52:27 UTC 2021 x86_64 GNU/Linux"); - std::string machine("x86_64"); - std::string minikube_version(""); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetMinikubeVersion()).WillOnce(Return(minikube_version)); - - auto ebpf_candidate = getMinikubeCandidate(host); - - EXPECT_FALSE(ebpf_candidate); -} - -TEST(getUserDriverCandidate, RelativePath) { - const char* user_input = "collector-mydriver.o"; - std::string expected_name(user_input); - std::string expected_path("/kernel-modules"); - - auto candidate = getUserDriverCandidate(user_input); - - EXPECT_EQ(candidate.GetName(), expected_name); - EXPECT_EQ(candidate.GetPath(), expected_path); - EXPECT_FALSE(candidate.IsDownloadable()); - EXPECT_EQ(candidate.GetCollectionMethod(), CollectionMethod::EBPF); -} - -TEST(getUserDriverCandidate, FullPath) { - const char* user_input = "/some/path/collector-mydriver.o"; - std::string expected_name("collector-mydriver.o"); - std::string expected_path("/some/path"); - - auto candidate = getUserDriverCandidate(user_input); - - EXPECT_EQ(candidate.GetName(), expected_name); - EXPECT_EQ(candidate.GetPath(), expected_path); - EXPECT_FALSE(candidate.IsDownloadable()); - EXPECT_EQ(candidate.GetCollectionMethod(), CollectionMethod::EBPF); -} - -TEST(normalizeReleaseStringTest, FedoraKernel) { - MockHostInfoLocal host; - std::string release("5.14.18-300.fc35.x86_64"); - std::string version("#1 SMP Fri Nov 12 16:43:17 UTC 2021"); - std::string machine("x86_64"); - std::string expected_kernel(release); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - EXPECT_CALL(host, IsCOS()).WillOnce(Return(false)); - EXPECT_CALL(host, IsDockerDesktop()).WillOnce(Return(false)); - - auto normalized_kernel = normalizeReleaseString(host); - - EXPECT_EQ(normalized_kernel, expected_kernel); -} - -TEST(normalizeReleaseStringTest, COSKernel) { - MockHostInfoLocal host; - std::string release("5.10.68+"); - std::string version("#1 SMP Fri Dec 3 10:04:10 UTC 2021"); - std::string machine("x86_64"); - std::string build("build"); - std::string os_id("os"); - std::string expected_kernel("5.10.68-build-os"); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - EXPECT_CALL(host, IsCOS()).WillOnce(Return(true)); - EXPECT_CALL(host, GetBuildID()).WillOnce(ReturnRef(build)); - EXPECT_CALL(host, GetOSID()).WillOnce(ReturnRef(os_id)); - - auto normalized_kernel = normalizeReleaseString(host); - - EXPECT_EQ(normalized_kernel, expected_kernel); -} - -TEST(normalizeReleaseStringTest, DockerDesktopKernel) { - MockHostInfoLocal host; - std::string release("5.10.47-linuxkit"); - std::string version("#1 SMP Sat Jul 3 21:51:47 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux"); - std::string machine("x86_64"); - std::string expected_kernel("5.10.47-dockerdesktop-2021-07-03-21-51-47"); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - EXPECT_CALL(host, IsCOS()).WillOnce(Return(false)); - EXPECT_CALL(host, IsDockerDesktop()).WillOnce(Return(true)); - - auto normalized_kernel = normalizeReleaseString(host); - - EXPECT_EQ(normalized_kernel, expected_kernel); -} - -TEST(normalizeReleaseStringTest, GardenKernel) { - MockHostInfoLocal host; - std::string release("5.10.0-9-cloud-amd64"); - std::string version("#1 SMP Debian 5.10.83-1gardenlinux1 (2021-12-03)"); - std::string machine("x86_64"); - std::string expected_kernel("5.10.0-9-cloud-amd64"); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - EXPECT_CALL(host, IsCOS()).WillOnce(Return(false)); - EXPECT_CALL(host, IsDockerDesktop()).WillOnce(Return(false)); - - auto normalized_kernel = normalizeReleaseString(host); - - EXPECT_EQ(normalized_kernel, expected_kernel); -} - -TEST(normalizeReleaseStringTest, Garden318Kernel) { - MockHostInfoLocal host; - std::string release("5.4.0-6-cloud-amd64"); - std::string version("#1 SMP Debian 5.4.93-1 (2021-02-09)"); - std::string machine("x86_64"); - std::string expected_kernel("5.4.0-6-cloud-amd64"); - KernelVersion kv(release, version, machine); - - EXPECT_CALL(host, GetKernelVersion()).WillOnce(Return(kv)); - EXPECT_CALL(host, IsCOS()).WillOnce(Return(false)); - EXPECT_CALL(host, IsDockerDesktop()).WillOnce(Return(false)); - - auto normalized_kernel = normalizeReleaseString(host); - - EXPECT_EQ(normalized_kernel, expected_kernel); -} -} // namespace collector diff --git a/collector/test/FileDownloaderTest.cpp b/collector/test/FileDownloaderTest.cpp deleted file mode 100644 index ded3a492d8..0000000000 --- a/collector/test/FileDownloaderTest.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/** collector - -A full notice with attributions is provided along with this source code. - - This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -* In addition, as a special exception, the copyright holders give -* permission to link the code of portions of this program with the -* OpenSSL library under certain conditions as described in each -* individual source file, and distribute linked combinations -* including the two. -* You must obey the GNU General Public License in all respects -* for all of the code used other than OpenSSL. If you modify -* file(s) with this exception, you may extend this exception to your -* version of the file(s), but you are not obligated to do so. If you -* do not wish to do so, delete this exception statement from your -* version. -*/ -#include - -#include "gtest/gtest.h" - -// Include FileDownloader.cpp in order to have direct access to static functions -#include "FileDownloader.cpp" -#include "FileDownloader.h" - -namespace collector { - -TEST(FileDownloaderTest, HeaderCallbackNonHTTPHeader) { - std::stringstream os; - DownloadData dd{.http_status = 0, .error_msg = "", .os = &os}; - char* header = const_cast("content-type: image/png\t\n"); - - size_t res = HeaderCallback(header, sizeof(char), strlen(header), static_cast(&dd)); - - ASSERT_EQ(res, strlen(header) * sizeof(char)); - ASSERT_EQ(dd.http_status, 0); - ASSERT_EQ(dd.error_msg, ""); -} - -TEST(FileDownloaderTest, HeaderCallbackUnauthorizedResponse) { - std::stringstream os; - DownloadData dd{.http_status = 0, .error_msg = "", .os = &os}; - char* header = const_cast("HTTP/1.1 403 \t\n"); - - size_t res = HeaderCallback(header, sizeof(char), strlen(header), static_cast(&dd)); - - ASSERT_EQ(res, strlen(header) * sizeof(char)); - ASSERT_EQ(dd.http_status, 403); - ASSERT_EQ(dd.error_msg, ""); -} - -TEST(FileDownloaderTest, HeaderCallbackMalformedHTTPResponse) { - std::stringstream os; - DownloadData dd{.http_status = 0, .error_msg = "", .os = &os}; - char* header = const_cast("HTTP/1.1403\t\n"); - - size_t res = HeaderCallback(header, sizeof(char), strlen(header), static_cast(&dd)); - - ASSERT_EQ(res, 0); - ASSERT_EQ(dd.http_status, 500); - ASSERT_TRUE(dd.error_msg.find(header) != std::string::npos); -} - -TEST(FileDownloaderTest, HeaderCallbackSuccessfulResponse) { - std::stringstream os; - DownloadData dd{.http_status = 0, .error_msg = "", .os = &os}; - char* header = const_cast("HTTP/1.1 200 \t\n"); - - size_t res = HeaderCallback(header, sizeof(char), strlen(header), static_cast(&dd)); - - ASSERT_EQ(res, strlen(header) * sizeof(char)); - ASSERT_EQ(dd.http_status, 200); - ASSERT_EQ(dd.error_msg, ""); -} - -TEST(FileDownloaderTest, WriteFileSuccess) { - std::stringstream os; - DownloadData dd{.http_status = 200, .error_msg = "", .os = &os}; - char* content = const_cast("This is some content that should be dumped into a file, for testing purposes it will be dumped to a string"); - - size_t res = WriteFile(content, sizeof(char), strlen(content), static_cast(&dd)); - - ASSERT_EQ(res, strlen(content) * sizeof(char)); - ASSERT_EQ(os.str(), content); -} - -TEST(FileDownloaderTest, WriteFileFailedRequest) { - std::stringstream os; - DownloadData dd{.http_status = 403, .error_msg = "", .os = &os}; - char* content = const_cast("This is some content that should be dumped into a file, for testing purposes it will be dumped to a string"); - - size_t res = WriteFile(content, sizeof(char), strlen(content), static_cast(&dd)); - - ASSERT_EQ(res, 0); - ASSERT_EQ(os.str(), ""); - ASSERT_TRUE(dd.error_msg.find(content) != std::string::npos); -} - -TEST(FileDownloaderTest, EffectiveURLBasic) { - std::string url = "https://sensor.stackrox.svc:443/some-file.o.gz"; - std::string_view expected_url = url; - FileDownloader fd; - - fd.SetURL(url); - - ASSERT_EQ(expected_url, fd.GetEffectiveURL()); -} - -TEST(FileDownloaderTest, EffectiveURLConnectTo) { - std::string url = "https://sensor.stackrox.svc:443/some-file.o.gz"; - std::string host = "sensor.stackrox.svc"; - std::string connect_to = "sensor.rhacs-operator.svc:443"; - std::string expected_url = "https://sensor.rhacs-operator.svc:443/some-file.o.gz"; - FileDownloader fd; - - fd.SetURL(url); - fd.SetConnectTo(host, connect_to); - - ASSERT_EQ(expected_url, fd.GetEffectiveURL()); -} -TEST(FileDownloaderTest, EffectiveURLConnectToNoMatch) { - std::string url = "https://sensor.stackrox.svc:8443/some-file.o.gz"; - std::string host = "sensor.stackrox.svc"; - std::string connect_to = "sensor.rhacs-operator.svc:443"; - std::string_view expected_url = url; - FileDownloader fd; - - fd.SetURL(url); - fd.SetConnectTo(host, connect_to); - - ASSERT_EQ(expected_url, fd.GetEffectiveURL()); -} -} // namespace collector diff --git a/collector/test/GetKernelObjectTest.cpp b/collector/test/GetKernelObjectTest.cpp deleted file mode 100644 index 7a42025bb8..0000000000 --- a/collector/test/GetKernelObjectTest.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include - -#include "GetKernelObject.cpp" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -/* - * The expected value for this test is the well known hash of an empty string: - * https://www.di-mgt.com.au/sha_testvectors.html - */ -TEST(Sha256HashStream, Empty) { - std::stringstream input(""); - std::string expected = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; - std::string output = collector::Sha256HashStream(input); - - ASSERT_EQ(output, expected); -} - -/* - * The expected value for this test was verified with the following bash commands: - * $ printf '0123456789ABCDEF' > newfile - * $ sha256sum newfile - */ -TEST(Sha256HashStream, SmallString) { - std::stringstream input("0123456789ABCDEF"); - std::string expected = "2125b2c332b1113aae9bfc5e9f7e3b4c91d828cb942c2df1eeb02502eccae9e9"; - std::string output = collector::Sha256HashStream(input); - - ASSERT_EQ(output, expected); -} - -/* - * The expected value for this test was verified with the following bash commands: - * $ yes . | head -n 10000 | tr -d "\n" > newfile - * $ sha256sum newfile - */ -TEST(Sha256HashStream, BigString) { - std::stringstream input{std::string(10000, '.')}; - std::string expected = "cca2be86bf2ea72443a30bb7b7733dfd09689f975dd8bc807344f32eff401404"; - std::string output = collector::Sha256HashStream(input); - - ASSERT_EQ(output, expected); -}