c398f7abb1
Blueprint cisco-plugin-v2-api-support New meta-plugin which makes use of the Quantum db_plugin and supports the new v2 API Changes to the Cisco DB model, now reusing quantum DB for core attributes Changes to the device sub plugins to access the quantum DB for core resources' state versus Cisco DB Addition of fake/dummy drivers to support testing of the device sub plugins even without actual hardware New v2 unit tests which exercise the meta-plugin and the device sub -plugins as well In general creating new v2 modules such that v1.x code can be deprecated easily by deleting the older modules. The following files are v2 versions of older modules, only the imports have changed, most of the other code is the same as from the older modules (already reviewed): quantum/plugins/cisco/common/cisco_credentials_v2.py quantum/plugins/cisco/db/network_db_v2.py quantum/plugins/cisco/db/network_models_v2.py quantum/plugins/cisco/db/nexus_db_v2.py quantum/plugins/cisco/db/nexus_models_v2.py quantum/plugins/cisco/db/ucs_db_v2.py quantum/plugins/cisco/db/ucs_models_v2.py quantum/plugins/cisco/nexus/cisco_nexus_plugin_v2.py quantum/plugins/cisco/ucs/cisco_ucs_inventory_v2.py quantum/plugins/cisco/ucs/cisco_ucs_plugin_v2.py quantum/plugins/cisco/segmentation/l2network_vlan_mgr_v2.py All changes are contained with the Cisco plugin. (Sumit & Rohit) Change-Id: Ib82a9f843548c286c84ba63caf5406a773ac85b1
710 lines
31 KiB
Python
710 lines
31 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
#
|
|
# Copyright 2012 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.
|
|
|
|
"""
|
|
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]}
|
|
}
|
|
"""
|
|
"""
|
|
_inventory_state data structure is organized as below:
|
|
{ucsm_ip:
|
|
{chassis_id:
|
|
{blade_id:
|
|
{'blade-data':
|
|
{blade-dn-1: {blade-intf-data},
|
|
blade-dn-2: {blade-intf-data}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'blade-data': Blade Data dictionary has the following keys:
|
|
===========================================================
|
|
const.BLADE_INTF_DATA: This is a dictionary, with the key as the
|
|
dn of the interface, and the value as the
|
|
Blade Interface Dictionary described next
|
|
const.BLADE_UNRESERVED_INTF_COUNT: Number of unreserved interfaces
|
|
on this blade
|
|
|
|
'blade-intf-data': Blade Interface dictionary has the following keys:
|
|
=====================================================================
|
|
const.BLADE_INTF_DN
|
|
const.BLADE_INTF_ORDER
|
|
const.BLADE_INTF_LINK_STATE
|
|
const.BLADE_INTF_OPER_STATE
|
|
const.BLADE_INTF_INST_TYPE
|
|
const.BLADE_INTF_RHEL_DEVICE_NAME
|
|
const.BLADE_INTF_RESERVATION
|
|
const.TENANTID
|
|
const.PORTID
|
|
const.PROFILE_ID
|
|
const.INSTANCE_ID
|
|
const.VIF_ID
|
|
"""
|
|
|
|
from copy import deepcopy
|
|
import logging
|
|
|
|
from quantum.common import exceptions as exc
|
|
from quantum.openstack.common import importutils
|
|
from quantum.plugins.cisco.common import cisco_constants as const
|
|
from quantum.plugins.cisco.common import cisco_credentials_v2 as cred
|
|
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
|
from quantum.plugins.cisco.db import ucs_db_v2 as udb
|
|
from quantum.plugins.cisco.l2device_inventory_base import (
|
|
L2NetworkDeviceInventoryBase,
|
|
)
|
|
from quantum.plugins.cisco.ucs import (
|
|
cisco_ucs_inventory_configuration as conf,
|
|
)
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class UCSInventory(L2NetworkDeviceInventoryBase):
|
|
"""
|
|
Manages the state of all the UCS chasses, and blades in
|
|
the system
|
|
"""
|
|
|
|
_inventory = {}
|
|
_host_names = {}
|
|
_inventory_state = {}
|
|
|
|
def __init__(self):
|
|
self._client = importutils.import_object(conf.UCSM_DRIVER)
|
|
self._load_inventory()
|
|
|
|
def _load_inventory(self):
|
|
"""Load the inventory from a config file"""
|
|
inventory = deepcopy(conf.INVENTORY)
|
|
LOG.info("Loaded UCS inventory: %s\n" % inventory)
|
|
LOG.info("Building UCS inventory state (this may take a while)...")
|
|
|
|
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
|
|
|
|
self._build_inventory_state()
|
|
|
|
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.get_username(ucsm_ip)
|
|
ucsm_password = cred.Store.get_password(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_initial_blade_state(chassis_id,
|
|
blade_id,
|
|
ucsm_ip,
|
|
ucsm_username,
|
|
ucsm_password)
|
|
blades_dict[blade_id] = blade_data
|
|
|
|
LOG.debug("UCS Inventory state is: %s\n" % self._inventory_state)
|
|
return True
|
|
|
|
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_initial_blade_state(self, chassis_id, blade_id, ucsm_ip,
|
|
ucsm_username, ucsm_password):
|
|
"""Get the initial 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():
|
|
dist_name = blade_intf_data[blade_intf][const.BLADE_INTF_DN]
|
|
# We first make a pass through the state in UCSM
|
|
# If a particular interface is showing as being allocated in
|
|
# UCSM then it is definitely being used and so should be
|
|
# marked as reserved, else we temporarily mark it as unreserved
|
|
# based on the UCSM state, but may later change it if a port
|
|
# association is found in the DB
|
|
if not const.TENANTID in blade_intf_data[blade_intf].keys():
|
|
blade_intf_data[blade_intf][const.TENANTID] = None
|
|
if not const.PORTID in blade_intf_data[blade_intf].keys():
|
|
blade_intf_data[blade_intf][const.PORTID] = None
|
|
if not const.PROFILE_ID in blade_intf_data[blade_intf].keys():
|
|
blade_intf_data[blade_intf][const.PROFILE_ID] = None
|
|
if not const.INSTANCE_ID in blade_intf_data[blade_intf].keys():
|
|
blade_intf_data[blade_intf][const.INSTANCE_ID] = None
|
|
if not const.VIF_ID in blade_intf_data[blade_intf].keys():
|
|
blade_intf_data[blade_intf][const.VIF_ID] = None
|
|
|
|
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)
|
|
|
|
port_binding = udb.get_portbinding_dn(dist_name)
|
|
if port_binding:
|
|
# We have found a port binding for this interface in the DB,
|
|
# so we have earlier marked this interface as unreserved, we
|
|
# need to change it, and also load the state from the DB for
|
|
# other associations
|
|
intf_data = blade_intf_data[blade_intf]
|
|
if ((intf_data[const.BLADE_INTF_RESERVATION] == const.
|
|
BLADE_INTF_UNRESERVED)):
|
|
unreserved_counter -= 1
|
|
intf_data[const.BLADE_INTF_RESERVATION] = (
|
|
const.BLADE_INTF_RESERVED)
|
|
intf_data[const.TENANTID] = port_binding[const.TENANTID]
|
|
intf_data[const.PORTID] = port_binding[const.PORTID]
|
|
intf_data[const.PROFILE_ID] = (
|
|
port_binding[const.PORTPROFILENAME])
|
|
intf_data[const.INSTANCE_ID] = port_binding[const.INSTANCE_ID]
|
|
intf_data[const.VIF_ID] = port_binding[const.VIF_ID]
|
|
host_name = self._get_host_name(ucsm_ip, chassis_id, blade_id)
|
|
blade_data = {const.BLADE_INTF_DATA: blade_intf_data,
|
|
const.BLADE_UNRESERVED_INTF_COUNT: unreserved_counter,
|
|
const.HOST_NAME: host_name}
|
|
return blade_data
|
|
|
|
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 a list of the IPs of all the UCSMs in the system"""
|
|
return {const.DEVICE_IP: self._inventory.keys()}
|
|
|
|
def _get_blade_for_port(self, args):
|
|
"""
|
|
Return the a dict with IP address of the blade
|
|
on which a dynamic vnic was reserved for this port
|
|
"""
|
|
tenant_id = args[0]
|
|
net_id = args[1]
|
|
port_id = args[2]
|
|
rsvd_info = self._get_rsvd_blade_intf_by_port(tenant_id, port_id)
|
|
if not rsvd_info:
|
|
raise exc.PortNotFound(net_id=net_id, port_id=port_id)
|
|
device_params = {const.DEVICE_IP: [rsvd_info[const.UCSM_IP]]}
|
|
return device_params
|
|
|
|
def _get_host_name_for_rsvd_intf(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():
|
|
tmp = deepcopy(blade_intf_data[blade_intf])
|
|
intf_data = blade_intf_data[blade_intf]
|
|
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
|
const.BLADE_INTF_RESERVED and
|
|
intf_data[const.TENANTID] == tenant_id and
|
|
intf_data[const.INSTANCE_ID] is None):
|
|
intf_data[const.INSTANCE_ID] = instance_id
|
|
host_name = self._get_host_name(ucsm_ip,
|
|
chassis_id,
|
|
blade_id)
|
|
port_binding = udb.get_portbinding_dn(blade_intf)
|
|
port_id = port_binding[const.PORTID]
|
|
udb.update_portbinding(port_id,
|
|
instance_id=instance_id)
|
|
return host_name
|
|
LOG.warn("Could not find a reserved dynamic nic for tenant: %s" %
|
|
tenant_id)
|
|
return None
|
|
|
|
def _get_instance_port(self, tenant_id, instance_id, vif_id):
|
|
"""
|
|
Return the device name for a reserved interface
|
|
"""
|
|
found_blade_intf_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]
|
|
blade_intf_data = blade_data[const.BLADE_INTF_DATA]
|
|
for blade_intf in blade_intf_data.keys():
|
|
intf_data = blade_intf_data[blade_intf]
|
|
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
|
const.BLADE_INTF_RESERVED and
|
|
intf_data[const.TENANTID] == tenant_id and
|
|
intf_data[const.INSTANCE_ID] == instance_id):
|
|
found_blade_intf_data = blade_intf_data
|
|
LOG.debug(("Found blade %s associated with this"
|
|
" instance: %s") % (blade_id,
|
|
instance_id))
|
|
break
|
|
|
|
if found_blade_intf_data:
|
|
blade_intf_data = found_blade_intf_data
|
|
for blade_intf in blade_intf_data.keys():
|
|
intf_data = blade_intf_data[blade_intf]
|
|
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
|
const.BLADE_INTF_RESERVED and
|
|
intf_data[const.TENANTID] == tenant_id and
|
|
(not intf_data[const.VIF_ID])):
|
|
intf_data[const.VIF_ID] = vif_id
|
|
intf_data[const.INSTANCE_ID] = instance_id
|
|
port_binding = udb.get_portbinding_dn(blade_intf)
|
|
port_id = port_binding[const.PORTID]
|
|
udb.update_portbinding(port_id, instance_id=instance_id,
|
|
vif_id=vif_id)
|
|
device_name = intf_data[const.BLADE_INTF_RHEL_DEVICE_NAME]
|
|
profile_name = port_binding[const.PORTPROFILENAME]
|
|
dynamicnic_details = {
|
|
const.DEVICENAME: device_name,
|
|
const.UCSPROFILE: profile_name,
|
|
}
|
|
LOG.debug(("Found reserved dynamic nic: %s"
|
|
"associated with port %s") %
|
|
(intf_data, port_id))
|
|
LOG.debug("Returning dynamic nic details: %s" %
|
|
dynamicnic_details)
|
|
return dynamicnic_details
|
|
|
|
LOG.warn("Could not find a reserved dynamic nic for tenant: %s" %
|
|
tenant_id)
|
|
return None
|
|
|
|
def _disassociate_vifid_from_port(self, tenant_id, instance_id, vif_id):
|
|
"""
|
|
Disassociate a VIF-ID from a port, this happens when a
|
|
VM is destroyed
|
|
"""
|
|
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():
|
|
intf_data = blade_intf_data[blade_intf]
|
|
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
|
const.BLADE_INTF_RESERVED and
|
|
intf_data[const.TENANTID] == tenant_id and
|
|
blade_intf_data[blade_intf][const.INSTANCE_ID]
|
|
== instance_id and
|
|
intf_data[const.VIF_ID][:const.UUID_LENGTH] ==
|
|
vif_id):
|
|
intf_data[const.VIF_ID] = None
|
|
intf_data[const.INSTANCE_ID] = None
|
|
port_binding = udb.get_portbinding_dn(blade_intf)
|
|
port_id = port_binding[const.PORTID]
|
|
udb.update_portbinding(port_id, instance_id=None,
|
|
vif_id=None)
|
|
LOG.debug(
|
|
("Disassociated VIF-ID: %s "
|
|
"from port: %s"
|
|
"in UCS inventory state for blade: %s") %
|
|
(vif_id, port_id, intf_data))
|
|
device_params = {const.DEVICE_IP: [ucsm_ip],
|
|
const.PORTID: port_id}
|
|
return device_params
|
|
LOG.warn(("Disassociating VIF-ID in UCS inventory failed. "
|
|
"Could not find a reserved dynamic nic for tenant: %s") %
|
|
tenant_id)
|
|
return None
|
|
|
|
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 ((not blade_intf_data[blade_intf][const.PORTID] or
|
|
not blade_intf_data[blade_intf][const.TENANTID])):
|
|
continue
|
|
intf_data = blade_intf_data[blade_intf]
|
|
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
|
const.BLADE_INTF_RESERVED and
|
|
intf_data[const.TENANTID] == tenant_id and
|
|
intf_data[const.PORTID] == port_id):
|
|
interface_dn = intf_data[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
|
|
LOG.warn("Could not find a reserved nic for tenant: %s port: %s" %
|
|
(tenant_id, port_id))
|
|
return None
|
|
|
|
def _get_least_reserved_blade(self, intf_count=1):
|
|
"""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 < intf_count:
|
|
LOG.warn(("Not enough dynamic nics available on a single host."
|
|
" Requested: %s, Maximum available: %s") %
|
|
(intf_count, unreserved_interface_count))
|
|
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,
|
|
}
|
|
LOG.debug("Found dynamic nic %s available for reservation",
|
|
least_reserved_blade_dict)
|
|
return least_reserved_blade_dict
|
|
|
|
def reload_inventory(self):
|
|
"""Reload the inventory from a conf file"""
|
|
self._load_inventory()
|
|
|
|
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.get_username(ucsm_ip)
|
|
ucsm_password = cred.Store.get_password(ucsm_ip)
|
|
"""
|
|
We are first getting the updated UCSM-specific 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]
|
|
chassis_data = self._inventory_state[ucsm_ip][chassis_id]
|
|
old_blade_intf_data = chassis_data[blade_id][const.BLADE_INTF_DATA]
|
|
|
|
"""
|
|
We will now copy the older non-UCSM-specific blade
|
|
interface state
|
|
"""
|
|
for blade_intf in blade_intf_data.keys():
|
|
old_intf_data = old_blade_intf_data[blade_intf]
|
|
blade_intf_data[blade_intf][const.BLADE_INTF_RESERVATION] = (
|
|
old_intf_data[const.BLADE_INTF_RESERVATION])
|
|
blade_intf_data[blade_intf][const.TENANTID] = (
|
|
old_intf_data[const.TENANTID])
|
|
blade_intf_data[blade_intf][const.PORTID] = (
|
|
old_intf_data[const.PORTID])
|
|
blade_intf_data[blade_intf][const.PROFILE_ID] = (
|
|
old_intf_data[const.PROFILE_ID])
|
|
blade_intf_data[blade_intf][const.INSTANCE_ID] = (
|
|
old_intf_data[const.INSTANCE_ID])
|
|
blade_intf_data[blade_intf][const.VIF_ID] = (
|
|
old_intf_data[const.VIF_ID])
|
|
|
|
blade_data[const.BLADE_UNRESERVED_INTF_COUNT] = (
|
|
chassis_data[blade_id][const.BLADE_UNRESERVED_INTF_COUNT])
|
|
"""
|
|
Now we will reserve an interface if its available
|
|
"""
|
|
for blade_intf in blade_intf_data.keys():
|
|
intf_data = blade_intf_data[blade_intf]
|
|
if (intf_data[const.BLADE_INTF_RESERVATION] ==
|
|
const.BLADE_INTF_UNRESERVED):
|
|
intf_data[const.BLADE_INTF_RESERVATION] = (
|
|
const.BLADE_INTF_RESERVED)
|
|
intf_data[const.TENANTID] = tenant_id
|
|
intf_data[const.PORTID] = port_id
|
|
intf_data[const.INSTANCE_ID] = None
|
|
dev_eth_name = intf_data[const.BLADE_INTF_RHEL_DEVICE_NAME]
|
|
"""
|
|
We are replacing the older blade interface state with new
|
|
"""
|
|
chassis_data[blade_id][const.BLADE_INTF_DATA] = blade_intf_data
|
|
chassis_data[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,
|
|
}
|
|
port_binding = udb.add_portbinding(port_id, blade_intf, None,
|
|
None, None, None)
|
|
udb.update_portbinding(port_id,
|
|
tenant_id=intf_data[const.TENANTID])
|
|
LOG.debug("Reserved blade interface: %s\n" % reserved_nic_dict)
|
|
return reserved_nic_dict
|
|
|
|
LOG.warn("Dynamic nic %s could not be reserved for port-id: %s" %
|
|
(blade_data, port_id))
|
|
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.get_username(ucsm_ip)
|
|
ucsm_password = cred.Store.get_password(ucsm_ip)
|
|
blade_data = self._inventory_state[ucsm_ip][chassis_id][blade_id]
|
|
|
|
blade_data[const.BLADE_UNRESERVED_INTF_COUNT] += 1
|
|
blade_intf = blade_data[const.BLADE_INTF_DATA][interface_dn]
|
|
blade_intf[const.BLADE_INTF_RESERVATION] = const.BLADE_INTF_UNRESERVED
|
|
blade_intf[const.TENANTID] = None
|
|
blade_intf[const.PORTID] = None
|
|
blade_intf[const.PROFILE_ID] = None
|
|
blade_intf[const.INSTANCE_ID] = None
|
|
blade_intf[const.VIF_ID] = None
|
|
LOG.debug("Unreserved blade interface %s\n" % interface_dn)
|
|
|
|
def add_blade(self, ucsm_ip, chassis_id, blade_id):
|
|
"""Add a blade to the inventory"""
|
|
# TODO (Sumit)
|
|
pass
|
|
|
|
def get_all_networks(self, args):
|
|
"""Return all UCSM IPs"""
|
|
LOG.debug("get_all_networks() called\n")
|
|
return self._get_all_ucsms()
|
|
|
|
def create_network(self, args):
|
|
"""Return all UCSM IPs"""
|
|
LOG.debug("create_network() called\n")
|
|
return self._get_all_ucsms()
|
|
|
|
def delete_network(self, args):
|
|
"""Return all UCSM IPs"""
|
|
LOG.debug("delete_network() called\n")
|
|
return self._get_all_ucsms()
|
|
|
|
def get_network_details(self, args):
|
|
"""Return all UCSM IPs"""
|
|
LOG.debug("get_network_details() called\n")
|
|
return self._get_all_ucsms()
|
|
|
|
def update_network(self, args):
|
|
"""Return all UCSM IPs"""
|
|
LOG.debug("update_network() called\n")
|
|
return self._get_all_ucsms()
|
|
|
|
def get_all_ports(self, args):
|
|
"""Return all UCSM IPs"""
|
|
LOG.debug("get_all_ports() called\n")
|
|
return self._get_all_ucsms()
|
|
|
|
def create_port(self, args):
|
|
"""
|
|
Return the a dict with information of the blade
|
|
on which a dynamic vnic is available
|
|
"""
|
|
LOG.debug("create_port() called\n")
|
|
least_reserved_blade_dict = self._get_least_reserved_blade()
|
|
if not least_reserved_blade_dict:
|
|
raise cexc.NoMoreNics()
|
|
ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM]
|
|
device_params = {
|
|
const.DEVICE_IP: [ucsm_ip],
|
|
const.UCS_INVENTORY: self,
|
|
const.LEAST_RSVD_BLADE_DICT: least_reserved_blade_dict,
|
|
}
|
|
return device_params
|
|
|
|
def delete_port(self, args):
|
|
"""
|
|
Return the a dict with information of the blade
|
|
on which a dynamic vnic was reserved for this port
|
|
"""
|
|
LOG.debug("delete_port() called\n")
|
|
tenant_id = args[0]
|
|
net_id = args[1]
|
|
port_id = args[2]
|
|
rsvd_info = self._get_rsvd_blade_intf_by_port(tenant_id, port_id)
|
|
if not rsvd_info:
|
|
LOG.warn("UCSInventory: Port not found: net_id: %s, port_id: %s" %
|
|
(net_id, port_id))
|
|
return {const.DEVICE_IP: []}
|
|
device_params = {
|
|
const.DEVICE_IP: [rsvd_info[const.UCSM_IP]],
|
|
const.UCS_INVENTORY: self,
|
|
const.CHASSIS_ID: rsvd_info[const.CHASSIS_ID],
|
|
const.BLADE_ID: rsvd_info[const.BLADE_ID],
|
|
const.BLADE_INTF_DN: rsvd_info[const.BLADE_INTF_DN],
|
|
}
|
|
return device_params
|
|
|
|
def update_port(self, args):
|
|
"""
|
|
Return the a dict with IP address of the blade
|
|
on which a dynamic vnic was reserved for this port
|
|
"""
|
|
LOG.debug("update_port() called\n")
|
|
return self._get_blade_for_port(args)
|
|
|
|
def get_port_details(self, args):
|
|
"""
|
|
Return the a dict with IP address of the blade
|
|
on which a dynamic vnic was reserved for this port
|
|
"""
|
|
LOG.debug("get_port_details() called\n")
|
|
return self._get_blade_for_port(args)
|
|
|
|
def plug_interface(self, args):
|
|
"""
|
|
Return the a dict with IP address of the blade
|
|
on which a dynamic vnic was reserved for this port
|
|
"""
|
|
LOG.debug("plug_interface() called\n")
|
|
return self._get_blade_for_port(args)
|
|
|
|
def unplug_interface(self, args):
|
|
"""
|
|
Return the a dict with IP address of the blade
|
|
on which a dynamic vnic was reserved for this port
|
|
"""
|
|
LOG.debug("unplug_interface() called\n")
|
|
return self._get_blade_for_port(args)
|
|
|
|
def schedule_host(self, args):
|
|
"""Provides the hostname on which a dynamic vnic is reserved"""
|
|
LOG.debug("schedule_host() called\n")
|
|
instance_id = args[1]
|
|
tenant_id = args[2][const.PROJECT_ID]
|
|
host_name = self._get_host_name_for_rsvd_intf(tenant_id, instance_id)
|
|
host_list = {const.HOST_LIST: {const.HOST_1: host_name}}
|
|
LOG.debug("host_list is: %s" % host_list)
|
|
return host_list
|
|
|
|
def associate_port(self, args):
|
|
"""
|
|
Get the portprofile name and the device name for the dynamic vnic
|
|
"""
|
|
LOG.debug("associate_port() called\n")
|
|
instance_id = args[1]
|
|
tenant_id = args[2][const.PROJECT_ID]
|
|
vif_id = args[2][const.VIF_ID]
|
|
vif_info = self._get_instance_port(tenant_id, instance_id, vif_id)
|
|
vif_desc = {const.VIF_DESC: vif_info}
|
|
|
|
LOG.debug("vif_desc is: %s" % vif_desc)
|
|
return vif_desc
|
|
|
|
def detach_port(self, args):
|
|
"""
|
|
Remove the VIF-ID and instance name association
|
|
with the port
|
|
"""
|
|
LOG.debug("detach_port() called\n")
|
|
instance_id = args[1]
|
|
tenant_id = args[2][const.PROJECT_ID]
|
|
vif_id = args[2][const.VIF_ID]
|
|
device_params = self._disassociate_vifid_from_port(tenant_id,
|
|
instance_id,
|
|
vif_id)
|
|
return device_params
|
|
|
|
def create_multiport(self, args):
|
|
"""
|
|
Create multiple ports for a VM
|
|
"""
|
|
LOG.debug("create_ports() called\n")
|
|
tenant_id = args[0]
|
|
ports_num = args[2]
|
|
least_reserved_blade_dict = self._get_least_reserved_blade(ports_num)
|
|
if not least_reserved_blade_dict:
|
|
raise cexc.NoMoreNics()
|
|
ucsm_ip = least_reserved_blade_dict[const.LEAST_RSVD_BLADE_UCSM]
|
|
device_params = {
|
|
const.DEVICE_IP: [ucsm_ip],
|
|
const.UCS_INVENTORY: self,
|
|
const.LEAST_RSVD_BLADE_DICT:
|
|
least_reserved_blade_dict,
|
|
}
|
|
return device_params
|