Overview
OpenStack Neutron project offers pluggable framework means you can extend the capability of Neutron by orchestrating the Neutron functions to your upstream networking gears. For example, if you have provisioned a VLAN tagged Neutron network in OpenStack, this VLAN (Segmentation ID) should also be provisioned in upstream switch and should be allowed in the trunk port. Manually performing this task does not scale for building your own on-premise cloud infrastructure. As a result, you need to automate this process using Neutron networking plugins.
The Modular Layer 2 (ML2) neutron plug-in is a framework allowing OpenStack Networking to simultaneously use the variety of layer 2 networking technologies found in complex real-world data centers.
In this blog, I’ll be writing very simple ML2 driver code in python. This code will be provisioning VLAN in Cisco UCS Manger cascaded with the creation of OpenStack Network either from CLI or from Horizon dashboard. Similarly, it will be deleting VLAN in UCS Manger when OpenStack network is deleted.
This driver will be performing very simple exercise of adding VLAN in UCSM LAN Cloud. It does not add VLAN in vNIC templates or the server’s service profile vNIC. However, this code can be modified to submit XML API calls for service profile. Further, for simplicity, this code hard coded certain things such as UCS credentials. However, in real scenario, it should be in the config file and your code should first read the config file and capture variable entries.
Similarly, let’s say, if we decide that this code should add VLAN in the vNIC of service profile, that service profile name should also be included in the config file and read from there inside the python code. Again, this module gives you a starting point. In this sample code, I’m making XML API calls, however, Cisco UCS python SDK is recommended. Take a look at the SDK, this would make your life lot easier in making Cisco UCS API calls.
Cisco also offers Cisco UCS Platform Emulator. You can setup this platform in Virtual Machine on your laptop. UCS Emulator gives you similar look and feel as if you are accessing the physical Fabric Interconnect. You can launch the UCS Manger GUI and perform management tasks. It’s a great platform to learn how to make API calls to UCS Manager as well. You can also use this emulator to code in PowerShell using Cisco UCS PowerTool module. In this example, I also setup UCS emulator on my laptop. You can find more information about Cisco UCS emulator at the below link.
https://community.cisco.com/t5/unified-computing-system/ucs-platform-emulator-downloads-ucspe-4-1-2cpe1-ucspe-4-0-4epe1/ta-p/3648177
Cisco UCS Manager offers API framework through which you can perform any task via the API calls that are available in Cisco UCS Manger GUI. PowerTool is also available to call those API via PowerShell as mentioned earlier. You can write complete UCS Manger automation using the Powershell. You can watch my video on how Powershell can configure the entire UCS with 1 — Click.
Cisco UCS also offers Python SDK which is a set of Python modules, each containing one or more classes, developed specifically to automate UCS Manager.
Or Alternatively, you can simply submit the POST request to Cisco UCS API. The request will contain the XML to perform certain action in UCS Manager.
Let’s start coding and gets our hands dirty. This is a very simple example for writing your own plugin to automate Cisco UCS Manger.
Instruction
Write two python module
- my_mechanism.py
- my_mech_ucs.py
my_mechanism.py
from neutron.openstack.common import log as logging
from neutron.plugins.ml2 import driver_api as api
from my_mech_ucs import ucs
LOG = logging.getLogger(__name__)
class MyDriver(api.MechanismDriver):
def initialize(self):
pass
def create_network_postcommit(self, context):
segments = context.network_segments
vlan_id = segments[0]['segmentation_id']
LOG.debug("creating vlan_id=%s",vlan_id)
ucsm = ucs()
token=ucsm.GetAuthCookie()
LOG.debug("UCSM Auth Cookie=%s",token)
ucsm.ProvisionVLAN(token,vlan_id)
ucsm.UCSLogout(token)
def delete_network_postcommit(self, context):
LOG.debug("This is from my plugin Afzal....")
segments = context.network_segments
vlan_id = segments[0]['segmentation_id']
LOG.debug("deleting vlan_id=%s",vlan_id)
ucsm = ucs()
token=ucsm.GetAuthCookie()
LOG.debug("UCSM Auth Cookie=%s",token)
ucsm.DeProvisionVLAN(token,vlan_id)
ucsm.UCSLogout(token)
my_mech_ucs.py
import urllib2
from xml.dom import minidom
class ucs():
ip = "http://<ucsm ip address>/nuova"
def GetAuthCookie(self):
outcookie="nocookie"
Authdata= "<aaaLogin inName='config' inPassword='config'></aaaLogin>"
request = urllib2.Request(self.ip, Authdata)
request.add_header("Content-Type","application/xml")
response=urllib2.urlopen(request)
xmlout= response.read()
xmldoc = minidom.parseString(xmlout)
xmlelement = xmldoc.getElementsByTagName("aaaLogin")
outcookie = xmlelement[0].attributes['outCookie'].value
return outcookie
def ProvisionVLAN(self, token, vlanid):
vlanstring = "<configConfMos inHierarchical='false' cookie='" + token + "'><inConfigs><pair key='fabric/lan/net-VLAN" + str(vlanid) + "'><fabricVlan compressionType='included' defaultNet='no' dn='fabric/lan/net-VLAN" + str(vlanid) + "' id='" + str(vlanid) + "' mcastPolicyName='' name='VLAN"+ str(vlanid) +"' pubNwName='' sharing='none' status='created'></fabricVlan></pair></inConfigs></configConfMos>"
request = urllib2.Request(self.ip, vlanstring)
response=urllib2.urlopen(request)
xmlout= response.read()
def DeProvisionVLAN(self, token, vlanid):
vlanstring = "<configConfMos inHierarchical='false' cookie='" + token + "'><inConfigs><pair key='fabric/lan/net-VLAN" + str(vlanid) + "'><fabricVlan compressionType='included' defaultNet='no' dn='fabric/lan/net-VLAN" + str(vlanid) + "' id='" + str(vlanid) + "' mcastPolicyName='' name='VLAN"+ str(vlanid) +"' pubNwName='' sharing='none' status='deleted'></fabricVlan></pair></inConfigs></configConfMos>"
request = urllib2.Request(self.ip, vlanstring)
response=urllib2.urlopen(request)
xmlout= response.read()
def UCSLogout(self, outcookie):
strlogout = "<aaaLogout cookie='" + outcookie + "'/>"
request = urllib2.Request(self.ip, strlogout)
response=urllib2.urlopen(request)
xmlout=response.read()
Setup Instructions
My_mechanism.py is the main driver file. It uses my_mech_ucs module to make cisco UCS xml api calls. It connects to Cisco UCSM with userid and password credentials, then it receives the authorization token. Then all subsequent API calls are made using authorization token.
My_mechanism.py and my_mech_ucs.py should be place in the following folder:
/usr/lib/python2.7/site-packages/neutron/plugins/ml2/drivers
Modify entry_points.txt in /usr/lib/python2.7/site-packages/neutron-2014.2-py2.7.egg-info (this neutron folder could be different in your environment)
Add following line in entry_points.txt under as below [neutron.ml2.mechanism.drivers] section
mydriver=neutron.plugins.ml2.drivers.my_mechansim:MyDriver (MyDriver is the class name in my_mechanism.py module which is located at /usr/lib/python2.7/site-packages/neutron/plugins/ml2/drivers
Modify ml2_conf.ini file located at /etc/neutron/plugins/ml2. This change will also be triggered in plugin.ini automatically.
Add the following in ml2_conf.ini
Mechanism_drivers = openvswtich,mydriver (Note: openvswitch might be already there)
Modify SELINUX in /etc/selinux/config file to SELINUX=disabled. This is required for UCS API calls to work within the plugin, otherwise it will not work. This is the work around and not considered as the best practice. There should be other ways to solve this. But I did it to see if it works for the sake of simplicity. SELINIX change also require system reboot.
Restart Neutron server by running
# service neutron-server restart
Note: Always restart Neutron service for any code change to take effect.
Now you are ready to see how the plugin works !!!
This plugin also works with Cisco UCS emulator. Make sure you can ping UCS emulator from the OpenStack Controller node.
Some Screen Shots
ml2_conf.ini file
specify mydriver in mechanism_driver section as shown below:
Module file
SELINUX Config
entry point
Module file entry in entry_point.txt. MyDriver is the class name in my_mechanism.py
Debug the module
With the following python code you can verify if the module is working. this would provision VLAN with the ID 20 is Cisco UCS Manager
#Python
>>>from my_mech_ucs import ucs
>>>x=uss()
>>>y=x.GetAuthCookie()
>>>print y
>>>x.ProvisionVLAN(y,20)
>>>x.UCSLogout(y)
Demo
The following demo show the working plugin.