Merge "Accept ucsm_host_list as part of Multi-UCSM config"
This commit is contained in:
commit
5d93dafd7c
|
@ -234,6 +234,11 @@
|
||||||
# ucsm_password = password
|
# ucsm_password = password
|
||||||
# ucsm_virtio_eth_ports = eth0, eth1
|
# ucsm_virtio_eth_ports = eth0, eth1
|
||||||
|
|
||||||
|
# Hostname to Service Profile mapping for Compute hosts managed by
|
||||||
|
# this UCS Manager. This config should be specified for hosts configured
|
||||||
|
# with only Service Profiles and not Service Profile Templates.
|
||||||
|
# ucsm_host_list=Hostname1:Serviceprofile1, Hostname2:Serviceprofile2
|
||||||
|
|
||||||
# Service Profile Template config per UCSM. This is a mapping of Service Profile
|
# Service Profile Template config per UCSM. This is a mapping of Service Profile
|
||||||
# Template to the list of UCS Servers controlled by this template.
|
# Template to the list of UCS Servers controlled by this template.
|
||||||
# sp_template_list = SP_Template1_path:SP_Template1:S1,S2 SP_Template2_path:SP_Template2:S3,S4
|
# sp_template_list = SP_Template1_path:SP_Template1:S1,S2 SP_Template2_path:SP_Template2:S3,S4
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import debtcollector
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
@ -82,38 +80,35 @@ def parse_pci_vendor_config():
|
||||||
return vendor_list
|
return vendor_list
|
||||||
|
|
||||||
|
|
||||||
@debtcollector.removals.remove(message=DEPRECATION_MESSAGE)
|
def parse_ucsm_host_config(ucsm_ip, ucsm_host_list):
|
||||||
def parse_ucsm_host_config():
|
|
||||||
sp_dict = {}
|
sp_dict = {}
|
||||||
host_dict = {}
|
host_dict = {}
|
||||||
if cfg.CONF.ml2_cisco_ucsm.ucsm_host_list:
|
for host in ucsm_host_list:
|
||||||
host_config_list = cfg.CONF.ml2_cisco_ucsm.ucsm_host_list
|
host = host.strip()
|
||||||
for host in host_config_list:
|
hostname, sep, service_profile = host.partition(':')
|
||||||
hostname, sep, service_profile = host.partition(':')
|
if not sep or not service_profile:
|
||||||
if not sep or not service_profile:
|
raise cfg.Error(_("UCS Mech Driver: Invalid Host Service "
|
||||||
raise cfg.Error(_("UCS Mech Driver: Invalid Host Service "
|
"Profile config: %s") % host)
|
||||||
"Profile config: %s") % host)
|
key = (ucsm_ip, hostname)
|
||||||
key = (cfg.CONF.ml2_cisco_ucsm.ucsm_ip, hostname)
|
if '/' not in service_profile:
|
||||||
if '/' not in service_profile:
|
# Assuming the service profile is at the root level
|
||||||
# Assuming the service profile is at the root level
|
# and the path is not specified. This option
|
||||||
# and the path is not specified. This option
|
# allows backward compatability with earlier config
|
||||||
# allows backward compatability with earlier config
|
# format
|
||||||
# format
|
sp_dict[key] = (const.SERVICE_PROFILE_PATH_PREFIX +
|
||||||
sp_dict[key] = (const.SERVICE_PROFILE_PATH_PREFIX +
|
service_profile.strip())
|
||||||
service_profile.strip())
|
else:
|
||||||
else:
|
# Assuming the complete path to Service Profile has
|
||||||
# Assuming the complete path to Service Profile has
|
# been provided in the config. The Service Profile
|
||||||
# been provided in the config. The Service Profile
|
# could be in an sub-org.
|
||||||
# could be in an sub-org.
|
sp_dict[key] = service_profile.strip()
|
||||||
sp_dict[key] = service_profile.strip()
|
|
||||||
|
|
||||||
LOG.debug('Service Profile for %s is %s',
|
LOG.debug('Service Profile for %s is %s',
|
||||||
hostname, sp_dict.get(key))
|
hostname, sp_dict.get(key))
|
||||||
host_dict[hostname] = cfg.CONF.ml2_cisco_ucsm.ucsm_ip
|
host_dict[hostname] = ucsm_ip
|
||||||
return sp_dict, host_dict
|
return sp_dict, host_dict
|
||||||
|
|
||||||
|
|
||||||
@debtcollector.removals.remove(message=DEPRECATION_MESSAGE)
|
|
||||||
def parse_virtio_eth_ports():
|
def parse_virtio_eth_ports():
|
||||||
eth_port_list = []
|
eth_port_list = []
|
||||||
if not cfg.CONF.ml2_cisco_ucsm.ucsm_virtio_eth_ports:
|
if not cfg.CONF.ml2_cisco_ucsm.ucsm_virtio_eth_ports:
|
||||||
|
@ -130,6 +125,8 @@ def parse_virtio_eth_ports():
|
||||||
class UcsmConfig(object):
|
class UcsmConfig(object):
|
||||||
"""ML2 Cisco UCSM Mechanism Driver Configuration class."""
|
"""ML2 Cisco UCSM Mechanism Driver Configuration class."""
|
||||||
ucsm_dict = {}
|
ucsm_dict = {}
|
||||||
|
ucsm_sp_dict = {}
|
||||||
|
ucsm_host_dict = {}
|
||||||
ucsm_port_dict = {}
|
ucsm_port_dict = {}
|
||||||
sp_template_dict = {}
|
sp_template_dict = {}
|
||||||
vnic_template_dict = {}
|
vnic_template_dict = {}
|
||||||
|
@ -149,7 +146,6 @@ class UcsmConfig(object):
|
||||||
raise cfg.Error(_('Insufficient UCS Manager configuration has '
|
raise cfg.Error(_('Insufficient UCS Manager configuration has '
|
||||||
'been provided to the plugin'))
|
'been provided to the plugin'))
|
||||||
|
|
||||||
@debtcollector.removals.remove(message=DEPRECATION_MESSAGE)
|
|
||||||
def _create_single_ucsm_dicts(self):
|
def _create_single_ucsm_dicts(self):
|
||||||
"""Creates a dictionary of UCSM data for 1 UCS Manager."""
|
"""Creates a dictionary of UCSM data for 1 UCS Manager."""
|
||||||
ucsm_info = []
|
ucsm_info = []
|
||||||
|
@ -166,6 +162,8 @@ class UcsmConfig(object):
|
||||||
"""Creates a dictionary of all UCS Manager data from config."""
|
"""Creates a dictionary of all UCS Manager data from config."""
|
||||||
username = None
|
username = None
|
||||||
password = None
|
password = None
|
||||||
|
local_sp_dict = {}
|
||||||
|
local_host_dict = {}
|
||||||
multi_parser = cfg.MultiConfigParser()
|
multi_parser = cfg.MultiConfigParser()
|
||||||
read_ok = multi_parser.read(cfg.CONF.config_file)
|
read_ok = multi_parser.read(cfg.CONF.config_file)
|
||||||
|
|
||||||
|
@ -181,7 +179,13 @@ class UcsmConfig(object):
|
||||||
eth_port_list = []
|
eth_port_list = []
|
||||||
for dev_key, value in parsed_file[parsed_item].items():
|
for dev_key, value in parsed_file[parsed_item].items():
|
||||||
config_item = dev_key.lower()
|
config_item = dev_key.lower()
|
||||||
if config_item == 'ucsm_virtio_eth_ports':
|
if config_item == 'ucsm_host_list':
|
||||||
|
local_sp_dict, local_host_dict = (
|
||||||
|
parse_ucsm_host_config(dev_ip,
|
||||||
|
value[0].split(',')))
|
||||||
|
self.ucsm_sp_dict.update(local_sp_dict)
|
||||||
|
self.ucsm_host_dict.update(local_host_dict)
|
||||||
|
elif config_item == 'ucsm_virtio_eth_ports':
|
||||||
for eth_port in value[0].split(','):
|
for eth_port in value[0].split(','):
|
||||||
eth_port_list.append(
|
eth_port_list.append(
|
||||||
const.ETH_PREFIX + str(eth_port).strip())
|
const.ETH_PREFIX + str(eth_port).strip())
|
||||||
|
@ -197,7 +201,7 @@ class UcsmConfig(object):
|
||||||
self.sriov_qos_policy[dev_ip] = value[0].strip()
|
self.sriov_qos_policy[dev_ip] = value[0].strip()
|
||||||
elif dev_key.lower() == 'ucsm_username':
|
elif dev_key.lower() == 'ucsm_username':
|
||||||
username = value[0].strip()
|
username = value[0].strip()
|
||||||
else:
|
elif dev_key.lower() == 'ucsm_password':
|
||||||
password = value[0].strip()
|
password = value[0].strip()
|
||||||
ucsm_info = (username, password)
|
ucsm_info = (username, password)
|
||||||
self.ucsm_dict[dev_ip] = ucsm_info
|
self.ucsm_dict[dev_ip] = ucsm_info
|
||||||
|
|
|
@ -104,10 +104,19 @@ class CiscoUcsmDriver(object):
|
||||||
# Check if Service Profile to Hostname mapping config has been provided
|
# Check if Service Profile to Hostname mapping config has been provided
|
||||||
if cfg.CONF.ml2_cisco_ucsm.ucsm_host_list:
|
if cfg.CONF.ml2_cisco_ucsm.ucsm_host_list:
|
||||||
self.ucsm_sp_dict, self.ucsm_host_dict = (
|
self.ucsm_sp_dict, self.ucsm_host_dict = (
|
||||||
config.parse_ucsm_host_config())
|
config.parse_ucsm_host_config(
|
||||||
|
cfg.CONF.ml2_cisco_ucsm.ucsm_ip,
|
||||||
|
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list))
|
||||||
|
elif self.ucsm_conf.multi_ucsm_mode:
|
||||||
|
self.ucsm_sp_dict.update(self.ucsm_conf.ucsm_sp_dict)
|
||||||
|
self.ucsm_host_dict.update(self.ucsm_conf.ucsm_host_dict)
|
||||||
else:
|
else:
|
||||||
self._create_ucsm_host_to_service_profile_mapping()
|
self._create_ucsm_host_to_service_profile_mapping()
|
||||||
|
|
||||||
|
if not self.ucsm_sp_dict:
|
||||||
|
LOG.error(_LE('UCS Manager network driver failed to get Service '
|
||||||
|
'Profile information for any of its nodes.'))
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def ucsm_connect_disconnect(self, ucsm_ip):
|
def ucsm_connect_disconnect(self, ucsm_ip):
|
||||||
handle = self.ucs_manager_connect(ucsm_ip)
|
handle = self.ucs_manager_connect(ucsm_ip)
|
||||||
|
|
|
@ -29,6 +29,7 @@ UCSM_IP_ADDRESS_1 = '1.1.1.1'
|
||||||
UCSM_USERNAME_1 = 'username1'
|
UCSM_USERNAME_1 = 'username1'
|
||||||
UCSM_PASSWORD_1 = 'password1'
|
UCSM_PASSWORD_1 = 'password1'
|
||||||
UCSM_VIRTIO_ETH_PORTS_1 = ['eth0, eth1']
|
UCSM_VIRTIO_ETH_PORTS_1 = ['eth0, eth1']
|
||||||
|
UCSM_HOST_LIST_1 = ['UCS-1:UCS-1-SP, UCS-2:org-root/test/ls-UCS-2-SP']
|
||||||
|
|
||||||
UCSM_IP_ADDRESS_2 = '2.2.2.2'
|
UCSM_IP_ADDRESS_2 = '2.2.2.2'
|
||||||
UCSM_USERNAME_2 = 'username2'
|
UCSM_USERNAME_2 = 'username2'
|
||||||
|
@ -63,6 +64,7 @@ class ConfigMixin(object):
|
||||||
'ml2_cisco_ucsm_ip: 1.1.1.1': {
|
'ml2_cisco_ucsm_ip: 1.1.1.1': {
|
||||||
'ucsm_username': [UCSM_USERNAME_1],
|
'ucsm_username': [UCSM_USERNAME_1],
|
||||||
'ucsm_password': [UCSM_PASSWORD_1],
|
'ucsm_password': [UCSM_PASSWORD_1],
|
||||||
|
'ucsm_host_list': UCSM_HOST_LIST_1,
|
||||||
'ucsm_virtio_eth_ports': UCSM_VIRTIO_ETH_PORTS_1,
|
'ucsm_virtio_eth_ports': UCSM_VIRTIO_ETH_PORTS_1,
|
||||||
'vnic_template_list': ['test-physnet:org-root:Test-VNIC'],
|
'vnic_template_list': ['test-physnet:org-root:Test-VNIC'],
|
||||||
'sriov_qos_policy': ['Test']
|
'sriov_qos_policy': ['Test']
|
||||||
|
@ -103,6 +105,11 @@ class ConfigMixin(object):
|
||||||
507, 508, 509, 700]
|
507, 508, 509, 700]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expected_sp_dict = {
|
||||||
|
('1.1.1.1', 'UCS-1'): ('org-root/ls-UCS-1-SP'),
|
||||||
|
('1.1.1.1', 'UCS-2'): ('org-root/test/ls-UCS-2-SP'),
|
||||||
|
}
|
||||||
|
|
||||||
self.mocked_parser = mock.patch.object(cfg,
|
self.mocked_parser = mock.patch.object(cfg,
|
||||||
'MultiConfigParser').start()
|
'MultiConfigParser').start()
|
||||||
self.mocked_parser.return_value.read.return_value = [ucsm_test_config]
|
self.mocked_parser.return_value.read.return_value = [ucsm_test_config]
|
||||||
|
@ -118,3 +125,5 @@ class ConfigMixin(object):
|
||||||
ucsm_config.UcsmConfig.sriov_qos_policy)
|
ucsm_config.UcsmConfig.sriov_qos_policy)
|
||||||
self.assertEqual(expected_multivlan_trunk_dict,
|
self.assertEqual(expected_multivlan_trunk_dict,
|
||||||
ucsm_config.UcsmConfig.multivlan_trunk_dict)
|
ucsm_config.UcsmConfig.multivlan_trunk_dict)
|
||||||
|
self.assertEqual(expected_sp_dict,
|
||||||
|
ucsm_config.UcsmConfig.ucsm_sp_dict)
|
||||||
|
|
|
@ -762,7 +762,9 @@ class TestCiscoUcsmMechDriver(testlib_api.SqlTestCase,
|
||||||
expected_ip = '1.1.1.1'
|
expected_ip = '1.1.1.1'
|
||||||
expected_sp1 = "org-root/ls-SP1"
|
expected_sp1 = "org-root/ls-SP1"
|
||||||
expected_sp2 = "org-root/ls-SP2"
|
expected_sp2 = "org-root/ls-SP2"
|
||||||
ucsm_sp_dict, ucsm_host_dict = conf.parse_ucsm_host_config()
|
ucsm_sp_dict, ucsm_host_dict = conf.parse_ucsm_host_config(
|
||||||
|
cfg.CONF.ml2_cisco_ucsm.ucsm_ip,
|
||||||
|
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list)
|
||||||
|
|
||||||
key = (cfg.CONF.ml2_cisco_ucsm.ucsm_ip, 'Host1')
|
key = (cfg.CONF.ml2_cisco_ucsm.ucsm_ip, 'Host1')
|
||||||
self.assertIn(key, ucsm_sp_dict)
|
self.assertIn(key, ucsm_sp_dict)
|
||||||
|
@ -783,11 +785,13 @@ class TestCiscoUcsmMechDriver(testlib_api.SqlTestCase,
|
||||||
"""Verifies malformed ucsm_host_list raises an error."""
|
"""Verifies malformed ucsm_host_list raises an error."""
|
||||||
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list = ['Host1:', 'Host2:SP2']
|
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list = ['Host1:', 'Host2:SP2']
|
||||||
self.assertRaisesRegex(cfg.Error, "Host1:",
|
self.assertRaisesRegex(cfg.Error, "Host1:",
|
||||||
conf.parse_ucsm_host_config)
|
conf.parse_ucsm_host_config, UCSM_IP_ADDRESS_1,
|
||||||
|
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list)
|
||||||
|
|
||||||
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list = ['Host1:SP1', 'Host2']
|
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list = ['Host1:SP1', 'Host2']
|
||||||
self.assertRaisesRegex(cfg.Error, "Host2",
|
self.assertRaisesRegex(cfg.Error, "Host2",
|
||||||
conf.parse_ucsm_host_config)
|
conf.parse_ucsm_host_config, UCSM_IP_ADDRESS_1,
|
||||||
|
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list)
|
||||||
|
|
||||||
def test_parse_virtio_eth_ports(self):
|
def test_parse_virtio_eth_ports(self):
|
||||||
cfg.CONF.ml2_cisco_ucsm.ucsm_virtio_eth_ports = ['test-eth1',
|
cfg.CONF.ml2_cisco_ucsm.ucsm_virtio_eth_ports = ['test-eth1',
|
||||||
|
@ -804,7 +808,9 @@ class TestCiscoUcsmMechDriver(testlib_api.SqlTestCase,
|
||||||
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list = ['Host1:SP1',
|
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list = ['Host1:SP1',
|
||||||
'Host2:org-root/sub-org1/ls-SP2']
|
'Host2:org-root/sub-org1/ls-SP2']
|
||||||
|
|
||||||
ucsm_sp_dict, ucsm_host_dict = conf.parse_ucsm_host_config()
|
ucsm_sp_dict, ucsm_host_dict = conf.parse_ucsm_host_config(
|
||||||
|
cfg.CONF.ml2_cisco_ucsm.ucsm_ip,
|
||||||
|
cfg.CONF.ml2_cisco_ucsm.ucsm_host_list)
|
||||||
|
|
||||||
key = ('1.1.1.1', 'Host1')
|
key = ('1.1.1.1', 'Host1')
|
||||||
actual_service_profile1 = ucsm_sp_dict.get(key)
|
actual_service_profile1 = ucsm_sp_dict.get(key)
|
||||||
|
|
Loading…
Reference in New Issue