[svn] commit: r296 - in /branches/jelte-datadef/src: bin/parkinglot/ lib/bind-cfgd/python/ lib/cc/cpp/
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Nov 18 10:12:32 UTC 2009
Author: jelte
Date: Wed Nov 18 10:12:32 2009
New Revision: 296
Log:
added datadefinition checking to the DataDefinition class, throw DataDefinitionError when that fails
first argument of group_sendmsg() is now const
parkinglot now reads a parkinglot.spec file and tries to send it to the config manager (which currently fails somewhere in the msgq), file is read from cwd for now (i.e. the bin/bind10/bind10 dir)
Modified:
branches/jelte-datadef/src/bin/parkinglot/ccsession.cc
branches/jelte-datadef/src/bin/parkinglot/ccsession.h
branches/jelte-datadef/src/lib/bind-cfgd/python/bind-cfgd.py
branches/jelte-datadef/src/lib/cc/cpp/Makefile.am
branches/jelte-datadef/src/lib/cc/cpp/data_def.cc
branches/jelte-datadef/src/lib/cc/cpp/data_def.h
branches/jelte-datadef/src/lib/cc/cpp/parkinglot.spec
branches/jelte-datadef/src/lib/cc/cpp/session.cc
branches/jelte-datadef/src/lib/cc/cpp/session.h
branches/jelte-datadef/src/lib/cc/cpp/test.cc
Modified: branches/jelte-datadef/src/bin/parkinglot/ccsession.cc
==============================================================================
--- branches/jelte-datadef/src/bin/parkinglot/ccsession.cc (original)
+++ branches/jelte-datadef/src/bin/parkinglot/ccsession.cc Wed Nov 18 10:12:32 2009
@@ -14,17 +14,26 @@
// $Id$
+//
+// todo: generalize this and make it into a specific API for all modules
+// to use (i.e. connect to cc, send config and commands, get config,
+// react on config change announcements)
+//
+
+
#include <stdexcept>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <iostream>
+#include <fstream>
#include <sstream>
#include <boost/foreach.hpp>
#include <cc/cpp/data.h>
+#include <cc/cpp/data_def.h>
#include <cc/cpp/session.h>
#include "common.h"
@@ -34,16 +43,53 @@
using ISC::Data::Element;
using ISC::Data::ElementPtr;
+using ISC::Data::DataDefinition;
+using ISC::Data::ParseError;
+using ISC::Data::DataDefinitionError;
+
+void
+CommandSession::read_data_definition(const std::string& filename) {
+ std::ifstream file;
+
+ // this file should be declared in a @something@ directive
+ file.open("parkinglot.spec");
+ if (!file) {
+ cout << "error opening parkinglot.spec" << endl;
+ exit(1);
+ }
+
+ try {
+ data_definition_ = DataDefinition(file, true);
+ cout << "Definition: " << endl;
+ cout << data_definition_.getDefinition() << endl;
+ } catch (ParseError pe) {
+ cout << "Error parsing definition file: " << pe.what() << endl;
+ exit(1);
+ } catch (DataDefinitionError dde) {
+ cout << "Error reading definition file: " << dde.what() << endl;
+ exit(1);
+ }
+ file.close();
+}
CommandSession::CommandSession() :
session_(ISC::CC::Session())
{
try {
+ // todo: workaround, let boss wait until msgq is started
+ // and remove sleep here
+ sleep(1);
session_.establish();
session_.subscribe("ParkingLot", "*", "meonly");
session_.subscribe("Boss", "*", "meonly");
session_.subscribe("ConfigManager", "*", "meonly");
session_.subscribe("statistics", "*", "meonly");
+ read_data_definition("parkinglot.spec");
+ sleep(1);
+ ElementPtr cmd = Element::create_from_string("{ \"config_manager\": 1}");
+ // why does the msgq seem to kill this msg?
+ session_.group_sendmsg(data_definition_.getDefinition(), "ConfigManager");
+ cout << "def sent" << endl;
} catch (...) {
throw std::runtime_error("SessionManager: failed to open sessions");
}
@@ -88,12 +134,12 @@
return std::pair<string, string>("unknown", "");
}
+// should be replaced by the general config-getter in cc setup
std::vector<std::string>
CommandSession::getZones() {
ElementPtr cmd, result, env;
std::vector<std::string> zone_names;
cmd = Element::create_from_string("{ \"command\": [ \"zone\", \"list\" ] }");
- sleep(1);
session_.group_sendmsg(cmd, "ConfigManager");
session_.group_recvmsg(env, result, false);
BOOST_FOREACH(ElementPtr zone_name, result->get("result")->list_value()) {
Modified: branches/jelte-datadef/src/bin/parkinglot/ccsession.h
==============================================================================
--- branches/jelte-datadef/src/bin/parkinglot/ccsession.h (original)
+++ branches/jelte-datadef/src/bin/parkinglot/ccsession.h Wed Nov 18 10:12:32 2009
@@ -20,6 +20,8 @@
#include <string>
#include <cc/cpp/session.h>
+#include <cc/cpp/data_def.h>
+#include <cc/cpp/data.h>
class CommandSession {
public:
@@ -28,7 +30,11 @@
std::pair<std::string, std::string> getCommand(int counter);
std::vector<std::string> getZones();
private:
+ void read_data_definition(const std::string& filename);
+
ISC::CC::Session session_;
+ ISC::Data::DataDefinition data_definition_;
+ ISC::Data::ElementPtr config_;
};
#endif // __CCSESSION_H
Modified: branches/jelte-datadef/src/lib/bind-cfgd/python/bind-cfgd.py
==============================================================================
--- branches/jelte-datadef/src/lib/bind-cfgd/python/bind-cfgd.py (original)
+++ branches/jelte-datadef/src/lib/bind-cfgd/python/bind-cfgd.py Wed Nov 18 10:12:32 2009
@@ -112,7 +112,6 @@
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
cm.read_config()
- # do loading here if necessary
cm.notify_boss()
cm.run()
cm.write_config()
Modified: branches/jelte-datadef/src/lib/cc/cpp/Makefile.am
==============================================================================
--- branches/jelte-datadef/src/lib/cc/cpp/Makefile.am (original)
+++ branches/jelte-datadef/src/lib/cc/cpp/Makefile.am Wed Nov 18 10:12:32 2009
@@ -1,4 +1,4 @@
-AM_CPPFLAGS = -I$(top_srcdir)/src/lib/cc/cpp -I$(top_srcdir)/ext
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib/cc/cpp -I$(top_srcdir)/ext -Wall -Werror
bin_PROGRAMS = test
test_SOURCES = test.cc
Modified: branches/jelte-datadef/src/lib/cc/cpp/data_def.cc
==============================================================================
--- branches/jelte-datadef/src/lib/cc/cpp/data_def.cc (original)
+++ branches/jelte-datadef/src/lib/cc/cpp/data_def.cc Wed Nov 18 10:12:32 2009
@@ -5,14 +5,150 @@
#include <boost/foreach.hpp>
+// todo: add more context to thrown DataDefinitionErrors?
using namespace ISC::Data;
-DataDefinition::DataDefinition(std::istream& in) throw(ParseError) {
+// todo: is there a direct way to get a std::string from an enum label?
+static std::string
+get_type_string(Element::types type)
+{
+ switch(type) {
+ case Element::integer:
+ return std::string("integer");
+ case Element::real:
+ return std::string("real");
+ case Element::boolean:
+ return std::string("boolean");
+ case Element::string:
+ return std::string("string");
+ case Element::list:
+ return std::string("list");
+ case Element::map:
+ return std::string("map");
+ default:
+ return std::string("unknown");
+ }
+}
+
+static Element::types
+get_type_value(const std::string& type_name) {
+ if (type_name == "integer") {
+ return Element::integer;
+ } else if (type_name == "real") {
+ return Element::real;
+ } else if (type_name == "boolean") {
+ return Element::boolean;
+ } else if (type_name == "string") {
+ return Element::string;
+ } else if (type_name == "list") {
+ return Element::list;
+ } else if (type_name == "map") {
+ return Element::map;
+ } else {
+ throw DataDefinitionError(type_name + " is not a valid type name");
+ }
+}
+
+static void
+check_leaf_item(const ElementPtr& spec, const std::string& name, Element::types type, bool mandatory)
+{
+ if (spec->contains(name)) {
+ if (spec->get(name)->get_type() == type) {
+ return;
+ } else {
+ throw DataDefinitionError(name + " not of type " + get_type_string(type));
+ }
+ } else if (mandatory) {
+ // todo: want parent item name, and perhaps some info about location
+ // in list? or just catch and throw new...
+ // or make this part non-throwing and check return value...
+ throw DataDefinitionError(name + " missing in " + spec->str());
+ }
+}
+
+static void check_config_item_list(const ElementPtr& spec);
+
+static void
+check_config_item(const ElementPtr& spec) {
+ check_leaf_item(spec, "item_name", Element::string, true);
+ check_leaf_item(spec, "item_type", Element::string, true);
+ check_leaf_item(spec, "item_optional", Element::boolean, true);
+ check_leaf_item(spec, "item_default",
+ get_type_value(spec->get("item_type")->string_value()),
+ !spec->get("item_optional")->bool_value()
+ );
+
+ // if list, check the list definition
+ if (get_type_value(spec->get("item_type")->string_value()) == Element::list) {
+ check_leaf_item(spec, "list_item_spec", Element::map, true);
+ check_config_item(spec->get("list_item_spec"));
+ }
+ // todo: add stuff for type map
+ if (get_type_value(spec->get("item_type")->string_value()) == Element::map) {
+ check_leaf_item(spec, "map_item_spec", Element::list, true);
+ check_config_item_list(spec);
+ }
+}
+
+static void
+check_config_item_list(const ElementPtr& spec) {
+ if (spec->get_type() != Element::list) {
+ throw DataDefinitionError("config_data is not a list of elements");
+ }
+ BOOST_FOREACH(ElementPtr item, spec->list_value()) {
+ check_config_item(item);
+ }
+}
+
+static void
+check_command(const ElementPtr& spec) {
+ check_leaf_item(spec, "command_name", Element::string, true);
+ check_leaf_item(spec, "command_args", Element::list, true);
+ check_config_item_list(spec->get("command_args"));
+}
+
+static void
+check_command_list(const ElementPtr& spec) {
+ if (spec->get_type() != Element::list) {
+ throw DataDefinitionError("commands is not a list of elements");
+ }
+ BOOST_FOREACH(ElementPtr item, spec->list_value()) {
+ check_command(item);
+ }
+}
+
+static void
+check_data_specification(const ElementPtr& spec) {
+ check_leaf_item(spec, "module_name", Element::string, true);
+ // not mandatory; module could just define commands and have
+ // no config
+ if (spec->contains("config_data")) {
+ check_config_item_list(spec->get("config_data"));
+ }
+ if (spec->contains("commands")) {
+ check_command_list(spec->get("commands"));
+ }
+}
+
+// checks whether the given element is a valid data definition
+// throws a DataDefinitionError if the specification is bad
+static void
+check_definition(const ElementPtr& def)
+{
+ if (!def->contains("data_specification")) {
+ throw DataDefinitionError("Data specification does not contain data_specification element");
+ } else {
+ check_data_specification(def->get("data_specification"));
+ }
+}
+
+DataDefinition::DataDefinition(std::istream& in, const bool check)
+ throw(ParseError, DataDefinitionError) {
definition = Element::create_from_string(in);
- // TODO, make sure the whole structure is complete and valid
- if (!definition->contains("data_specification")) {
- throw ParseError("Data specification does not contain data_specification element");
+ // make sure the whole structure is complete and valid
+ if (check) {
+ check_definition(definition);
}
}
@@ -100,7 +236,6 @@
DataDefinition::validate_spec_list(const ElementPtr spec, const ElementPtr data) {
ElementPtr cur_data_el;
std::string cur_item_name;
- bool optional;
BOOST_FOREACH(ElementPtr cur_spec_el, spec->list_value()) {
if (!validate_spec(cur_spec_el, data)) {
return false;
Modified: branches/jelte-datadef/src/lib/cc/cpp/data_def.h
==============================================================================
--- branches/jelte-datadef/src/lib/cc/cpp/data_def.h (original)
+++ branches/jelte-datadef/src/lib/cc/cpp/data_def.h Wed Nov 18 10:12:32 2009
@@ -7,11 +7,22 @@
namespace ISC { namespace Data {
+ class DataDefinitionError : public std::exception {
+ public:
+ DataDefinitionError(std::string m = "Data definition is invalid") : msg(m) {}
+ ~DataDefinitionError() throw() {}
+ const char* what() const throw() { return msg.c_str(); }
+ private:
+ std::string msg;
+ };
+
class DataDefinition {
public:
explicit DataDefinition() {};
explicit DataDefinition(ElementPtr e) : definition(e) {};
- explicit DataDefinition(std::istream& in) throw(ParseError);
+ // todo: make check default false, or leave out option completely and always check?
+ explicit DataDefinition(std::istream& in, const bool check = true)
+ throw(ParseError, DataDefinitionError);
const ElementPtr getDefinition() { return definition; };
// returns true if the given element conforms to this data
Modified: branches/jelte-datadef/src/lib/cc/cpp/parkinglot.spec
==============================================================================
--- branches/jelte-datadef/src/lib/cc/cpp/parkinglot.spec (original)
+++ branches/jelte-datadef/src/lib/cc/cpp/parkinglot.spec Wed Nov 18 10:12:32 2009
@@ -1,6 +1,6 @@
{
"data_specification": {
- "module_name": "parkinglot",
+ "module_name": "ParkingLot",
"config_data": [
{
"item_name": "port",
@@ -24,21 +24,21 @@
"commands": [
{
"command_name": "zone_add",
- "command_args": {
+ "command_args": [ {
"item_name": "zone_name",
"item_type": "string",
"item_optional": false,
"item_default": ""
- }
+ } ]
},
{
"command_name": "zone_delete",
- "command_args": {
+ "command_args": [ {
"item_name": "zone_name",
"item_type": "string",
"item_optional": false,
"item_default": ""
- }
+ } ]
}
]
}
Modified: branches/jelte-datadef/src/lib/cc/cpp/session.cc
==============================================================================
--- branches/jelte-datadef/src/lib/cc/cpp/session.cc (original)
+++ branches/jelte-datadef/src/lib/cc/cpp/session.cc Wed Nov 18 10:12:32 2009
@@ -138,7 +138,8 @@
}
unsigned int
-Session::group_sendmsg(ElementPtr& msg, std::string group, std::string instance, std::string to)
+Session::group_sendmsg(const ElementPtr& msg, std::string group,
+ std::string instance, std::string to)
{
ElementPtr env = Element::create(std::map<std::string, ElementPtr>());
Modified: branches/jelte-datadef/src/lib/cc/cpp/session.h
==============================================================================
--- branches/jelte-datadef/src/lib/cc/cpp/session.h (original)
+++ branches/jelte-datadef/src/lib/cc/cpp/session.h Wed Nov 18 10:12:32 2009
@@ -43,7 +43,7 @@
std::string subtype = "normal");
void unsubscribe(std::string group,
std::string instance = "*");
- unsigned int group_sendmsg(ISC::Data::ElementPtr& msg,
+ unsigned int group_sendmsg(const ISC::Data::ElementPtr& msg,
std::string group,
std::string instance = "*",
std::string to = "*");
Modified: branches/jelte-datadef/src/lib/cc/cpp/test.cc
==============================================================================
--- branches/jelte-datadef/src/lib/cc/cpp/test.cc (original)
+++ branches/jelte-datadef/src/lib/cc/cpp/test.cc Wed Nov 18 10:12:32 2009
@@ -27,6 +27,9 @@
} catch (ParseError pe) {
cout << "Error parsing definition file: " << pe.what() << endl;
return 1;
+ } catch (DataDefinitionError dde) {
+ cout << "Error reading definition file: " << dde.what() << endl;
+ return 1;
}
file.close();
More information about the bind10-changes
mailing list