From 44dfcb7c6a35dc14236efcd12f08fe03fdd6d005 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Tue, 29 May 2018 14:07:26 -0700 Subject: [PATCH] Start clusterizing configuration framework. This is not finished and currently does not work due Broker not liking to serialize into any types. --- scripts/base/frameworks/config/input.bro | 6 +- scripts/base/frameworks/config/main.bro | 60 ++++++++++++++++++ .../base/frameworks/config/basic_cluster.bro | 61 +++++++++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 testing/btest/scripts/base/frameworks/config/basic_cluster.bro diff --git a/scripts/base/frameworks/config/input.bro b/scripts/base/frameworks/config/input.bro index 87acb50065..aaef2e59b1 100644 --- a/scripts/base/frameworks/config/input.bro +++ b/scripts/base/frameworks/config/input.bro @@ -54,12 +54,14 @@ event InputConfig::new_value(name: string, source: string, id: string, value: an { if ( sub_bytes(name, 1, 15) != "config-oneshot-" && source !in config_files ) return; - - Option::set(id, value, source); + + Config::set_value(id, value, source); } function read_config(filename: string) { + # Only read the configuration on the manager. The other nodes are being fed from + # the manager. if ( Cluster::is_enabled() && Cluster::local_node_type() != Cluster::MANAGER ) return; diff --git a/scripts/base/frameworks/config/main.bro b/scripts/base/frameworks/config/main.bro index ffd9e764ef..c93271efa1 100644 --- a/scripts/base/frameworks/config/main.bro +++ b/scripts/base/frameworks/config/main.bro @@ -2,6 +2,8 @@ ##! (as specified by the "option" keyword) at runtime. It also logs runtime ##! changes to options to config.log. +@load base/frameworks/cluster + module Config; export { @@ -25,8 +27,63 @@ export { ## Event that can be handled to access the :bro:type:`Config::Info` ## record as it is sent on to the logging framework. global log_config: event(rec: Info); + + ## Broker topic for announcing new configuration value. Sending new_value, + ## peers can send configuration changes that will be distributed accross + ## the entire cluster. + const change_topic = "bro/config/change"; + + ## This function is the config framework layer around the lower-level + ## :bro:see:`Option::set` call. Config::set_value will set the configuration + ## value for all nodes in the cluster, no matter where it was called. Note + ## that `bro:see:`Option::set` does not distribute configuration changes + ## to other nodes. + ## + ## ID: The ID of the option to update. + ## + ## val: The new value of the option. + ## + ## location: Optional parameter detailing where this change originated from. + ## + ## Returns: true on success, false when an error ocured. + global set_value: function(ID: string, val: any, location: string &default = "" &optional): bool; } +@if ( Cluster::is_enabled() ) +event bro_init() + { + Broker::subscribe(change_topic); + } + +event Config::cluster_set_option(ID: string, val: any, location: string) + { + Option::set(ID, val, location); + } + +function set_value(ID: string, val: any, location: string &default = "" &optional): bool + { + # First try setting it locally - abort if not possible. + if ( ! Option::set(ID, val, location) ) + { + return F; + } + # If it turns out that it is possible - send it to everyone else to apply. + Broker::publish(change_topic, Config::cluster_set_option, ID, val, location); + if ( Cluster::local_node_type() != Cluster::MANAGER ) + { + Broker::relay(change_topic, change_topic, Config::cluster_set_option, ID, val, location); + } + return T; + } +@else + # Standalone implementation + function set_value(ID: string, val: any, location: string &default = "" &optional): bool + { + return Option::set(ID, val, location); + } +@endif + + function format_value(value: any) : string { local tn = type_name(value); @@ -64,6 +121,8 @@ event bro_init() &priority=10 { Log::create_stream(LOG, [$columns=Info, $ev=log_config, $path="config"]); + # Limit logging to the manager - everyone else just feeds off it. +@if ( !Cluster::is_enabled() || Cluster::local_node_type() == Cluster::MANAGER ) # Iterate over all existing options and add ourselves as change handlers with # a low priority so that we can log the changes. local gids = global_ids(); @@ -74,4 +133,5 @@ event bro_init() &priority=10 Option::set_change_handler(i, config_option_changed, -100); } +@endif } diff --git a/testing/btest/scripts/base/frameworks/config/basic_cluster.bro b/testing/btest/scripts/base/frameworks/config/basic_cluster.bro new file mode 100644 index 0000000000..8882c6d66a --- /dev/null +++ b/testing/btest/scripts/base/frameworks/config/basic_cluster.bro @@ -0,0 +1,61 @@ +# @TEST-EXEC: btest-bg-run manager-1 BROPATH=$BROPATH:.. CLUSTER_NODE=manager-1 bro %INPUT +# @TEST-EXEC: sleep 1 +# @TEST-EXEC: btest-bg-run worker-1 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-1 bro %INPUT +# @TEST-EXEC: btest-bg-run worker-2 BROPATH=$BROPATH:.. CLUSTER_NODE=worker-2 bro %INPUT +# @TEST-EXEC: btest-bg-wait 10 + +@load base/frameworks/config + + +@TEST-START-FILE cluster-layout.bro +redef Cluster::nodes = { + ["manager-1"] = [$node_type=Cluster::MANAGER, $ip=127.0.0.1, $p=37757/tcp], + ["worker-1"] = [$node_type=Cluster::WORKER, $ip=127.0.0.1, $p=37760/tcp, $manager="manager-1", $interface="eth0"], + ["worker-2"] = [$node_type=Cluster::WORKER, $ip=127.0.0.1, $p=37761/tcp, $manager="manager-1", $interface="eth1"], +}; +@TEST-END-FILE + +redef Log::default_rotation_interval = 0secs; + +export { + option testport = 42/tcp; + option teststring = "a"; +} + +global n = 0; + +event bro_init() &priority=5 + { + } + +event Broker::peer_lost(endpoint: Broker::EndpointInfo, msg: string) + { + terminate(); + } + +global ready_for_data: event(); + +event bro_init() + { + Broker::auto_publish(Cluster::worker_topic, ready_for_data); + } + +@if ( Cluster::node == "worker-1" ) +event ready_for_data() + { + Config::set_value("testport", 44/tcp); + Config::set_value("teststring", "b", "comment"); + } +@endif + +@if ( Cluster::local_node_type() == Cluster::MANAGER ) + +global peer_count = 0; +event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string) + { + ++peer_count; + if ( peer_count == 2 ) + event ready_for_data(); + } + +@endif