[asterisk-scf-commits] asterisk-scf/release/configurator.git branch "master" created.
Commits to the Asterisk SCF project code repositories
asterisk-scf-commits at lists.digium.com
Wed Apr 20 16:58:18 CDT 2011
branch "master" has been created
at 3af0760b0e3d33267a7eaaf02c8e63a17bacc729 (commit)
- Log -----------------------------------------------------------------
commit 3af0760b0e3d33267a7eaaf02c8e63a17bacc729
Author: Joshua Colp <jcolp at digium.com>
Date: Mon Apr 11 14:47:48 2011 -0300
Tweak message so that people can know to specify --help for usage details if nothing is specified.
diff --git a/Configurator.py b/Configurator.py
index 2b1c5da..718f16a 100755
--- a/Configurator.py
+++ b/Configurator.py
@@ -153,7 +153,7 @@ class ConfiguratorApp(Ice.Application):
configurationWipe = True
if configurationService == None:
- print >> sys.stderr, "No configuration service to configure."
+ print >> sys.stderr, "No configuration service to configure. For usage details please run " + __file__ + " --help"
return -1
print "Reading configuration from file " + configFile
commit 15138e4da8d4a3eb286a4d3bd60a564608d1349f
Author: Joshua Colp <jcolp at digium.com>
Date: Sun Mar 20 11:16:47 2011 -0300
I do believe we are in the year 2011 these days.
diff --git a/Configurator.py b/Configurator.py
index 4c3d2fc..2b1c5da 100755
--- a/Configurator.py
+++ b/Configurator.py
@@ -3,7 +3,7 @@
#
# Asterisk SCF -- An open-source communications framework.
#
-# Copyright (C) 2010, Digium, Inc.
+# Copyright (C) 2011, Digium, Inc.
#
# See http://www.asterisk.org for more information about
# the Asterisk SCF project. Please do not directly contact
commit 99764b169d9f01c407605797b7e1903a5007699c
Author: Joshua Colp <jcolp at digium.com>
Date: Sun Mar 20 11:08:47 2011 -0300
Incorporate even more code review feedback.
diff --git a/Configurator.py b/Configurator.py
index 84a45a4..4c3d2fc 100755
--- a/Configurator.py
+++ b/Configurator.py
@@ -1,5 +1,21 @@
#!/usr/bin/env python
+#
+# 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.
+#
+
# Asterisk SCF Configurator Module
import ConfigParser, os, Ice, getopt, sys
@@ -45,18 +61,19 @@ class OptionMapper():
def map(self, option, object, item, item_name, method, default = None):
setattr(object, item, default)
- self.options[option] = [ object, item, item_name, method, default ]
+ self.options[option] = { 'object': object, 'item': item, 'item_name': item_name, 'method': method, 'default': default }
def execute(self, group, section, option):
"""Map options to configuration items based on options set"""
try:
- object = self.options[option][0]
+ object = self.options[option]['object']
except:
return
- item = self.options[option][1]
- item_name = self.options[option][2]
- method = self.options[option][3]
- default = self.options[option][4]
+
+ item = self.options[option]['item']
+ item_name = self.options[option]['item_name']
+ method = self.options[option]['method']
+ default = self.options[option]['default']
try:
setattr(object, item, method(section, option))
@@ -77,8 +94,8 @@ class OptionMapper():
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][1]
- default = self.options[option][4]
+ item = self.options[option]['item']
+ default = self.options[option]['default']
if default == None:
if item == None:
print "Option '" + option + "' requires a value to be set and no default value exists."
commit a9710935203651fdbe13bd2bd147bdc3c5df3a4f
Author: Joshua Colp <jcolp at digium.com>
Date: Sun Mar 20 10:59:24 2011 -0300
Incorporate feedback from code review.
diff --git a/Configurator.py b/Configurator.py
index 8bef119..84a45a4 100755
--- a/Configurator.py
+++ b/Configurator.py
@@ -2,7 +2,7 @@
# Asterisk SCF Configurator Module
-import ConfigParser, os, Ice, getopt
+import ConfigParser, os, Ice, getopt, sys
# Load and make the configuration interface available, we require it
Ice.loadSlice('-I. --all ConfigurationIf.ice')
@@ -33,7 +33,7 @@ class SectionVisitors():
def visit_unsupported(self, config, section):
"""Handle an unsupported configuration section"""
- print "Unsupported configuration section " + section
+ print >> sys.stderr, "Unsupported configuration section " + section
# Common option to item mapper implementation
class OptionMapper():
@@ -136,8 +136,8 @@ class ConfiguratorApp(Ice.Application):
configurationWipe = True
if configurationService == None:
- print "No configuration service to configure."
- return 0
+ print >> sys.stderr, "No configuration service to configure."
+ return -1
print "Reading configuration from file " + configFile
config = ConfigParser.ConfigParser()
@@ -146,8 +146,8 @@ class ConfiguratorApp(Ice.Application):
try:
config.readfp(open(configFile))
except IOError:
- print "Specified configuration file " + configFile + " could not be loaded."
- return 0
+ print >> sys.stderr, "Specified configuration file " + configFile + " could not be loaded."
+ return -1
print "Building configuration changes to send to component"
for section in config.sections():
@@ -162,8 +162,8 @@ class ConfiguratorApp(Ice.Application):
groups = configurationService.getConfigurationGroups()
configurationService.removeConfigurationGroups(groups)
except:
- print "Configuration could not be wiped - Failed to contact component"
- return 0
+ print >> sys.stderr, "Configuration could not be wiped - Failed to contact component"
+ return -1
print "Applying configuration"
commit 38dd03fdce2ff014ad6de91788439b71af0e5f24
Author: Joshua Colp <jcolp at digium.com>
Date: Wed Mar 2 10:50:34 2011 -0400
Don't require every option in a config file to be mapped.
diff --git a/Configurator.py b/Configurator.py
index 7737542..8bef119 100755
--- a/Configurator.py
+++ b/Configurator.py
@@ -49,7 +49,10 @@ class OptionMapper():
def execute(self, group, section, option):
"""Map options to configuration items based on options set"""
- object = self.options[option][0]
+ try:
+ object = self.options[option][0]
+ except:
+ return
item = self.options[option][1]
item_name = self.options[option][2]
method = self.options[option][3]
commit eaafaf0a795eedeb446b612217f5970b49340dbc
Author: Joshua Colp <jcolp at digium.com>
Date: Tue Mar 1 17:14:12 2011 -0400
Use setattr to set the value of the variable on the object and not the variable holding where the object is.
diff --git a/Configurator.py b/Configurator.py
index 04061bf..7737542 100755
--- a/Configurator.py
+++ b/Configurator.py
@@ -43,19 +43,20 @@ class OptionMapper():
"""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 map(self, option, object, item, item_name, method, default = None):
+ setattr(object, item, default)
+ self.options[option] = [ object, 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]
+ object = self.options[option][0]
+ item = self.options[option][1]
+ item_name = self.options[option][2]
+ method = self.options[option][3]
+ default = self.options[option][4]
try:
- item = method(section, option)
+ setattr(object, item, method(section, option))
except ValueError:
# This is not a fatal error since we just use the default value.
@@ -63,18 +64,18 @@ class OptionMapper():
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
+ setattr(object, 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
+ group.configurationItems[item_name] = object
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]
+ item = self.options[option][1]
+ default = self.options[option][4]
if default == None:
if item == None:
print "Option '" + option + "' requires a value to be set and no default value exists."
@@ -126,7 +127,7 @@ class ConfiguratorApp(Ice.Application):
configFile = a
elif o in ("-p", "--proxy"):
- configurationService = AsteriskSCF.System.Configuration.V1.ConfigurationServicePrx.uncheckedCast(self.communicator().stringToProxy(a))
+ configurationService = AsteriskSCF.System.Configuration.V1.ConfigurationServicePrx.checkedCast(self.communicator().stringToProxy(a))
elif o in ("-w", "--wipe"):
configurationWipe = True
diff --git a/ExampleConfigurator.py b/ExampleConfigurator.py
index bf53cdb..ac27850 100755
--- a/ExampleConfigurator.py
+++ b/ExampleConfigurator.py
@@ -20,12 +20,12 @@ class ExampleSectionVisitors(Configurator.SectionVisitors):
mapper = Configurator.OptionMapper()
# Enable is easy
- mapper.map('enable', AsteriskSCF.System.Configuration.Example.V1.EnableItem().enabled, 'enabled', config.getboolean, False)
+ 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)
+ 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):
@@ -42,8 +42,8 @@ class ExampleSectionVisitors(Configurator.SectionVisitors):
# 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)
+ 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)
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/release/configurator.git
More information about the asterisk-scf-commits
mailing list