<commit_before>/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
/*
 * Main implementation for OVS agent
 *
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

#include <opflexagent/Agent.h>
#include <opflexagent/logging.h>
#include <opflexagent/cmd.h>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filter/line.hpp>

#include <string>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

#include <csignal>
#include <string.h>

using std::string;
namespace po = boost::program_options;
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
using namespace opflexagent;

#define DEFAULT_CONF SYSCONFDIR"/opflex-agent-ovs/opflex-agent-ovs.conf"

class strip_comments : public boost::iostreams::line_filter {
private:
    std::string do_filter(const std::string& line) {
        // for now we only support comments that begin the line
        auto trimmed = line;
        boost::trim(trimmed);
        if (boost::starts_with(trimmed, "#") ||
            boost::starts_with(trimmed, "//")) {
            return std::string();
        }
        return line;
    }
};

static void readConfig(Agent& agent, string configFile) {
    pt::ptree properties;

    LOG(INFO) << "Reading configuration from " << configFile;

    std::ifstream file(configFile, std::ios_base::in | std::ios_base::binary);
    boost::iostreams::filtering_streambuf<boost::iostreams::input> inbuf;
    inbuf.push(strip_comments());
    inbuf.push(file);
    std::istream instream(&inbuf);

    try {
        pt::read_json(instream, properties);
    } catch (pt::json_parser_error& e) {
        LOG(ERROR) << "Error parsing config file: " << configFile << "("
                   << e.line() << "): " << e.message();
        throw e;
    }
    agent.setProperties(properties);
}

bool isConfigPath(const fs::path& file) {
    const string fstr = file.filename().string();
    if (boost::algorithm::ends_with(fstr, ".conf") &&
        !boost::algorithm::starts_with(fstr, ".")) {
        return true;
    }

    return false;
}

class AgentLauncher : FSWatcher::Watcher {
public:
    AgentLauncher(bool watch_, std::vector<string>& configFiles_)
        : watch(watch_), configFiles(configFiles_),
          stopped(false), need_reload(false) {}

    int run() {
        try {
            FSWatcher configWatcher;

            addWatches(configWatcher);
            configWatcher.setInitialScan(false);
            configWatcher.start();

            while (true) {
                std::unique_lock<std::mutex> lock(mutex);
                opflex::ofcore::OFFramework framework;
                Agent agent(framework);

                configure(agent);
                agent.start();

                cond.wait(lock, [this]{ return stopped || need_reload; });
                if (!stopped && need_reload) {
                    LOG(INFO) << "Reloading agent because of " <<
                        "configuration update";
                }

                agent.stop();

                if (stopped) {
                    return 0;
                }
                need_reload = false;
            }

            configWatcher.stop();
        } catch (pt::json_parser_error& e) {
            return 4;
        } catch (const std::exception& e) {
            LOG(ERROR) << "Fatal error: " << e.what();
            return 2;
        } catch (...) {
            LOG(ERROR) << "Unknown fatal error";
            return 3;
        }
        // unreachable
        return 0;
    }

    virtual void updated(const boost::filesystem::path& filePath) {
        if (!isConfigPath(filePath))
            return;

        {
            std::unique_lock<std::mutex> lock(mutex);
            need_reload = true;
        }
        cond.notify_all();
    }

    virtual void deleted(const boost::filesystem::path& filePath) {
        updated(filePath);
    }

    void stop() {
        {
            std::unique_lock<std::mutex> lock(mutex);
            stopped = true;
        }
        cond.notify_all();
    }

private:
    bool watch;
    std::vector<string>& configFiles;

    bool stopped;
    bool need_reload;
    std::mutex mutex;
    std::condition_variable cond;

    void addWatches(FSWatcher& configWatcher) {
        if (!watch) return;
        for (const string& configFile : configFiles) {
            if (fs::is_directory(configFile)) {
                LOG(INFO) << "Watching configuration directory "
                          << configFile << " for changes";
                configWatcher.addWatch(configFile, *this);
            }
        }
    }

    void configure(Agent& agent) {
        for (const string& configFile : configFiles) {
            if (fs::is_directory(configFile)) {
                LOG(INFO) << "Reading configuration from config directory "
                          << configFile;

                fs::directory_iterator end;
                std::set<string> files;
                for (fs::directory_iterator it(configFile);
                     it != end; ++it) {
                    if (isConfigPath(it->path())) {
                        files.insert(it->path().string());
                    }
                }
                for (const std::string& fstr : files) {
                    readConfig(agent, fstr);
                }
            } else {
                readConfig(agent, configFile);
            }
        }

        agent.applyProperties();
    }
};

int main(int argc, char** argv) {
    signal(SIGPIPE, SIG_IGN);<commit_msg>Reload OpflexAgent based on the signal in OVS boot-up sequence (through reboot.conf file write)<commit_after>/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
/*
 * Main implementation for OVS agent
 *
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

#include <opflexagent/Agent.h>
#include <opflexagent/logging.h>
#include <opflexagent/cmd.h>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/filter/line.hpp>

#include <string>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

#include <csignal>
#include <string.h>

using std::string;
namespace po = boost::program_options;
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
using namespace opflexagent;

#define DEFAULT_CONF SYSCONFDIR"/opflex-agent-ovs/opflex-agent-ovs.conf"

class strip_comments : public boost::iostreams::line_filter {
private:
    std::string do_filter(const std::string& line) {
        // for now we only support comments that begin the line
        auto trimmed = line;
        boost::trim(trimmed);
        if (boost::starts_with(trimmed, "#") ||
            boost::starts_with(trimmed, "//")) {
            return std::string();
        }
        return line;
    }
};

static void readConfig(Agent& agent, string configFile) {
    pt::ptree properties;

    LOG(INFO) << "Reading configuration from " << configFile;

    std::ifstream file(configFile, std::ios_base::in | std::ios_base::binary);
    boost::iostreams::filtering_streambuf<boost::iostreams::input> inbuf;
    inbuf.push(strip_comments());
    inbuf.push(file);
    std::istream instream(&inbuf);

    try {
        pt::read_json(instream, properties);
    } catch (pt::json_parser_error& e) {
        LOG(ERROR) << "Error parsing config file: " << configFile << "("
                   << e.line() << "): " << e.message();
        throw e;
    }
    agent.setProperties(properties);
}

bool isConfigPath(const fs::path& file) {
    const string fstr = file.filename().string();
    if (boost::algorithm::ends_with(fstr, ".conf") &&
        !boost::algorithm::starts_with(fstr, ".")) {
        return true;
    }

    return false;
}

bool isRebootConfigPath(const fs::path& file) {
    const string fstr = file.filename().string();
    if (boost::algorithm::ends_with(fstr, ".conf") &&
        boost::algorithm::starts_with(fstr, "reboot")) {
        LOG(INFO) << "Config filename: " << fstr;
        return true;
    }
    return false;
}

class AgentLauncher : FSWatcher::Watcher {
public:
    AgentLauncher(bool watch_, std::vector<string>& configFiles_)
        : watch(watch_), configFiles(configFiles_),
          stopped(false), need_reload(false) {}

    int run() {
        try {
            FSWatcher configWatcher;

            addWatches(configWatcher);
            configWatcher.setInitialScan(false);
            configWatcher.start();

            while (true) {
                std::unique_lock<std::mutex> lock(mutex);
                opflex::ofcore::OFFramework framework;
                Agent agent(framework);

                configure(agent);
                agent.start();

                cond.wait(lock, [this]{ return stopped || need_reload; });
                if (!stopped && need_reload) {
                    LOG(INFO) << "Reloading agent because of " <<
                        "configuration update";
                }

                agent.stop();

                if (stopped) {
                    return 0;
                }
                need_reload = false;
            }

            configWatcher.stop();
        } catch (pt::json_parser_error& e) {
            return 4;
        } catch (const std::exception& e) {
            LOG(ERROR) << "Fatal error: " << e.what();
            return 2;
        } catch (...) {
            LOG(ERROR) << "Unknown fatal error";
            return 3;
        }
        // unreachable
        return 0;
    }

    virtual void updated(const boost::filesystem::path& filePath) {
        if (!isConfigPath(filePath))
            return;

        {
            std::unique_lock<std::mutex> lock(mutex);
            need_reload = true;
        }
        cond.notify_all();
    }

    virtual void deleted(const boost::filesystem::path& filePath) {
        updated(filePath);
    }

    void stop() {
        {
            std::unique_lock<std::mutex> lock(mutex);
            stopped = true;
        }
        cond.notify_all();
    }

private:
    bool watch;
    std::vector<string>& configFiles;

    bool stopped;
    bool need_reload;
    std::mutex mutex;
    std::condition_variable cond;

    void addWatches(FSWatcher& configWatcher) {
        if (!watch) return;
        for (const string& configFile : configFiles) {
            if (fs::is_directory(configFile)) {
                LOG(INFO) << "Watching configuration directory "
                          << configFile << " for changes";
                configWatcher.addWatch(configFile, *this);
            }
        }
    }

    void configure(Agent& agent) {
        for (const string& configFile : configFiles) {
            if (fs::is_directory(configFile)) {
                LOG(INFO) << "Reading configuration from config directory "
                          << configFile;

                fs::directory_iterator end;
                std::set<string> files;
                for (fs::directory_iterator it(configFile);
                     it != end; ++it) {
                    if (isConfigPath(it->path()) && !isRebootConfigPath(it->path())) {
                        files.insert(it->path().string());
                    }
                }
                for (const std::string& fstr : files) {
                    readConfig(agent, fstr);
                }
            } else {
                readConfig(agent, configFile);
            }
        }

        agent.applyProperties();
    }
};

int main(int argc, char** argv) {
    signal(SIGPIPE, SIG_IGN);
{'fraction_non_alphanumeric': 0.12804292120435617, 'fraction_numerical': 0.002242152466367713, 'mean_word_length': 2.132430398796087, 'pattern_counts': {'":': 0, '<': 129, '<?xml version=': 0, '>': 58, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4487046', 'n_tokens_mistral': 3664, 'n_tokens_neox': 3517, 'n_words': 784}