Merge "Added support for NOS version 4.1.0, 5.0.0 and greater"

This commit is contained in:
Jenkins 2014-07-16 21:44:55 +00:00 committed by Gerrit Code Review
commit ac78a0f5df
5 changed files with 234 additions and 6 deletions

View File

@ -3,6 +3,7 @@
# password = <mgmt admin password>
# address = <switch mgmt ip address>
# ostype = NOS
# osversion = autodetect | n.n.n
# physical_networks = physnet1,physnet2
#
# Example:
@ -10,4 +11,5 @@
# password = password
# address = 10.24.84.38
# ostype = NOS
# osversion = 4.1.1
# physical_networks = physnet1,physnet2

View File

@ -39,7 +39,9 @@ ML2_BROCADE = [cfg.StrOpt('address', default='',
cfg.StrOpt('physical_networks', default='',
help=_('Allowed physical networks')),
cfg.StrOpt('ostype', default='NOS',
help=_('Unused'))
help=_('OS Type of the switch')),
cfg.StrOpt('osversion', default='4.0.0',
help=_('OS Version number'))
]
cfg.CONF.register_opts(ML2_BROCADE, "ml2_brocade")
@ -66,12 +68,52 @@ class BrocadeMechanism(driver_api.MechanismDriver):
def brocade_init(self):
"""Brocade specific initialization for this class."""
self._switch = {'address': cfg.CONF.ml2_brocade.address,
'username': cfg.CONF.ml2_brocade.username,
'password': cfg.CONF.ml2_brocade.password
}
osversion = None
self._switch = {
'address': cfg.CONF.ml2_brocade.address,
'username': cfg.CONF.ml2_brocade.username,
'password': cfg.CONF.ml2_brocade.password,
'ostype': cfg.CONF.ml2_brocade.ostype,
'osversion': cfg.CONF.ml2_brocade.osversion}
self._driver = importutils.import_object(NOS_DRIVER)
# Detect version of NOS on the switch
osversion = self._switch['osversion']
if osversion == "autodetect":
osversion = self._driver.get_nos_version(
self._switch['address'],
self._switch['username'],
self._switch['password'])
virtual_fabric_enabled = self._driver.is_virtual_fabric_enabled(
self._switch['address'],
self._switch['username'],
self._switch['password'])
if virtual_fabric_enabled:
LOG.debug(_("Virtual Fabric: enabled"))
else:
LOG.debug(_("Virtual Fabric: not enabled"))
self.set_features_enabled(osversion, virtual_fabric_enabled)
def set_features_enabled(self, nos_version, virtual_fabric_enabled):
self._virtual_fabric_enabled = virtual_fabric_enabled
version = nos_version.split(".", 2)
# Starting 4.1.0 port profile domains are supported
if int(version[0]) >= 5 or (int(version[0]) >= 4
and int(version[1]) >= 1):
self._pp_domains_supported = True
else:
self._pp_domains_supported = False
self._driver.set_features_enabled(self._pp_domains_supported,
self._virtual_fabric_enabled)
def get_features_enabled(self):
return self._pp_domains_supported, self._virtual_fabric_enabled
def create_network_precommit(self, mech_context):
"""Create Network in the mechanism specific database table."""

View File

