summaryrefslogtreecommitdiffstats
path: root/logforwarder/src/apps/vespa-logforwarder-start/cf-handler.cpp
blob: bf98bbd75ef1f53b8e0d130745514daa82997dfd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "cf-handler.h"
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <vespa/defaults.h>
#include <vespa/config/common/configsystem.h>
#include <vespa/config/common/exceptions.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)
{
    _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;
    }
    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);
    }
    return true;
}

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()
{
    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 )
        {
        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\n", getenv("VESPA_TENANT"), getenv("VESPA_APPLICATION"), getenv("VESPA_INSTANCE"));
            fclose(fp);
            rename(tmpPath.c_str(), path.c_str());
        }
    }
    if (config.clientName.size() == 0 ||
        config.deploymentServer.size() == 0)
    {
        childHandler.stopChild(config.splunkHome);
    } else {
        childHandler.startChild(config.splunkHome);
    }
}

void
CfHandler::check()
{
    if (_subscriber.nextConfigNow()) {
        doConfigure();
    }
}

constexpr std::chrono::milliseconds CONFIG_TIMEOUT_MS(30 * 1000);

void
CfHandler::start(const char *configId)
{
    LOG(debug, "Reading configuration with id '%s'", configId);
    try {
        subscribe(configId, CONFIG_TIMEOUT_MS);
    } catch (config::ConfigTimeoutException & ex) {
        LOG(warning, "Timout getting config, please check your setup. Will exit and restart: %s", ex.getMessage().c_str());
        exit(EXIT_FAILURE);
    } catch (config::InvalidConfigException& ex) {
        LOG(error, "Fatal: Invalid configuration, please check your setup: %s", ex.getMessage().c_str());
        exit(EXIT_FAILURE);
    } catch (config::ConfigRuntimeException& ex) {
        LOG(error, "Fatal: Could not get config, please check your setup: %s", ex.getMessage().c_str());
        exit(EXIT_FAILURE);
    }
}