Initial commit with lots of changes.
This commit is contained in:
parent
629b9bae28
commit
d047001964
|
@ -128,5 +128,17 @@ VIF_DESC = 'vif_desc'
|
|||
DEVICENAME = 'device'
|
||||
UCSPROFILE = 'portprofile'
|
||||
|
||||
IP_ADDRESS = 'ip_address'
|
||||
CHASSIS_ID = 'chassis_id'
|
||||
BLADE_ID = 'blade_id'
|
||||
HOST_NAME = 'host_name'
|
||||
|
||||
INSTANCE_ID = 'instance_id'
|
||||
|
||||
UCS_INVENTORY = 'ucs_inventory'
|
||||
LEAST_RSVD_BLADE_DICT = 'least_rsvd_blade_dict'
|
||||
|
||||
UCSM_IP = 'ucsm_ip_address'
|
||||
|
||||
MAX_CREDENTIALS = 65568
|
||||
MAX_QOS_LEVELS = 1024
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[VLANS]
|
||||
vlan_start=<put_vlan_id_range_start_here>
|
||||
vlan_end=<put_vlan_id_range_end_here>
|
||||
vlan_start=100
|
||||
vlan_end=3000
|
||||
vlan_name_prefix=q-
|
||||
|
||||
[PORTS]
|
||||
|
@ -13,4 +13,7 @@ max_port_profiles=65568
|
|||
max_networks=65568
|
||||
|
||||
[MODEL]
|
||||
model_class=quantum.plugins.cisco.l2network_model.L2NetworkModel
|
||||
model_class=quantum.plugins.cisco.models.l2network_single_blade.L2NetworkSinlgeBlade
|
||||
|
||||
[SEGMENTATION]
|
||||
manager_class=quantum.plugins.cisco.segmentation.l2network_vlan_mgr.L2NetworkVLANMgr
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
[ucsm-1]
|
||||
ip_address = <put_ucsm_ip_address_here>
|
||||
[[chassis-1]]
|
||||
chassis_id = <put_the_chassis_id_here>
|
||||
[[[blade-1]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
[[[blade-2]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
[[[blade-3]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
|
||||
[ucsm-2]
|
||||
ip_address = <put_ucsm_ip_address_here>
|
||||
[[chassis-1]]
|
||||
chassis_id = <put_the_chassis_id_here>
|
||||
[[[blade-1]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
||||
[[[blade-2]]]
|
||||
blade_id = <put_blade_id_here>
|
||||
host_name = <put_hostname_here>
|
|
@ -47,6 +47,7 @@ class L2Network(QuantumPluginBase):
|
|||
def __init__(self):
|
||||
self._vlan_counter = int(conf.VLAN_START) - 1
|
||||
self._model = utils.import_object(conf.MODEL_CLASS)
|
||||
self._vlan_mgr = utils.import_object(conf.MANAGER_CLASS)
|
||||
cdb.initialize()
|
||||
# TODO (Sumit): The following should move to the segmentation module
|
||||
cdb.create_vlanids()
|
||||
|
@ -442,41 +443,35 @@ class L2Network(QuantumPluginBase):
|
|||
def get_host(self, tenant_id, instance_id, instance_desc):
|
||||
"""Provides the hostname on which a dynamic vnic is reserved"""
|
||||
LOG.debug("get_host() called\n")
|
||||
host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}}
|
||||
return host_list
|
||||
return self._invoke_device_plugins(self._func_name(), [tenant_id,
|
||||
instance_id,
|
||||
instance_desc])
|
||||
|
||||
def get_instance_port(self, tenant_id, instance_id, instance_desc):
|
||||
"""
|
||||
Get the portprofile name and the device namei for the dynamic vnic
|
||||
"""
|
||||
LOG.debug("get_instance_port() called\n")
|
||||
vif_desc = {const.VIF_DESC:
|
||||
{const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}}
|
||||
return vif_desc
|
||||
return self._invoke_device_plugins(self._func_name(), [tenant_id,
|
||||
instance_id,
|
||||
instance_desc])
|
||||
|
||||
"""
|
||||
Private functions
|
||||
"""
|
||||
def _invoke_device_plugins(self, function_name, args):
|
||||
"""
|
||||
All device-specific calls are delegate to the model
|
||||
All device-specific calls are delegated to the model
|
||||
"""
|
||||
getattr(self._model, function_name)(args)
|
||||
|
||||
def _get_vlan_for_tenant(self, tenant_id, net_name):
|
||||
"""Get vlan ID"""
|
||||
# TODO (Sumit):
|
||||
# The VLAN ID for a tenant might need to be obtained from
|
||||
# somewhere (from Donabe/Melange?)
|
||||
# Also need to make sure that the VLAN ID is not being used already
|
||||
# Currently, just a wrap-around counter ranging from VLAN_START to
|
||||
# VLAN_END
|
||||
return cdb.reserve_vlanid()
|
||||
return self._vlan_mgr.reserve_segmentation_id(tenant_id, net_name)
|
||||
|
||||
def _release_vlan_for_tenant(self, tenant_id, net_id):
|
||||
"""Relase VLAN"""
|
||||
vlan_binding = cdb.get_vlan_binding(net_id)
|
||||
return cdb.release_vlanid(vlan_binding[const.VLANID])
|
||||
return self._vlan_mgr.release_segmentation_id(tenant_id, net_id)
|
||||
|
||||
def _get_vlan_name(self, net_id, vlan):
|
||||
"""Getting the vlan name from the tenant and vlan"""
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import inspect
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
|
||||
class L2NetworkSegmentationMgrBase(object):
|
||||
"""
|
||||
Base class for L2 Network Segmentation Manager
|
||||
"""
|
||||
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def reserve_segmentation_id(self, tenant_id, net_name, **kwargs):
|
||||
"""
|
||||
:returns:
|
||||
:raises:
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def release_segmentation_id(self, tenant_id, net_id, **kwargs):
|
||||
"""
|
||||
:returns:
|
||||
:raises:
|
||||
"""
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def __subclasshook__(cls, klass):
|
||||
"""
|
||||
The __subclasshook__ method is a class method
|
||||
that will be called everytime a class is tested
|
||||
using issubclass(klass, Plugin).
|
||||
In that case, it will check that every method
|
||||
marked with the abstractmethod decorator is
|
||||
provided by the plugin class.
|
||||
"""
|
||||
if cls is L2NetworkSegementationMgrBase:
|
||||
for method in cls.__abstractmethods__:
|
||||
method_ok = False
|
||||
for base in klass.__mro__:
|
||||
if method in base.__dict__:
|
||||
fn_obj = base.__dict__[method]
|
||||
if inspect.isfunction(fn_obj):
|
||||
abstract_fn_obj = cls.__dict__[method]
|
||||
arg_count = fn_obj.func_code.co_argcount
|
||||
expected_arg_count = \
|
||||
abstract_fn_obj.func_code.co_argcount
|
||||
method_ok = arg_count == expected_arg_count
|
||||
if method_ok:
|
||||
continue
|
||||
return NotImplemented
|
||||
return True
|
||||
return NotImplemented
|
|
@ -0,0 +1,20 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
|
@ -0,0 +1,170 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import logging as LOG
|
||||
|
||||
from quantum.common import utils
|
||||
from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase
|
||||
from quantum.plugins.cisco import l2network_plugin_configuration as conf
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.ucs import cisco_ucs_inventory as ucsinv
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
|
||||
class L2NetworkMultiBlade(L2NetworkModelBase):
|
||||
"""
|
||||
Implements the L2NetworkModelBase
|
||||
This implementation works with UCS and Nexus plugin for the
|
||||
following topology:
|
||||
One or more UCSM (each with one or more chasses connected)
|
||||
All UCSM connected to a single Nexus Switch
|
||||
"""
|
||||
_plugins = {}
|
||||
|
||||
def __init__(self):
|
||||
for key in conf.PLUGINS[const.PLUGINS].keys():
|
||||
self._plugins[key] = utils.import_object(
|
||||
conf.PLUGINS[const.PLUGINS][key])
|
||||
LOG.debug("Loaded device plugin %s\n" % \
|
||||
conf.PLUGINS[const.PLUGINS][key])
|
||||
|
||||
self._ucs_inventory = ucsinv.UCSInventory()
|
||||
|
||||
def _func_name(self, offset=0):
|
||||
"""Get the name of the calling function"""
|
||||
return inspect.stack()[1 + offset][3]
|
||||
|
||||
def _invoke_all_device_plugins(self, function_name, args, kwargs):
|
||||
"""Invoke all device plugins for this model implementation"""
|
||||
for plugin_obj_ref in self._plugins.values():
|
||||
getattr(plugin_obj_ref, function_name)(*args, **kwargs)
|
||||
|
||||
def _invoke_ucs_plugin(self, function_name, args, kwargs):
|
||||
"""Invoke only the UCS plugin"""
|
||||
if const.UCS_PLUGIN in self._plugins.keys():
|
||||
getattr(self._plugins[const.UCS_PLUGIN],
|
||||
function_name)(*args, **kwargs)
|
||||
|
||||
def _invoke_ucs_plugin_per_device(self, function_name, args):
|
||||
"""Invoke only UCS plugin for all the UCSMs in the system"""
|
||||
ucsm_ips = self._ucs_inventory.get_all_ucsms()
|
||||
for ucsm_ip in ucsm_ips:
|
||||
device_params = {const.DEVICE_IP: ucsm_ip}
|
||||
self._invoke_ucs_plugin(function_name, args, device_params)
|
||||
|
||||
def _invoke_nexus_plugin(self, function_name, args, kwargs):
|
||||
"""Invoke only the Nexus plugin"""
|
||||
if const.NEXUS_PLUGIN in self._plugins.keys():
|
||||
getattr(self._plugins[const.NEXUS_PLUGIN],
|
||||
function_name)(*args, **kwargs)
|
||||
|
||||
def _invoke_nexus_plugin_per_device(self, function_name, args):
|
||||
"""Invoke only the nexus plugin for all the switches in the system"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_nexus_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def get_all_networks(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def create_network(self, args):
|
||||
"""Support for the Quantum core API call"""
|
||||
self._invoke_ucs_plugin_per_device(self._func_name(), args)
|
||||
self._invoke_nexus_plugin_per_device(self._func_name(), args)
|
||||
|
||||
def delete_network(self, args):
|
||||
"""Support for the Quantum core API call"""
|
||||
self._invoke_ucs_plugin_per_device(self._func_name(), args)
|
||||
self._invoke_nexus_plugin_per_device(self._func_name(), args)
|
||||
|
||||
def get_network_details(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def rename_network(self, args):
|
||||
"""Support for the Quantum core API call"""
|
||||
self._invoke_ucs_plugin_per_device(self._func_name(), args)
|
||||
self._invoke_nexus_plugin_per_device(self._func_name(), args)
|
||||
|
||||
def get_all_ports(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def create_port(self, args):
|
||||
"""Support for the Quantum core API call"""
|
||||
least_reserved_blade_dict = \
|
||||
self._ucs_inventory.get_least_reserved_blade()
|
||||
ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM]
|
||||
device_params = {const.DEVICE_IP: ucsm_ip,
|
||||
const.UCS_INVENTORY: self._ucs_inventory,
|
||||
const.LEAST_RSVD_BLADE_DICT:\
|
||||
least_reserved_blade_dict}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def delete_port(self, args):
|
||||
"""Support for the Quantum core API call"""
|
||||
rsvd_info = \
|
||||
self._ucs_inventory.get_rsvd_blade_intf_by_port(args[0],
|
||||
args[2])
|
||||
device_params = \
|
||||
{const.DEVICE_IP: rsvd_info[const.UCSM_IP],
|
||||
const.UCS_INVENTORY: self._ucs_inventory,
|
||||
const.CHASSIS_ID: rsvd_info[const.const.CHASSIS_ID],
|
||||
const.BLADE_ID: rsvd_info[const.const.BLADE_ID],
|
||||
const.BLADE_INTF_DN: rsvd_info[const.BLADE_INTF_DN]}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def update_port(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def get_port_details(self, args):
|
||||
"""Not implemented for this model"""
|
||||
pass
|
||||
|
||||
def plug_interface(self, args):
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def unplug_interface(self, args):
|
||||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def get_host(self, args):
|
||||
"""Provides the hostname on which a dynamic vnic is reserved"""
|
||||
LOG.debug("get_host() called\n")
|
||||
host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}}
|
||||
return host_list
|
||||
|
||||
def get_instance_port(self, args):
|
||||
"""
|
||||
Get the portprofile name and the device namei for the dynamic vnic
|
||||
"""
|
||||
LOG.debug("get_instance_port() called\n")
|
||||
vif_desc = {const.VIF_DESC:
|
||||
{const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}}
|
||||
return vif_desc
|
||||
|
|
@ -31,7 +31,7 @@ LOG.basicConfig(level=LOG.WARN)
|
|||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
|
||||
class L2NetworkModel(L2NetworkModelBase):
|
||||
class L2NetworkSinlgeBlade(L2NetworkModelBase):
|
||||
"""
|
||||
Implements the L2NetworkModelBase
|
||||
This implementation works with UCS and Nexus plugin,
|
||||
|
@ -121,3 +121,19 @@ class L2NetworkModel(L2NetworkModelBase):
|
|||
"""Support for the Quantum core API call"""
|
||||
device_params = {const.DEVICE_IP: ""}
|
||||
self._invoke_ucs_plugin(self._func_name(), args, device_params)
|
||||
|
||||
def get_host(self, args):
|
||||
"""Provides the hostname on which a dynamic vnic is reserved"""
|
||||
LOG.debug("get_host() called\n")
|
||||
host_list = {const.HOST_LIST: {const.HOST_1: platform.node()}}
|
||||
return host_list
|
||||
|
||||
def get_instance_port(self, args):
|
||||
"""
|
||||
Get the portprofile name and the device namei for the dynamic vnic
|
||||
"""
|
||||
LOG.debug("get_instance_port() called\n")
|
||||
vif_desc = {const.VIF_DESC:
|
||||
{const.DEVICENAME: "eth2", const.UCSPROFILE: "default"}}
|
||||
return vif_desc
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
"""
|
||||
|
||||
import logging as LOG
|
||||
|
||||
from quantum.common import utils
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.db import l2network_db as cdb
|
||||
from quantum.plugins.cisco.l2network_segmentation_base \
|
||||
import L2NetworkSegmentationMgrBase
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
class L2NetworkVLANMgr(L2NetworkSegmentationMgrBase):
|
||||
"""
|
||||
VLAN Manager which gets VLAN ID from DB
|
||||
"""
|
||||
|
||||
def reserve_segmentation_id(self, tenant_id, net_name, **kwargs):
|
||||
"""Get an available VLAN ID"""
|
||||
return cdb.reserve_vlanid()
|
||||
|
||||
|
||||
def release_segmentation_id(self, tenant_id, net_id, **kwargs):
|
||||
"""Release the ID"""
|
||||
vlan_binding = cdb.get_vlan_binding(net_id)
|
||||
return cdb.release_vlanid(vlan_binding[const.VLANID])
|
||||
|
|
@ -37,3 +37,10 @@ PROFILE_NAME_PREFIX = SECTION['profile_name_prefix']
|
|||
|
||||
SECTION = CP['DRIVER']
|
||||
UCSM_DRIVER = SECTION['name']
|
||||
|
||||
CONF_FILE = "../conf/ucs_inventory.ini"
|
||||
|
||||
CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
+ "/" + CONF_FILE)
|
||||
|
||||
INVENTORY = CP.walk(CP.dummy)
|
||||
|
|
|
@ -0,0 +1,361 @@
|
|||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2011 Cisco Systems, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
||||
#
|
||||
|
||||
import logging as LOG
|
||||
|
||||
from quantum.common import exceptions as exc
|
||||
from quantum.plugins.cisco.common import cisco_constants as const
|
||||
from quantum.plugins.cisco.common import cisco_credentials as cred
|
||||
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
||||
from quantum.plugins.cisco.common import cisco_utils as cutil
|
||||
from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf
|
||||
from quantum.plugins.cisco.ucs import cisco_ucs_network_driver
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
"""
|
||||
The _inventory data strcuture contains a nested disctioary:
|
||||
{"UCSM_IP: {"Chassis-ID": [Balde-ID, Blade-ID],
|
||||
"Chassis-ID": [Blade-ID, Blade-ID, Blade-ID]]},
|
||||
"UCSM_IP: {"Chassis-ID": [Balde-ID]}
|
||||
}
|
||||
"""
|
||||
|
||||
class UCSInventory(object):
|
||||
|
||||
_inventory = {}
|
||||
_host_names = {}
|
||||
_inventory_state = {}
|
||||
|
||||
def __init__(self):
|
||||
self._client = cisco_ucs_network_driver.CiscoUCSMDriver()
|
||||
self._load_inventory()
|
||||
|
||||
def _load_inventory(self):
|
||||
"""Load the inventory from a config file"""
|
||||
inventory = conf.INVENTORY
|
||||
for ucsm in inventory.keys():
|
||||
ucsm_ip = inventory[ucsm][const.IP_ADDRESS]
|
||||
inventory[ucsm].pop(const.IP_ADDRESS)
|
||||
chassis_dict = {}
|
||||
for chassis in inventory[ucsm].keys():
|
||||
chassis_id = inventory[ucsm][chassis][const.CHASSIS_ID]
|
||||
inventory[ucsm][chassis].pop(const.CHASSIS_ID)
|
||||
blade_list = []
|
||||
for blade in inventory[ucsm][chassis].keys():
|
||||
blade_id = \
|
||||
inventory[ucsm][chassis][blade][const.BLADE_ID]
|
||||
host_name = \
|
||||
inventory[ucsm][chassis][blade][const.HOST_NAME]
|
||||
host_key = ucsm_ip + "-" + chassis_id + "-" + blade_id
|
||||
self._host_names[host_key] = host_name
|
||||
blade_list.append(blade_id)
|
||||
chassis_dict[chassis_id] = blade_list
|
||||
self._inventory[ucsm_ip] = chassis_dict
|
||||
|
||||
def _get_host_name(self, ucsm_ip, chassis_id, blade_id):
|
||||
"""Get the hostname based on the blade info"""
|
||||
host_key = ucsm_ip + "-" + chassis_id + "-" + blade_id
|
||||
return self._host_names[host_key]
|
||||
|
||||
def _get_blade_state(self, chassis_id, blade_id, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
"""Get the blade state"""
|
||||
blade_intf_data = self._client.get_blade_data(chassis_id, blade_id,
|
||||
ucsm_ip, ucsm_username,
|
||||
ucsm_password)
|
||||
unreserved_counter = 0
|
||||
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
if (blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \
|
||||
const.BLADE_INTF_STATE_UNALLOCATED or \
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_LINK_STATE] == \
|
||||
const.BLADE_INTF_STATE_UNKNOWN) and \
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_OPER_STATE] == \
|
||||
const.BLADE_INTF_STATE_UNKNOWN:
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \
|
||||
const.BLADE_INTF_UNRESERVED
|
||||
unreserved_counter += 1
|
||||
else:
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \
|
||||
const.BLADE_INTF_RESERVED
|
||||
|
||||
blade_data = {const.BLADE_INTF_DATA: blade_intf_data,
|
||||
const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter}
|
||||
return blade_data
|
||||
|
||||
def get_all_ucsms(self):
|
||||
return self._inventory.keys()
|
||||
|
||||
def reload_inventory(self):
|
||||
"""Reload the inventory from a conf file"""
|
||||
self._load_inventory()
|
||||
pass
|
||||
|
||||
def build_inventory_state(self):
|
||||
"""Populate the state of all the blades"""
|
||||
for ucsm_ip in self._inventory.keys():
|
||||
self._inventory_state[ucsm_ip] = {ucsm_ip: {}}
|
||||
ucsm_username = cred.Store.getUsername(ucsm_ip)
|
||||
ucsm_password = cred.Store.getPassword(ucsm_ip)
|
||||
chasses_state = {}
|
||||
self._inventory_state[ucsm_ip] = chasses_state
|
||||
ucsm = self._inventory[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
blades_dict = {}
|
||||
chasses_state[chassis_id] = blades_dict
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = self._get_blade_state(chassis_id, blade_id,
|
||||
ucsm_ip, ucsm_username,
|
||||
ucsm_password)
|
||||
blades_dict[blade_id] = blade_data
|
||||
|
||||
return True
|
||||
|
||||
def get_least_reserved_blade(self):
|
||||
"""Return the blade with least number of dynamic nics reserved"""
|
||||
unreserved_interface_count = 0
|
||||
least_reserved_blade_ucsm = None
|
||||
least_reserved_blade_chassis = None
|
||||
least_reserved_blade_id = None
|
||||
least_reserved_blade_data = None
|
||||
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
if blade_data[const.BLADE_UNRESERVED_INTF_COUNT] > \
|
||||
unreserved_interface_count:
|
||||
unreserved_interface_count = \
|
||||
blade_data[const.BLADE_UNRESERVED_INTF_COUNT]
|
||||
least_reserved_blade_ucsm = ucsm_ip
|
||||
least_reserved_blade_chassis = chassis_id
|
||||
least_reserved_blade_id = blade_id
|
||||
least_reserved_blade_data = blade_data
|
||||
|
||||
if unreserved_interface_count == 0:
|
||||
return False
|
||||
|
||||
least_reserved_blade_dict = \
|
||||
{const.LEAST_RSVD_BLADE_UCSM: least_reserved_blade_ucsm,
|
||||
const.LEAST_RSVD_BLADE_CHASSIS: least_reserved_blade_chassis,
|
||||
const.LEAST_RSVD_BLADE_ID: least_reserved_blade_id,
|
||||
const.LEAST_RSVD_BLADE_DATA: least_reserved_blade_data}
|
||||
return least_reserved_blade_dict
|
||||
|
||||
def reserve_blade_interface(self, ucsm_ip, chassis_id, blade_id,
|
||||
blade_data_dict, tenant_id, port_id,
|
||||
portprofile_name):
|
||||
"""Reserve an interface on a blade"""
|
||||
ucsm_username = cred.Store.getUsername(ucsm_ip)
|
||||
ucsm_password = cred.Store.getPassword(ucsm_ip)
|
||||
"""
|
||||
We are first getting the updated blade interface state
|
||||
"""
|
||||
blade_data = self._get_blade_state(chassis_id, blade_id, ucsm_ip,
|
||||
ucsm_username, ucsm_password)
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
old_blade_intf_data = blade_data_dict[const.BLADE_INTF_DATA]
|
||||
|
||||
"""
|
||||
We will now copy the older blade interface reservation state
|
||||
"""
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \
|
||||
old_blade_intf_data[blade_intf]\
|
||||
[const.BLADE_INTF_RESERVATION]
|
||||
|
||||
blade_data[const.BLADE_UNRESERVED_INTF_COUNT] = \
|
||||
blade_data_dict[const.BLADE_UNRESERVED_INTF_COUNT]
|
||||
"""
|
||||
Now we will reserve an interface if its available
|
||||
"""
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
if blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] == \
|
||||
const.BLADE_INTF_UNRESERVED:
|
||||
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = \
|
||||
const.BLADE_INTF_RESERVED
|
||||
blade_intf_data[blade_intf][const.TENANTID] = tenant_id
|
||||
blade_intf_data[blade_intf][const.PORTID] = port_id
|
||||
blade_intf_data[blade_intf][const.PROFILEID] = portprofile_name
|
||||
blade_intf_data[blade_intf][const.INSTANCE_ID] = None
|
||||
dev_eth_name = blade_intf_data[blade_intf] \
|
||||
[const.BLADE_INTF_RHEL_DEVICE_NAME]
|
||||
"""
|
||||
We are replacing the older blade interface state with new
|
||||
"""
|
||||
self._inventory_state[ucsm_ip][chassis_id][blade_id] \
|
||||
[const.BLADE_INTF_DATA] = blade_intf_data
|
||||
self._inventory_state[ucsm_ip][chassis_id][blade_id] \
|
||||
[const.BLADE_UNRESERVED_INTF_COUNT] -= 1
|
||||
host_name = self._get_host_name(ucsm_ip, chassis_id,
|
||||
blade_id)
|
||||
reserved_nic_dict = {const.RESERVED_NIC_HOSTNAME: host_name,
|
||||
const.RESERVED_NIC_NAME: dev_eth_name,
|
||||
const.BLADE_INTF_DN: blade_intf}
|
||||
LOG.debug("Reserved blade interface: %s\n" % reserved_nic_dict)
|
||||
return reserved_nic_dict
|
||||
|
||||
return False
|
||||
|
||||
def unreserve_blade_interface(self, ucsm_ip, chassis_id, blade_id,
|
||||
interface_dn):
|
||||
"""Unreserve a previously reserved interface on a blade"""
|
||||
ucsm_username = cred.Store.getUsername(ucsm_ip)
|
||||
ucsm_password = cred.Store.getPassword(ucsm_ip)
|
||||
self._inventory_state[ucsm_ip][chassis_id][blade_id]\
|
||||
[const.BLADE_INTF_DATA] \
|
||||
[interface_dn][const.BLADE_INTF_RESERVATION] = \
|
||||
const.BLADE_INTF_UNRESERVED
|
||||
self._inventory_state[ucsm_ip][chassis_id][blade_id] \
|
||||
[const.BLADE_UNRESERVED_INTF_COUNT] += 1
|
||||
LOG.debug("Unreserved blade interface %s\n" % interface_dn)
|
||||
|
||||
def get_rsvd_blade_intf_by_port(self, tenant_id, port_id):
|
||||
"""
|
||||
Lookup a reserved blade interface based on tenant_id and port_id
|
||||
and return the blade interface info
|
||||
"""
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
if blade_intf_data[blade_intf]\
|
||||
[const.BLADE_INTF_RESERVATION] == \
|
||||
const.BLADE_INTF_RESERVED and \
|
||||
blade_intf_data[blade_intf]\
|
||||
[const.TENANTID] == tenant_id and \
|
||||
blade_intf_data[blade_intf]\
|
||||
[const.PORTID] == port_id:
|
||||
interface_dn = blade_intf_data[blade_intf]\
|
||||
[const.BLADE_INTF_DN]
|
||||
blade_intf_info = {const.UCSM_IP: ucsm_ip,
|
||||
const.CHASSIS_ID: chassis_id,
|
||||
const.BLADE_ID: blade_id,
|
||||
const.BLADE_INTF_DN:
|
||||
interface_dn}
|
||||
return blade_intf_info
|
||||
return None
|
||||
|
||||
def get_host_name(self, tenant_id, instance_id):
|
||||
"""
|
||||
Return the hostname of the blade with a reserved instance
|
||||
for this tenant
|
||||
"""
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
if blade_intf_data[blade_intf]\
|
||||
[const.BLADE_INTF_RESERVATION] == \
|
||||
const.BLADE_INTF_RESERVED and \
|
||||
blade_intf_data[blade_intf]\
|
||||
[const.TENANTID] == tenant_id and \
|
||||
blade_intf_data[blade_intf]\
|
||||
[const.INSTANCE_ID] == None:
|
||||
blade_intf_data[blade_intf]\
|
||||
[const.INSTANCE_ID] = instance_id
|
||||
host_name = self._get_host_name(ucsm_ip,
|
||||
chassis_id,
|
||||
blade_id)
|
||||
return host_name
|
||||
return None
|
||||
|
||||
def get_instance_port(self, tenant_id, instance_id):
|
||||
"""
|
||||
Return the device name for a reserved interface
|
||||
"""
|
||||
for ucsm_ip in self._inventory_state.keys():
|
||||
ucsm = self._inventory_state[ucsm_ip]
|
||||
for chassis_id in ucsm.keys():
|
||||
for blade_id in ucsm[chassis_id]:
|
||||
blade_data = ucsm[chassis_id][blade_id]
|
||||
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
||||
for blade_intf in blade_intf_data.keys():
|
||||
if blade_intf_data[blade_intf]\
|
||||
[const.BLADE_INTF_RESERVATION] == \
|
||||
const.BLADE_INTF_RESERVED and \
|
||||
blade_intf_data[blade_intf]\
|
||||
[const.TENANTID] == tenant_id and \
|
||||
blade_intf_data[blade_intf]\
|
||||
[const.INSTANCE_ID] == instance_id:
|
||||
return blade_intf_data[blade_intf]\
|
||||
[const.BLADE_INTF_RHEL_DEVICE_NAME]
|
||||
return None
|
||||
|
||||
def add_blade(self, ucsm_ip, chassis_id, blade_id):
|
||||
"""Add a blade to the inventory"""
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
#client = UCSInventory()
|
||||
#client.build_state()
|
||||
ucsinv = UCSInventory()
|
||||
reserved_nics = []
|
||||
ucsinv.build_inventory_state()
|
||||
while True:
|
||||
reserved_blade_dict = ucsinv.get_least_reserved_blade()
|
||||
if not reserved_blade_dict:
|
||||
print "No more unreserved blades\n"
|
||||
break
|
||||
|
||||
least_reserved_blade_ucsm = reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM]
|
||||
least_reserved_blade_chassis = \
|
||||
reserved_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS]
|
||||
least_reserved_blade_id = \
|
||||
reserved_blade_dict[const.LEAST_RSVD_BLADE_ID]
|
||||
least_reserved_blade_data = \
|
||||
reserved_blade_dict[const.LEAST_RSVD_BLADE_DATA]
|
||||
reserved_nic_dict = \
|
||||
ucsinv.reserve_blade_interface(least_reserved_blade_ucsm,
|
||||
least_reserved_blade_chassis,
|
||||
least_reserved_blade_id,
|
||||
least_reserved_blade_data,
|
||||
"demo")
|
||||
if reserved_nic_dict:
|
||||
reserved_intf_nic_info = {const.RESERVED_INTERFACE_UCSM:
|
||||
least_reserved_blade_ucsm,
|
||||
const.RESERVED_INTERFACE_CHASSIS:
|
||||
least_reserved_blade_chassis,
|
||||
const.RESERVED_INTERFACE_BLADE:
|
||||
least_reserved_blade_id,
|
||||
const.RESERVED_INTERFACE_DN:
|
||||
reserved_nic_dict[const.BLADE_INTF_DN]}
|
||||
reserved_nics.append(reserved_intf_nic_info)
|
||||
#break
|
||||
|
||||
for rnic in reserved_nics:
|
||||
ucsinv.unreserve_blade_interface(
|
||||
rnic[const.RESERVED_INTERFACE_UCSM],
|
||||
rnic[const.RESERVED_INTERFACE_CHASSIS],
|
||||
rnic[const.RESERVED_INTERFACE_BLADE],
|
||||
rnic[const.RESERVED_INTERFACE_DN])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -32,7 +32,8 @@ from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
|||
from quantum.plugins.cisco.ucs import cisco_getvif as gvif
|
||||
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.basicConfig(level=LOG.DEBUG)
|
||||
#LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
COOKIE_VALUE = "cookie_placeholder"
|
||||
|
@ -41,6 +42,9 @@ PROFILE_CLIENT = "profileclient_placeholder"
|
|||
VLAN_NAME = "vlanname_placeholder"
|
||||
VLAN_ID = "vlanid_placeholder"
|
||||
OLD_VLAN_NAME = "old_vlanname_placeholder"
|
||||
BLADE_VALUE = "blade_number_placeholder"
|
||||
BLADE_DN_VALUE = "blade_dn_placeholder"
|
||||
CHASSIS_VALUE = "chassis_number_placeholder"
|
||||
DYNAMIC_NIC_PREFIX = "eth"
|
||||
|
||||
# The following are standard strings, messages used to communicate with UCSM,
|
||||
|
@ -112,6 +116,27 @@ DELETE_PROFILE = "<configConfMos cookie=\"" + COOKIE_VALUE + \
|
|||
PROFILE_NAME + "\" status=\"deleted\"> </vnicProfile>" \
|
||||
"</pair> </inConfigs> </configConfMos>"
|
||||
|
||||
GET_BLADE_INTERFACE_STATE = "<configScope cookie=\"" + COOKIE_VALUE + \
|
||||
"\" dn=\"" + BLADE_DN_VALUE + "\" inClass=\"dcxVIf\" " + \
|
||||
"inHierarchical=\"false\" inRecursive=\"false\"> " + \
|
||||
"<inFilter> </inFilter> </configScope>"
|
||||
|
||||
GET_BLADE_INTERFACE = "<configResolveClass cookie=\"" + COOKIE_VALUE + \
|
||||
"\" classId=\"vnicEther\"" + \
|
||||
" inHierarchical=\"false\">" + \
|
||||
" <inFilter> <eq class=\"vnicEther\" property=\"equipmentDn\"" + \
|
||||
" value=\"sys/chassis-" + CHASSIS_VALUE +"/blade-" + \
|
||||
BLADE_VALUE + "/adaptor-1/host-eth-?\"/> " + \
|
||||
"</inFilter> </configResolveClass>"
|
||||
|
||||
# TODO (Sumit): Assumes "adaptor-1", check if this has to be discovered too
|
||||
GET_BLADE_INTERFACES = "<configResolveChildren cookie=\"" + \
|
||||
COOKIE_VALUE + "\" inDn=\"sys/chassis-" + \
|
||||
CHASSIS_VALUE + "/blade-" + BLADE_VALUE + \
|
||||
"/adaptor-1\"" + \
|
||||
" inHierarchical=\"false\"> <inFilter> </inFilter>" + \
|
||||
" </configResolveChildren>"
|
||||
|
||||
|
||||
class CiscoUCSMDriver():
|
||||
"""UCSM Driver"""
|
||||
|
@ -130,6 +155,7 @@ class CiscoUCSMDriver():
|
|||
LOG.debug(response.status)
|
||||
LOG.debug(response.reason)
|
||||
LOG.debug(response_data)
|
||||
#print("***Sumit: response %s") % response_data
|
||||
# TODO (Sumit): If login is not successful, throw exception
|
||||
xml_tree = et.XML(response_data)
|
||||
cookie = xml_tree.attrib["outCookie"]
|
||||
|
@ -142,6 +168,8 @@ class CiscoUCSMDriver():
|
|||
LOG.debug(response.status)
|
||||
LOG.debug(response.reason)
|
||||
LOG.debug("UCSM Response: %s" % response_data)
|
||||
#print("***Sumit: response %s") % response_data
|
||||
post_data_response = response_data
|
||||
|
||||
logout_data = "<aaaLogout inCookie=\"" + cookie + "\" />"
|
||||
conn.request(METHOD, URL, logout_data, HEADERS)
|
||||
|
@ -150,6 +178,8 @@ class CiscoUCSMDriver():
|
|||
LOG.debug(response.status)
|
||||
LOG.debug(response.reason)
|
||||
LOG.debug(response_data)
|
||||
#print("***Sumit: response %s") % response_data
|
||||
return post_data_response
|
||||
|
||||
def _create_vlan_post_data(self, vlan_name, vlan_id):
|
||||
"""Create command"""
|
||||
|
@ -196,6 +226,81 @@ class CiscoUCSMDriver():
|
|||
else:
|
||||
raise cexc.NoMoreNics()
|
||||
|
||||
def _get_blade_interfaces_post_data(self, chassis_number, blade_number):
|
||||
data = GET_BLADE_INTERFACES.replace(CHASSIS_VALUE, chassis_number)
|
||||
data = data.replace(BLADE_VALUE, blade_number)
|
||||
return data
|
||||
|
||||
def _get_blade_interface_state_post_data(self, blade_dn):
|
||||
data = GET_BLADE_INTERFACE_STATE.replace(BLADE_DN_VALUE, blade_dn)
|
||||
return data
|
||||
|
||||
def _get_blade_interfaces(self, chassis_number, blade_number, ucsm_ip,
|
||||
ucsm_username, ucsm_password):
|
||||
data = self._get_blade_interfaces_post_data(chassis_number,
|
||||
blade_number)
|
||||
response = self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
|
||||
"""
|
||||
print("***Sumit: ucsmp_ip %s ucsm_username %s ucsm_password %s data %s \
|
||||
response %s") % (ucsm_ip, ucsm_username, ucsm_password, data,
|
||||
response)
|
||||
"""
|
||||
elements = \
|
||||
et.XML(response).find("outConfigs").findall("adaptorHostEthIf")
|
||||
bladeInterfaces = {}
|
||||
for element in elements:
|
||||
dn = element.get("dn", default=None)
|
||||
if dn:
|
||||
order = element.get("order", default=None)
|
||||
bladeInterface = {const.BLADE_INTF_DN: dn,
|
||||
const.BLADE_INTF_ORDER: order,
|
||||
const.BLADE_INTF_LINK_STATE: None,
|
||||
const.BLADE_INTF_OPER_STATE: None,
|
||||
const.BLADE_INTF_INST_TYPE: None,
|
||||
const.BLADE_INTF_RHEL_DEVICE_NAME:
|
||||
self._get_rhel_device_name(order)}
|
||||
bladeInterfaces[dn] = bladeInterface
|
||||
|
||||
return bladeInterfaces
|
||||
|
||||
def _get_blade_interface_state(self, bladeIntf, ucsm_ip,
|
||||
ucsm_username, ucsm_password):
|
||||
data = \
|
||||
self._get_blade_interface_state_post_data(bladeIntf[const.BLADE_INTF_DN])
|
||||
response = self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
|
||||
elements = \
|
||||
et.XML(response).find("outConfigs").findall("dcxVIf")
|
||||
for element in elements:
|
||||
bladeIntf[const.BLADE_INTF_LINK_STATE] = element.get("linkState",
|
||||
default=None)
|
||||
bladeIntf[const.BLADE_INTF_OPER_STATE] = element.get("operState",
|
||||
default=None)
|
||||
bladeIntf[const.BLADE_INTF_INST_TYPE] = element.get("instType",
|
||||
default=None)
|
||||
|
||||
def _get_rhel_device_name(self, order):
|
||||
deviceName = const.RHEL_DEVICE_NAME_REPFIX + str(int(order) - 1)
|
||||
return deviceName
|
||||
|
||||
def _get_dynamic_interface(self, chassis_number, blade_number,
|
||||
ucsm_ip,ucsm_username,
|
||||
ucsm_password):
|
||||
bladeInterfaces = client._get_blade_interfaces(chassis_number,
|
||||
blade_number,
|
||||
ucsm_ip,
|
||||
ucsm_username,
|
||||
ucsm_password)
|
||||
for bladeIntf in bladeInterfaces.values():
|
||||
client._get_blade_interface_state(bladeIntf, ucsm_ip,
|
||||
ucsm_username, ucsm_password)
|
||||
if bladeIntf[const.BLADE_INTF_INST_TYPE] == \
|
||||
const.BLADE_INTF_DYNAMIC and \
|
||||
bladeIntf[const.BLADE_INTF_LINK_STATE] == \
|
||||
const.BLADE_INTF_STATE_UNKNOWN and \
|
||||
bladeIntf[const.BLADE_INTF_OPER_STATE] == \
|
||||
const.BLADE_INTF_STATE_UNKNOWN:
|
||||
return bladeIntf
|
||||
|
||||
def create_vlan(self, vlan_name, vlan_id, ucsm_ip, ucsm_username,
|
||||
ucsm_password):
|
||||
"""Create request for UCSM"""
|
||||
|
@ -234,6 +339,26 @@ class CiscoUCSMDriver():
|
|||
LOG.debug("Reserving dynamic nic %s" % dynamic_nic_name)
|
||||
return dynamic_nic_name
|
||||
|
||||
def get_blade_data(self, chassis_number, blade_number,
|
||||
ucsm_ip,ucsm_username,
|
||||
ucsm_password):
|
||||
"""
|
||||
Returns only the dynamic interfaces on the blade
|
||||
"""
|
||||
bladeInterfaces = self._get_blade_interfaces(chassis_number,
|
||||
blade_number,
|
||||
ucsm_ip,
|
||||
ucsm_username,
|
||||
ucsm_password)
|
||||
for bladeIntf in bladeInterfaces.keys():
|
||||
self._get_blade_interface_state(bladeInterfaces[bladeIntf], ucsm_ip,
|
||||
ucsm_username, ucsm_password)
|
||||
if bladeInterfaces[bladeIntf][const.BLADE_INTF_INST_TYPE] != \
|
||||
const.BLADE_INTF_DYNAMIC:
|
||||
bladeInterfaces.pop(bladeIntf)
|
||||
|
||||
return bladeInterfaces
|
||||
|
||||
def delete_vlan(self, vlan_name, ucsm_ip, ucsm_username, ucsm_password):
|
||||
"""Create request for UCSM"""
|
||||
data = self._delete_vlan_post_data(vlan_name)
|
||||
|
|
|
@ -42,10 +42,6 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
self._client = utils.import_object(conf.UCSM_DRIVER)
|
||||
LOG.debug("Loaded driver %s\n" % conf.UCSM_DRIVER)
|
||||
self._utils = cutil.DBUtils()
|
||||
# TODO (Sumit) This is for now, when using only one chassis
|
||||
self._ucsm_ip = conf.UCSM_IP_ADDRESS
|
||||
self._ucsm_username = cred.Store.getUsername(conf.UCSM_IP_ADDRESS)
|
||||
self._ucsm_password = cred.Store.getPassword(conf.UCSM_IP_ADDRESS)
|
||||
# TODO (Sumit) Make the counter per UCSM
|
||||
self._port_profile_counter = 0
|
||||
|
||||
|
@ -56,6 +52,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
the specified tenant.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:get_all_networks() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
return self._networks.values()
|
||||
|
||||
def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id,
|
||||
|
@ -65,6 +62,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
a symbolic name.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:create_network() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
self._client.create_vlan(vlan_name, str(vlan_id), self._ucsm_ip,
|
||||
self._ucsm_username, self._ucsm_password)
|
||||
new_net_dict = {const.NET_ID: net_id,
|
||||
|
@ -81,6 +79,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
belonging to the specified tenant.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:delete_network() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
net = self._networks.get(net_id)
|
||||
# TODO (Sumit) : Verify that no attachments are plugged into the
|
||||
# network
|
||||
|
@ -99,6 +98,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
spec
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:get_network_details() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
return network
|
||||
|
||||
|
@ -108,6 +108,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
Virtual Network.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:rename_network() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
network[const.NET_NAME] = new_name
|
||||
return network
|
||||
|
@ -118,6 +119,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:get_all_ports() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
network = self._get_network(tenant_id, net_id)
|
||||
ports_on_net = network[const.NET_PORTS].values()
|
||||
return ports_on_net
|
||||
|
@ -127,27 +129,28 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
Creates a port on the specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:create_port() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
ucs_inventory = kwargs[const.UCS_INVENTORY]
|
||||
least_rsvd_blade_dict = kwargs[const.LEAST_RSVD_BLADE_DICT]
|
||||
chassis_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_CHASSIS]
|
||||
blade_id = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_ID]
|
||||
blade_data_dict = least_rsvd_blade_dict[const.LEAST_RSVD_BLADE_DATA]
|
||||
net = self._get_network(tenant_id, net_id)
|
||||
ports = net[const.NET_PORTS]
|
||||
# TODO (Sumit): This works on a single host deployment,
|
||||
# in multi-host environment, dummy needs to be replaced with the
|
||||
# hostname
|
||||
dynamic_nic_name = self._client.get_dynamic_nic("dummy")
|
||||
new_port_profile = self._create_port_profile(tenant_id, net_id,
|
||||
port_id,
|
||||
conf.DEFAULT_VLAN_NAME,
|
||||
conf.DEFAULT_VLAN_ID)
|
||||
profile_name = new_port_profile[const.PROFILE_NAME]
|
||||
sql_query = "INSERT INTO ports (port_id, profile_name, dynamic_vnic," \
|
||||
"host, instance_name, instance_nic_name, used) VALUES" \
|
||||
"('%s', '%s', '%s', 'dummy', NULL, NULL, 0)" % \
|
||||
(port_id, profile_name, dynamic_nic_name)
|
||||
self._utils.execute_db_query(sql_query)
|
||||
new_port_dict = {const.PORT_ID: port_id,
|
||||
const.PORT_STATE: const.PORT_UP,
|
||||
const.ATTACHMENT: None,
|
||||
const.PORT_PROFILE: new_port_profile}
|
||||
ports[port_id] = new_port_dict
|
||||
ucs_inventory.reserve_blade_interface(self._ucsm_ip, chassis_id,
|
||||
blade_id, blade_data_dict,
|
||||
tenant_id, port_id,
|
||||
portprofile_name)
|
||||
return new_port_dict
|
||||
|
||||
def delete_port(self, tenant_id, net_id, port_id, **kwargs):
|
||||
|
@ -158,6 +161,11 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
then the port can be deleted.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:delete_port() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
ucs_inventory = kwargs[const.UCS_INVENTORY]
|
||||
chassis_id = kwargs[const.const.CHASSIS_ID]
|
||||
blade_id = kwargs[const.const.BLADE_ID]
|
||||
interface_dn = kwargs[const.BLADE_INTF_DN]
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
if port[const.ATTACHMENT]:
|
||||
raise exc.PortInUse(net_id=net_id, port_id=port_id,
|
||||
|
@ -169,11 +177,10 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
port_profile = port[const.PORT_PROFILE]
|
||||
self._delete_port_profile(port_id,
|
||||
port_profile[const.PROFILE_NAME])
|
||||
sql_query = "delete from ports where port_id = \"%s\"" % \
|
||||
(port[const.PORT_ID])
|
||||
self._utils.execute_db_query(sql_query)
|
||||
net = self._get_network(tenant_id, net_id)
|
||||
net[const.NET_PORTS].pop(port_id)
|
||||
ucs_inventory.unreserve_blade_interface(ucsm_ip, chassis_id,
|
||||
blade_id, interface_dn)
|
||||
except KeyError:
|
||||
raise exc.PortNotFound(net_id=net_id, port_id=port_id)
|
||||
|
||||
|
@ -182,6 +189,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
Updates the state of a port on the specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:update_port() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
self._validate_port_state(port_state)
|
||||
port[const.PORT_STATE] = port_state
|
||||
|
@ -193,6 +201,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
that is attached to this particular port.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:get_port_details() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
return self._get_port(tenant_id, net_id, port_id)
|
||||
|
||||
def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id,
|
||||
|
@ -202,6 +211,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:plug_interface() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
self._validate_attachment(tenant_id, net_id, port_id,
|
||||
remote_interface_id)
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
|
@ -227,6 +237,7 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
specified Virtual Network.
|
||||
"""
|
||||
LOG.debug("UCSVICPlugin:unplug_interface() called\n")
|
||||
self._set_ucsm(kwargs[const.DEVICE_IP])
|
||||
port = self._get_port(tenant_id, net_id, port_id)
|
||||
port[const.ATTACHMENT] = None
|
||||
port_profile = port[const.PORT_PROFILE]
|
||||
|
@ -308,3 +319,9 @@ class UCSVICPlugin(L2DevicePluginBase):
|
|||
self._client.delete_profile(profile_name, self._ucsm_ip,
|
||||
self._ucsm_username, self._ucsm_password)
|
||||
self._port_profile_counter -= 1
|
||||
|
||||
def _set_ucsm(self, ucsm_ip):
|
||||
self._ucsm_ip = ucsm_ip
|
||||
self._ucsm_username = cred.Store.getUsername(conf.UCSM_IP_ADDRESS)
|
||||
self._ucsm_password = cred.Store.getPassword(conf.UCSM_IP_ADDRESS)
|
||||
|
||||
|
|
Loading…
Reference in New Issue