@ -23,6 +23,24 @@
Interface Configuration Commands
"""
# Get NOS Version
SHOW_FIRMWARE_VERSION = (
"show-firmware-version xmlns:nc="
"'urn:brocade.com:mgmt:brocade-firmware-ext'"
)
GET_VCS_DETAILS = (
'get-vcs-details xmlns:nc="urn:brocade.com:mgmt:brocade-vcs"'
)
SHOW_VIRTUAL_FABRIC = (
'show-virtual-fabric xmlns:nc="urn:brocade.com:mgmt:brocade-vcs"'
)
GET_VIRTUAL_FABRIC_INFO = (
'interface xmlns:nc="urn:brocade.com:mgmt:brocade-firmware-ext"'
)
NOS_VERSION = "./*/{urn:brocade.com:mgmt:brocade-firmware-ext}os-version"
VFAB_ENABLE = "./*/*/*/{urn:brocade.com:mgmt:brocade-vcs}vfab-enable"
# Create VLAN (vlan_id)
CREATE_VLAN_INTERFACE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
@ -72,6 +90,20 @@ CREATE_VLAN_PROFILE_FOR_PORT_PROFILE = """
</config>
"""
# Configure L2 mode for VLAN sub-profile (port_profile_name)
CONFIGURE_L2_MODE_FOR_VLAN_PROFILE_IN_DOMAIN = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<name>{name}</name>
<vlan-profile>
<switchport-basic>
<basic/>
</switchport-basic>
</vlan-profile>
</port-profile>
</config>
"""
# Configure L2 mode for VLAN sub-profile (port_profile_name)
CONFIGURE_L2_MODE_FOR_VLAN_PROFILE = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
@ -185,6 +217,29 @@ xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">
</config>
"""
#port-profile domain management commands
REMOVE_PORTPROFILE_FROM_DOMAIN = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile-domain xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<port-profile-domain-name>{domain_name}</port-profile-domain-name>
<profile operation="delete">
<profile-name>{name}</profile-name>
</profile>
</port-profile-domain>
</config>
"""
#put port profile in default domain
CONFIGURE_PORTPROFILE_IN_DOMAIN = """
<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
<port-profile-domain xmlns="urn:brocade.com:mgmt:brocade-port-profile">
<port-profile-domain-name>{domain_name}</port-profile-domain-name>
<profile>
<profile-name>{name}</profile-name>
</profile>
</port-profile-domain>
</config>
"""
#
# Constants
#

View File

