Add eLCM APIs to control VIOM table
This patch adds a feature to control VIOM table in iRMC with eLCM API. VIOM table is updated by setting AdapterConfig profile. This feature enables virtualizing MACs and WWNs of I/O cards and booting a server with specifying boot protocol such as PXE, FC and iSCSI. The feature is required for server redundancy with remote volume. This patch defines classes representing VIOM table elements and a client setting this table to iRMC. VIOM stands for Virtual I/O Manager. Change-Id: I65369d42d22cfbdea9613a5fe59838cd03754419
This commit is contained in:
parent
2329a7d016
commit
90e902fb44
0
scciclient/irmc/viom/__init__.py
Normal file
0
scciclient/irmc/viom/__init__.py
Normal file
958
scciclient/irmc/viom/elcm.py
Normal file
958
scciclient/irmc/viom/elcm.py
Normal file
@ -0,0 +1,958 @@
|
|||||||
|
# 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 json
|
||||||
|
import time
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
from scciclient.irmc import elcm
|
||||||
|
from scciclient.irmc import scci
|
||||||
|
|
||||||
|
|
||||||
|
PROFILE_NAME = 'AdapterConfigIrmc'
|
||||||
|
PARAM_PATH = 'Server/AdapterConfigIrmc'
|
||||||
|
|
||||||
|
|
||||||
|
class ELCMVIOMClient(object):
|
||||||
|
"""Client calling eLCM REST APIs for VIOM feature"""
|
||||||
|
|
||||||
|
def __init__(self, irmc_info):
|
||||||
|
self.irmc_info = irmc_info
|
||||||
|
|
||||||
|
def _wait_session(self, session_id, timeout=1800):
|
||||||
|
session_expiration = time.time() + timeout
|
||||||
|
|
||||||
|
while True:
|
||||||
|
resp = elcm.elcm_session_get_status(self.irmc_info, session_id)
|
||||||
|
|
||||||
|
status = resp['Session']['Status']
|
||||||
|
if status == 'running' or status == 'activated':
|
||||||
|
# Sleep a bit
|
||||||
|
time.sleep(5)
|
||||||
|
elif status == 'terminated regularly':
|
||||||
|
return {}
|
||||||
|
else:
|
||||||
|
# Error occurred, get session log to see what happened
|
||||||
|
try:
|
||||||
|
session_log = elcm.elcm_session_get_log(
|
||||||
|
irmc_info=self.irmc_info, session_id=session_id)
|
||||||
|
except scci.SCCIClientError as e:
|
||||||
|
raise scci.SCCIClientError(
|
||||||
|
('Operation Failed. Session %(session_id)s state is '
|
||||||
|
'%(session_state)s. Session log collection failed: '
|
||||||
|
'%(reason)s' %
|
||||||
|
{'session_id': session_id,
|
||||||
|
'session_state': resp['Session']['Status'],
|
||||||
|
'reason': e}))
|
||||||
|
|
||||||
|
raise scci.SCCIClientError(
|
||||||
|
('Operation failed. Session %(session_id)s state is '
|
||||||
|
'%(session_state)s. Session log is: "%(session_log)s".' %
|
||||||
|
{'session_id': session_id,
|
||||||
|
'session_state': resp['Session']['Status'],
|
||||||
|
'session_log': json.dumps(session_log)}))
|
||||||
|
|
||||||
|
# Check for timeout
|
||||||
|
if time.time() > session_expiration:
|
||||||
|
# Timeout occurred, get session log to see what happened
|
||||||
|
try:
|
||||||
|
session_log = elcm.elcm_session_get_log(
|
||||||
|
irmc_info=self.irmc_info, session_id=session_id)
|
||||||
|
except scci.SCCIClientError as e:
|
||||||
|
raise elcm.ELCMSessionTimeout(
|
||||||
|
'Operation timed out. Session %(session_id)s has not '
|
||||||
|
'finished in %(timeout)d seconds. Session log '
|
||||||
|
'collection failed: %(reason)s' %
|
||||||
|
{'session_id': session_id,
|
||||||
|
'timeout': timeout,
|
||||||
|
'reason': e})
|
||||||
|
|
||||||
|
raise elcm.ELCMSessionTimeout(
|
||||||
|
'Operation timed out. Session %(session_id)s has not '
|
||||||
|
'finished in %(timeout)d seconds. Session log is: '
|
||||||
|
'"%(session_log)s.' %
|
||||||
|
{'session_id': session_id,
|
||||||
|
'timeout': timeout,
|
||||||
|
'session_log': json.dumps(session_log)})
|
||||||
|
|
||||||
|
def set_profile(self, adapter_config):
|
||||||
|
_adapter_config = dict(adapter_config)
|
||||||
|
_adapter_config.update({'@Processing': 'execute'})
|
||||||
|
req = {'Server': {'AdapterConfigIrmc': _adapter_config}}
|
||||||
|
resp = elcm.elcm_profile_set(self.irmc_info, req)
|
||||||
|
self._wait_session(resp['Session']['Id'])
|
||||||
|
|
||||||
|
def get_profile(self):
|
||||||
|
|
||||||
|
# delete old one
|
||||||
|
try:
|
||||||
|
elcm.elcm_profile_delete(self.irmc_info, PROFILE_NAME)
|
||||||
|
except elcm.ELCMProfileNotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
|
resp = elcm.elcm_profile_create(self.irmc_info, PARAM_PATH)
|
||||||
|
self._wait_session(resp['Session']['Id'])
|
||||||
|
resp = elcm.elcm_profile_get(self.irmc_info, PROFILE_NAME)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
class VIOMAttribute(object):
|
||||||
|
"""Attribute in VIOM Element.
|
||||||
|
|
||||||
|
This class is used for conversion between Python class and JSON table.
|
||||||
|
"""
|
||||||
|
def __init__(self, name, key, init=None):
|
||||||
|
self.name = name
|
||||||
|
self.key = key
|
||||||
|
self.init = init
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class VIOMElement(object):
|
||||||
|
"""Element in VIOM table."""
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
for attr in self.__class__._BASIC_ATTRIBUTES:
|
||||||
|
setattr(self, attr.name, kwargs.get(attr.name, attr.init))
|
||||||
|
|
||||||
|
def get_basic_json(self):
|
||||||
|
table = {}
|
||||||
|
for attr in self.__class__._BASIC_ATTRIBUTES:
|
||||||
|
value = getattr(self, attr.name)
|
||||||
|
if value is not None:
|
||||||
|
table[attr.key] = value
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
|
class VIOMTable(VIOMElement):
|
||||||
|
"""Root class of VIOM table"""
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('use_virtual_addresses', 'UseVirtualAddresses'),
|
||||||
|
VIOMAttribute('viom_boot_enable', 'VIOMBootEnable'),
|
||||||
|
VIOMAttribute('boot_menu_enable', 'BootMenuEnable'),
|
||||||
|
VIOMAttribute('sriov', 'SRIOV'),
|
||||||
|
VIOMAttribute('smux', 'Smux'),
|
||||||
|
VIOMAttribute('boot_mode', 'BootMode'),
|
||||||
|
VIOMAttribute('init_boot', 'InitBoot'),
|
||||||
|
VIOMAttribute('processing', '@Processing'),
|
||||||
|
VIOMAttribute('mode', 'Mode')
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(VIOMTable, self).__init__(**kwargs)
|
||||||
|
self.slots = {}
|
||||||
|
self.manage = None
|
||||||
|
|
||||||
|
def get_slot(self, slot_idx, create=True):
|
||||||
|
slot = self.slots.get(slot_idx)
|
||||||
|
if slot or not create:
|
||||||
|
return slot
|
||||||
|
slot = Slot(slot_idx)
|
||||||
|
self.slots[slot_idx] = slot
|
||||||
|
return slot
|
||||||
|
|
||||||
|
def set_manage_table(self, manage):
|
||||||
|
self.manage = manage
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON data for AdapterConfig.
|
||||||
|
|
||||||
|
:returns: JSON data as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"VIOMManage":{
|
||||||
|
},
|
||||||
|
"InitBoot":{
|
||||||
|
},
|
||||||
|
"UseVirtualAddresses":{
|
||||||
|
},
|
||||||
|
"BootMenuEnable":{
|
||||||
|
},
|
||||||
|
"SmuxSetting":{
|
||||||
|
},
|
||||||
|
"Slots":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
viom_table = self.get_basic_json()
|
||||||
|
if self.slots:
|
||||||
|
viom_table['Slots'] = {
|
||||||
|
'Slot': [s.get_json() for s in self.slots.values()]
|
||||||
|
}
|
||||||
|
if self.manage:
|
||||||
|
viom_table['VIOMManage'] = self.manage.get_json()
|
||||||
|
return viom_table
|
||||||
|
|
||||||
|
|
||||||
|
class ManageTable(VIOMElement):
|
||||||
|
"""Class for ViomManage element."""
|
||||||
|
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('manage', 'Manage'),
|
||||||
|
VIOMAttribute('identification', 'Identification'),
|
||||||
|
VIOMAttribute('trap_destination', 'TrapDestination'),
|
||||||
|
VIOMAttribute('force', 'Force'),
|
||||||
|
VIOMAttribute('preferred_version', 'PreferredInventoryVersion')
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(ManageTable, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON data for ViomManage.
|
||||||
|
|
||||||
|
:returns: JSON data for ViomManage as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"Manage":{
|
||||||
|
},
|
||||||
|
"Force":{
|
||||||
|
},
|
||||||
|
"Identification":{
|
||||||
|
},
|
||||||
|
"TrapDestination":{
|
||||||
|
},
|
||||||
|
"PreferredInventoryVersion":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
return self.get_basic_json()
|
||||||
|
|
||||||
|
|
||||||
|
class Slot(VIOMElement):
|
||||||
|
"""Class for Slot element."""
|
||||||
|
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('slot_idx', '@SlotIdx', 0),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, slot_idx, **kwargs):
|
||||||
|
super(Slot, self).__init__(slot_idx=slot_idx, **kwargs)
|
||||||
|
self.onboard_cards = {}
|
||||||
|
self.addon_cards = {}
|
||||||
|
|
||||||
|
def add_card(self, card):
|
||||||
|
if isinstance(card, OnboardCard):
|
||||||
|
self.onboard_cards[card.card_idx] = card
|
||||||
|
else:
|
||||||
|
self.addon_cards[card.card_idx] = card
|
||||||
|
|
||||||
|
def get_onboard_card(self, card_idx):
|
||||||
|
return self.onboard_cards.get(card_idx)
|
||||||
|
|
||||||
|
def get_addon_card(self, card_idx):
|
||||||
|
return self.addon_cards.get(card_idx)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON data for slot.
|
||||||
|
|
||||||
|
:returns: JSON data for slot as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"@SlotIdx":0,
|
||||||
|
"OnboardControllers":{
|
||||||
|
"OnboardController": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"AddOnCards":{
|
||||||
|
"AddOnCard": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
json = self.get_basic_json()
|
||||||
|
if self.onboard_cards:
|
||||||
|
json['OnboardControllers'] = {
|
||||||
|
'OnboardController':
|
||||||
|
[c.get_json() for c in self.onboard_cards.values()]
|
||||||
|
}
|
||||||
|
if self.addon_cards:
|
||||||
|
json['AddOnCards'] = {
|
||||||
|
'AddOnCard': [c.get_json() for c in self.addon_cards.values()]
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class PCICard(object):
|
||||||
|
"Abstract class for PCI cards."
|
||||||
|
def __init__(self, card_idx, adapter):
|
||||||
|
self.card_idx = card_idx
|
||||||
|
self.adapter = adapter
|
||||||
|
|
||||||
|
def add_port(self, port):
|
||||||
|
self.adapter.add_port(port)
|
||||||
|
|
||||||
|
def get_port(self, port_idx):
|
||||||
|
return self.adapter.get_port(port_idx)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON data for PCI card element.
|
||||||
|
|
||||||
|
:returns: JSON data for PCI card.
|
||||||
|
Data for onboard card is as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"@OnboardControllerIdx":1,
|
||||||
|
"LANAdapter":{
|
||||||
|
},
|
||||||
|
"CNAAdapter":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Data for add-on card is as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"@AddOnCardIdx":1,
|
||||||
|
"LANAdapter":{
|
||||||
|
},
|
||||||
|
"FCAdapter":{
|
||||||
|
},
|
||||||
|
"CNAAdapter":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
json = {self.INDEX_KEY: self.card_idx}
|
||||||
|
json.update(self.adapter.get_json())
|
||||||
|
return json
|
||||||
|
|
||||||
|
|
||||||
|
class OnboardCard(PCICard):
|
||||||
|
"""Class for onboard Card."""
|
||||||
|
INDEX_KEY = '@OnboardControllerIdx'
|
||||||
|
|
||||||
|
|
||||||
|
class AddOnCard(PCICard):
|
||||||
|
"""Class for add on card."""
|
||||||
|
INDEX_KEY = '@AddOnCardIdx'
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class Adapter(object):
|
||||||
|
"""Abstract class for adapters.
|
||||||
|
|
||||||
|
Adapter represents type of PCI card.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.ports = {}
|
||||||
|
|
||||||
|
def add_port(self, port):
|
||||||
|
self.ports[port.port_idx] = port
|
||||||
|
|
||||||
|
def get_port(self, port_idx):
|
||||||
|
return self.ports.get(port_idx)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON data for adapter
|
||||||
|
|
||||||
|
:returns: JSON data for adapter as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"LANAdapter":{
|
||||||
|
"Ports":{
|
||||||
|
"Port": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
self.ADAPTER_NAME: {
|
||||||
|
'Ports': {
|
||||||
|
'Port': [p.get_json() for p in self.ports.values()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class LANAdapter(Adapter):
|
||||||
|
"""LAN adapter."""
|
||||||
|
ADAPTER_NAME = 'LANAdapter'
|
||||||
|
|
||||||
|
|
||||||
|
class FCAdapter(Adapter):
|
||||||
|
"""FC adapter."""
|
||||||
|
ADAPTER_NAME = 'FCAdapter'
|
||||||
|
|
||||||
|
|
||||||
|
class CNAAdapter(Adapter):
|
||||||
|
"""CNA adatper."""
|
||||||
|
ADAPTER_NAME = 'CNAAdapter'
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class AdapterPort(VIOMElement):
|
||||||
|
"""Port in adapters."""
|
||||||
|
|
||||||
|
def __init__(self, port_idx, **kwargs):
|
||||||
|
super(AdapterPort, self).__init__(port_idx=port_idx, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class LANPort(AdapterPort):
|
||||||
|
"""LAN Port."""
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('port_idx', '@PortIdx', 1),
|
||||||
|
VIOMAttribute('port_enable', 'PortEnable'),
|
||||||
|
VIOMAttribute('sriov', 'SRIOV'),
|
||||||
|
VIOMAttribute('use_virtual_addresses', 'UseVirtualAddresses'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, port_idx, port_enable=True, mac=None, boot=None,
|
||||||
|
**kwargs):
|
||||||
|
super(LANPort, self).__init__(port_idx, port_enable=port_enable,
|
||||||
|
**kwargs)
|
||||||
|
self.mac = mac
|
||||||
|
self.boot = boot if boot else NoneBoot()
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON data for LANPort.
|
||||||
|
|
||||||
|
:returns: JSON data as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"@PortIdx":1,
|
||||||
|
"PortEnable":{
|
||||||
|
},
|
||||||
|
"UseVirtualAddresses":{
|
||||||
|
},
|
||||||
|
"BootProtocol":{
|
||||||
|
},
|
||||||
|
"VirtualAddress":{
|
||||||
|
"MAC":{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"BootPriority":{
|
||||||
|
},
|
||||||
|
"ISCSIBootEnvironment":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
port = self.get_basic_json()
|
||||||
|
port.update({
|
||||||
|
'BootProtocol': self.boot.BOOT_PROTOCOL,
|
||||||
|
'BootPriority': self.boot.boot_prio,
|
||||||
|
})
|
||||||
|
boot_env = self.boot.get_json()
|
||||||
|
if boot_env:
|
||||||
|
port.update(boot_env)
|
||||||
|
if self.use_virtual_addresses and self.mac:
|
||||||
|
port['VirtualAddress'] = {'MAC': self.mac}
|
||||||
|
return port
|
||||||
|
|
||||||
|
|
||||||
|
class FCPort(AdapterPort):
|
||||||
|
"""FC Port."""
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('port_idx', '@PortIdx', 1),
|
||||||
|
VIOMAttribute('port_enable', 'PortEnable'),
|
||||||
|
VIOMAttribute('sriov', 'SRIOV'),
|
||||||
|
VIOMAttribute('use_virtual_addresses', 'UseVirtualAddresses'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, port_idx, port_enable=True, wwnn=None, wwpn=None,
|
||||||
|
boot=None, **kwargs):
|
||||||
|
super(FCPort, self).__init__(port_idx, port_enable=port_enable,
|
||||||
|
**kwargs)
|
||||||
|
self.wwnn = wwnn
|
||||||
|
self.wwpn = wwpn
|
||||||
|
self.boot = boot if boot else NoneBoot()
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create FC port.
|
||||||
|
|
||||||
|
:returns: JSON for FC port as follows:
|
||||||
|
{
|
||||||
|
"@PortIdx":1,
|
||||||
|
"PortEnable":{
|
||||||
|
},
|
||||||
|
"UseVirtualAddresses":{
|
||||||
|
},
|
||||||
|
"VirtualAddress":{
|
||||||
|
"WWNN":{
|
||||||
|
},
|
||||||
|
"WWPN":{
|
||||||
|
},
|
||||||
|
"MAC":{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"BootProtocol":{
|
||||||
|
},
|
||||||
|
"BootPriority":{
|
||||||
|
},
|
||||||
|
"FCBootEnvironment":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
port = self.get_basic_json()
|
||||||
|
port.update({
|
||||||
|
'BootProtocol': self.boot.BOOT_PROTOCOL,
|
||||||
|
'BootPriority': self.boot.boot_prio,
|
||||||
|
})
|
||||||
|
boot_env = self.boot.get_json()
|
||||||
|
if boot_env:
|
||||||
|
port.update(boot_env)
|
||||||
|
if self.use_virtual_addresses:
|
||||||
|
addresses = {}
|
||||||
|
if self.wwnn:
|
||||||
|
addresses['WWNN'] = self.wwnn
|
||||||
|
if self.wwpn:
|
||||||
|
addresses['WWPN'] = self.wwpn
|
||||||
|
if addresses:
|
||||||
|
port['VirtualAddress'] = addresses
|
||||||
|
return port
|
||||||
|
|
||||||
|
|
||||||
|
class CNAPort(AdapterPort):
|
||||||
|
"""CNA port."""
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('port_idx', '@PortIdx', 1),
|
||||||
|
VIOMAttribute('port_enable', 'PortEnable'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, port_idx, port_enable=True):
|
||||||
|
super(CNAPort, self).__init__(port_idx, port_enable=port_enable)
|
||||||
|
self.functions = {}
|
||||||
|
|
||||||
|
def add_function(self, function):
|
||||||
|
self.functions[function.func_idx] = function
|
||||||
|
|
||||||
|
def get_function(self, func_idx):
|
||||||
|
return self.functions.get(func_idx)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON for CNA port.
|
||||||
|
|
||||||
|
:returns: JSON for CNA port as follows:
|
||||||
|
{
|
||||||
|
"@PortIdx":1,
|
||||||
|
"PortEnable":{
|
||||||
|
},
|
||||||
|
"Functions":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
port = self.get_basic_json()
|
||||||
|
port['Functions'] = {
|
||||||
|
'Function': [f.get_json() for f in self.functions.values()]
|
||||||
|
}
|
||||||
|
return port
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class CNAFunction(VIOMElement):
|
||||||
|
"""Abstract class for Functions for CNA card"""
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('function_enable', 'FunctionEnable'),
|
||||||
|
VIOMAttribute('vlan_id', 'VLANId'),
|
||||||
|
VIOMAttribute('sriov', 'SRIOV'),
|
||||||
|
VIOMAttribute('use_virtual_addresses', 'UseVirtualAddresses'),
|
||||||
|
VIOMAttribute('bandwidth', 'Bandwidth'),
|
||||||
|
VIOMAttribute('rate_limit', 'RateLimit'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, func_idx, function_enable=True, boot=None, **kwargs):
|
||||||
|
super(CNAFunction, self).__init__(**kwargs)
|
||||||
|
self.func_idx = func_idx
|
||||||
|
self.boot = boot if boot else NoneBoot()
|
||||||
|
self.function_enable = function_enable
|
||||||
|
|
||||||
|
def _get_virtual_addresses_json(self, json):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON for CNA function.
|
||||||
|
|
||||||
|
:returns: JSON for CNA function.
|
||||||
|
* LANFunction creates the following JSON:
|
||||||
|
|
||||||
|
{
|
||||||
|
"LANFunction":{
|
||||||
|
"FunctionEnable":{
|
||||||
|
},
|
||||||
|
"BootProtocol":{
|
||||||
|
},
|
||||||
|
"UseVirtualAddresses":{
|
||||||
|
},
|
||||||
|
"BootPriority":{
|
||||||
|
},
|
||||||
|
"Bandwidth":{
|
||||||
|
},
|
||||||
|
"RateLimit":{
|
||||||
|
},
|
||||||
|
"VLANId":{
|
||||||
|
},
|
||||||
|
"VirtualAddress":{
|
||||||
|
"MAC":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* FCoEFunction creates the following JSON:
|
||||||
|
|
||||||
|
{
|
||||||
|
"FCoEFunction":{
|
||||||
|
"FunctionEnable":{
|
||||||
|
},
|
||||||
|
"BootProtocol":{
|
||||||
|
},
|
||||||
|
"UseVirtualAddresses":{
|
||||||
|
},
|
||||||
|
"BootPriority":{
|
||||||
|
},
|
||||||
|
"Bandwidth":{
|
||||||
|
},
|
||||||
|
"RateLimit":{
|
||||||
|
},
|
||||||
|
"VLANId":{
|
||||||
|
},
|
||||||
|
"VirtualAddress":{
|
||||||
|
"WWNN":{
|
||||||
|
},
|
||||||
|
"WWPN":{
|
||||||
|
},
|
||||||
|
"MAC":{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FCBootEnvironment":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
* ISCSIFunction creates the following JSON:
|
||||||
|
|
||||||
|
{
|
||||||
|
"@FunctionIdx": 1,
|
||||||
|
"ISCSIFunction":{
|
||||||
|
"FunctionEnable":{
|
||||||
|
},
|
||||||
|
"BootProtocol":{
|
||||||
|
},
|
||||||
|
"UseVirtualAddresses":{
|
||||||
|
},
|
||||||
|
"BootPriority":{
|
||||||
|
},
|
||||||
|
"Bandwidth":{
|
||||||
|
},
|
||||||
|
"RateLimit":{
|
||||||
|
},
|
||||||
|
"VLANId":{
|
||||||
|
},
|
||||||
|
"VirtualAddress":{
|
||||||
|
"MAC":{
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ISCSIBootEnvironment":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
function = self.get_basic_json()
|
||||||
|
function['BootProtocol'] = self.boot.BOOT_PROTOCOL
|
||||||
|
function['BootPriority'] = self.boot.boot_prio
|
||||||
|
if self.use_virtual_addresses:
|
||||||
|
virtual_addresses = self._get_virtual_addresses_json()
|
||||||
|
if virtual_addresses:
|
||||||
|
function['VirtualAddress'] = virtual_addresses
|
||||||
|
boot_env = self.boot.get_json()
|
||||||
|
if boot_env:
|
||||||
|
function.update(boot_env)
|
||||||
|
return {'@FunctionIdx': self.func_idx,
|
||||||
|
self.FUNCTION_NAME: function}
|
||||||
|
|
||||||
|
|
||||||
|
class LANFunction(CNAFunction):
|
||||||
|
"""LAN function for CNA card"""
|
||||||
|
FUNCTION_NAME = 'LANFunction'
|
||||||
|
|
||||||
|
def __init__(self, func_idx, function_enable=True, boot=None, mac=None,
|
||||||
|
**kwargs):
|
||||||
|
super(LANFunction, self).__init__(
|
||||||
|
func_idx, function_enable=function_enable, boot=boot, **kwargs)
|
||||||
|
self.mac = mac
|
||||||
|
|
||||||
|
def _get_virtual_addresses_json(self):
|
||||||
|
return {'MAC': self.mac} if self.mac else None
|
||||||
|
|
||||||
|
|
||||||
|
class FCoEFunction(CNAFunction):
|
||||||
|
"""FCoE Function for CNA card."""
|
||||||
|
FUNCTION_NAME = 'FCoEFunction'
|
||||||
|
|
||||||
|
def __init__(self, func_idx, function_enable=True, boot=None, wwnn=None,
|
||||||
|
wwpn=None, mac=None, **kwargs):
|
||||||
|
super(FCoEFunction, self).__init__(
|
||||||
|
func_idx, function_enable=function_enable, boot=boot, **kwargs)
|
||||||
|
self.wwnn = wwnn
|
||||||
|
self.wwpn = wwpn
|
||||||
|
self.mac = mac
|
||||||
|
|
||||||
|
def _get_virtual_addresses_json(self):
|
||||||
|
virtual_addresses = {}
|
||||||
|
if self.mac:
|
||||||
|
virtual_addresses['MAC'] = self.mac
|
||||||
|
if self.wwnn:
|
||||||
|
virtual_addresses['WWNN'] = self.wwnn
|
||||||
|
if self.wwpn:
|
||||||
|
virtual_addresses['WWPN'] = self.wwpn
|
||||||
|
return virtual_addresses
|
||||||
|
|
||||||
|
|
||||||
|
class ISCSIFunction(CNAFunction):
|
||||||
|
"""iSCSI Function for CNA card."""
|
||||||
|
FUNCTION_NAME = 'ISCSIFunction'
|
||||||
|
|
||||||
|
def __init__(self, func_idx, function_enable=True, boot=None, mac=None,
|
||||||
|
**kwargs):
|
||||||
|
super(ISCSIFunction, self).__init__(
|
||||||
|
func_idx, function_enable=function_enable, boot=boot, **kwargs)
|
||||||
|
self.mac = mac
|
||||||
|
|
||||||
|
def _get_virtual_addresses_json(self):
|
||||||
|
return {'MAC': self.mac} if self.mac else None
|
||||||
|
|
||||||
|
|
||||||
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class Boot(VIOMElement):
|
||||||
|
"""Abstract class for BootProtocol"""
|
||||||
|
_BASIC_ATTRIBUTES = []
|
||||||
|
|
||||||
|
def __init__(self, boot_prio=1, **kwargs):
|
||||||
|
super(Boot, self).__init__(**kwargs)
|
||||||
|
self.boot_prio = boot_prio
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
class NoneBoot(Boot):
|
||||||
|
"""None BootProtocol."""
|
||||||
|
BOOT_PROTOCOL = 'None'
|
||||||
|
|
||||||
|
|
||||||
|
class PXEBoot(Boot):
|
||||||
|
"""PXE BootProtocol."""
|
||||||
|
BOOT_PROTOCOL = 'PXE'
|
||||||
|
|
||||||
|
|
||||||
|
class FCBoot(Boot):
|
||||||
|
"""FC BootProtocol with FCBootEnvironment elemnt."""
|
||||||
|
BOOT_PROTOCOL = 'FC'
|
||||||
|
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('link_speed', 'FCLinkSpeed', 'auto'),
|
||||||
|
VIOMAttribute('topology', 'FCTopology', 'auto_loop'),
|
||||||
|
VIOMAttribute('boot_enable', 'SANBootEnable'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, boot_prio=1, **kwargs):
|
||||||
|
super(FCBoot, self).__init__(boot_prio, **kwargs)
|
||||||
|
self.targets = []
|
||||||
|
|
||||||
|
def add_target(self, target):
|
||||||
|
self.targets.append(target)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON for FCBootEnvironment.
|
||||||
|
|
||||||
|
:returns: JSON for FCBootEnvironment as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"FCBootEnvironment":{
|
||||||
|
"FCTargets":{
|
||||||
|
"FCTarget":[
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"FCLinkSpeed":{
|
||||||
|
},
|
||||||
|
"SANBootEnable":{
|
||||||
|
},
|
||||||
|
"FCTopology":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
json = self.get_basic_json()
|
||||||
|
for i in range(len(self.targets)):
|
||||||
|
# @FCTargetIdx starts from 1.
|
||||||
|
self.targets[i].set_index(i + 1)
|
||||||
|
json['FCTargets'] = {
|
||||||
|
'FCTarget': [t.get_json() for t in self.targets]
|
||||||
|
}
|
||||||
|
return {'FCBootEnvironment': json}
|
||||||
|
|
||||||
|
|
||||||
|
class FCTarget(VIOMElement):
|
||||||
|
"""FC Target."""
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('index', '@FCTargetIdx', 1),
|
||||||
|
VIOMAttribute('wwpn', 'TargetWWPN'),
|
||||||
|
VIOMAttribute('lun', 'TargetLUN')
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, wwpn, lun=0, **kwargs):
|
||||||
|
super(FCTarget, self).__init__(wwpn=wwpn, lun=lun)
|
||||||
|
|
||||||
|
def set_index(self, index):
|
||||||
|
self.index = index
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON for FCTarget.
|
||||||
|
|
||||||
|
:returns: JSON data for FCTarget as follows:
|
||||||
|
{
|
||||||
|
"@FCTargetIdx":1,
|
||||||
|
"TargetWWPN":{
|
||||||
|
},
|
||||||
|
"TargetLUN":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
return self.get_basic_json()
|
||||||
|
|
||||||
|
|
||||||
|
class ISCSIBoot(Boot):
|
||||||
|
"""iSCSI BootProtocol with ISCSIBootEnvironment elment."""
|
||||||
|
BOOT_PROTOCOL = 'ISCSI'
|
||||||
|
|
||||||
|
def __init__(self, initiator, target, boot_prio=1):
|
||||||
|
super(ISCSIBoot, self).__init__(boot_prio)
|
||||||
|
self.initiator = initiator
|
||||||
|
self.target = target
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON for ISCSIBoot.
|
||||||
|
|
||||||
|
:returns: JSON data for ISCSIBoot as follows:
|
||||||
|
{
|
||||||
|
"ISCSIBootEnvironment":{
|
||||||
|
"ISCSIInitiator":{
|
||||||
|
},
|
||||||
|
"ISCSITarget":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'ISCSIBootEnvironment': {
|
||||||
|
'ISCSIInitiator': self.initiator.get_json(),
|
||||||
|
'ISCSITarget': self.target.get_json()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ISCSIInitiator(VIOMElement):
|
||||||
|
"""iSCSIInitiator."""
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('dhcp_usage', 'DHCPUsage', False),
|
||||||
|
VIOMAttribute('iqn', 'Name'),
|
||||||
|
VIOMAttribute('ip', 'IPv4Address'),
|
||||||
|
VIOMAttribute('subnet', 'SubnetMask'),
|
||||||
|
VIOMAttribute('gateway', 'GatewayIPv4Address'),
|
||||||
|
VIOMAttribute('vlan_id', 'VLANId', 0),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(ISCSIInitiator, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON data for iSCSI initiator.
|
||||||
|
|
||||||
|
:returns: JSON data for iSCSI initiator as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"DHCPUsage":{
|
||||||
|
},
|
||||||
|
"Name":{
|
||||||
|
},
|
||||||
|
"IPv4Address":{
|
||||||
|
},
|
||||||
|
"SubnetMask":{
|
||||||
|
},
|
||||||
|
"GatewayIPv4Address":{
|
||||||
|
},
|
||||||
|
"VLANId":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
if self.dhcp_usage:
|
||||||
|
return {'DHCPUsage': self.dhcp_usage,
|
||||||
|
'Name': self.iqn}
|
||||||
|
else:
|
||||||
|
return self.get_basic_json()
|
||||||
|
|
||||||
|
|
||||||
|
class ISCSITarget(VIOMElement):
|
||||||
|
"""iSCSI target."""
|
||||||
|
_BASIC_ATTRIBUTES = [
|
||||||
|
VIOMAttribute('dhcp_usage', 'DHCPUsage', False),
|
||||||
|
VIOMAttribute('iqn', 'Name'),
|
||||||
|
VIOMAttribute('ip', 'IPv4Address'),
|
||||||
|
VIOMAttribute('port', 'PortNumber', 3260),
|
||||||
|
VIOMAttribute('lun', 'BootLUN', 0),
|
||||||
|
VIOMAttribute('auth_method', 'AuthenticationMethod', 'None'),
|
||||||
|
VIOMAttribute('chap_user', 'ChapUserName'),
|
||||||
|
VIOMAttribute('chap_secret', 'ChapSecret'),
|
||||||
|
VIOMAttribute('mutual_chap_secret', 'MutualChapSecret'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(ISCSITarget, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
"""Create JSON data for iSCSI target.
|
||||||
|
|
||||||
|
:returns: JSON data for iSCSI target as follows:
|
||||||
|
|
||||||
|
{
|
||||||
|
"DHCPUsage":{
|
||||||
|
},
|
||||||
|
"Name":{
|
||||||
|
},
|
||||||
|
"IPv4Address":{
|
||||||
|
},
|
||||||
|
"PortNumber":{
|
||||||
|
},
|
||||||
|
"BootLUN":{
|
||||||
|
},
|
||||||
|
"AuthenticationMethod":{
|
||||||
|
},
|
||||||
|
"ChapUserName":{
|
||||||
|
},
|
||||||
|
"ChapSecret":{
|
||||||
|
},
|
||||||
|
"MutualChapSecret":{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
json = {
|
||||||
|
'DHCPUsage': self.dhcp_usage,
|
||||||
|
'AuthenticationMethod': self.auth_method,
|
||||||
|
}
|
||||||
|
if not self.dhcp_usage:
|
||||||
|
json['Name'] = self.iqn
|
||||||
|
json['IPv4Address'] = self.ip
|
||||||
|
json['PortNumber'] = self.port
|
||||||
|
json['BootLUN'] = self.lun
|
||||||
|
if self.chap_user:
|
||||||
|
json['ChapUserName'] = self.chap_user
|
||||||
|
if self.chap_secret:
|
||||||
|
json['ChapSecret'] = self.chap_secret
|
||||||
|
if self.mutual_chap_secret:
|
||||||
|
json['MutualChapSecret'] = self.mutual_chap_secret
|
||||||
|
return json
|
0
scciclient/tests/irmc/viom/__init__.py
Normal file
0
scciclient/tests/irmc/viom/__init__.py
Normal file
1342
scciclient/tests/irmc/viom/test_elcm.py
Normal file
1342
scciclient/tests/irmc/viom/test_elcm.py
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user