[asterisk-scf-commits] asterisk-scf/integration/configurator.git branch "master" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Fri Feb 18 07:01:51 CST 2011


branch "master" has been created
        at  1e20913bf7364a4f91beadc7e94934472a55204a (commit)

- Log -----------------------------------------------------------------
commit 1e20913bf7364a4f91beadc7e94934472a55204a
Author: Joshua Colp <jcolp at digium.com>
Date:   Fri Feb 18 09:01:30 2011 -0400

    Add Configurator python module with example.

diff --git a/Configurator.py b/Configurator.py
new file mode 100755
index 0000000..04061bf
--- /dev/null
+++ b/Configurator.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+
+# Asterisk SCF Configurator Module
+
+import ConfigParser, os, Ice, getopt
+
+# Load and make the configuration interface available, we require it
+Ice.loadSlice('-I. --all ConfigurationIf.ice')
+import AsteriskSCF.System.Configuration.V1
+
+# Exception class used within the configurator application
+class ConfiguratorError(Exception):
+    def __init__(self, value):
+        self.value = value
+
+    def __str__(self):
+        return repr(self.value)
+
+# Common section visitor pattern implementation
+class SectionVisitors():
+    def __init__(self):
+        """Generic class meant to be inherited from for section visitors"""
+        self.groups = []
+
+    def visit(self, config, section):
+        """Execute the visit_ function corresponding to the section name"""
+        try:
+            method = getattr(self, 'visit_' + section)
+        except AttributeError:
+            self.visit_unsupported(config, section)
+        else:
+            method(config, section);
+
+    def visit_unsupported(self, config, section):
+        """Handle an unsupported configuration section"""
+        print "Unsupported configuration section " + section
+
+# Common option to item mapper implementation
+class OptionMapper():
+    options = { }
+
+    def __init(self):
+        """Generic class meant to perform option to item mapping"""
+        self.options = { }
+
+    def map(self, option, item, item_name, method, default = None):
+        item = default
+        self.options[option] = [ item, item_name, method, default ]
+
+    def execute(self, group, section, option):
+        """Map options to configuration items based on options set"""
+        item = self.options[option][0]
+        item_name = self.options[option][1]
+        method = self.options[option][2]
+        default = self.options[option][3]
+
+        try:
+            item = method(section, option)
+
+        except ValueError:
+            # This is not a fatal error since we just use the default value.
+            if default == None:
+                print "The specified value for option '" + option + "' is not valid and no default value exists."
+            else:
+                print "The specified value for option '" + option + "' is not valid. Using default value."
+                item = default
+
+        # This has the potential to overwrite an existing item but this is done on purpose so that
+        # configuration options that all map to a single item can happily exist
+        if item != None:
+            group.configurationItems[item_name] = item
+
+    def finish(self, group):
+        """Finish mapping options by finding ones that should have a value but do not"""
+        for option in self.options:
+            item = self.options[option][0]
+            default = self.options[option][3]
+            if default == None:
+                if item == None:
+                    print "Option '" + option + "' requires a value to be set and no default value exists."
+
+# Common configurator application logic
+class ConfiguratorApp(Ice.Application):
+    def __init__(self, defaultConfigFile, visitor, configurationService = None):
+        """Common configuration utility class"""
+
+        if defaultConfigFile == '':
+            raise ConfiguratorError('Configuration utility implementation issue - No default configuration filename specified.')
+
+        self.defaultConfigFile = defaultConfigFile
+        self.visitor = visitor
+        self.configurationService = configurationService
+
+    def usage(self):
+        """Print usage information for the configuration utility"""
+
+        print "Usage: " + self.appName() + " [--config=filename] [--proxy=stringified configuration service proxy] [--wipe]"
+        print "Push a configuration to a component."
+        print ""
+        print "Mandatory arguments to long options are mandatory for short options too."
+        print "-h, --help              display help information"
+        print "-c, --config=FILENAME   use specified configuration file instead of " + self.defaultConfigFile
+        print "-p, --proxy=PROXY       use specified proxy instead of locating component"
+        print "-w, --wipe              remove existing configuration before applying new one"
+
+    def run(self, args):
+        """Parse options, read configuration file, produce configuration data, and submit it"""
+
+        try:
+            opts, arguments = getopt.getopt(args[1:], "hc:p:w", ["help", "config=", "proxy=", "wipe"])
+        except getopt.GetoptError, err:
+            print str(err)
+            self.usage()
+            return 1
+
+        configFile = self.defaultConfigFile
+        configurationService = self.configurationService
+        configurationWipe = False
+
+        for o, a in opts:
+            if o in ("-h", "--help"):
+                self.usage()
+                return 1
+
+            elif o in ("-c", "--config"):
+                configFile = a
+
+            elif o in ("-p", "--proxy"):
+                configurationService = AsteriskSCF.System.Configuration.V1.ConfigurationServicePrx.uncheckedCast(self.communicator().stringToProxy(a))
+
+            elif o in ("-w", "--wipe"):
+                configurationWipe = True
+
+        if configurationService == None:
+            print "No configuration service to configure."
+            return 0
+
+        print "Reading configuration from file " + configFile
+        config = ConfigParser.ConfigParser()
+
+        # This purposely uses open and readfp so that the file is required to be present
+        try:
+            config.readfp(open(configFile))
+        except IOError:
+            print "Specified configuration file " + configFile + " could not be loaded."
+            return 0
+
+        print "Building configuration changes to send to component"
+        for section in config.sections():
+            self.visitor.visit(config, section)
+
+        if self.visitor.groups:
+            if configurationWipe == True:
+                print "Wiping existing configuration before applying changes"
+                # There is a race condition here where another component could modify the groups present, but if two
+                # components are altering the configuration we are best effort to begin with
+                try:
+                    groups = configurationService.getConfigurationGroups()
+                    configurationService.removeConfigurationGroups(groups)
+                except:
+                    print "Configuration could not be wiped - Failed to contact component"
+                    return 0
+
+            print "Applying configuration"
+
+            try:
+                configurationService.setConfiguration(self.visitor.groups)
+                print "Configuration applied"
+            except:
+                print "Configuration could not be applied - Failed to contact component"
+
+        else:
+            print "No configuration to apply"
+
+        return 0
diff --git a/Example.config b/Example.config
new file mode 100644
index 0000000..9ca996e
--- /dev/null
+++ b/Example.config
@@ -0,0 +1,9 @@
+[general]
+enable=yes
+instances=10
+
+[network]
+ipv6=never ever
+ipv4=yes
+
+[bob]
diff --git a/ExampleConfigurationIf.ice b/ExampleConfigurationIf.ice
new file mode 100644
index 0000000..422deba
--- /dev/null
+++ b/ExampleConfigurationIf.ice
@@ -0,0 +1,71 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+
+#pragma once
+
+#include "ConfigurationIf.ice"
+
+module AsteriskSCF
+{
+
+module System
+{
+
+module Configuration
+{
+
+module Example
+{
+
+["suppress"]
+module V1
+{
+
+   /* General configuration group for items that do not belong in any specific group */
+   class GeneralGroup extends AsteriskSCF::System::Configuration::V1::ConfigurationGroup
+   {
+   };
+
+   /* Network configuration group for network specific items */
+   class NetworkGroup extends AsteriskSCF::System::Configuration::V1::ConfigurationGroup
+   {
+   };
+
+   /* Simple enable and disable item */
+   class EnableItem extends AsteriskSCF::System::Configuration::V1::ConfigurationItem
+   {
+      bool enabled;
+   };
+
+   /* Instance information item */
+   class InstanceInfoItem extends AsteriskSCF::System::Configuration::V1::ConfigurationItem
+   {
+      /* Name of the instances */
+      string name;
+
+      /* How many there should be */
+      int num;
+   };
+
+}; /* End of namespace V1 */
+
+}; /* End of namespace Example */
+
+}; /* End of namespace Configuration */
+
+}; /* End of namespace System */
+
+}; /* End of namespace AsteriskSCF */
diff --git a/ExampleConfigurator.py b/ExampleConfigurator.py
new file mode 100755
index 0000000..bf53cdb
--- /dev/null
+++ b/ExampleConfigurator.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+# Example configurator
+
+# Bring in the common configuration infrastructure
+import Ice, Configurator, sys
+
+# Load our component specific configuration definitions
+Ice.loadSlice('-I. --all ExampleConfigurationIf.ice')
+import AsteriskSCF.System.Configuration.Example.V1
+
+# Add our own visitor implementations for the sections we support
+class ExampleSectionVisitors(Configurator.SectionVisitors):
+    def visit_general(self, config, section):
+        # Create the general group where items from this section will go
+        group = AsteriskSCF.System.Configuration.Example.V1.GeneralGroup()
+        group.configurationItems = { }
+
+        # Create an option mapper and make it aware of the options and their mappings
+        mapper = Configurator.OptionMapper()
+
+        # Enable is easy
+        mapper.map('enable',  AsteriskSCF.System.Configuration.Example.V1.EnableItem().enabled, 'enabled', config.getboolean, False)
+
+        # What will be the name and how many of them?
+        item = AsteriskSCF.System.Configuration.Example.V1.InstanceInfoItem()
+        mapper.map('name', item.name, 'instance_info', config.get, None)
+        mapper.map('instances', item.num, 'instance_info', config.getint, 1)
+
+        # Map all the options to the corresponding items and stuff them in the group!
+        for option in config.options(section):
+            mapper.execute(group, section, option)
+        mapper.finish(group)
+
+        # Add the general group to the groups that will be pushed to the component
+        self.groups.append(group)
+
+    def visit_network(self, config, section):
+        # Create the network group where items from this section will go
+        group = AsteriskSCF.System.Configuration.Example.V1.NetworkGroup()
+        group.configurationItems = { }
+
+        # Create an option mapper, put our options in, and map them
+        mapper = Configurator.OptionMapper()
+        mapper.map('ipv4', AsteriskSCF.System.Configuration.Example.V1.EnableItem().enabled, 'ipv4_enabled', config.getboolean, False)
+        mapper.map('ipv6', AsteriskSCF.System.Configuration.Example.V1.EnableItem().enabled, 'ipv6_enabled', config.getboolean, False)
+        for option in config.options(section):
+            mapper.execute(group, section, option)
+
+        mapper.finish(group)
+
+        # Add the network group to the groups that will be pushed to the component
+        self.groups.append(group)
+
+    def visit_unsupported(self, config, section):
+        # If this function is not defined then the configurator will simply print an unsupported option message
+        print "Have unsupported option, should I create some sort of endpoint?"
+
+# Make a configurator application and let it run
+app = Configurator.ConfiguratorApp('Example.config', ExampleSectionVisitors())
+sys.exit(app.main(sys.argv))

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/configurator.git



More information about the asterisk-scf-commits mailing list