<html>
<head>
<base href="https://wiki.asterisk.org/wiki">
<link rel="stylesheet" href="/wiki/s/2042/1/7/_/styles/combined.css?spaceKey=TOP&forWysiwyg=true" type="text/css">
</head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
<h2><a href="https://wiki.asterisk.org/wiki/display/TOP/Configurator+Python+Module">Configurator Python Module</a></h2>
<h4>Page <b>edited</b> by <a href="https://wiki.asterisk.org/wiki/display/~jcolp">Joshua Colp</a>
</h4>
<br/>
<h4>Changes (1)</h4>
<div id="page-diffs">
<table class="diff" cellpadding="0" cellspacing="0">
<tr><td class="diff-snipped" >...<br></td></tr>
<tr><td class="diff-unchanged" >The module is located in the configurator repository and includes a complete example named ExampleConfigurator.py <br> <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: #dfd;">Creation of this module was driven by research done to find the best solution for a common configuration infrastructure. This research can be found [here|TOP:Common Configuration Infrastructure]. <br> <br>{note}This is a utility python module created to make implementation of a command line configuration tool for components quick and easy. There is no requirement to utilize this.{note} <br> <br></td></tr>
<tr><td class="diff-unchanged" >h3. Configuration File Layout <br> <br></td></tr>
<tr><td class="diff-snipped" >...<br></td></tr>
</table>
</div> <h4>Full Content</h4>
<div class="notificationGreySide">
<h3><a name="ConfiguratorPythonModule-Introduction"></a>Introduction</h3>
<p>The Configurator python module makes it easy to create a configuration utility for any component. It takes care of the following items:</p>
<ol>
        <li>Implementing the core of the application itself</li>
        <li>Supporting various application command line arguments</li>
        <li>Finding the component</li>
        <li>Parsing the configuration file</li>
        <li>Pushing the configuration to the component</li>
        <li>Executing section visitors</li>
        <li>Mapping provided options to items</li>
</ol>
<p>The configuration utility is expected to implement the following:</p>
<ol>
        <li>Provide implementations of supported configuration sections</li>
        <li>Provide mapping details for configuration options</li>
</ol>
<p>The module is located in the configurator repository and includes a complete example named ExampleConfigurator.py</p>
<p>Creation of this module was driven by research done to find the best solution for a common configuration infrastructure. This research can be found <a href="/wiki/display/TOP/Common+Configuration+Infrastructure" title="Common Configuration Infrastructure">here</a>.</p>
<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/warning.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>This is a utility python module created to make implementation of a command line configuration tool for components quick and easy. There is no requirement to utilize this.</td></tr></table></div>
<h3><a name="ConfiguratorPythonModule-ConfigurationFileLayout"></a>Configuration File Layout</h3>
<p>Configuration files are expected to follow the INI file style. They each have a section which contains options and each option has a value.</p>
<p>An example is provided below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
[section1]
option1=duck
option2=goose
[section2]
option1=zimbabwe
option2=tacos
]]></script>
</div></div>
<p>Unless specifically implemented as such the options of one section are not expected to apply to other sections.</p>
<h3><a name="ConfiguratorPythonModule-UsingtheConfiguratorpythonmodule"></a>Using the Configurator python module</h3>
<p>The Configurator module can simply be used by importing it into your python script as shown below.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
import Configurator
]]></script>
</div></div>
<p>Once imported this will automatically load the configuration API since it is a core part of Configurator.</p>
<h3><a name="ConfiguratorPythonModule-Addingsupportforconfigurationsections"></a>Adding support for configuration sections</h3>
<p>Section support is implemented using a visitor pattern by subclassing the SectionVisitors class of the Configurator module. The SectionVisitors class takes care of finding the section visitor function to execute and also provides some notification if an unsupported section is encountered.</p>
<p>Visitor functions are expected to look like the following:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
def visit_<section>(self, config, section):
]]></script>
</div></div>
<p>An example is provided below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
class ExampleSectionVisitors(Configurator.SectionVisitors):
        def visit_general(self, config, section):
                print "Encountered general section"
]]></script>
</div></div>
<p>In this example a visitor function is written to support the general section when encountered in the configuration file. Once encountered the function is executed and option level handling can occur.</p>
<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/warning.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>All visit_* functions must accept three arguments as provided above.</td></tr></table></div>
<div class='panelMacro'><table class='tipMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/check.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>For cases where you can't create functions for all possible sections you can implement a visit_unsupported function that will be called when no visitor function exists for the section name. This is useful for dynamic environments where sections may actually represent entities.</td></tr></table></div>
<p>In each visitor section you will normally create a configuration group to contain configuration items relevant to that group. It might look like this:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
group = AsteriskSCF.System.Configuration.Example.V1.GeneralGroup()
group.configurationItems = { }
]]></script>
</div></div>
<p>When mapping options to items this group will get passed in so items get added to it. Once all option mapping operations are complete the group should be added to the sequence of groups to be pushed to the component. It can be done like so from inside the section visitor function:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
self.groups.append(group)
]]></script>
</div></div>
<h3><a name="ConfiguratorPythonModule-Addingsupportforconfigurationoptions"></a>Adding support for configuration options</h3>
<p>The Configurator python module provides an OptionMapper class which is used to map an option in the configuration file to a variable in a configuration item. It optionally provides the ability to have a default value provided if an invalid value is provided or if no value is provided.</p>
<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/information.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>The OptionMapper class is provided to accelerate implementation of a configuration utility. It is not a required aspect of the above section visitor class.</td></tr></table></div>
<p>To start off using this class you first have to create one like so:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
mapper = Configurator.OptionMapper()
]]></script>
</div></div>
<p>Once finished you have to tell the OptionMapper class how to map options to items by using the map function. The map function has the following arguments:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
mapper.map(<option name>, <object>, <variable name in object>, <group item name>, <function to retrieve value>, <default value>)
]]></script>
</div></div>
<div class='panelMacro'><table class='tipMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/check.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>If no default value is possible for an option name then the default value argument can be provided as None or simply not provided at all.</td></tr></table></div>
<p>An example is provided below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
mapper.map('enable', AsteriskSCF.System.Configuration.Example.V1.EnableItem(), 'enabled', 'enabled', config.getboolean, False)
]]></script>
</div></div>
<p>This maps the configuration option 'enable' to the AsteriskSCF.System.Configuration.Example.V1.EnableItem().enabled item variable using the config.getboolean function. Once the value is set it is added to the configuration group under the name 'enabled'. If this option is not set in the configuration file it is set to False.</p>
<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/warning.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>The function to retrieve the value is expected to have three arguments: self, section, option. This is because the ConfigParser get functions are expected to be used here. If not you will have to create your own class that is initialized with the config value and use config.get inside of it when called.</td></tr></table></div>
<p>Once all mapping of supported configuration options is complete you will need to iterate through the options and once done finish the mapping.</p>
<p>An example is provided below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
for option in config.options(section):
        mapper.execute(group, section, option)
