summaryrefslogtreecommitdiffstats
path: root/logforwarder
diff options
context:
space:
mode:
authorArne Juul <arnej@yahooinc.com>2022-09-15 11:17:26 +0000
committerArne Juul <arnej@yahooinc.com>2022-09-15 11:20:38 +0000
commita5fbb5b41765fa12ea8da3cb6f7837325d3bb3d9 (patch)
tree0a2da1a3f6986f402f75486d1fa6fdb2bf313a86 /logforwarder
parent641561888e998be6d198c651c3c45de9f1915b31 (diff)
be more careful about splunk start/stop
* validate the configurable splunk-home * do stopping via C++ program instead of shell command * some refactoring of C++ code as well
Diffstat (limited to 'logforwarder')
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/CMakeLists.txt2
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/cf-handler.cpp94
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/cf-handler.h5
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/child-handler.cpp17
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/child-handler.h1
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/main.cpp33
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/splunk-starter.cpp95
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/splunk-starter.h19
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/splunk-stopper.cpp18
-rw-r--r--logforwarder/src/apps/vespa-logforwarder-start/splunk-stopper.h14
10 files changed, 208 insertions, 90 deletions
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/CMakeLists.txt b/logforwarder/src/apps/vespa-logforwarder-start/CMakeLists.txt
index 74ca0ff6abc..eb19ed3e45c 100644
--- a/logforwarder/src/apps/vespa-logforwarder-start/CMakeLists.txt
+++ b/logforwarder/src/apps/vespa-logforwarder-start/CMakeLists.txt
@@ -2,6 +2,8 @@
vespa_add_executable(logforwarder-start_app
SOURCES
main.cpp
+ splunk-stopper.cpp
+ splunk-starter.cpp
cf-handler.cpp
child-handler.cpp
OUTPUT_NAME vespa-logforwarder-start
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.cpp b/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.cpp
index b8e2a95783e..5d17357e74e 100644
--- a/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.cpp
+++ b/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.cpp
@@ -4,100 +4,44 @@
#include <vespa/config/common/configsystem.h>
#include <vespa/config/common/exceptions.h>
#include <vespa/config/subscription/configsubscriber.hpp>
-#include <dirent.h>
+
+#include <sys/types.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <vespa/log/log.h>
LOG_SETUP(".cf-handler");
-
CfHandler::CfHandler() = default;
CfHandler::~CfHandler() = default;
-void
-CfHandler::subscribe(const std::string & configId, std::chrono::milliseconds timeout)
-{
+void CfHandler::subscribe(const std::string & configId, std::chrono::milliseconds timeout) {
_handle = _subscriber.subscribe<LogforwarderConfig>(configId, timeout);
}
namespace {
-
-bool fixDir(const vespalib::string &path) {
- if (path.size() == 0) return true;
- size_t lastSlash = path.rfind('/');
- if (lastSlash != vespalib::string::npos) {
- vespalib::string parent = path.substr(0, lastSlash);
- if (!fixDir(parent)) return false;
+bool isExecutable(const char *path) {
+ struct stat statbuf;
+ if (stat(path, &statbuf) != 0) {
+ return false;
}
- DIR *dp = opendir(path.c_str());
- if (dp == NULL) {
- if (errno != ENOENT || mkdir(path.c_str(), 0755) != 0) {
- perror(path.c_str());
- return false;
- }
- } else {
- closedir(dp);
+ if (! S_ISREG(statbuf.st_mode)) {
+ return false;
}
- return true;
+ return ((statbuf.st_mode & S_IXOTH) != 0);
}
-
-vespalib::string
-cfFilePath(const vespalib::string &parent, const vespalib::string &filename) {
- vespalib::string path = parent + "/etc/system/local";
- fixDir(path);
- path += "/";
- path += filename;
- return path;
}
-} // namespace <unnamed>
-
-void
-CfHandler::doConfigure()
-{
+void CfHandler::doConfigure() {
std::unique_ptr<LogforwarderConfig> cfg(_handle->getConfig());
const LogforwarderConfig& config(*cfg);
-
- vespalib::string path = cfFilePath(config.splunkHome, "deploymentclient.conf");
- vespalib::string tmpPath = path + ".new";
- FILE *fp = fopen(tmpPath.c_str(), "w");
- if (fp == NULL) return;
-
- fprintf(fp, "[deployment-client]\n");
- fprintf(fp, "clientName = %s\n", config.clientName.c_str());
- fprintf(fp, "phoneHomeIntervalInSecs = %i\n", config.phoneHomeInterval);
- fprintf(fp, "\n");
- fprintf(fp, "[target-broker:deploymentServer]\n");
- fprintf(fp, "targetUri = %s\n", config.deploymentServer.c_str());
-
- fclose(fp);
- rename(tmpPath.c_str(), path.c_str());
-
- if (getenv("VESPA_HOSTNAME") != NULL &&
- getenv("VESPA_TENANT") != NULL &&
- getenv("VESPA_APPLICATION")!= NULL &&
- getenv("VESPA_INSTANCE") != NULL &&
- getenv("VESPA_ENVIRONMENT") != NULL &&
- getenv("VESPA_REGION") != NULL)
- {
- path = cfFilePath(config.splunkHome, "inputs.conf");
- tmpPath = path + ".new";
- fp = fopen(tmpPath.c_str(), "w");
- if (fp != NULL) {
- fprintf(fp, "[default]\n");
- fprintf(fp, "host = %s\n", getenv("VESPA_HOSTNAME"));
- fprintf(fp, "_meta = vespa_tenant::%s vespa_app::%s.%s vespa_zone::%s.%s\n", getenv("VESPA_TENANT"), getenv("VESPA_APPLICATION"), getenv("VESPA_INSTANCE"), getenv("VESPA_ENVIRONMENT"), getenv("VESPA_REGION"));
- fclose(fp);
- rename(tmpPath.c_str(), path.c_str());
- }
- }
- if (config.clientName.size() == 0 ||
- config.deploymentServer.size() == 0)
- {
- _childHandler.stopChild();
+ LOG(debug, "validating splunk home '%s'", config.splunkHome.c_str());
+ auto program = config.splunkHome + "/bin/splunk";
+ if (isExecutable(program.c_str())) {
+ gotConfig(config);
} else {
- _childHandler.startChild(config.splunkHome);
+ LOG(warning, "invalid splunk home, '%s' is not an executable", program.c_str());
}
}
@@ -109,10 +53,6 @@ CfHandler::check()
}
}
-void CfHandler::stop() {
- _childHandler.stopChild();
-}
-
constexpr std::chrono::milliseconds CONFIG_TIMEOUT_MS(30 * 1000);
void
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.h b/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.h
index 651b8d22fa8..c66be0e2099 100644
--- a/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.h
+++ b/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.h
@@ -1,7 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
-#include "child-handler.h"
#include <vespa/config-logforwarder.h>
#include <vespa/config/subscription/configsubscriber.h>
@@ -9,7 +8,6 @@ using cloud::config::LogforwarderConfig;
class CfHandler {
private:
- ChildHandler _childHandler;
config::ConfigSubscriber _subscriber;
config::ConfigHandle<LogforwarderConfig>::UP _handle;
void subscribe(const std::string & configId, std::chrono::milliseconds timeout);
@@ -18,6 +16,7 @@ public:
CfHandler();
virtual ~CfHandler();
void start(const char *configId);
- void stop();
void check();
+
+ virtual void gotConfig(const LogforwarderConfig&) = 0;
};
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/child-handler.cpp b/logforwarder/src/apps/vespa-logforwarder-start/child-handler.cpp
index a478e0bbd01..301c5055272 100644
--- a/logforwarder/src/apps/vespa-logforwarder-start/child-handler.cpp
+++ b/logforwarder/src/apps/vespa-logforwarder-start/child-handler.cpp
@@ -76,6 +76,7 @@ runSplunk(const vespalib::string &prefix, std::vector<const char *> args)
void
ChildHandler::startChild(const vespalib::string &prefix)
{
+ LOG(debug, "startChild '%s'", prefix.c_str());
if (_childRunning && prefix == _runningPrefix) {
runSplunk(prefix, {"restart"});
} else {
@@ -93,9 +94,17 @@ ChildHandler::startChild(const vespalib::string &prefix)
}
}
-void
-ChildHandler::stopChild()
-{
- runSplunk(_runningPrefix, {"stop"});
+void ChildHandler::stopChild() {
+ if (_runningPrefix != "") {
+ LOG(debug, "stopChild '%s'", _runningPrefix.c_str());
+ runSplunk(_runningPrefix, {"stop"});
+ }
_childRunning = false;
}
+
+void
+ChildHandler::stopChild(const vespalib::string &prefix) {
+ stopChild();
+ _runningPrefix = prefix;
+ stopChild();
+}
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/child-handler.h b/logforwarder/src/apps/vespa-logforwarder-start/child-handler.h
index 22396a0e448..f512d241c71 100644
--- a/logforwarder/src/apps/vespa-logforwarder-start/child-handler.h
+++ b/logforwarder/src/apps/vespa-logforwarder-start/child-handler.h
@@ -10,5 +10,6 @@ private:
public:
void startChild(const vespalib::string &prefix);
void stopChild();
+ void stopChild(const vespalib::string &prefix);
ChildHandler();
};
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/main.cpp b/logforwarder/src/apps/vespa-logforwarder-start/main.cpp
index 33fe4489811..d24c9c982a1 100644
--- a/logforwarder/src/apps/vespa-logforwarder-start/main.cpp
+++ b/logforwarder/src/apps/vespa-logforwarder-start/main.cpp
@@ -6,7 +6,8 @@
#include <vespa/log/log.h>
LOG_SETUP("vespa-logforwarder-start");
-#include "cf-handler.h"
+#include "splunk-starter.h"
+#include "splunk-stopper.h"
#include <vespa/vespalib/util/sig_catch.h>
class Wrapper {
@@ -15,7 +16,7 @@ public:
Wrapper(const char *cfid) : _configId(cfid) {}
void run() {
vespalib::SigCatch catcher;
- CfHandler handler;
+ SplunkStarter handler;
handler.start(_configId);
while (! catcher.receivedStopSignal()) {
handler.check();
@@ -28,12 +29,32 @@ public:
int
main(int argc, char** argv)
{
- int c = getopt(argc, argv, "c:");
- if (c != 'c') {
+ int c = -1;
+ bool stopMode = false;
+ const char *cfid = nullptr;
+ while ((c = getopt(argc, argv, "Sc:")) != -1) {
+ switch (c) {
+ case 'S':
+ stopMode = true;
+ break;
+ case 'c':
+ cfid = optarg;
+ break;
+ default:
+ cfid = nullptr;
+ break;
+ }
+ }
+ if (cfid == nullptr) {
LOG(error, "Usage: %s -c <config-id>", argv[0]);
return EXIT_FAILURE;
}
- Wrapper wrapper(optarg);
- wrapper.run();
+ if (stopMode) {
+ SplunkStopper stopper(cfid);
+ stopper.check();
+ } else {
+ Wrapper wrapper(cfid);
+ wrapper.run();
+ }
return 0;
}
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/splunk-starter.cpp b/logforwarder/src/apps/vespa-logforwarder-start/splunk-starter.cpp
new file mode 100644
index 00000000000..905f4640c92
--- /dev/null
+++ b/logforwarder/src/apps/vespa-logforwarder-start/splunk-starter.cpp
@@ -0,0 +1,95 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "splunk-starter.h"
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <vespa/log/log.h>
+LOG_SETUP(".splunk-starter");
+
+SplunkStarter::SplunkStarter() = default;
+
+SplunkStarter::~SplunkStarter() = default;
+
+namespace {
+
+vespalib::string fixDir(const vespalib::string &parent, const vespalib::string &subdir) {
+ auto dirname = parent + "/" + subdir;
+ DIR *dp = opendir(dirname.c_str());
+ if (dp == NULL) {
+ if (errno != ENOENT || mkdir(dirname.c_str(), 0755) != 0) {
+ LOG(warning, "Could not create directory '%s'", dirname.c_str());
+ perror(dirname.c_str());
+ }
+ } else {
+ closedir(dp);
+ }
+ return dirname;
+}
+
+vespalib::string
+cfFilePath(const vespalib::string &parent, const vespalib::string &filename) {
+ vespalib::string path = parent;
+ path = fixDir(path, "etc");
+ path = fixDir(path, "system");
+ path = fixDir(path, "local");
+ return path + "/" + filename;
+}
+
+} // namespace <unnamed>
+
+void SplunkStarter::gotConfig(const LogforwarderConfig& config) {
+ vespalib::string path = cfFilePath(config.splunkHome, "deploymentclient.conf");
+ LOG(debug, "got config, writing %s", path.c_str());
+ vespalib::string tmpPath = path + ".new";
+ FILE *fp = fopen(tmpPath.c_str(), "w");
+ if (fp == NULL) {
+ LOG(warning, "could not open '%s' for write", tmpPath.c_str());
+ return;
+ }
+
+ fprintf(fp, "[deployment-client]\n");
+ fprintf(fp, "clientName = %s\n", config.clientName.c_str());
+ fprintf(fp, "phoneHomeIntervalInSecs = %i\n", config.phoneHomeInterval);
+ fprintf(fp, "\n");
+ fprintf(fp, "[target-broker:deploymentServer]\n");
+ fprintf(fp, "targetUri = %s\n", config.deploymentServer.c_str());
+
+ fclose(fp);
+ rename(tmpPath.c_str(), path.c_str());
+
+ if (getenv("VESPA_HOSTNAME") != NULL &&
+ getenv("VESPA_TENANT") != NULL &&
+ getenv("VESPA_APPLICATION")!= NULL &&
+ getenv("VESPA_INSTANCE") != NULL &&
+ getenv("VESPA_ENVIRONMENT") != NULL &&
+ getenv("VESPA_REGION") != NULL)
+ {
+ path = cfFilePath(config.splunkHome, "inputs.conf");
+ tmpPath = path + ".new";
+ fp = fopen(tmpPath.c_str(), "w");
+ if (fp != NULL) {
+ fprintf(fp, "[default]\n");
+ fprintf(fp, "host = %s\n", getenv("VESPA_HOSTNAME"));
+ fprintf(fp, "_meta = vespa_tenant::%s vespa_app::%s.%s vespa_zone::%s.%s\n",
+ getenv("VESPA_TENANT"),
+ getenv("VESPA_APPLICATION"),
+ getenv("VESPA_INSTANCE"),
+ getenv("VESPA_ENVIRONMENT"),
+ getenv("VESPA_REGION"));
+ fclose(fp);
+ rename(tmpPath.c_str(), path.c_str());
+ }
+ }
+ if (config.clientName.size() == 0 ||
+ config.deploymentServer.size() == 0)
+ {
+ _childHandler.stopChild();
+ } else {
+ _childHandler.startChild(config.splunkHome);
+ }
+}
+
+void SplunkStarter::stop() {
+ _childHandler.stopChild();
+}
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/splunk-starter.h b/logforwarder/src/apps/vespa-logforwarder-start/splunk-starter.h
new file mode 100644
index 00000000000..39cb8ca0efe
--- /dev/null
+++ b/logforwarder/src/apps/vespa-logforwarder-start/splunk-starter.h
@@ -0,0 +1,19 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include "cf-handler.h"
+#include "child-handler.h"
+#include <vespa/config-logforwarder.h>
+
+using cloud::config::LogforwarderConfig;
+
+class SplunkStarter : public CfHandler {
+private:
+ ChildHandler _childHandler;
+public:
+ SplunkStarter();
+ virtual ~SplunkStarter();
+ void stop();
+ void gotConfig(const LogforwarderConfig& config) override;
+};
+
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/splunk-stopper.cpp b/logforwarder/src/apps/vespa-logforwarder-start/splunk-stopper.cpp
new file mode 100644
index 00000000000..2da8a1acd5c
--- /dev/null
+++ b/logforwarder/src/apps/vespa-logforwarder-start/splunk-stopper.cpp
@@ -0,0 +1,18 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "splunk-stopper.h"
+#include "child-handler.h"
+
+#include <vespa/log/log.h>
+LOG_SETUP(".splunk-stopper");
+
+SplunkStopper::SplunkStopper(const char *configId) {
+ start(configId);
+}
+
+SplunkStopper::~SplunkStopper() = default;
+
+void SplunkStopper::gotConfig(const LogforwarderConfig& config) {
+ LOG(debug, "got config with splunk home '%s'", config.splunkHome.c_str());
+ ChildHandler().stopChild(config.splunkHome);
+}
diff --git a/logforwarder/src/apps/vespa-logforwarder-start/splunk-stopper.h b/logforwarder/src/apps/vespa-logforwarder-start/splunk-stopper.h
new file mode 100644
index 00000000000..8ff520fcc4d
--- /dev/null
+++ b/logforwarder/src/apps/vespa-logforwarder-start/splunk-stopper.h
@@ -0,0 +1,14 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#pragma once
+
+#include "cf-handler.h"
+#include <vespa/config-logforwarder.h>
+
+using cloud::config::LogforwarderConfig;
+
+class SplunkStopper : public CfHandler {
+public:
+ SplunkStopper(const char *cfid);
+ virtual ~SplunkStopper();
+ void gotConfig(const LogforwarderConfig& config) override;
+};