[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "configuration" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Tue Mar 8 06:55:18 CST 2011


branch "configuration" has been updated
       via  891cedd06767489bf8e00b9c1b98318d9c09d3ef (commit)
       via  0f17de699ae1b4e8f7abdb69053405a30b4b7952 (commit)
      from  4c5178bacdf897e9717c93187b2bcb657f2e1871 (commit)

Summary of changes:
 config/Configurator.py             |  179 ++++++++++++++++++++++++++++++++++++
 config/Sip.config                  |   77 +++++++++++++++
 config/SipConfigurator.py          |  150 ++++++++++++++++++++++++++++++
 local-slice/SipConfigurationIf.ice |    2 +-
 4 files changed, 407 insertions(+), 1 deletions(-)
 create mode 100755 config/Configurator.py
 create mode 100644 config/Sip.config
 create mode 100755 config/SipConfigurator.py


- Log -----------------------------------------------------------------
commit 891cedd06767489bf8e00b9c1b98318d9c09d3ef
Author: Joshua Colp <jcolp at digium.com>
Date:   Tue Mar 8 08:54:39 2011 -0400

    Add python script that configures the SIP component.
    
    Pitfalls:
    1. Right now this includes a copy of the Configurator. Once reviewed and +1ed this will no longer be the case.
    2. This uses dynamic slice loading meaning it must be run from within this directory. Once the proper way to
    install translated slice is explored and implement this will no longer be true.
    3. It hard codes an include directory to the Ice slice. Once the above is done this should also no longer be needed.

diff --git a/config/Configurator.py b/config/Configurator.py
new file mode 100755
index 0000000..6e20173
--- /dev/null
+++ b/config/Configurator.py
@@ -0,0 +1,179 @@
+#!/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 ../../slice/AsteriskSCF/System/Component/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, 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"""
+        try:
+            object = self.options[option][0]
+        except:
+            return
+        item = self.options[option][1]
+        item_name = self.options[option][2]
+        method = self.options[option][3]
+        default = self.options[option][4]
+
+        try:
+            setattr(object, 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."
+                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] = 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][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."
+
+# 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.checkedCast(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/config/Sip.config b/config/Sip.config
new file mode 100644
index 0000000..048a751
--- /dev/null
+++ b/config/Sip.config
@@ -0,0 +1,77 @@
+# General Configuation Options
+# Currently contains nothing, stay tuned!
+[general]
+
+# Example of a UDP transport binding to IPv4 localhost
+# The section name is considered the name of this transport
+[localhost-udp]
+# Type specifies what type of section this is, transport-udp is for UDP obviously
+type=transport-udp
+# Host is the address that we should bind to
+host=127.0.0.1
+# Port is the port that we should bind to, by default this is 5060
+port=5061
+
+# Example of a UDP transport binding to IPv6 localhost
+[localhost-udp6]
+type=transport-udp
+# Note that is IPv6
+host=::1
+port=5061
+
+# Example of a TCP transport binding to IPv4 localhost
+[localhost-tcp]
+# A type of transport-tcp specifies transport using TCP
+type=transport-tcp
+host=127.0.0.1
+port=5061
+
+# Example of a TCP transport binding to IPv6 localhost
+[localhost-tcp6]
+type=transport-tcp
+host=::1
+port=5061
+
+# Example of a TLS transport binding to IPv4 localhost
+[localhost-tls]
+# A type of translort-tls specifies transport using TLS
+type=transport-tls
+host=127.0.0.1
+port=5061
+# Filename (with path) to the certificate authority file
+#certificateauthorityfile=/tmp/bob.ca
+# Filename (with path) to the certificate file
+#certificatefile=/tmp/bob.cert
+# Filename (with path) to the private key file
+#privatekeyfile=/tmp/bob.key
+# Password to open the above private key file
+#privatekeypassword=zombies
+# Whether to require the server certificate to be verified or not
+#requireverifiedserver=yes
+# Whether to require the client certificate to be verified or not
+#requireverifiedclient=yes
+# Whether to require a client certificate
+#requireclientcertificate=yes
+# Supported cryptography ciphers (in OpenSSL format)
+#supportedciphers=
+# TLS server name
+#tlsservername=
+# Timeout value for TLS negotiation (0 means no timeout)
+tlstimeout=0
+# TLS protocol method to use (valid options are unspecified, tlsv1, sslv2, sslv3, sslv23)
+#tlsprotocolmethod=tlsv1
+
+# Example of a SIP endpoint configuration
+[bob]
+# A type of endpoint specifies this section is for a SIP endpoint
+type=endpoint
+# IP address or host of the SIP device we are targetting
+targethost=192.168.2.99
+# Port number of the SIP device we are targetting
+targetport=5060
+# Source IP address or host of the transport to use
+#sourcehost=
+# Source port of the transport to use
+#sourceport=
+# What directions calls are permitted in. Valid options are inbound, outbound, and both.
+direction=both
diff --git a/config/SipConfigurator.py b/config/SipConfigurator.py
new file mode 100755
index 0000000..018bdc0
--- /dev/null
+++ b/config/SipConfigurator.py
@@ -0,0 +1,150 @@
+#!/usr/bin/env python
+
+# Sip configurator
+
+# Bring in the common configuration infrastructure
+import Ice, Configurator, sys
+
+# Load our component specific configuration definitions
+Ice.loadSlice('-I. -I/opt/Ice-3.4.1/slice -I../../slice --all ../local-slice/SipConfigurationIf.ice')
+import AsteriskSCF.SIP.V1
+
+# Add our own visitor implementations for the sections we support
+class SipSectionVisitors(Configurator.SectionVisitors):
+    def visit_general(self, config, section):
+        group = AsteriskSCF.SIP.V1.SipGeneralGroup()
+        group.configurationItems = { }
+        self.groups.append(group)
+
+    def visit_transport_udp(self, config, section):
+        group = AsteriskSCF.SIP.V1.SipUDPTransportGroup()
+        group.name = section
+        group.configurationItems = { }
+
+        mapper = Configurator.OptionMapper()
+        item = AsteriskSCF.SIP.V1.SipHostItem()
+        mapper.map('host', item, 'host', 'address', config.get, None)
+        mapper.map('port', item, 'port', 'address', config.getint, 5060)
+        for option in config.options(section):
+            mapper.execute(group, section, option)
+
+        mapper.finish(group)
+
+        self.groups.append(group)
+
+    def visit_transport_tcp(self, config, section):
+        group = AsteriskSCF.SIP.V1.SipTCPTransportGroup()
+        group.name = section
+        group.configurationItems = { }
+
+        mapper = Configurator.OptionMapper()
+        item = AsteriskSCF.SIP.V1.SipHostItem()
+        mapper.map('host', item, 'host', 'address', config.get, None)
+        mapper.map('port', item, 'port', 'address', config.getint, 5060)
+        for option in config.options(section):
+            mapper.execute(group, section, option)
+
+        mapper.finish(group)
+
+        self.groups.append(group)
+
+    def visit_transport_tls(self, config, section):
+        group = AsteriskSCF.SIP.V1.SipTLSTransportGroup()
+        group.name = section
+        group.configurationItems = { }
+
+        mapper = Configurator.OptionMapper()
+        item = AsteriskSCF.SIP.V1.SipHostItem()
+        mapper.map('host', item, 'host', 'address', config.get, None)
+        mapper.map('port', item, 'port', 'address', config.getint, 5060)
+        for option in config.options(section):
+            mapper.execute(group, section, option)
+
+        mapper.finish(group)
+
+        self.groups.append(group)
+
+    def visit_endpoint(self, config, section):
+        group = AsteriskSCF.SIP.V1.SipEndpointGroup()
+        group.name = section
+        group.configurationItems = { }
+
+        mapper = Configurator.OptionMapper()
+
+        mapper.map('routing', AsteriskSCF.SIP.V1.SipRoutingItem(), 'routingServiceName', 'routingService', config.get, None)
+
+        item = AsteriskSCF.SIP.V1.SipSourceTransportAddressItem()
+        mapper.map('sourcehost', item, 'host', 'sourceaddress', config.get, None)
+        mapper.map('sourceport', item, 'port', 'sourceaddress', config.getint, 5060)
+
+        item = AsteriskSCF.SIP.V1.SipTargetDestinationAddressItem()
+        mapper.map('targethost', item, 'host', 'targetaddress', config.get, None)
+        mapper.map('targetport', item, 'port', 'targetaddress', config.getint, 5060)
+
+        class AllowableCallDirectionTransformer():
+            def __init__(self, config):
+                self.config = config
+            def get(self, section, item):
+                if self.config.get(section, item) == 'inbound':
+                    return AsteriskSCF.SIP.V1.SipAllowableCallDirection.Inbound
+                elif self.config.get(section, item) == 'outbound':
+                    return AsteriskSCF.SIP.V1.SipAllowableCallDirection.Outbound
+                elif self.config.get(section, item) == 'both':
+                    return AsteriskSCF.SIP.V1.SipAllowableCallDirection.Both
+
+        transformer = AllowableCallDirectionTransformer(config)
+        mapper.map('direction', AsteriskSCF.SIP.V1.SipAllowableCallDirectionItem(), 'callDirection', 'callDirection', transformer.get, None)
+
+        item = AsteriskSCF.SIP.V1.SipCryptoCertificateItem()
+        mapper.map('certificateauthorityfile', item, 'certificateAuthority', 'cryptocert', config.get, None)
+        mapper.map('certificatefile', item, 'certificate', 'cryptocert', config.get, None)
+        mapper.map('privatekeyfile', item, 'privateKey', 'cryptocert', config.get, None)
+        mapper.map('privatekeypassword', item, 'privateKeyPassword', 'cryptocert', config.get, None)
+
+        item = AsteriskSCF.SIP.V1.SipCryptoRequirementsItem()
+        mapper.map('requireverifiedserver', item, 'requireVerifiedServer', 'cryptorequirements', config.getboolean, None)
+        mapper.map('requireverifiedclient', item, 'requireVerifiedClient', 'cryptorequirements', config.getboolean, None)
+        mapper.map('requireclientcertificate', item, 'requireClientCertificate', 'cryptorequirements', config.getboolean, None)
+
+        item = AsteriskSCF.SIP.V1.SipCryptoItem()
+        mapper.map('supportedciphers', item, 'supportedCiphers', 'crypto', config.get, None)
+        mapper.map('tlsservername', item, 'serverName', 'crypto', config.get, None)
+        mapper.map('tlstimeout', item, 'timeout', 'crypto', config.getint, None)
+
+        class TLSProtocolMethodTransformer():
+            def __init__(self, config):
+                self.config = config
+            def get(self, section, item):
+                if self.config.get(section, item) == 'unspecified':
+                    return AsteriskSCF.SIP.V1.TLSProtocolMethod.PROTOCOLMETHODUNSPECIFIED
+                elif self.config.get(section, item) == 'tlsv1':
+                    return AsteriskSCF.SIP.V1.TLSProtocolMethod.PROTOCOLMETHODTLSV1
+                elif self.config.get(section, item) == 'sslv2':
+                    return AsteriskSCF.SIP.V1.TLSProtocolMethod.PROTOCOLMETHODTSSLV2
+                elif self.config.get(section, item) == 'sslv3':
+                    return AsteriskSCF.SIP.V1.TLSProtocolMethod.PROTOCOLMETHODSSLV3
+                elif self.config.get(section, item) == 'sslv23':
+                    return AsteriskSCF.SIP.V1.TLSProtocolMethod.PROTOCOLMETHODSSLV23
+
+        transformer = TLSProtocolMethodTransformer(config)
+        mapper.map('tlsprotocolmethod', item, 'protocolMethod', 'crypto', transformer.get, None)
+
+        for option in config.options(section):
+            mapper.execute(group, section, option)
+        mapper.finish(group)
+
+        self.groups.append(group)
+
+    def visit_unsupported(self, config, section):
+        if config.get(section, 'type') == 'transport-udp':
+            self.visit_transport_udp(config, section)
+        elif config.get(section, 'type') == 'transport-tcp':
+            self.visit_transport_tcp(config, section)
+        elif config.get(section, 'type') == 'transport-tls':
+            self.visit_transport_tls(config, section)
+        elif config.get(section, 'type') == 'endpoint':
+            self.visit_endpoint(config, section)
+
+# Make a configurator application and let it run
+app = Configurator.ConfiguratorApp('Sip.config', SipSectionVisitors())
+sys.exit(app.main(sys.argv))

commit 0f17de699ae1b4e8f7abdb69053405a30b4b7952
Author: Joshua Colp <jcolp at digium.com>
Date:   Tue Mar 8 08:54:33 2011 -0400

    Tweak include.

diff --git a/local-slice/SipConfigurationIf.ice b/local-slice/SipConfigurationIf.ice
index 9fa7d55..73e31cd 100644
--- a/local-slice/SipConfigurationIf.ice
+++ b/local-slice/SipConfigurationIf.ice
@@ -16,7 +16,7 @@
 
 #pragma once
 #include <Ice/BuiltinSequences.ice>
-#include "AsteriskSCF/System/Component/ConfigurationIf.ice"
+#include <AsteriskSCF/System/Component/ConfigurationIf.ice>
 
 module AsteriskSCF
 {

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


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list