mapper.finish(group)
]]></script>
</div></div>
<p>These steps iterate through all configuration options provided in the configuration file, map them to the respective configuration item, and add them to the configuration group.</p>
<h3><a name="ConfiguratorPythonModule-Creatinganapplication"></a>Creating an application</h3>
<p>The Configurator module provides an application class that takes care of most of the configuration related tasks. The class has the following arguments:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
Configurator.ConfiguratorApp(<default configuration file>, <section visitors implementation>, <proxy to configuration service>)
]]></script>
</div></div>
<div class='panelMacro'><table class='tipMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/check.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>The proxy to configuration service argument can be left out if you do not have a proxy.</td></tr></table></div>
<p>An example of using this class is provided below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
app = Configurator.ConfiguratorApp('Example.config', ExampleSectionVisitors())
sys.exit(app.main(sys.argv))
]]></script>
</div></div>
<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/wiki/images/icons/emoticons/warning.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td>You will need to import sys in order to use sys.exit</td></tr></table></div>
<p>Since this class encompasses a full application by using it the following command line arguments and features are provided:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<script type="syntaxhighlighter" class="toolbar: false; theme: Confluence; brush: java; gutter: false"><![CDATA[
Usage: ./ExampleConfigurator.py [--config=filename] [--proxy=stringified configuration service proxy] [--wipe]
Push a configuration to a component.
Mandatory arguments to long options are mandatory for short options too.
-h, --help display help information
-c, --config=FILENAME use specified configuration file instead of Example.config
-p, --proxy=PROXY use specified proxy instead of locating component
-w, --wipe remove existing configuration before applying new one
]]></script>
</div></div>
</div>
<div id="commentsSection" class="wiki-content pageSection">
<div style="float: right;">
<a href="https://wiki.asterisk.org/wiki/users/viewnotifications.action" class="grey">Change Notification Preferences</a>
</div>
<a href="https://wiki.asterisk.org/wiki/display/TOP/Configurator+Python+Module">View Online</a>
|
<a href="https://wiki.asterisk.org/wiki/pages/diffpagesbyversion.action?pageId=12550194&revisedVersion=8&originalVersion=7">View Changes</a>
|
<a href="https://wiki.asterisk.org/wiki/display/TOP/Configurator+Python+Module?showComments=true&showCommentArea=true#addcomment">Add Comment</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>