diff --git a/src/docker.cc b/src/docker.cc index f9b8b7a4..39a4ece2 100644 --- a/src/docker.cc +++ b/src/docker.cc @@ -46,6 +46,24 @@ constexpr const char kDockerContainerResourcePrefix[] = "container"; DockerReader::DockerReader(const MetadataAgentConfiguration& config) : config_(config), environment_(config) {} +bool DockerReader::ValidateConfiguration() const { + try { + const std::string container_filter( + config_.DockerContainerFilter().empty() + ? "" : "&" + config_.DockerContainerFilter()); + + // A limit may exist in the container_filter, however, the docker API only + // uses the first limit provided in the query params. + (void) QueryDocker(std::string(kDockerEndpointPath) + + "/json?all=true&limit=1" + container_filter); + + return true; + } catch (const QueryException& e) { + // Already logged. + return false; + } +} + MetadataUpdater::ResourceMetadata DockerReader::GetContainerMetadata( const json::Object* container, Timestamp collected_at) const throw(json::Exception) { @@ -187,4 +205,12 @@ json::value DockerReader::QueryDocker(const std::string& path) const } } +bool DockerUpdater::ValidateConfiguration() const { + if (!PollingMetadataUpdater::ValidateConfiguration()) { + return false; + } + + return reader_.ValidateConfiguration(); +} + } diff --git a/src/docker.h b/src/docker.h index da54446b..13344d9c 100644 --- a/src/docker.h +++ b/src/docker.h @@ -32,6 +32,10 @@ class DockerReader { // A Docker metadata query function. std::vector MetadataQuery() const; + // Validates the relevant configuration and returns true if it's correct. + // Returns a bool that represents if it's configured properly. + bool ValidateConfiguration() const; + private: // A representation of all query-related errors. class QueryException { @@ -60,8 +64,13 @@ class DockerUpdater : public PollingMetadataUpdater { public: DockerUpdater(MetadataAgent* server) : reader_(server->config()), PollingMetadataUpdater( - server, server->config().DockerUpdaterIntervalSeconds(), + server, "DockerUpdater", + server->config().DockerUpdaterIntervalSeconds(), std::bind(&google::DockerReader::MetadataQuery, &reader_)) { } + + protected: + bool ValidateConfiguration() const; + private: DockerReader reader_; }; diff --git a/src/instance.h b/src/instance.h index 6fa612f7..7c3cfd30 100644 --- a/src/instance.h +++ b/src/instance.h @@ -45,7 +45,8 @@ class InstanceUpdater : public PollingMetadataUpdater { public: InstanceUpdater(MetadataAgent* server) : reader_(server->config()), PollingMetadataUpdater( - server, server->config().InstanceUpdaterIntervalSeconds(), + server, "InstanceUpdater", + server->config().InstanceUpdaterIntervalSeconds(), std::bind(&google::InstanceReader::MetadataQuery, &reader_)) { } private: InstanceReader reader_; diff --git a/src/kubernetes.cc b/src/kubernetes.cc index 6205d8bc..30d5b421 100644 --- a/src/kubernetes.cc +++ b/src/kubernetes.cc @@ -961,6 +961,33 @@ json::value KubernetesReader::FindTopLevelOwner( return FindTopLevelOwner(ns, GetOwner(ns, ref->As())); } +bool KubernetesReader::ValidateConfiguration() const { + try { + (void) QueryMaster(std::string(kKubernetesEndpointPath) + "/nodes?limit=1"); + } catch (const QueryException& e) { + // Already logged. + return false; + } + + try { + const std::string pod_label_selector( + config_.KubernetesPodLabelSelector().empty() + ? "" : "&" + config_.KubernetesPodLabelSelector()); + + (void) QueryMaster(std::string(kKubernetesEndpointPath) + "/pods?limit=1" + + pod_label_selector); + } catch (const QueryException& e) { + // Already logged. + return false; + } + + if (CurrentNode().empty()) { + return false; + } + + return true; +} + void KubernetesReader::PodCallback( MetadataUpdater::UpdateCallback callback, const json::Object* pod, Timestamp collected_at, bool is_deleted) const @@ -1034,8 +1061,15 @@ void KubernetesReader::WatchNode(MetadataUpdater::UpdateCallback callback) LOG(INFO) << "Watch thread (node) exiting"; } -void KubernetesUpdater::start() { - PollingMetadataUpdater::start(); +bool KubernetesUpdater::ValidateConfiguration() const { + if (!PollingMetadataUpdater::ValidateConfiguration()) { + return false; + } + + return reader_.ValidateConfiguration(); +} + +void KubernetesUpdater::StartUpdater() { if (config().KubernetesUseWatch()) { // Wrap the bind expression into a function to use as a bind argument. UpdateCallback cb = std::bind(&KubernetesUpdater::MetadataCallback, this, @@ -1044,6 +1078,9 @@ void KubernetesUpdater::start() { std::thread(&KubernetesReader::WatchNode, &reader_, cb); pod_watch_thread_ = std::thread(&KubernetesReader::WatchPods, &reader_, cb); + } else { + // Only try to poll if watch is disabled. + PollingMetadataUpdater::StartUpdater(); } } diff --git a/src/kubernetes.h b/src/kubernetes.h index 3ed88cdc..c20984ca 100644 --- a/src/kubernetes.h +++ b/src/kubernetes.h @@ -38,6 +38,10 @@ class KubernetesReader { // A Kubernetes metadata query function. std::vector MetadataQuery() const; + // Validates the relevant configuration and returns true if it's correct. + // Returns a bool that represents if it's configured properly. + bool ValidateConfiguration() const; + // Node watcher. void WatchNode(MetadataUpdater::UpdateCallback callback) const; @@ -147,7 +151,8 @@ class KubernetesUpdater : public PollingMetadataUpdater { public: KubernetesUpdater(MetadataAgent* server) : reader_(server->config()), PollingMetadataUpdater( - server, server->config().KubernetesUpdaterIntervalSeconds(), + server, "KubernetesUpdater", + server->config().KubernetesUpdaterIntervalSeconds(), std::bind(&google::KubernetesReader::MetadataQuery, &reader_)) { } ~KubernetesUpdater() { if (node_watch_thread_.joinable()) { @@ -158,7 +163,9 @@ class KubernetesUpdater : public PollingMetadataUpdater { } } - void start(); + protected: + bool ValidateConfiguration() const; + void StartUpdater(); private: // Metadata watcher callback. diff --git a/src/updater.cc b/src/updater.cc index 4e3b7df4..e7593c5e 100644 --- a/src/updater.cc +++ b/src/updater.cc @@ -22,15 +22,28 @@ namespace google { -MetadataUpdater::MetadataUpdater(MetadataAgent* store) - : store_(store) {} +MetadataUpdater::MetadataUpdater(MetadataAgent* store, const std::string& name) + : store_(store), name_(name) {} MetadataUpdater::~MetadataUpdater() {} +void MetadataUpdater::start() { + if (!ValidateConfiguration()) { + LOG(ERROR) << "Failed to validate configuration for " << name_; + return; + } + + StartUpdater(); +} + +void MetadataUpdater::stop() { + StopUpdater(); +} + PollingMetadataUpdater::PollingMetadataUpdater( - MetadataAgent* store, double period_s, + MetadataAgent* store, const std::string& name, double period_s, std::function()> query_metadata) - : MetadataUpdater(store), + : MetadataUpdater(store, name), period_(period_s), query_metadata_(query_metadata), timer_(), @@ -42,7 +55,11 @@ PollingMetadataUpdater::~PollingMetadataUpdater() { } } -void PollingMetadataUpdater::start() { +bool PollingMetadataUpdater::ValidateConfiguration() const { + return period_ >= seconds::zero(); +} + +void PollingMetadataUpdater::StartUpdater() { timer_.lock(); if (config().VerboseLogging()) { LOG(INFO) << "Timer locked"; @@ -53,7 +70,7 @@ void PollingMetadataUpdater::start() { } } -void PollingMetadataUpdater::stop() { +void PollingMetadataUpdater::StopUpdater() { timer_.unlock(); if (config().VerboseLogging()) { LOG(INFO) << "Timer unlocked"; diff --git a/src/updater.h b/src/updater.h index d4878962..ff013d72 100644 --- a/src/updater.h +++ b/src/updater.h @@ -46,7 +46,7 @@ class MetadataUpdater { MetadataAgent::Metadata metadata; }; - MetadataUpdater(MetadataAgent* store); + MetadataUpdater(MetadataAgent* store, const std::string& name); virtual ~MetadataUpdater(); const MetadataAgentConfiguration& config() { @@ -54,15 +54,27 @@ class MetadataUpdater { } // Starts updating. - virtual void start() = 0; + void start(); // Stops updating. - virtual void stop() = 0; + void stop(); using UpdateCallback = std::function&&)>; protected: + // Validates the relevant configuration and returns true if it's correct. + // Returns a bool that represents if it's configured properly. + virtual bool ValidateConfiguration() const { + return true; + } + + // Internal method for starting the updater's logic. + virtual void StartUpdater() = 0; + + // Internal method for stopping the updater's logic. + virtual void StopUpdater() = 0; + // Updates the resource map in the store. void UpdateResourceCallback(const ResourceMetadata& result) { store_->UpdateResource(result.ids, result.resource); @@ -74,6 +86,9 @@ class MetadataUpdater { } private: + // The name of the updater provided by subclasses. + std::string name_; + // The store for the metadata. MetadataAgent* store_; }; @@ -82,12 +97,14 @@ class MetadataUpdater { class PollingMetadataUpdater : public MetadataUpdater { public: PollingMetadataUpdater( - MetadataAgent* store, double period_s, + MetadataAgent* store, const std::string& name, double period_s, std::function()> query_metadata); ~PollingMetadataUpdater(); - void start(); - void stop(); + protected: + bool ValidateConfiguration() const; + void StartUpdater(); + void StopUpdater(); private: using seconds = std::chrono::duration;