Add configuration client for VIOM configuration

This patch adds configuration client, which makes it easier to set a
VIOM(AdapterConfig) profile to iRMC than creating a VIOM profile
directly. This client provides features to set up volume boot to a
server, which is necessary for OpenStack Ironic iRMC driver.

Change-Id: I6e946f5344c67a676a5f8e7cead2a8eb62150f8b
This commit is contained in:
Hironori Shiina
2017-04-26 16:21:50 +00:00
parent 90e902fb44
commit 7e9169b2a1
2 changed files with 1341 additions and 0 deletions

View File

@@ -0,0 +1,447 @@
# Copyright 2017 FUJITSU LIMITED
#
# 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.
import abc
import re
import six
import socket
import struct
from scciclient.irmc import scci
from scciclient.irmc.viom import elcm
ONBOARD = 'onboard'
ADDON = 'addon'
_CARD_DICT = {
ONBOARD: elcm.OnboardCard,
ADDON: elcm.AddOnCard}
LAN = 'LAN'
FC = 'FC'
CNA = 'CNA'
_ADAPTER_DICT = {
LAN: elcm.LANAdapter,
FC: elcm.FCAdapter,
CNA: elcm.CNAAdapter
}
_POSSIBLE_CARD_TYPE = _ADAPTER_DICT.keys()
_CNA_LAN_FUNC_IDX = 1
_CNA_FCOE_FUNC_IDX = 2
_CNA_ISCSI_FUNC_IDX = 3
@six.add_metaclass(abc.ABCMeta)
class _PortHandler(object):
"""VIOM Configurator with physical port information"""
def __init__(self, slot_type, card_type, slot_idx, card_idx, port_idx):
self.slot_type = slot_type
self.card_type = card_type
self.slot_idx = slot_idx
self.card_idx = card_idx
self.port_idx = port_idx
def need_padding(self):
return False
def create_card(self):
return _CARD_DICT[self.slot_type](
self.card_idx, _ADAPTER_DICT[self.card_type]())
def create_lan_port(self, mac=None, port_enable=True):
raise NotImplementedError()
def set_lan_port(self, port, mac=None):
raise NotImplementedError()
def set_iscsi_port(self, port, iscsi_boot):
raise NotImplementedError()
def create_iscsi_port(self, iscsi_boot):
raise NotImplementedError()
def set_fc_port(self, port, fc_boot, wwnn=None, wwpn=None):
raise NotImplementedError()
def create_fc_port(self, fc_boot, wwnn=None, wwpn=None):
raise NotImplementedError()
class _LANPortHandler(_PortHandler):
"""Configurator for LAN card."""
def need_padding(self):
return True if self.slot_type == ONBOARD else False
def create_lan_port(self, mac=None, port_enable=True):
return elcm.LANPort(self.port_idx,
port_enable=port_enable,
use_virtual_addresses=bool(mac),
mac=mac)
def set_lan_port(self, port, mac=None):
port.port_enable = True
port.mac = mac
port.use_virtual_addresses = bool(mac)
def set_iscsi_port(self, port, iscsi_boot):
port.boot = iscsi_boot
def create_iscsi_port(self, iscsi_boot):
return elcm.LANPort(self.port_idx, boot=iscsi_boot, port_enable=True)
class _FCPortHandler(_PortHandler):
"""Configurator for FC card."""
def set_fc_port(self, port, fc_boot, wwnn=None, wwpn=None):
port.boot = fc_boot
port.port_enable = True
port.use_virtual_addresses = bool(wwnn or wwpn)
port.wwnn = wwnn
port.wwpn = wwpn
def create_fc_port(self, fc_boot, wwnn=None, wwpn=None):
return elcm.FCPort(self.port_idx, boot=fc_boot, wwnn=wwnn, wwpn=wwpn,
use_virtual_addresses=bool(wwnn or wwpn),
port_enable=True)
class _CNAPortHandler(_PortHandler):
"""Configurator for CNA card."""
def _create_port(self, function):
cna_port = elcm.CNAPort(self.port_idx)
if not isinstance(function, elcm.LANFunction):
# LanFunction is must
cna_port.add_function(
elcm.LANFunction(_CNA_LAN_FUNC_IDX, function_enable=False,
boot=None))
cna_port.add_function(function)
return cna_port
def create_lan_port(self, mac=None, port_enable=True):
function = elcm.LANFunction(_CNA_LAN_FUNC_IDX,
function_enable=port_enable,
use_virtual_addresses=bool(mac),
mac=mac)
return self._create_port(function)
def set_lan_port(self, port, mac=None):
function = port.get_function(_CNA_LAN_FUNC_IDX)
# Lan Function is always created when port is created.
function.function_enable = True
function.mac = mac
function.use_virtual_addresses = bool(mac)
def set_iscsi_port(self, port, iscsi_boot):
function = port.get_function(_CNA_ISCSI_FUNC_IDX)
if function:
function.boot = iscsi_boot
else:
function = elcm.ISCSIFunction(_CNA_ISCSI_FUNC_IDX, boot=iscsi_boot,
function_enable=True)
port.add_function(function)
def create_iscsi_port(self, iscsi_boot):
function = elcm.ISCSIFunction(_CNA_ISCSI_FUNC_IDX, boot=iscsi_boot)
return self._create_port(function)
def set_fc_port(self, port, fc_boot, wwnn=None, wwpn=None):
function = port.get_function(_CNA_FCOE_FUNC_IDX)
if function:
function.boot = fc_boot
function.use_virtual_addresses = bool(wwnn or wwpn)
function.wwnn = wwnn
function.wwpn = wwpn
else:
function = elcm.FCoEFunction(
_CNA_FCOE_FUNC_IDX, boot=fc_boot, function_enable=True,
use_virtual_addresses=bool(wwnn or wwpn), wwnn=wwnn, wwpn=wwpn)
port.add_function(function)
def create_fc_port(self, fc_boot, wwnn=None, wwpn=None):
function = elcm.FCoEFunction(
_CNA_FCOE_FUNC_IDX, boot=fc_boot, function_enable=True,
use_virtual_addresses=bool(wwnn or wwpn), wwnn=wwnn, wwpn=wwpn)
return self._create_port(function)
_PORT_HANDLERS = {
LAN: _LANPortHandler,
FC: _FCPortHandler,
CNA: _CNAPortHandler,
}
def _parse_physical_port_id(port_id):
message = ('Physical port ID should follow the format: '
'<card-type><slot-idx>-<port-idx> like CNA1-1. '
'<card-type> must be chosen from CNA, FC, or LAN. '
'<slot-idx> should be 0 for onboard slot or 1-9 for addon '
'slot. <port-idx> should be 1-9.')
m = re.match('^([a-zA-Z]+)([0-9])-([1-9])$', port_id)
if not m:
raise scci.SCCIInvalidInputError(message)
card_type = m.group(1).upper()
if card_type not in _POSSIBLE_CARD_TYPE:
raise scci.SCCIInvalidInputError(message)
slot_idx = 0
if int(m.group(2)) == 0:
slot_type = ONBOARD
card_idx = 1
else:
slot_type = ADDON
card_idx = int(m.group(2))
port_idx = int(m.group(3))
return _PORT_HANDLERS[card_type](slot_type, card_type, slot_idx, card_idx,
port_idx)
def _create_iscsi_boot(initiator_iqn,
initiator_dhcp=False, initiator_ip=None,
initiator_netmask=None,
target_dhcp=False, target_iqn=None, target_ip=None,
target_port=None, target_lun=None, boot_prio=1,
chap_user=None, chap_secret=None,
mutual_chap_secret=None):
iscsi_initiator = elcm.ISCSIInitiator(dhcp_usage=initiator_dhcp,
iqn=initiator_iqn,
ip=initiator_ip,
subnet=initiator_netmask)
if chap_user and chap_secret:
auth_method = 'MutualCHAP' if mutual_chap_secret else 'CHAP'
else:
auth_method = 'None'
iscsi_target = elcm.ISCSITarget(dhcp_usage=target_dhcp,
iqn=target_iqn,
ip=target_ip,
port=target_port,
lun=target_lun,
auth_method=auth_method,
chap_user=chap_user,
chap_secret=chap_secret,
mutual_chap_secret=mutual_chap_secret)
iscsi_boot = elcm.ISCSIBoot(iscsi_initiator,
iscsi_target,
boot_prio=boot_prio)
return iscsi_boot
def _convert_netmask(mask):
"""Convert netmask from CIDR format(integer) to doted decimal string."""
if mask not in range(0, 33):
raise scci.SCCIInvalidInputError(
'Netmask value is invalid.')
return socket.inet_ntoa(struct.pack(
'!L', int('1' * mask + '0' * (32 - mask), 2)))
class VIOMConfiguration(object):
"""VIOM Configurator for volume boot"""
def __init__(self, irmc_info, identification):
self.client = elcm.ELCMVIOMClient(irmc_info)
self.root = elcm.VIOMTable()
self.root.set_manage_table(
elcm.ManageTable(identification=identification))
def apply(self, reboot=False):
"""Apply the configuration to iRMC."""
self.root.use_virtual_addresses = True
self.root.manage.manage = True
self.root.mode = 'new'
self.root.init_boot = reboot
self.client.set_profile(self.root.get_json())
def terminate(self, reboot=False):
"""Delete VIOM configuration from iRMC."""
self.root.manage.manage = False
self.root.mode = 'delete'
self.root.init_boot = reboot
self.client.set_profile(self.root.get_json())
def _find_card(self, port_handler):
slot = self.root.get_slot(port_handler.slot_idx, create=False)
if not slot:
return None
if port_handler.slot_type == ONBOARD:
return slot.get_onboard_card(port_handler.card_idx)
else:
return slot.get_addon_card(port_handler.card_idx)
def _get_card(self, port_handler):
card = self._find_card(port_handler)
if card:
return card
card = port_handler.create_card()
self.root.get_slot(port_handler.slot_idx).add_card(card)
return card
def _find_port(self, port_handler):
card = self._find_card(port_handler)
if not card:
return None
return card.get_port(port_handler.port_idx)
def _add_port(self, port_handler, port):
self._pad_former_ports(port_handler)
card = self._get_card(port_handler)
card.add_port(port)
def set_lan_port(self, port_id, mac=None):
"""Set LAN port information to configuration.
:param port_id: Physical port ID.
:param mac: virtual MAC address if virtualization is necessary.
"""
port_handler = _parse_physical_port_id(port_id)
port = self._find_port(port_handler)
if port:
port_handler.set_lan_port(port, mac)
else:
self._add_port(port_handler, port_handler.create_lan_port(mac))
def set_iscsi_volume(self, port_id,
initiator_iqn, initiator_dhcp=False,
initiator_ip=None, initiator_netmask=None,
target_dhcp=False, target_iqn=None, target_ip=None,
target_port=3260, target_lun=0, boot_prio=1,
chap_user=None, chap_secret=None,
mutual_chap_secret=None):
"""Set iSCSI volume information to configuration.
:param port_id: Physical port ID.
:param initiator_iqn: IQN of initiator.
:param initiator_dhcp: True if DHCP is used in the iSCSI network.
:param initiator_ip: IP address of initiator. None if DHCP is used.
:param initiator_netmask: Netmask of initiator as integer. None if
DHCP is used.
:param target_dhcp: True if DHCP is used for iSCSI target.
:param target_iqn: IQN of target. None if DHCP is used.
:param target_ip: IP address of target. None if DHCP is used.
:param target_port: Port number of target. None if DHCP is used.
:param target_lun: LUN number of target. None if DHCP is used,
:param boot_prio: Boot priority of the volume. 1 indicates the highest
priority.
"""
initiator_netmask = (_convert_netmask(initiator_netmask)
if initiator_netmask else None)
port_handler = _parse_physical_port_id(port_id)
iscsi_boot = _create_iscsi_boot(
initiator_iqn,
initiator_dhcp=initiator_dhcp,
initiator_ip=initiator_ip,
initiator_netmask=initiator_netmask,
target_dhcp=target_dhcp,
target_iqn=target_iqn,
target_ip=target_ip,
target_port=target_port,
target_lun=target_lun,
boot_prio=boot_prio,
chap_user=chap_user,
chap_secret=chap_secret,
mutual_chap_secret=mutual_chap_secret)
port = self._find_port(port_handler)
if port:
port_handler.set_iscsi_port(port, iscsi_boot)
else:
port = port_handler.create_iscsi_port(iscsi_boot)
self._add_port(port_handler, port)
def set_fc_volume(self, port_id,
target_wwn, target_lun=0, boot_prio=1,
initiator_wwnn=None, initiator_wwpn=None):
"""Set FibreChannel volume information to configuration.
:param port_id: Physical port ID.
:param target_wwn: WWN of target.
:param target_lun: LUN number of target.
:param boot_prio: Boot priority of the volume. 1 indicates the highest
priority.
:param initiator_wwnn: Virtual WWNN for initiator if necessary.
:param initiator_wwpn: Virtual WWPN for initiator if necessary.
"""
port_handler = _parse_physical_port_id(port_id)
fc_target = elcm.FCTarget(target_wwn, target_lun)
fc_boot = elcm.FCBoot(boot_prio=boot_prio, boot_enable=True)
fc_boot.add_target(fc_target)
port = self._find_port(port_handler)
if port:
port_handler.set_fc_port(port, fc_boot,
wwnn=initiator_wwnn, wwpn=initiator_wwpn)
else:
port = port_handler.create_fc_port(fc_boot,
wwnn=initiator_wwnn,
wwpn=initiator_wwpn)
self._add_port(port_handler, port)
def dump_json(self):
"""Create JSON profile based on current configuration.
:returns: JSON data created from current configurtion. It can be
logged by a caller.
"""
return self.root.get_json()
def _pad_former_ports(self, port_handler):
"""Create ports with former port index.
:param port_handler: Port information to be registered.
Depending on slot type and card type, it is necessary to register
LAN ports with former index to VIOM table.
"""
if not port_handler.need_padding():
return
for port_idx in range(1, port_handler.port_idx):
pad_handler = port_handler.__class__(
port_handler.slot_type,
port_handler.card_type,
port_handler.slot_idx,
port_handler.card_idx,
port_idx)
if not self._find_port(pad_handler):
self._add_port(pad_handler,
pad_handler.create_lan_port())
def validate_physical_port_id(port_id):
"""Validate physical port ID.
Physical port ID is required for configure interfaces with VIOM API. The
format is:
<Card type><Slot Idx>-<Port Idx>
* Card type is chosen from CNA, FC or LAN.
* Slot Idx should be 0, which indecates on-board slot or 1-9, which
specify add-on slot index.
* Port Idx should be 1-9, which indicate port number.
:param port_id: Physical port ID following the format.
"""
_parse_physical_port_id(port_id)

