yencap documentation - loriamadynes.loria.fr/ensuite/documentation/yencap_doc.pdf · yencap...
TRANSCRIPT
YencaP DocumentationRelease: yencap-1.1.15
Release: yencapClient-1.1.15
Vincent CRIDLIG, [email protected]
Radu STATE, [email protected]
Madynes Research team
LORIA-INRIA Lorraine
rue du jardin botanique
Villers-les-Nancy
FRANCE
1
Contents
1 Introduction 51.1 Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.1 YencaP’s author information . . . . . . . . . . . . . . . . 51.1.2 Software information . . . . . . . . . . . . . . . . . . . . . 5
2 Installation 52.1 Download . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2 System requirements . . . . . . . . . . . . . . . . . . . . . . . . . 62.3 YencaP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.4 YencaPClient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3 User guide 73.1 YencaP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.1.1 Netconf over SSH . . . . . . . . . . . . . . . . . . . . . . . 73.1.2 Netconf over XMLSec . . . . . . . . . . . . . . . . . . . . 8
3.2 YencapClient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.2.1 Netconf over SSH . . . . . . . . . . . . . . . . . . . . . . . 83.2.2 Interactive mode . . . . . . . . . . . . . . . . . . . . . . . 8
3.3 Simple example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4 YencaP Netconf agent architecture 114.1 General architecture . . . . . . . . . . . . . . . . . . . . . . . . . 114.2 Application protocol layer . . . . . . . . . . . . . . . . . . . . . . 114.3 RPC layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124.4 Operation layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124.5 Content layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134.6 Communication between layers . . . . . . . . . . . . . . . . . . . 134.7 Netconf session management . . . . . . . . . . . . . . . . . . . . 144.8 File organization . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
5 YencaP native modules 145.1 BGP module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145.2 Asterisk module . . . . . . . . . . . . . . . . . . . . . . . . . . . 165.3 Network interfaces module . . . . . . . . . . . . . . . . . . . . . . 16
5.3.1 Data model (XML Schema) . . . . . . . . . . . . . . . . . 165.3.2 UML diagram of commands . . . . . . . . . . . . . . . . . 165.3.3 Request examples . . . . . . . . . . . . . . . . . . . . . . 16
5.4 Routes module . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165.5 RBAC module . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6 YencaP native extensions 166.1 RBAC extension . . . . . . . . . . . . . . . . . . . . . . . . . . . 166.2 get-Modules extension . . . . . . . . . . . . . . . . . . . . . . . . 216.3 yum extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2
7 Developer’s guide for extensions 217.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217.2 Extending the data model . . . . . . . . . . . . . . . . . . . . . . 22
7.2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 227.2.2 Code Auto-generation . . . . . . . . . . . . . . . . . . . . 227.2.3 Module registration . . . . . . . . . . . . . . . . . . . . . 237.2.4 Implementing the main class . . . . . . . . . . . . . . . . 237.2.5 Returning the Reply to Core YencaP . . . . . . . . . . . . 25
7.3 Extending the capabilities (operations) . . . . . . . . . . . . . . . 267.3.1 Creating a new operation . . . . . . . . . . . . . . . . . . 267.3.2 Connecting the operation to YencaP . . . . . . . . . . . . 26
7.4 Implementing a new application protocol (BEEP, SOAP, ...) . . . 28
8 Appendix 288.1 Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288.2 EasyModule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318.3 ModuleReply . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3
List of Figures
1 YencaP layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 YencaPClient menu . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Netconf agent architecture . . . . . . . . . . . . . . . . . . . . . . 114 Application layer implementation . . . . . . . . . . . . . . . . . . 125 Operation layer implementation . . . . . . . . . . . . . . . . . . . 126 Content layer implementation . . . . . . . . . . . . . . . . . . . . 137 Communications between layers . . . . . . . . . . . . . . . . . . . 138 Session and access control management implementation . . . . . 149 YencaP Netconf agent home directory . . . . . . . . . . . . . . . 1510 Merge interface eth0, changing the mtu and netmask value or only the mtu 1711 Get-config of network interfaces using XPath . . . . . . . . . . . 1812 Get-config of routes using XPath . . . . . . . . . . . . . . . . . . 1913 Get-config on RBAC module using XPath . . . . . . . . . . . . . 2014 RBAC roles (de)activation . . . . . . . . . . . . . . . . . . . . . . 2115 BGP Module Registration . . . . . . . . . . . . . . . . . . . . . . 2316 Sample module implementation . . . . . . . . . . . . . . . . . . . 2417 RBAC module implementation . . . . . . . . . . . . . . . . . . . 2518 Log module implementation . . . . . . . . . . . . . . . . . . . . . 2519 Edit-config . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2520 Sample operation implementation . . . . . . . . . . . . . . . . . . 2721 Update to operations.xml file . . . . . . . . . . . . . . . . . . . . 27
4
1 Introduction
1.1 Information
1.1.1 YencaP’s author information
Author names and organism attachment:Vincent Cridlig, Jerome Bourdellon and Radu Statevincent.cridlig, jerome.bourdellon, [email protected] Research teamLORIA-INRIA Lorrainerue du jardin botaniqueVillers-les-NancyFRANCE
If you have any requests, comments, ideas for improvement or questionsconcerning YencaP, if you think you find a bug, please send emails to [email protected].
1.1.2 Software information
Software name: YencaPVersion: 1.1.2Programming language: PythonOperating System: Linux (tested in Fedora core 3 and 4)License: GNU Lesser General Public License (LGPL)
YencaP is an implementation of Netconf and follows the seventh version ofNetconf draft. It implements all NetConf operations, #writable-running, #url,#startup, #candidate and #xpath capabilities. Get-config and get supportboth subtree filtering and xpath methods for selecting device data.
YencaP can run over SSH or over a customized XML security (see Figure 1).YencaPClient is a light client to connect to YencaP and can run interactivelyor not. It is used mostly for test purposes. For both of them, the defaultunderlying protocol is SSH.
XML−DigitalSignature
XML−Encryption
Compression
SSH
Netconf
TCP
Figure 1: YencaP layers
2 Installation
2.1 Download
YencaP and YencapClient are available in our web page: download.
5
2.2 System requirements
YencaP requires the following libraries. Packages marked with a star (*) areavailable in the default package list of Fedora Core 4. Therefore, they can beinstalled easily using yum install package-name if not already installed:
python (python-2.4.1-2) *
python-devel (python-devel-2.4.1-2) *
xmlsec1 (xmlsec1-1.2.7-4) *
xmlsec1-devel (xmlsec1-devel-1.2.7-4) *
xmlsec1-openssl (xmlsec1-openssl-1.2.7-4) *
xmlsec1-openssl-devel (xmlsec1-openssl-devel-1.2.7-4) *
libxml2 (libxml2-2.6.19-1) *
libxml2-devel (libxml2-devel-2.6.19-1) *
libxml2-python (libxml2-python-2.6.19-1) *
PyXML (PyXML-0.8.4-3) *
4Suite (4Suite-1.0-8.b1) *
PyXMLSec 0.2.1 Please choose openSSL option during the installation.
paramiko 1.4 Provides SSH2 support.
pycrypto 2.0.1 Python Cryptography Toolkit
LTXML and PyLTXML-1.3-7-p332.i386.rpm
XSV-2.0-3.noarch.rpm
In order for YencaP to find the right libraries, please update your PYTHON-PATH environment variable depending on the installation paths. As python2.4is getting more and more used, every Python libraries should be somewhere in”/usr/lib/python2.4”.
2.3 YencaP
You must have root privileges to perform the YencaP installation. Assumethat yencap-1.1.2.tar.gz is stored in /tmp directory. Go to /tmp directoryand unzip the compressed file. Change directory to yencap-VERSION andinstall the software. The $YENCAP HOME environment variable must be setto /usr/local/yencap:
% cd /tmp
% tar -xzvf yencap-{VERSION}.tar.gz
% cd yencap-{VERSION}
% su
% make uninstall (# if you had a previous installed yencap)
% make install
% export YENCAP_HOME="/usr/local/yencap"
% netconfd
6
To start, stop and restart YencaP as a deamon service, run the following.
% /etc/init.d/netconfd start // To start
% /etc/init.d/netconfd stop // To stop
% /etc/init.d/netconfd restart // To restart
2.4 YencaPClient
You must have root privileges to perform the YencaPClient installation. Assumethat yencapClient-VERSION.tar.gz is stored in /tmp directory. The installationprocess is similar to YencaP installation:
% cd /tmp
% tar -xzvf yencapClient-{VERSION}.tar.gz
% cd yencapClient-{VERSION}
% su
% make uninstall (# if you had a previous installed yencapClient)
% make install
% export YENCAP_CLIENT_HOME="/usr/local/yencapClient"
YencapClient can run in interactive or non-interactive mode. The interactivemode allows to open a Netconf session and to send requests dynamically in thissession. YencapClient querries the user to get the needed parameters and buildsthe Netconf requests dynamically from these user choices. The non-interactivemode allows to send one prepared Netconf request.
% cd /usr/local/yencapClient
#To use interactive mode, run:
% ./netconfc.py localhost
#To use non-interactive mode with a prepared request (get_config_subtree_ifeth0.xml), run:
% ./netconfc.py localhost tests/get_config_subtree_ifeth0.xml
3 User guide
3.1 YencaP
3.1.1 Netconf over SSH
There is two important files to make the agent work over SSH:
• /usr/local/yencap/conf/netconfd.xml
• /usr/local/yencap/conf/rbac.xml
First, netconfd.xml allows to choose the listenning port and the IP version (4or 6). It also proposes some underlying protocols (SSH and XMLSec). In orderto use SSH, set the status attribute to active and set the path of the privatekey file of the agent (YencaP).
Second, rbac.xml allows to configure some well known users that will beable to request the agent. A user can be authenticated with login password orlogin and public/private key. In order to authenticate users with public/privatekey, just set the text value of the allowkeys tag to the public key of the user.Public/private key is prioritary to password.
The agent is now ready to restart.
7
3.1.2 Netconf over XMLSec
If you run YencaP over TCP, it is possible to setup compression and encryptionoptions. To enable these features, edit the conf/netconfd.xml file:
• To enable encryption, set the encryption node to 1,
• To disable encryption, set the encryption node to 0,
• To enable compression, set the compression node to 1,
• To disable compression, set the compression node to 0,
Role keys generation In order to generate a key for encryption, the headcommand line utility is used. The following command creates a key of 128 bitsand stores the result in a file named keyrole1 :
cd /usr/local/yencap/bin head -c 128 /dev/urandom > keyrole1
You can generate as much key as needed, depending on the number of roles(RBAC) you use. These files must be stored in the keystore directory of theNetconf agent. Alternatively, you can use the keyGenerator.py utility. In orderto build a new role key, run the following command line in bin directory andfollow the instructions:
% python keyGenerator.py
The generated key will be stored automatically in keystore directory. A Netconfmanager must know that key so that the related role can be used. Therefore,once a key was generated, it must be distributed to authorized managers.
3.2 YencapClient
3.2.1 Netconf over SSH
One file must be configured to use YencaPClient over SSH:
• /usr/local/yencapClient/conf/yencapClient.xml
yencapClient.xml allows to configure the server port and the IP version (4or 6). As for YencaP, you can choose between several underlying transportapplications. To select SSH, set the status attribute to active in the rightapplication-protocol tag. Then set the users allowed to use YencaPClient alongwith a password and/or their private key. Finally, add some allowed agents(name, IP, ... and their public key).
The manager is now ready to send a request to the agent, for instance:./netconfc.py localhost tests/get config subtree ifeth0.xml.
3.2.2 Interactive mode
The interactive mode prompts for a login. This login must be known by bothYencaP and YencapClient. Depending on the options, the user will be promptfor a password. Once the user is logged in, YencapClient displays the agent’s ca-pabilities. Finally, YencapClient displays a menu that allows to choose betweenthe possible Netconf operations. Depending on the operations, some submenusmay appear to select different parameters. Figure 2 shows the main menu:
8
__________________________
[0] get-config
[1] get
[2] edit-config
[3] copy-config
[4] delete-config
[5] lock
[6] unlock
[7] kill-session
[8] close-session
[9] get-modules
Choose Netconf operation:
Figure 2: YencaPClient menu
3.3 Simple example
To test the server, you can use the client that allows to open a Netconf sessionwith the server:
% ./netconfc agentHostName tests/xpathGetRequest12.xml
xpathGetRequest12.xml embeds a Netconf request (get-config) using the sub-tree filtering method. The message-id attribute is modified by the client accord-ing to Netconf protocol rules.
<rpc message-id="102" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-config>
<source>
<running/>
</source>
<filter type="subtree">
<netconf>
<security>
<rbac>
<permissions>
<permission>
<scope/>
</permission>
</permissions>
</rbac>
</security>
</netconf>
</filter>
</get-config>
</rpc>
Here is the reply for xpathGetRequest12.xml.
<rpc-reply message-id="1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<?xml version="1.0" encoding="UTF-8"?>
<netconf>
<security>
<rbac>
<permissions>
<permission type="+" id="1" op="rw">
<scope>/netconf/security</scope>
</permission>
9
<permission type="+" id="2" op="rw">
<scope>/netconf/interfaces</scope>
</permission>
<permission type="+" id="3" op="rw">
<scope>/netconf/routing/bgp</scope>
</permission>
<permission type="+" id="4" op="rw">
<scope>/netconf/system</scope>
</permission>
<permission type="+" id="5" op="r">
<scope>/netconf/log</scope>
</permission>
<permission type="+" id="6" op="rw">
<scope>/netconf/tests</scope>
</permission>
</permissions>
</rbac>
</security>
</netconf>
</rpc-reply>
In order to get the log of the agent using the xpath capabilities, please tryxpathGetRequest4.xml
<rpc message-id="104" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-config>
<source>
<running/>
</source>
<filter type="xpath">
/netconf/log
</filter>
</get-config>
</rpc>
The reply will look like this XML document:
<rpc-reply message-id="1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<netconf>
<log>
<nbOp>
<get>0</get>
<get-config>601</get-config>
<edit-config>72</edit-config>
<copy-config>0</copy-config>
<delete-config>1</delete-config>
<close-session>429</close-session>
</nbOp>
<sessions>
<number>249</number>
<average-time>0.91176626481</average-time>
</sessions>
<requests>
<number>672</number>
<average-time>0.267890569</average-time>
</requests>
</log>
</netconf>
</rpc-reply>
Many test requests (get-config, copy-config, edit-config) are located in /usr/local/yencapClient/tests.
10
4 YencaP Netconf agent architecture
4.1 General architecture
Figure 3 illustrates the general architecture of the YencaP NetConf agent. Itstrongly follows the layer architecture proposed in the Netconf draft:
• Application protocol layer
• RPC layer
• Operation layer
• Content layer
Netconf splits the responsabilities into these layers. To be more maintainableand understable by Netconf specialists or new developers, there is a clear sep-aration of these layers in the code of YencaP. The implementation relies on acouple of design patterns like facade, command, composite, rbac so that it canbe understood more quickly.
WAN
Netconf operation
module (Content)
Generic server
Operation
Server
Module
Rpcxmlsec_serverSSH_server
netconfd
Easy_Module route_Moduleif_Module
rbac_Module
asteriks_Module
...
bgp_Module
Commanddesign pattern
module inheritancetree
Vendor_Module
multi−socketSSH or XMLSec
Get_config Edit_config Close_session Vendor_operation
Figure 3: Netconf agent architecture
4.2 Application protocol layer
In Netconf configuration protocol, the application protocol layer is the low-est one and must implement SSH and optionnally SOAP and BEEP protocols.YencaP implements not only SSH but also an experimental XML-Security basedlayer. However, the preferred protocol is SSH in operational environment. Fig-ure 4 illustrates the structure: Server class implements the most importantpart of this layer. SSH Server and XMLSec Server inherits from Server andimplements their specific features.
11
SSH_Server XMLSec_Server BEEP_Server SOAP_Server
not implementednot implemented
Server
Figure 4: Application layer implementation
4.3 RPC layer
The RPC layer is simple and therfore is implemented a single class (Rpc). Thereis nothing special here. Rpc class does not need to be extensible.
4.4 Operation layer
The Operation layer is responsible for Netconf operations like get, get-config,edit-config... The command design pattern, illustrated in Figure 5 suits verywell for this kind of situation. YencaP has an Operation class that representsan abstract command (or operation). Each concrete command inheriting fromOperation must implement execute() and optionally rollback(). Each Netconfoperation is implemented in a specific class: Get Config, Get, Edit config, Lock,Unlock... The operation set is extensible: an XML file stores the descriptionof the available operations. Therefore, YencaP is easily extensible with newoperation. Vendor can create a new operation that inherits from Operation classand implements the required methods. An example is given with rbac operationthat allows Netconf managers to (de)activate RBAC roles at execution time.
Edit_config_op
Copy_config_op
Delete_config_op
Lock_op
Get_config_op
Unlock_op
Kill_session_op Close_session_op
Get_op
execute()rollback()
Operation()
Operation
Rbac_op
Vendor2_op
Vendor1_op
Vendor3_op
Command Design Pattern
MacroCommand
Figure 5: Operation layer implementation
12
4.5 Content layer
The content layer is in charge of the Netconf data model. The YencaP datamodel is splitted into different sub-data model, each being managed by a module,see Figure 6 . The classes inheriting from module must at least implement thebase Netconf operation: get, get-config, edit-config... Since a module is in chargeof a sub-data model, it is the only one which knows how to get and update theXML configuration of it. The Module class provides the general interface, likethe methods that have to be implemented and their signatures. By default, itimplements the copy-config operation with the edit-config operation. This ispossible with a merge operation on the top level XML element. Easy Moduleimplements all the base operations (See later in the doc.). However, there aresome restrictions with Easy Module. Modules are described in an XML file andare loaded dynamically, so that the system is extensible.
Interfaces
RBAC
Route IPSecEasyModule
Asterisk
Module
Figure 6: Content layer implementation
4.6 Communication between layers
The communications between layers is done by direct invokation for the requestsand by specific reply classes for the responses. After executing an operation,each module is able to send back a ModuleReply to the Operation layer. Simi-larly, each operation is able to send an OperationReply to the Rpc layer. At end,the Rpc layer sends a Rpc reply as a serialized string value to the Applicationprotocol layer (Server). The mechanism is illustrated on Figure 7.
WAN
Operation
Server
Module
Rpc
OperationReply
Serialized XML
ModuleReply
Figure 7: Communications between layers
13
4.7 Netconf session management
Netconf sessions are managed by a SessionManager class which is implementedas a Singleton Design Pattern. It is responsible for opening/closing Netconf ses-sions and allocating locks to the manager on the datastores. The RbacManagerclass manages the RBAC system and relies on the RBAC XML policy file. Itcan not only (de)activate roles within sessions, but also check permissions atexecution time. Note that an RBAC session and a Netconf session is obviouslythe same thing. To hide the complexity, all this part of the code is a facade de-sign pattern, illustrated on Figure 8. The entry points are the SessionManager,RbacManager.
User Role
Session
Permission
Facade Design Pattern
Singleton Design Pattern Singleton Design Pattern
RBAC design pattern
RbacManagerSessionManager
Figure 8: Session and access control management implementation
4.8 File organization
Figure 9 shows the home directory and sub-directories along with their func-tional roles.
ModuleResolver is in charge of loading the different YencaP modules. It alsofinds the right modules when YencaP receives a Netconf request. Sometimes,ModuleResolver is not able to find the corresponding modules. This happenswhen a XPath request without absolute path (//user[name=’foo’]) is processed.In these cases, all YencaP modules are querried by default. If you want thebest performances, you may prefer to send absolute XPath requests so thatModuleResolver only querries the corresponding modules.
When Dispatcher querries a set of modules, one of them may reply with anerror. In that case, the request processing is stopped and a rpc-error is sentback to the manager, even if the other modules did not go to an error.
5 YencaP native modules
5.1 BGP module
BGP module allows to setup the configuration of a BGP router. Its documen-tation is provided on the madynes.loria.fr/ensuite web page.
14
+ server
- README
- TODO
- netconfd.py // YencaP daemon (executable file)
- rbacManager.py // Manages access control using rbac.xml policy
- constants.py // Netconf protocol constants
- logger.py // Logs YencaP statistics
- util.py // Helps for (de)compression, XML/String convertion
- xmlResponseBuilder.py // Builds XML response from modules replies
- moduleResolver.py // Finds competent modules
- xmlResponseFilter.py // Filters XML responses (XPath request and RBAC)
- sessionManager.py // Manages Netconf sessions
- __init__.py // Defines a new package
- session.py // A Netconf session
+ conf
- candidate.xml // Netconf candidate configuration file
- encrypt-tmp.xml // template to produce encrypted documents
- log.xml // log file
- netconfSchema.xsd // Netconf protocol schema
- rbac.xml // XML access control policy (RBAC model)
- hello.xml // Netconf hello message containing capabilities
- modules.xml // modules registration file
- operations.xml // operations registration file
+ Server // Servers directory
- server.py // generic server
- serverSSH.py // SSH server
- serverXMLSec.py // XMLSec server
- sshModule.py // SSH authentication module
- crypto.py // XML cryptography module
+ Operations // operationss directory
+ base
- get_config_operation.py // get-config
- get_operation.py // get
- copy_config_operation.py // copy-config
- delete_config_operation.py // delete-config
- edit_config_operation.py // edit-config
- lock_operation.py // lock
- unlock_operation.py // unlock
- close_session_operation.py // close-session
- kill_session_operation.py // kill-session
+ ext
+ Modules // modules directory
- module.py // generic module implementation (copy-config)
- easyModule.py // generic module implementation (edit-config)
- moduleReply.py // interface for modules replies
- meta.xsl // XSL stylesheet for XSL edit-config generation
+ RBAC_Module // RBAC module
- __init__.py // package definition
- rbacModule.py // main RBAC module file
+ System_Module // module for system data
+ Test_Module // test module
+ keystore // stores role keys
- systemAdmin // key for systemAdmin role
- networkAdmin // key for networkAdmin role
+ docs
- documentation.pdf // this documentation
Figure 9: YencaP Netconf agent home directory
15
5.2 Asterisk module
Asterisk module allows to setup the configuration of Asterisk software. Itsdocumentation is provided on the madynes.loria.fr/ensuite web page.
5.3 Network interfaces module
The goal of this module is to allow network interfaces management. A managercan retrieve the configuration (name, IP addresses, netmask, broadcast, mtu,flags and IPv6 addresses) and modify it. It also allows to retrieve the statisticsof all network interfaces.
The module is based on a ifconfig.py file that allows to interact with theOS using ioctl, socket and struct python packages. It provides the setters andgetters for MTU, Netmask ans so on.
The module defines a set of command (setMTU, setNetmask, ...) that areinstanciated from an edit-config request. Theses commands are added to amacroCommand and are then executed. All these commands can be rolled backif an exception is raised.
5.3.1 Data model (XML Schema)
5.3.2 UML diagram of commands
5.3.3 Request examples
name is the key node: it allows to select the interface which will be modified.netconf is our top element.
5.4 Routes module
The purpose of the RouteModule is to manage routes. It currently uses theLinux route program but it will be full python in the future.
5.5 RBAC module
The purpose of the RBACModule is to manage the local access control policy.
6 YencaP native extensions
6.1 RBAC extension
The only RBAC operations that a regular manager can do is to open/closea session and (de)activate some roles to be granted some privileges. Openingand closing an RBAC session is transparent, since it is done when opening andclosing a Netconf session. So, the only needed operation is (de)activate roles.See Figure 14.
The creation of new roles, users, permissions and their relationships is tobe done through the RBACModule. RBACModule and RBAC extension aretwo different things. While the first is dedicated to the access control policymanagement, the second is dedicated to operational use.
16
<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
<running/>
</target>
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<netconf>
<network>
<interfaces>
<interface xc:operation="merge">
<name>eth0</name>
<mtu>1540</mtu>
<netmask>255.255.240.0</netmask>
</interface>
</interfaces>
</network>
</netconf>
</config>
</edit-config>
</rpc>
<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
<running/>
</target>
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<netconf>
<network>
<interfaces>
<interface>
<name>eth0</name>
<mtu xc:operation="merge">1540</mtu>
</interface>
</interfaces>
</network>
</netconf>
</config>
</edit-config>
</rpc>
Figure 10: Merge interface eth0, changing the mtu and netmask value or onlythe mtu
17
<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="1">
<get-config>
<source>
<running/>
</source>
<filter type="xpath">/netconf/network/interfaces</filter>
</get-config>
</rpc>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
<data>
<netconf>
<network>
<interfaces>
<interface>
<name>lo</name>
<mac-address>00:00:00:00:00:00</mac-address>
<mtu>16436</mtu>
<flags broadcast="false" running="false" multicast="false" up="true"/>
<ipv4>
<netmask>255.0.0.0</netmask>
<broadcast>0.0.0.0</broadcast>
<address>127.0.0.1</address>
</ipv4>
<ipv6>
<address scope="10" prefix="80">00000000000000000000000000000001</address>
</ipv6>
</interface>
<interface>
<name>eth0</name>
<mac-address>00:0c:f1:82:47:5e</mac-address>
<mtu>1500</mtu>
<flags broadcast="false" running="false" multicast="false" up="true"/>
<ipv4>
<netmask>255.255.240.0</netmask>
<broadcast>152.81.15.255</broadcast>
<address>152.81.8.136</address>
</ipv4>
<ipv6>
<address scope="global" prefix="40">2001066045010001020cf1fffe82475e</address>
<address scope="link-local" prefix="40">fe80000000000000020cf1fffe82475e</address>
</ipv6>
</interface>
</interfaces>
</network>
</netconf>
</data>
</rpc-reply>
Figure 11: Get-config of network interfaces using XPath
18
<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="1">
<get-config>
<source>
<running/>
</source>
<filter type="xpath">/netconf/network/route</filter>
</get-config>
</rpc>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
<data>
<netconf>
<network>
<route>
<route-entry>
<Destination>152.81.0.0</Destination>
<Passerelle>*</Passerelle>
<Genmask>255.255.240.0</Genmask>
<Indic>U</Indic>
<Metric>0</Metric>
<Ref>0</Ref>
<Use>0</Use>
<Iface>eth0</Iface>
</route-entry>
<route-entry>
<Destination>169.254.0.0</Destination>
<Passerelle>*</Passerelle>
<Genmask>255.255.0.0</Genmask>
<Indic>U</Indic>
<Metric>0</Metric>
<Ref>0</Ref>
<Use>0</Use>
<Iface>eth0</Iface>
</route-entry>
<route-entry>
<Destination>default</Destination>
<Passerelle>cat-481.loria.f</Passerelle>
<Genmask>0.0.0.0</Genmask>
<Indic>UG</Indic>
<Metric>0</Metric>
<Ref>0</Ref>
<Use>0</Use>
<Iface>eth0</Iface>
</route-entry>
</route>
</network>
</netconf>
</data>
</rpc-reply>
Figure 12: Get-config of routes using XPath
19
<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="1">
<get-config>
<source>
<running/>
</source>
<filter type="xpath">/netconf/security</filter>
</get-config>
</rpc>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
<data>
<netconf>
<security>
<rbac>
<users>
<user id="15">
<login>netconf</login>
<password>netconf</password>
<public-key keytype="rsa">AAAAB3NzaC1yc2EAAAABIwAAAIEAqSmp0ibI/kvv92aVz8A40GZA8hXomqcuwn9adOnuT5Sms9yaXwa2dFErOe6aghK550PvlSMNrMFw0caM2erD3xDM5B8XxQ7+RMZL6mSUndBN8/yIU3T/Ep4PLlL8wZ3B6SyfGbqVUj4v+taX7RtzupSpblQbP0CDbc350RfDJ6M=</public-key>
<room>B213</room>
</user>
<!-- [...] -->
</users>
<roles>
<role id="1">
<name>sysAdmin</name>
<junior-roles>
<junior-role roleRef="2"/>
<junior-role roleRef="3"/>
</junior-roles>
</role>
<!-- [...] -->
</roles>
<permissions>
<permission type="+" id="1" op="rw">
<scope>/netconf/security/rbac/permissions/permission[@id=’5’]</scope>
</permission>
<!-- [...] -->
</permissions>
<user-assignements>
<user-assignement roleRef="1" userRef="13" id="1"/>
<user-assignement roleRef="2" userRef="14" id="2"/>
</user-assignements>
<permission-assignements>
<permission-assignement roleRef="1" permRef="1" id="1"/>
<permission-assignement roleRef="2" permRef="2" id="2"/>
<!-- [...] -->
</permission-assignements>
</rbac>
</security>
</netconf>
</data>
</rpc-reply>
Figure 13: Get-config on RBAC module using XPath
20
<rbac>
<activate>
<roles>
<role>sysAdmin</role>
<role>netAdmin</role>
</roles>
</activate>
</rbac>
<rbac>
<deactivate>
<roles>
<role>sysAdmin</role>
</roles>
</deactivate>
</rbac>
Figure 14: RBAC roles (de)activation
YencaP is ready for access control on get and get-config operations. Toconfigure the privileges, edit the rbac.xml file. You can manage users, roles,permissions and their relationships.
At execution time, the Netconf managers will have to activate some roles tobe granted some privileges. RBAC is implemented with a role hierarchy. Whenactivating a role r1, a manager will be granted all privileges of this role, plus allprivileges of the junior roles of r1. A filtering process is responsible for cuttingthe XML nodes that a manager is not allowed to see. Only those nodes selectedby the XPath scopes in rbac.xml and their parent nodes can appear in the reply.
When a manager closes a Netconf session, it closes transparently the RBACsession and therefore deactivate all roles of the related session. A Netconf sessionis the same as an RBAC session in YencaP.
Edit-config (and therefore copy-config) still has to be updated to work withRBAC. Lock and unlock could also be allowed or disallowed with the RBACpolicy. We are working on this.
6.2 get-Modules extension
Under development
6.3 yum extension
Under development
7 Developer’s guide for extensions
7.1 Introduction
The YencaP architecture is designed to be extensible. It makes it easier forvendors to both support a larger data model and develop some new operations.These extensions don’t require to modify the core agent. It means that vendors
21
will be able to migrate to future YencaP implementation updates without prob-lems. Also YencaP allows to use different application protocols like SSH, BEEP,SOAP. Only SSH is implemented but the architecture is ready to support theseprotocols.
• To allow data model extension, YencaP is based on a module system. Themodules described in an configuration file are loaded dynamically. Eachmodule is responsible for a part of the whole data model. Although Yen-caP delegates the implementation of Netconf operations to the modules,it provides a programming interface for easy integration in YencaP. CoreYencaP also provides an interface for standard modules replies (ModuleRe-ply).
• To allow new operations, YencaP uses a command design pattern. Inthis design pattern, a Netconf operation is defined as a class and inheritsfrom a general command class (e.g. Get config operation class inheritsfrom Operation class). The advantage is that a new operation can beadded simply by coding a new class. As for modules, a configuration filedescribes the available operations, thus avoiding to update the code of coreYencaP. Core YencaP also provides an interface for standard operationreplies (OperationReply).
• To allow new application protocols, YencaP defines a generic server. It canbe inherited to support for instance BEEP or SOAP. A SSH Server andXMLSec Server are already implemented. A configuration file describeswhich one must be used.
7.2 Extending the data model
7.2.1 Introduction
In order to develop and integrate a new module in the YencaP software, someguidelines have to be followed. Each module implements a feature (service con-figuration, service monitoring) and will be in charge of performing the Netconfrequests related to its data. The whole agent configuration abstract view isan XML tree. A module is responsible for a subtree, which can be a sub-tree of another module. For instance, if moduleA is in charge of a subtreewhose root node is /foo/bar, moduleB can be in charge of a subtree whose rootnode is /foo/bar/fooB. It is also possible to define two modules as following:ModuleA is in charge of /foo/bar[@name=’A’] and ModuleB is in charge of/foo/bar[@name=’B’], thus allowing different equivalent vendors to distinguishtheir own subtree.
In the code, python modules are dynamically imported, meaning that noth-ing has to be updated in the core YencaP Agent.
7.2.2 Code Auto-generation
You can generate a new YencaP module with moduleGenerator Python module.The command line is the following:
% python moduleGenerator.py moduleName InheritedModuleName Xpath
22
First parameter, moduleName, is the name of the module to be created. Secondparameter, InheritedModuleName, is the parent inherited module. It must beone of Module or EasyModule. Third parameter, Xpath, is the XPath expressiongiving the XML node where the configuration data must be appended in thewhole configuration tree. The modules.xml file is automatically updated andthe directory for the new module is automatically created along with two files:init .py to build a new package and the main class of the new YencaP module.
7.2.3 Module registration
The conf/modules.xml file describes the list of module that are loaded by theagent. It means that, if a ’Quagga’ module is defined in this module, netconfdwill try to find the ’Quagga’ directory in the ’Module’ directory. Then netconfdwill build an instance of this module dynamically.
In Figure 15, the module name is ’Quagga’. This name must be the same asits directory. The ’mainFileName’ is the main file of the module and implementsthe Netconf operations: ’get-config’, ’edit-config’, ’copy-config’, ...
<module>
<name>Quagga</name>
<mainFileName>BGP_Module</mainFileName>
<className>BGP_Module</className>
<xpath>/netconf/routing/quagga</xpath>
<xsdfile>bgp.xsd</xsdfile>
<parameters>
<host>127.0.0.1</host>
<port>2605</port>
<password>a</password>
<enable_pass></enable_pass>
</parameters>
</module>
Figure 15: BGP Module Registration
The className is the Class of the object that will be instantiated. Thisobject is then stored in a list of Netconf modules. This class must inherit fromthe ”Module” class defined in module.py.
The xpath element defines the element the module is responsible for in thewhole configuration. It means that the module specific configuration will be asubtree of the whole configuration. The root of this subtree is the node givenby the xpath expression. Only one node of the whole configuration must matchthis xpath expression.
The ”parameters” element describes the parameters needed by the modulewhen being instanciated. This set of parameters is given to the init methodas a dictionnary.
7.2.4 Implementing the main class
The code of your module must be located in the directory you created withinModules directory. There are two ways to implement the main class of a newmodule:
23
1. The main class of the new module can inherit from Module class. In thatcase, one has to implement at least get-config and edit-config. copy-configis generic and is a particular case of edit-config
2. The main class of the new module can inherit from EasyModule class. Inthat case, one has to implement at least get-config and copy-config. edit-config is already implemented and relies on get-config and copy-config.
In both cases, you can override the Netconf methods.
Inheriting Module Your main class must inherit from the Module class. The”Module” class implements the copy-config method since it can be implementedon the base of ”edit-config” with special parameters. Therefore, a developer isfree to override it or not in its Netconf module. Typically, a developer will onlyimplement get-config and edit-config.
Figure 16 illustrates a module SampleModule inheriting from Module andimplementing get-config and edit-config. The dictionnary parameter containsthe parameters of the module entry in the modules.conf file.
from Modules.module import Module
class SampleModule(Module):
def __init__(self, dictionnary):
...
def get-config(self):
...
def edit-config(self):
...
Figure 16: Sample module implementation
Inheriting EasyModule In the last version of the agent, the module de-velopper task is simplified to the implementation of get-config and copy-config.Experience with Netconf showed that, in most cases, copy-config implementa-tion is easier than the edit-config one.
Therefore, a generic edit-config is now implemented in the super class. In-heriting from EasyModule is particularly interesting when the configuration tobe managed by the module is a XML file. In that case, adding a new moduleconsists in writing 4 lines. Figures 17 and 18 illustrate the implementation ofthe RBAC module and the Log module.
If the data you want to manage within hte module is not simply a XML file,you will have to implement get-config and copy-config. By default, EasyModuleconsiders that a XML file contains the managed data.
Figure 19 illustrates the approach followed for the edit-config netconf op-eration. The idea is that each edit-config is translated to an equivalent xsldocument. A meta stylesheet can parse the edit-config and generate the related
24
from Modules.easyModule import EasyModule
class RBACModule(EasyModule):
def __init__(self, arguments):
self.dataFile = "conf/rbac.xml"
Figure 17: RBAC module implementation
from Modules.easyModule import EasyModule
class Log_Module(EasyModule):
def __init__(self, arguments):
self.dataFile = "conf/log.xml"
Figure 18: Log module implementation
XSL document. Then the generated xsl stylesheet is applied to the device con-figuration. The latter is retrieved with a local get-config. Then a call to thecopy-config is performed to setup the new configuration.
Netconf request<Edit−Config>
meta.xsl
generated.xsl
old XML sourcedocument
new XML sourcedocument
copy−configget−config
XSLT
XSLT
Figure 19: Edit-config
In the current version, the xc:operation must be present in the edit-config.
7.2.5 Returning the Reply to Core YencaP
A generic class ModuleReply is provided in order to help module developer toreturn the module reply to the core agent. A ModuleReply can embed an error,an ok reply or some XML data. Here is an example code to be used in the caseof :
25
• An error:
moduleReply = ModuleReply(
error_type=ModuleReply.APPLICATION,
error_tag=ModuleReply.OPERATION_FAILED,
error_severity=ModuleReply.ERROR,
error_message="An helpful error message"
return moduleReply
• A success:
modulereply = ModuleReply()
return modulereply
• A get* request:
modulereply = ModuleReply(replynode=xmlnode)
return modulereply
7.3 Extending the capabilities (operations)
7.3.1 Creating a new operation
Let’s create an new operation called My operation. The first step is to create afile my operation.py in yencap/Operations/ext directory (yencap/Operations/basedirectory is dedicated to the base Netconf operations). Our convention is usethe pattern Aaaaa operation for the class name and aaaaa operation.py forthe python file name. For multiple words operation, use underscore like inGet config operation.
My operation must inherit from Operation class. It also must implementthe constructor init () without parameters, the setParameters() and execute()methods. init () is supposed to instantiate the ”my” operation parameterswith the default values. setParameters() parses the XML operation node, ex-tracts the parameters and checks the validity of the request. execute() theoperation.
Three main attributes are inherited from Operation class:
• self.operation: the XML node containing the operation:
<my>
<param1>v1</param1>
<param2>v2</param2>
</my>
• self.operationReply: The object that must be replied by the execute methodto the rpc layer.
• self.session: the Netconf session of the current manager.
7.3.2 Connecting the operation to YencaP
In order to activate this new operation, what must be done is to update theyencap/conf/operations.xml file with the following XML node:
26
from Operations.operation import Operation
from Operations.operationReply import OperationReply
from xml.dom import Node
class My_operation(Operation):
"""
Concrete command (see command design pattern) for "my" operation.
"""
def __init__(self):
"""
Constructor of a My_operation command.
"""
# Initializes the default value for filtering method
def setParameters(self):
"""
Parse the XML operation and get the fields
"""
# python code
# get value v1 from parameter param1
# get value v2 from parameter param2
def execute(self):
"""
Execute the get-config operation.
"""
# python code
# Use v1 and v2 to perform the operation.
self.operationReply.setNode(xmlreplynode)
return self.operationReply
Figure 20: Sample operation implementation
<operation>
<name>my</name>
<mainFileName>ext.my_operation</mainFileName>
<className>My_operation</className>
</operation>
Figure 21: Update to operations.xml file
27
7.4 Implementing a new application protocol (BEEP, SOAP,...)
Still in development.TODO: mv netconfd.xml to servers.xml (like operations.xml or modules.xml)
8 Appendix
8.1 Module
import string
from modulereply import ModuleReply
class Module:
"""
This class should be inherited by each module that want
to be add to the Agent.
Its specified the main functions needed for the Agent to
follow the NETCONF protocol.
"""
# CONFIGURATION DATASTORES
RUNNING_TARGET = "running"
CANDIDATE_TARGET = "candidate"
STARTUP_TARGET = "startup"
# ERROR OPTION
ROLL_BACK_ON_ERROR = "rollback-on-error"
STOP_ON_ERROR = "stop-on-error"
IGNORE_ERROR = "ignore-error"
# TEST OPTION
SET = "set"
TEST_AND_SET = "test-and-set"
# OPERATION ATTRIBUTE TAG
OPERATION_TAG = "operation"
XPATH_TAG = "xpath"
CONFIG_URI = "urn:ietf:params:xml:ns:netconf:base:1.0"
# OPERATION VALUES
CREATE_OPERATION = "create"
MERGE_OPERATION = "merge"
REPLACE_OPERATION = "replace"
DELETE_OPERATION = "delete"
NONE_OPERATION = "none"
def __init__(self, arguments):
"""
This method should be overrided by the module.
@type arguments : dictionary,
@param arguments : data specified in modules.xml for module creation.
"""
pass
def close(self):
"""
Should be overrided if the module needs to close some resurces,i.e. sockets.
"""
pass
28
def setAttributes(self, name, path, fileName):
"""
It is used by the Agent to manipulate the modules.It shouldn’t be overrided.
@type name: string
@param name: name of the module
@type path: string
@param path: xpath specifying the node for the module.
@type fileName: string
@param fileName: Main file name of the Module
"""
self.name = name
self.path = path
self.fileName = fileName
def get(self):
"""
Generate the device’s XML state data if any of the current module.
@rtype: ModuleReply
@return: It should return the device’s configuration or an error
** Relates to the netconf get-config operation
"""
xmlreply = ModuleReply(
error_type=ModuleReply.APPLICATION,
error_tag=ModuleReply.OPERATION_NOT_SUPPORTED,
error_severity=ModuleReply.ERROR,
error_message="OPERATION-NOT-SUPPORTED")
return xmlreply
def getConfig(self):
"""
Generate the device’s XML configuration of the current module.
@rtype: ModuleReply
@return: It should return the device’s configuration or an error
** Relates to the netconf get-config operation
"""
xmlreply = ModuleReply(
error_type=ModuleReply.APPLICATION,
error_tag=ModuleReply.OPERATION_NOT_SUPPORTED,
error_severity=ModuleReply.ERROR,
error_message="OPERATION-NOT-SUPPORTED")
return xmlreply
def copyConfig(self, sourceNode, targetName, urlValue=None):
"""
Copy the sourceNode’s XML configuration of the current module
to the targenName.
@type targetName: string
@param targetName: Is always the "running" configuration datastore because
"startup", "candidate") is managed by the core Netconf module
@rtype: ModuleReply
@return: It should return the device’s configuration or an error
** Relates to the netconf copy-config operation
"""
if (targetName == self.RUNNING_TARGET):
return self.editConfig(self.REPLACE_OPERATION, self.SET, self.STOP_ON_ERROR,
self.RUNNING_TARGET, sourceNode)
if (targetName == self.CANDIDATE_TARGET or targetName == self.STARTUP_TARGET):
29
# Replace the candidate xml file with the docsource
f = open("conf/" + targetName + ".xml",’w’)
PrettyPrint(sourceNode, f)
f.close()
return ModuleReply()
if (targetName == "url" and urlValue != None):
xmlreply = ModuleReply(error_type=ModuleReply.APPLICATION,
error_tag=ModuleReply.OPERATION_NOT_SUPPORTED,
error_severity=ModuleReply.ERROR,
error_message="OPERATION-NOT-SUPPORTED")
return xmlreply
def editConfig(self, defaultoperation, testoption, erroroption, target,
confignode, targetnode=None):
"""
Apply the request specified in confignode to the targetnode.
@type defaultoperation: MERGE_OPERATION | REPLACE_OPERATION | NONE_OPERATION
@param defaultoperation : as specified in NETCONF protocol
@type testoption : SET | TEST_AND_SET
@param testoption : as specified in NETCONF protocol
@type erroroption : STOP_ON_ERROR | IGNORE_ERROR | ROLL_BACK_ON_ERROR
@param erroroption : as specified in NETCONF protocol
@type target : RUNNING_TARGET | CANDIDATE_TARGET | STARTUP_TARGET
@param target : as specified in NETCONF protocol
@type targetnode : string
@param targetnode : if the target is RUNNING_TARGET or STARTUP_TARGET
it will be ignored otherwise should be the node of the CANDIDATE_TARGET
that this module should procees
@rtype: ModuleReply
@return: It should return a success or error message.
** Relates to the netconf edit-config operation
"""
xmlreply = ModuleReply(error_type=ModuleReply.APPLICATION,
error_tag=ModuleReply.OPERATION_NOT_SUPPORTED,
error_severity=ModuleReply.ERROR,
error_message="OPERATION-NOT-SUPPORTED")
return xmlreply
def rollBack(self):
"""
It restablish the last state of the device’s configuration. Note that the
last editConfig should had received erroroption equal to
ROLL_BACK_ON_ERROR in order to achived this request,
otherwise returns in error.
@rtype: ModuleReply
@return: It should return the device’s configuration or an error
"""
xmlreply = ModuleReply(error_type=ModuleReply.APPLICATION,
error_tag=ModuleReply.OPERATION_NOT_SUPPORTED,
error_severity=ModuleReply.ERROR,
error_message="OPERATION-NOT-SUPPORTED")
return xmlreply
def manage(self, xpath=None):
"""
Shouldn’t be overrided, it is used by the Netconf Agent.
@rtype : boolean
@return: A boolean value if this module is responsible for the request
xpath expression
"""
tab1 = xpath.split(’/’)
30
tab2 = self.path.split(’/’)
i=1
while i<len(tab1) and i<len(tab2) and tab1[i]==tab2[i] :
i=i+1
return i==(len(tab2)) or i==(len(tab1))
8.2 EasyModule
from Modules.module import Module
from Modules.modulereply import ModuleReply
from Ft.Xml.Domlette import NonvalidatingReader, PrettyPrint
from Ft.Xml import XPath, InputSource
from Ft.Xml.Xslt import Processor, DomWriter
import util
metaFile = "Modules/meta.xsl"
class EasyModule(Module):
def __init__(self, arguments):
pass
# This method must return the root node
# corresponding to the current module
def getConfig(self):
# This is for test purpose
doc = NonvalidatingReader.parseUri("file:"+self.dataFile)
xmlreply = ModuleReply(replynode=doc.documentElement)
return xmlreply
# This method must return the root node
# corresponding to the current module
def copyConfig(self, sourceNode, targetName, urlValue=None):
util.printNodeToFile(sourceNode, self.dataFile)
moduleReply = ModuleReply()
return moduleReply
def editConfig(self,defaultoperation,testoption,erroroption,target,confignode,targetnode=None):
"""
Apply a BGP request from the confignode to the targetnode.
@type defaultoperation: MERGE_OPERATION | REPLACE_OPERATION | NONE_OPERATION
@param defaultoperation : as specified in NETCONF protocol
@type testoption : SET | TEST_AND_SET
@param testoption : as specified in NETCONF protocol
@type erroroption : STOP_ON_ERROR | IGNORE_ERROR | ROLL_BACK_ON_ERROR
@param erroroption : as specified in NETCONF protocol
@type target : RUNNING_TARGET | CANDIDATE_TARGET | STARTUP_TARGET
@param target : as specified in NETCONF protocol
@type targetnode : string
@param targetnode : if the target is RUNNING_TARGET or STARTUP_TARGET it will be ignored otherwise should be the node of the CANDIDATE_TARGET that this module should procees
@rtype: ModuleReply
@return: It returns a success or error message.
** Relates to the netconf edit-config operation
"""
try:
# Generate a stylesheet equivalent to the edit-config
31
df = InputSource.DefaultFactory
editXMLRequest = df.fromString(util.convertNodeToString(confignode), ’urn:dummy’)
stylesheet = df.fromUri("file:"+metaFile, ’urn:sty’)
p = Processor.Processor()
p.appendStylesheet(stylesheet)
wr = DomWriter.DomWriter()
p.run(editXMLRequest, writer=wr)
generatedStyleSheet = wr.getResult()
# Apply the generated stylesheet to the source document
inputStyleSheet = df.fromString(util.convertNodeToString(generatedStyleSheet), ’urn:sty’)
oldXMLDocument = self.getConfig().getXMLNodeReply()
inputDocument = df.fromString(util.convertNodeToString(oldXMLDocument), ’urn:dummy’)
p = Processor.Processor()
p.appendStylesheet(inputStyleSheet)
wr = DomWriter.DomWriter()
p.run(inputDocument, writer=wr)
newXMLDoc = wr.getResult()
# Copy the new document over the old one
xmlReply = self.copyConfig(newXMLDoc, target)
return xmlReply
except Exception,exp:
print str(exp)
moduleReply = ModuleReply(
error_type=ModuleReply.APPLICATION,
error_tag=ModuleReply.OPERATION_FAILED,
error_severity=ModuleReply.ERROR,
error_message=str(exp))
return moduleReply
8.3 ModuleReply
from Ft.Xml.Domlette import NonvalidatingReader, implementation
from Ft.Xml import EMPTY_NAMESPACE
class ModuleReply:
"""
This class is used as a container of data for every module reply to the Agent.
"""
### Tag ###
IN_USE = "IN_USE"
INVALID_VALUE = "INVALID_VALUE"
TOO_BIG = "TOO_BIG"
MISSING_ATTRIBUTE = "MISSING_ATTRIBUTE"
BAD_ATTRIBUTE = "BAD_ATTRIBUTE"
UNKNOWN_ATTRIBUTE = "UNKNOWN_ATTRIBUTE"
MISSING_ELEMENT = "MISSING_ELEMENT"
BAD_ELEMENT = "BAD_ELEMENT"
UNKNOWN_ELEMENT = "UNKNOWN_ELEMENT"
ACCESS_DENIED = "ACCESS_DENIED"
LOCK_DENIED = "LOCK_DENIED"
RESOURCE_DENIED = "RESOURCE_DENIED"
ROLLBACK_FAILED = "ROLLBACK_FAILED"
DATA_EXISTS = "DATA_EXISTS"
DATA_MISSING = "DATA_MISSING"
OPERATION_NOT_SUPPORTED = "OPERATION_NOT_SUPPORTED"
32
OPERATION_FAILED = "OPERATION_FAILED"
PARTIAL_OPERATION = "PARTIAL_OPERATION"
### Error-type ###
TRANSPORT = "transport"
RPC = "rpc"
PROTOCOL = "protocol"
APPLICATION = "application"
### Severity ###
ERROR = "error"
WARNNING = "warnning"
### Error-info ###
BAD_ATTRIBUTE_INFO = "bad-attribute"
BAD_ELEMENT_INFO = "bad-element"
SESSION_ID_INFO = "session-id"
OK_ELEMENT_INFO = "ok-element"
ERR_ELEMENT_INFO = "err-element"
NOOP_ELEMENT_INFO = "noop-element"
def __init__(self,replynode=None ,error_type=None, error_tag=None,
error_severity=None, error_tag_app= None, error_path= None, error_message=None):
"""
It creates an Struture that will be used in every function that a module has been called by the Agent
If the request was succesfull it should create an instance with any parameters.
If the request produced an XML node that should be included in the reply the instance should be created just with the replynode parameter.
Otherwise, it shoud specify the error according to the NETCONF Protocol
"""
self.replynode = replynode
self.error_type = error_type
self.error_tag = error_tag
self.error_severity = error_severity
self.error_tag_app = error_tag_app
self.error_path = error_path
self.error_message = error_message
self.error_info = []
def setReplyNode(self,xmlnode):
self.replynode = xmlnode
def setErrorType(self,error_type):
self.error_type = error_type
def setErrorTag(self,error_tag):
self.error_tag = error_tag
def setSeverityError(self,error_severity):
self.error_severity = error_severity
def setErrorAppTag(self,error_tag_app):
self.error_tag_app = error_tag_app
def setErrorPath(self,error_path):
self.error_path = error_path
def setErrorMessage(self,error_message):
self.error_message = error_message
33
def addErrorInfo(self,error_info_tag,error_message):
self.error_info.append((error_info_tag,error_message))
def isError(self):
return self.error_type != None
def createNode(self,doc,parent,tag,value=None):
element = doc.createElementNS(EMPTY_NAMESPACE,tag)
parent.appendChild(element)
if (value != None):
text = doc.createTextNode(value)
element.appendChild(text)
return element
def getXMLNodeReply(self):
"""
Generate the XML node with the contents of the instance.
@rtype: cDomlette
@return: It is an XML node.
"""
if (self.isError()):
doc = implementation.createDocument(EMPTY_NAMESPACE, None, None)
rpcerrornode = self.createNode(doc=doc, parent=doc,tag="rpc-error",value=None)
self.createNode(doc=doc,parent=rpcerrornode,tag="error-type",value=self.error_type)
self.createNode(doc=doc,parent=rpcerrornode,tag="error-tag",value=self.error_tag)
self.createNode(doc=doc,parent=rpcerrornode,tag="error-severity",value=self.error_severity)
if ( self.error_tag_app != None):
self.createNode(doc=doc,parent=rpcerrornode,tag="error-app-tag",value=self.error_tag_app)
if ( self.error_path != None):
self.createNode(doc=doc,parent=rpcerrornode,tag="error-path",value=self.error_path)
if ( self.error_message != None):
self.createNode(doc=doc,parent=rpcerrornode,tag="error-message",value=self.error_message)
if ( self.error_info != {}):
infonode = self.createNode(doc=doc,parent=rpcerrornode,tag="error-info",value=None)
for key,item in self.error_info:
self.createNode(doc=doc,parent=infonode,tag=key,value=item)
self.replynode = doc.documentElement
elif (self.replynode == None):
doc = implementation.createDocument(EMPTY_NAMESPACE, None, None)
self.createNode(doc=doc,parent=doc,tag="ok",value=None)
self.replynode = doc.documentElement
return self.replynode
34