@ -23,6 +23,7 @@ Neutron network life-cycle management.
"""
from ncclient import manager
from xml.etree import ElementTree
from neutron.openstack.common import excutils
from neutron.openstack.common import log as logging
@ -51,6 +52,18 @@ class NOSdriver():
def __init__(self):
self.mgr = None
self._virtual_fabric_enabled = False
self._pp_domains_supported = False
def set_features_enabled(self, pp_domains_supported,
virtual_fabric_enabled):
"""Set features in the driver based on what was detected by the MD."""
self._pp_domains_supported = pp_domains_supported
self._virtual_fabric_enabled = virtual_fabric_enabled
def get_features_enabled(self):
"""Respond to status of features enabled."""
return self._pp_domains_supported, self._virtual_fabric_enabled
def connect(self, host, username, password):
"""Connect via SSH and initialize the NETCONF session."""
@ -69,6 +82,7 @@ class NOSdriver():
self.mgr = manager.connect(host=host, port=SSH_PORT,
username=username, password=password,
unknown_host_cb=nos_unknown_host_cb)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Connect failed to switch"))
@ -83,16 +97,46 @@ class NOSdriver():
self.mgr.close_session()
self.mgr = None
def get_nos_version(self, host, username, password):
"""Show version of NOS."""
try:
mgr = self.connect(host, username, password)
return self.nos_version_request(mgr)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("NETCONF error"))
self.close_session()
def is_virtual_fabric_enabled(self, host, username, password):
"""Show version of NOS."""
try:
mgr = self.connect(host, username, password)
return (self.virtual_fabric_info(mgr) == "enabled")
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("NETCONF error"))
self.close_session()
def create_network(self, host, username, password, net_id):
"""Creates a new virtual network."""
domain_name = "default"
name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
try:
mgr = self.connect(host, username, password)
self.create_vlan_interface(mgr, net_id)
self.create_port_profile(mgr, name)
if self._pp_domains_supported and self._virtual_fabric_enabled:
self.configure_port_profile_in_domain(mgr, domain_name, name)
self.create_vlan_profile_for_port_profile(mgr, name)
self.configure_l2_mode_for_vlan_profile(mgr, name)
if self._pp_domains_supported:
self.configure_l2_mode_for_vlan_profile_with_domains(mgr, name)
else:
self.configure_l2_mode_for_vlan_profile(mgr, name)
self.configure_trunk_mode_for_vlan_profile(mgr, name)
self.configure_allowed_vlans_for_vlan_profile(mgr, name, net_id)
self.activate_port_profile(mgr, name)
@ -104,9 +148,12 @@ class NOSdriver():
def delete_network(self, host, username, password, net_id):
"""Deletes a virtual network."""
domain_name = "default"
name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
try:
mgr = self.connect(host, username, password)
if self._pp_domains_supported and self._virtual_fabric_enabled:
self.remove_port_profile_from_domain(mgr, domain_name, name)
self.deactivate_port_profile(mgr, name)
self.delete_port_profile(mgr, name)
self.delete_vlan_interface(mgr, net_id)
@ -234,3 +281,37 @@ class NOSdriver():
confstr = template.CONFIGURE_ALLOWED_VLANS_FOR_VLAN_PROFILE.format(
name=name, vlan_id=vlan_id)
mgr.edit_config(target='running', config=confstr)
def remove_port_profile_from_domain(self, mgr, domain_name, name):
"""Remove port-profile from default domain."""
confstr = template.REMOVE_PORTPROFILE_FROM_DOMAIN.format(
domain_name=domain_name, name=name)
mgr.edit_config(target='running', config=confstr)
def configure_port_profile_in_domain(self, mgr, domain_name, name):
"""put port-profile in default domain."""
confstr = template.CONFIGURE_PORTPROFILE_IN_DOMAIN.format(
domain_name=domain_name, name=name)
mgr.edit_config(target='running', config=confstr)
def configure_l2_mode_for_vlan_profile_with_domains(self, mgr, name):
"""Configures L2 mode for VLAN sub-profile."""
confstr = template.CONFIGURE_L2_MODE_FOR_VLAN_PROFILE_IN_DOMAIN.format(
name=name)
mgr.edit_config(target='running', config=confstr)
def nos_version_request(self, mgr):
"""Get firmware information using NETCONF rpc."""
reply = mgr.dispatch(template.SHOW_FIRMWARE_VERSION, None, None)
et = ElementTree.fromstring(str(reply))
return et.find(template.NOS_VERSION).text
def virtual_fabric_info(self, mgr):
"""Get virtual fabric info using NETCONF get-config."""
response = mgr.get_config('running',
filter=("xpath", "/vcs/virtual-fabric"))
et = ElementTree.fromstring(str(response))
vfab_enable = et.find(template.VFAB_ENABLE)
if vfab_enable is not None:
return "enabled"
return "disabled"

View File

@ -66,3 +66,51 @@ class TestBrocadeMechDriverPortsV2(test_db_plugin.TestPortsV2,
class TestBrocadeMechDriverSubnetsV2(test_db_plugin.TestSubnetsV2,
TestBrocadeMechDriverV2):
pass
class TestBrocadeMechDriverFeaturesEnabledTestCase(TestBrocadeMechDriverV2):
def setUp(self):
super(TestBrocadeMechDriverFeaturesEnabledTestCase, self).setUp()
def test_version_features(self):
vf = True
# Test for NOS version 4.0.3
self.mechanism_driver.set_features_enabled("4.0.3", vf)
# Verify
pp_domain_support, virtual_fabric_enabled = (
self.mechanism_driver.get_features_enabled()
)
self.assertFalse(pp_domain_support)
self.assertTrue(virtual_fabric_enabled)
# Test for NOS version 4.1.0
vf = True
self.mechanism_driver.set_features_enabled("4.1.0", vf)
# Verify
pp_domain_support, virtual_fabric_enabled = (
self.mechanism_driver.get_features_enabled()
)
self.assertTrue(pp_domain_support)
self.assertTrue(virtual_fabric_enabled)
# Test for NOS version 4.1.3
vf = False
self.mechanism_driver.set_features_enabled("4.1.3", vf)
# Verify
pp_domain_support, virtual_fabric_enabled = (
self.mechanism_driver.get_features_enabled()
)
self.assertTrue(pp_domain_support)
self.assertFalse(virtual_fabric_enabled)
# Test for NOS version 5.0.0
vf = True
self.mechanism_driver.set_features_enabled("5.0.0", vf)
# Verify
pp_domain_support, virtual_fabric_enabled = (
self.mechanism_driver.get_features_enabled()
)
self.assertTrue(pp_domain_support)
self.assertTrue(virtual_fabric_enabled)