View File

@@ -0,0 +1,894 @@
# Copyright 2017 FUJITSU LIMITED
#
# 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.
import mock
import testtools
from scciclient.irmc import scci
from scciclient.irmc.viom import client as viom_client
from scciclient.irmc.viom import elcm as viom_elcm
class VIOMConfigurationTestCase(testtools.TestCase):
def setUp(self):
super(VIOMConfigurationTestCase, self).setUp()
self.irmc_info = {
'irmc_address': '10.124.196.159',
'irmc_username': 'admin',
'irmc_password': 'admin0',
'irmc_port': 80,
'irmc_auth_method': 'basic',
'irmc_client_timeout': 60,
}
self.identification = 'viom_identification'
self.configurator = viom_client.VIOMConfiguration(
self.irmc_info, self.identification)
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def _test_terminate(self, mock_set, reboot=None):
if reboot is None:
self.configurator.terminate()
reboot = False
else:
self.configurator.terminate(reboot=reboot)
expected_json = {
'VIOMManage': {
'Manage': False,
'Identification': 'viom_identification',
},
'InitBoot': reboot,
'Mode': 'delete',
}
mock_set.assert_called_once_with(expected_json)
def test_terminate(self):
self._test_terminate()
def test_terminate_reboot_true(self):
self._test_terminate(reboot=True)
def test_terminate_reboot_false(self):
self._test_terminate(reboot=False)
@staticmethod
def _create_json_for_apply(slot_json, init_boot=False):
return {
'UseVirtualAddresses': True,
'Mode': 'new',
'InitBoot': init_boot,
'VIOMManage': {
'Manage': True,
'Identification': 'viom_identification'
},
'Slots': {
'Slot': [slot_json]
}
}
@staticmethod
def _create_json_before_apply(slot_json):
return {
'VIOMManage': {
'Identification': 'viom_identification'
},
'Slots': {
'Slot': [slot_json]
}
}
@staticmethod
def _create_json_slot_onbaord_lan(lan_port):
lan_ports = []
for port_idx in range(1, lan_port['@PortIdx']):
lan_ports.append(
{'@PortIdx': port_idx,
'BootPriority': 1,
'BootProtocol': 'None',
'PortEnable': True,
'UseVirtualAddresses': False})
lan_ports.append(lan_port)
return {
'@SlotIdx': 0,
'OnboardControllers': {
'OnboardController': [
{'@OnboardControllerIdx': 1,
'LANAdapter': {
'Ports': {
'Port': lan_ports
}
}}
]
}
}
@staticmethod
def _create_json_slot_with_cna_lan(card_idx, port_idx, lan_function):
return {
'@SlotIdx': 0,
'AddOnCards': {
'AddOnCard': [
{'@AddOnCardIdx': card_idx,
'CNAAdapter': {
'Ports': {
'Port': [
{'@PortIdx': port_idx,
'PortEnable': True,
'Functions': {
'Function': [
{'@FunctionIdx': 1,
'LANFunction': lan_function},
]
}}
]
}
}}
]
}
}
@staticmethod
def _create_json_slot_with_cna_iscsi(card_idx, port_idx, iscsi_function,
lan_function=None):
if not lan_function:
lan_function = {
'FunctionEnable': False,
'BootProtocol': 'None',
'BootPriority': 1,
}
return {
'@SlotIdx': 0,
'AddOnCards': {
'AddOnCard': [
{'@AddOnCardIdx': card_idx,
'CNAAdapter': {
'Ports': {
'Port': [
{'@PortIdx': port_idx,
'PortEnable': True,
'Functions': {
'Function': [
{'@FunctionIdx': 1,
'LANFunction': lan_function},
{'@FunctionIdx': 3,
'ISCSIFunction': iscsi_function}
]
}}
]
}
}}
]
}
}
@staticmethod
def _create_json_slot_with_fc(card_idx, fc_port):
return {
'@SlotIdx': 0,
'AddOnCards': {
'AddOnCard': [
{'@AddOnCardIdx': card_idx,
'FCAdapter': {
'Ports': {
'Port': [
fc_port
]
}
}}
]
}
}
@staticmethod
def _create_json_slot_with_cna_fcoe(card_idx, port_idx, fcoe_function,
lan_function=None):
if not lan_function:
lan_function = {
'FunctionEnable': False,
'BootProtocol': 'None',
'BootPriority': 1,
}
return {
'@SlotIdx': 0,
'AddOnCards': {
'AddOnCard': [
{'@AddOnCardIdx': card_idx,
'CNAAdapter': {
'Ports': {
'Port': [
{'@PortIdx': port_idx,
'PortEnable': True,
'Functions': {
'Function': [
{'@FunctionIdx': 1,
'LANFunction': lan_function},
{'@FunctionIdx': 2,
'FCoEFunction': fcoe_function}
]
}}
]
}
}}
]
}
}
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_lan_port_to_onboard(self, mock_set):
self.configurator.set_lan_port('LAN0-1')
port = {
'@PortIdx': 1,
'PortEnable': True,
'BootProtocol': 'None',
'BootPriority': 1,
'UseVirtualAddresses': False,
}
slot = VIOMConfigurationTestCase._create_json_slot_onbaord_lan(port)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_lan_port_to_onboard_with_virtual_mac(self, mock_set):
self.configurator.set_lan_port('LAN0-9', mac='aa:bb:cc:dd:ee')
port = {
'@PortIdx': 9,
'PortEnable': True,
'BootProtocol': 'None',
'BootPriority': 1,
'UseVirtualAddresses': True,
'VirtualAddress': {
'MAC': 'aa:bb:cc:dd:ee'
}
}
slot = VIOMConfigurationTestCase._create_json_slot_onbaord_lan(port)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply(reboot=True)
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot,
init_boot=True))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_lan_port_to_cna(self, mock_set):
self.configurator.set_lan_port('CNA5-6')
function = {
'FunctionEnable': True,
'BootProtocol': 'None',
'BootPriority': 1,
'UseVirtualAddresses': False,
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_lan(
5, 6, function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_lan_port_to_cna_with_virtual_mac(self, mock_set):
self.configurator.set_lan_port('CNA9-1', mac='12:34:56:78:90')
function = {
'FunctionEnable': True,
'BootProtocol': 'None',
'BootPriority': 1,
'UseVirtualAddresses': True,
'VirtualAddress': {
'MAC': '12:34:56:78:90'
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_lan(
9, 1, function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_iscsi_volume_to_onboard_lan(self, mock_set):
self.configurator.set_iscsi_volume(
'LAN0-9',
'iqn-2017-04.com.fujitsu:01',
initiator_ip='192.168.11.11',
initiator_netmask=24,
target_iqn='iqn-2017-04.com.fujitsu:11',
target_ip='192.168.22.22')
port = {
'@PortIdx': 9,
'PortEnable': True,
'BootProtocol': 'ISCSI',
'BootPriority': 1,
'ISCSIBootEnvironment': {
'ISCSIInitiator': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:01',
'IPv4Address': '192.168.11.11',
'SubnetMask': '255.255.255.0',
'VLANId': 0,
},
'ISCSITarget': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:11',
'IPv4Address': '192.168.22.22',
'PortNumber': 3260,
'BootLUN': 0,
'AuthenticationMethod': 'None'
}
}
}
slot = VIOMConfigurationTestCase._create_json_slot_onbaord_lan(port)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_iscsi_volume_to_cna_card(self, mock_set):
self.configurator.set_iscsi_volume(
'CNA1-2',
'iqn-2017-04.com.fujitsu:01',
initiator_ip='192.168.11.11',
initiator_netmask=16,
target_iqn='iqn-2017-04.com.fujitsu:11',
target_ip='192.168.22.22')
iscsi_function = {
'FunctionEnable': True,
'BootProtocol': 'ISCSI',
'BootPriority': 1,
'ISCSIBootEnvironment': {
'ISCSIInitiator': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:01',
'IPv4Address': '192.168.11.11',
'SubnetMask': '255.255.0.0',
'VLANId': 0,
},
'ISCSITarget': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:11',
'IPv4Address': '192.168.22.22',
'PortNumber': 3260,
'BootLUN': 0,
'AuthenticationMethod': 'None'
}
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi(
1, 2, iscsi_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_iscsi_volume_to_cna_card_chap(self, mock_set):
self.configurator.set_iscsi_volume(
'CNA9-9',
'iqn-2017-04.com.fujitsu:01',
initiator_ip='192.168.11.11',
initiator_netmask=30,
target_iqn='iqn-2017-04.com.fujitsu:11',
target_ip='192.168.22.22',
chap_user='chap-user',
chap_secret='chap-secret')
iscsi_function = {
'FunctionEnable': True,
'BootProtocol': 'ISCSI',
'BootPriority': 1,
'ISCSIBootEnvironment': {
'ISCSIInitiator': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:01',
'IPv4Address': '192.168.11.11',
'SubnetMask': '255.255.255.252',
'VLANId': 0,
},
'ISCSITarget': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:11',
'IPv4Address': '192.168.22.22',
'PortNumber': 3260,
'BootLUN': 0,
'AuthenticationMethod': 'CHAP',
'ChapUserName': 'chap-user',
'ChapSecret': 'chap-secret'
}
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi(
9, 9, iscsi_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_iscsi_volume_to_cna_card_mutual_chap(self, mock_set):
self.configurator.set_iscsi_volume(
'CNA2-1',
'iqn-2017-04.com.fujitsu:01',
initiator_ip='192.168.11.11',
initiator_netmask=8,
target_iqn='iqn-2017-04.com.fujitsu:11',
target_ip='192.168.22.22',
boot_prio=2,
target_lun=3,
chap_user='chap-user',
chap_secret='chap-secret',
mutual_chap_secret='mutual-secret')
iscsi_function = {
'FunctionEnable': True,
'BootProtocol': 'ISCSI',
'BootPriority': 2,
'ISCSIBootEnvironment': {
'ISCSIInitiator': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:01',
'IPv4Address': '192.168.11.11',
'SubnetMask': '255.0.0.0',
'VLANId': 0,
},
'ISCSITarget': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:11',
'IPv4Address': '192.168.22.22',
'PortNumber': 3260,
'BootLUN': 3,
'AuthenticationMethod': 'MutualCHAP',
'ChapUserName': 'chap-user',
'ChapSecret': 'chap-secret',
'MutualChapSecret': 'mutual-secret',
}
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi(
2, 1, iscsi_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_iscsi_volume_to_cna_card_initiator_dhcp(self, mock_set):
self.configurator.set_iscsi_volume(
'CNA1-2',
'iqn-2017-04.com.fujitsu:01',
initiator_dhcp=True,
target_iqn='iqn-2017-04.com.fujitsu:11',
target_ip='192.168.22.22')
iscsi_function = {
'FunctionEnable': True,
'BootProtocol': 'ISCSI',
'BootPriority': 1,
'ISCSIBootEnvironment': {
'ISCSIInitiator': {
'DHCPUsage': True,
'Name': 'iqn-2017-04.com.fujitsu:01',
},
'ISCSITarget': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:11',
'IPv4Address': '192.168.22.22',
'PortNumber': 3260,
'BootLUN': 0,
'AuthenticationMethod': 'None'
}
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi(
1, 2, iscsi_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_iscsi_volume_to_cna_card_target_dhcp(self, mock_set):
self.configurator.set_iscsi_volume(
'CNA1-2',
'iqn-2017-04.com.fujitsu:01',
initiator_ip='192.168.11.11',
initiator_netmask=16,
target_dhcp=True)
iscsi_function = {
'FunctionEnable': True,
'BootProtocol': 'ISCSI',
'BootPriority': 1,
'ISCSIBootEnvironment': {
'ISCSIInitiator': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:01',
'IPv4Address': '192.168.11.11',
'SubnetMask': '255.255.0.0',
'VLANId': 0,
},
'ISCSITarget': {
'DHCPUsage': True,
'AuthenticationMethod': 'None'
}
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi(
1, 2, iscsi_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_lan_and_iscsi_volume_to_cna_card(self, mock_set):
self.configurator.set_lan_port('CNA1-2')
self.configurator.set_iscsi_volume(
'CNA1-2',
'iqn-2017-04.com.fujitsu:01',
initiator_ip='192.168.11.11',
initiator_netmask=1,
target_iqn='iqn-2017-04.com.fujitsu:11',
target_ip='192.168.22.22')
lan_function = {
'FunctionEnable': True,
'BootProtocol': 'None',
'BootPriority': 1,
'UseVirtualAddresses': False,
}
iscsi_function = {
'FunctionEnable': True,
'BootProtocol': 'ISCSI',
'BootPriority': 1,
'ISCSIBootEnvironment': {
'ISCSIInitiator': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:01',
'IPv4Address': '192.168.11.11',
'SubnetMask': '128.0.0.0',
'VLANId': 0,
},
'ISCSITarget': {
'DHCPUsage': False,
'Name': 'iqn-2017-04.com.fujitsu:11',
'IPv4Address': '192.168.22.22',
'PortNumber': 3260,
'BootLUN': 0,
'AuthenticationMethod': 'None'
}
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_iscsi(
1, 2, iscsi_function, lan_function=lan_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_fc_volume_to_fc_card(self, mock_set):
self.configurator.set_fc_volume('FC1-1', '11:22:33:44:55')
port = {
'@PortIdx': 1,
'UseVirtualAddresses': False,
'PortEnable': True,
'BootProtocol': 'FC',
'BootPriority': 1,
'FCBootEnvironment': {
'FCTargets': {
'FCTarget': [
{'@FCTargetIdx': 1,
'TargetWWPN': '11:22:33:44:55',
'TargetLUN': 0}
]
},
'FCLinkSpeed': 'auto',
'FCTopology': 'auto_loop',
'SANBootEnable': True,
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_fc(1, port)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_fc_volume_to_fc_card_with_virtual_wwn(self, mock_set):
self.configurator.set_fc_volume('FC2-1', '11:22:33:44:55',
boot_prio=3, target_lun=2,
initiator_wwnn='aa:bb:cc:dd:ee',
initiator_wwpn='12:34:56:78:90')
port = {
'@PortIdx': 1,
'UseVirtualAddresses': True,
'VirtualAddress': {
'WWNN': 'aa:bb:cc:dd:ee',
'WWPN': '12:34:56:78:90'
},
'PortEnable': True,
'BootProtocol': 'FC',
'BootPriority': 3,
'FCBootEnvironment': {
'FCTargets': {
'FCTarget': [
{'@FCTargetIdx': 1,
'TargetWWPN': '11:22:33:44:55',
'TargetLUN': 2}
]
},
'FCLinkSpeed': 'auto',
'FCTopology': 'auto_loop',
'SANBootEnable': True,
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_fc(2, port)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_fc_volume_to_cna_card(self, mock_set):
self.configurator.set_fc_volume('CNA2-1', '11:22:33:44:55')
fcoe_function = {
'UseVirtualAddresses': False,
'FunctionEnable': True,
'BootProtocol': 'FC',
'BootPriority': 1,
'FCBootEnvironment': {
'FCTargets': {
'FCTarget': [
{'@FCTargetIdx': 1,
'TargetWWPN': '11:22:33:44:55',
'TargetLUN': 0}
]
},
'FCLinkSpeed': 'auto',
'FCTopology': 'auto_loop',
'SANBootEnable': True,
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_fcoe(
2, 1, fcoe_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_fc_volume_to_cna_card_with_virtual_wwn(self, mock_set):
self.configurator.set_fc_volume('CNA9-9', '11:22:33:44:55',
boot_prio=2, target_lun=3,
initiator_wwnn='aa:bb:cc:dd:ee',
initiator_wwpn='12:34:56:78:90')
fcoe_function = {
'UseVirtualAddresses': True,
'VirtualAddress': {
'WWNN': 'aa:bb:cc:dd:ee',
'WWPN': '12:34:56:78:90'
},
'FunctionEnable': True,
'BootProtocol': 'FC',
'BootPriority': 2,
'FCBootEnvironment': {
'FCTargets': {
'FCTarget': [
{'@FCTargetIdx': 1,
'TargetWWPN': '11:22:33:44:55',
'TargetLUN': 3}
]
},
'FCLinkSpeed': 'auto',
'FCTopology': 'auto_loop',
'SANBootEnable': True,
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_fcoe(
9, 9, fcoe_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
@mock.patch.object(viom_elcm.ELCMVIOMClient, 'set_profile')
def test_set_lan_and_fc_volume_to_cna_card(self, mock_set):
self.configurator.set_lan_port('CNA2-1')
self.configurator.set_fc_volume('CNA2-1', '11:22:33:44:55')
lan_function = {
'FunctionEnable': True,
'BootProtocol': 'None',
'BootPriority': 1,
'UseVirtualAddresses': False,
}
fcoe_function = {
'UseVirtualAddresses': False,
'FunctionEnable': True,
'BootProtocol': 'FC',
'BootPriority': 1,
'FCBootEnvironment': {
'FCTargets': {
'FCTarget': [
{'@FCTargetIdx': 1,
'TargetWWPN': '11:22:33:44:55',
'TargetLUN': 0}
]
},
'FCLinkSpeed': 'auto',
'FCTopology': 'auto_loop',
'SANBootEnable': True,
}
}
slot = VIOMConfigurationTestCase._create_json_slot_with_cna_fcoe(
2, 1, fcoe_function, lan_function=lan_function)
self.assertEqual(
VIOMConfigurationTestCase._create_json_before_apply(slot),
self.configurator.dump_json())
self.configurator.apply()
mock_set.assert_called_once_with(
VIOMConfigurationTestCase._create_json_for_apply(slot))
def test_set_lan_port_to_onboard_overwrite(self):
self.configurator.set_lan_port('LAN0-9')
self.test_set_lan_port_to_onboard_with_virtual_mac()
def test_set_lan_port_to_cna_overwrite(self):
self.configurator.set_lan_port('CNA5-6', mac='12:34:56:78:90')
self.test_set_lan_port_to_cna()
def test_set_iscsi_volume_to_onboard_lan_overwrite(self):
self.configurator.set_iscsi_volume(
'LAN0-9',
'iqn-initiator',
initiator_ip='192.168.99.99',
initiator_netmask=32,
target_iqn='iqn-target',
target_ip='192.168.88.88')
self.test_set_iscsi_volume_to_onboard_lan()
def test_set_iscsi_volume_to_cna_card_overwrite(self):
self.configurator.set_iscsi_volume(
'CNA1-2',
'iqn-initiator',
initiator_ip='192.168.99.99',
initiator_netmask=16,
target_iqn='iqn-target',
target_ip='192.168.88.88')
self.test_set_iscsi_volume_to_cna_card()
def test_set_fc_volume_to_fc_card_overwrite(self):
self.configurator.set_fc_volume('FC2-1', '11:22:33:44:55')
self.test_set_fc_volume_to_fc_card_with_virtual_wwn()
def test_set_fc_volume_to_cna_card_overwrite(self):
self.configurator.set_fc_volume('CNA2-1', '11:22:33:44:55',
boot_prio=2, target_lun=3,
initiator_wwnn='aa:bb:cc:dd:ee',
initiator_wwpn='12:34:56:78:90')
self.test_set_fc_volume_to_cna_card()
class PhysicalPortIDParseTestCase(testtools.TestCase):
def _validate_handler(self, handler, handler_class, slot_type, card_type,
slot_idx, card_idx, port_idx):
self.assertTrue(isinstance(handler, handler_class))
self.assertEqual(slot_type, handler.slot_type)
self.assertEqual(card_type, handler.card_type)
self.assertEqual(slot_idx, handler.slot_idx)
self.assertEqual(card_idx, handler.card_idx)
self.assertEqual(port_idx, handler.port_idx)
def test_lan_onboard(self):
handler = viom_client._parse_physical_port_id('LAN0-1')
self._validate_handler(handler, viom_client._LANPortHandler,
viom_client.ONBOARD, viom_client.LAN,
0, 1, 1)
def test_lan_onboard_lower(self):
handler = viom_client._parse_physical_port_id('lan0-2')
self._validate_handler(handler, viom_client._LANPortHandler,
viom_client.ONBOARD, viom_client.LAN,
0, 1, 2)
def test_lan_onboard_cammel(self):
handler = viom_client._parse_physical_port_id('Lan0-9')
self._validate_handler(handler, viom_client._LANPortHandler,
viom_client.ONBOARD, viom_client.LAN,
0, 1, 9)
def test_lan_addon(self):
handler = viom_client._parse_physical_port_id('LAN1-3')
self._validate_handler(handler, viom_client._LANPortHandler,
viom_client.ADDON, viom_client.LAN,
0, 1, 3)
def test_fc_addon(self):
handler = viom_client._parse_physical_port_id('FC2-5')
self._validate_handler(handler, viom_client._FCPortHandler,
viom_client.ADDON, viom_client.FC,
0, 2, 5)
def test_cna_addon(self):
handler = viom_client._parse_physical_port_id('CNA9-2')
self._validate_handler(handler, viom_client._CNAPortHandler,
viom_client.ADDON, viom_client.CNA,
0, 9, 2)
def test_unkown_card(self):
self.assertRaises(scci.SCCIInvalidInputError,
viom_client._parse_physical_port_id, 'HCA1-1')
def test_slot_out_of_range(self):
self.assertRaises(scci.SCCIInvalidInputError,
viom_client._parse_physical_port_id, 'CNA10-9')
def test_port_out_of_range_min(self):
self.assertRaises(scci.SCCIInvalidInputError,
viom_client._parse_physical_port_id, 'FC0-0')
def test_port_out_of_range_max(self):
self.assertRaises(scci.SCCIInvalidInputError,
viom_client._parse_physical_port_id, 'FC9-10')
def test_public_validation(self):
self.assertIsNone(viom_client.validate_physical_port_id('LAN0-2'))
def test_public_validation_error(self):
self.assertRaises(scci.SCCIInvalidInputError,
viom_client.validate_physical_port_id, 'CNA1-0')
class ConvertNetMaskTestCase(testtools.TestCase):
def test_convert_zero(self):
self.assertEqual('0.0.0.0',
viom_client._convert_netmask(0))
def test_convert_max(self):
self.assertEqual('255.255.255.255',
viom_client._convert_netmask(32))
def test_convert_nagative(self):
self.assertRaises(scci.SCCIInvalidInputError,
viom_client._convert_netmask, -1)
def test_convert_too_large(self):
self.assertRaises(scci.SCCIInvalidInputError,
viom_client._convert_netmask, 33)