Merge "Support EthernetInterface resource in the emulator"

This commit is contained in:
Zuul authored and Gerrit Code Review committed 2018-09-18 13:06:31 +00:00
commit f575f8a921
12 files changed
+283

No files matched your search

+1
View File
@@ -23,6 +23,7 @@ linecache2==1.0.0
MarkupSafe==1.0
mock==2.0.0
mox3==0.20.0
munch==2.1.0
openstackdocstheme==1.18.1
openstacksdk===0.11.2
oslotest==3.2.0
+7
View File
@@ -144,3 +144,10 @@ class AbstractDriver(object):
:raises: `FishyError` if BIOS attributes cannot be processed
"""
@abc.abstractmethod
def get_nics(self, identity):
"""Get list of NICs and their attributes
:returns: list of dictionaries of NICs and their attributes
"""
@@ -472,3 +472,19 @@ class LibvirtDriver(AbstractDriver):
"""
self._process_bios(identity, self.DEFAULT_BIOS_ATTRIBUTES,
update_existing_attributes=True)
def get_nics(self, identity):
"""Get list of network interfaces and their MAC addresses
Use MAC address as network interface's id
:param identity: libvirt domain name or ID
:returns: list of network interfaces dict with their attributes
"""
with libvirt_open(self._uri, readonly=True) as conn:
domain = conn.lookupByName(identity)
tree = ET.fromstring(domain.XMLDesc())
return [{'id': iface.get('address'), 'mac': iface.get('address')}
for iface in tree.findall(
".//devices/interface[@type='network']/mac")]
@@ -284,3 +284,26 @@ class OpenStackDriver(AbstractDriver):
def reset_bios(self, identity):
"""Not supported as Openstack SDK does not expose API for BIOS"""
raise NotImplementedError
def get_nics(self, identity):
"""Get server's network interfaces
Use MAC address as network interface's id
:param identity: OpenStack instance name or ID
:returns: list of dictionaries with NIC attributes (id and mac)
"""
instance = self._get_instance(identity)
macs = set()
if not instance.addresses:
return macs
for addresses in instance.addresses.values():
for adr in addresses:
try:
macs.add(adr['OS-EXT-IPS-MAC:mac_addr'])
except KeyError:
logger.warning('Could not find MAC address in %s', adr)
return [{'id': mac, 'mac': mac}
for mac in macs]
+25
View File
@@ -164,6 +164,31 @@ def system_resource(identity):
return '', 204
@app.route('/redfish/v1/Systems/<identity>/EthernetInterfaces',
methods=['GET'])
@init_virt_driver
@returns_json
def ethernet_interfaces_collection(identity):
nics = driver.get_nics(identity)
return flask.render_template(
'ethernet_interfaces_collection.json', identity=identity,
nics=nics)
@app.route('/redfish/v1/Systems/<identity>/EthernetInterfaces/<nic_id>',
methods=['GET'])
@init_virt_driver
@returns_json
def ethernet_interface(identity, nic_id):
nics = driver.get_nics(identity)
for nic in nics:
if nic['id'] == nic_id:
return flask.render_template(
'ethernet_interface.json', identity=identity, nic=nic)
return 'Not found', 404
@app.route('/redfish/v1/Systems/<identity>/Actions/ComputerSystem.Reset',
methods=['POST'])
@init_virt_driver
@@ -0,0 +1,9 @@
{
"@odata.type": "#EthernetInterface.v1_0_2.EthernetInterface",
"Id": "{{ nic['id'] }}",
"Name": "VNIC {{ nic['id'] }}",
"PermanentMACAddress": "{{ nic['mac'] }}",
"MACAddress": "{{ nic['mac'] }}",
"@odata.context": "/redfish/v1/$metadata#EthernetInterface.EthernetInterface",
"@odata.id": "/redfish/v1/Systems/{{ identity }}/EthernetInterfaces/{{ nic['id'] }}"
}
@@ -0,0 +1,17 @@
{
"@odata.type": "#EthernetInterfaceCollection.EthernetInterfaceCollection",
"Name": "Ethernet Interface Collection",
"Description": "Virtual NICs",
"Members@odata.count": {{ nics|length }},
"Members": [
{% for nic in nics %}
{
"@odata.id": "/redfish/v1/Systems/{{ identity }}/EthernetInterfaces/{{ nic.id }}"
}{% if not loop.last %},{% endif %}
{% endfor %}
],
"Oem": {},
"@odata.context": "/redfish/v1/$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection",
"@odata.id": "/redfish/v1/Systems/{{ identity }}/EthernetInterfaces"
}
@@ -0,0 +1,35 @@
<domain type='qemu'>
<name>QEmu-fedora-i686</name>
<uuid>c7a5fdbd-cdaf-9455-926a-d65c16db1809</uuid>
<memory>219200</memory>
<currentMemory>219200</currentMemory>
<vcpu>2</vcpu>
<os>
<type arch='i686' machine='pc'>hvm</type>
<boot dev='cdrom'/>
<loader type='rom'/>
</os>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='cdrom'>
<source file='/home/user/boot.iso'/>
<target dev='hdc'/>
<readonly/>
</disk>
<disk type='file' device='disk'>
<source file='/home/user/fedora.img'/>
<target dev='hda'/>
</disk>
<interface type='network'>
<mac address='52:54:00:4e:5d:37'/>
<source network='default'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<interface type='network'>
<source network='default' portgroup='engineering'/>
<target dev='vnet7'/>
<mac address='00:11:22:33:44:55'/>
</interface>
<graphics type='vnc' port='-1'/>
</devices>
</domain>
@@ -318,3 +318,31 @@ class EmulatorTestCase(base.BaseTestCase):
'xxx-yyy-zzz',
{"BootMode": "Uefi",
"ProcTurboMode": "Enabled"})
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_nics(self, libvirt_mock):
with open('sushy_tools/tests/unit/emulator/domain_nics.xml') as f:
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock.XMLDesc.return_value = domain_xml
nics = self.test_driver.get_nics('xxx-yyy-zzz')
self.assertEqual([{'id': '00:11:22:33:44:55',
'mac': '00:11:22:33:44:55'},
{'id': '52:54:00:4e:5d:37',
'mac': '52:54:00:4e:5d:37'}],
sorted(nics, key=lambda k: k['id']))
@mock.patch('libvirt.openReadOnly', autospec=True)
def test_get_nics_empty(self, libvirt_mock):
with open('sushy_tools/tests/unit/emulator/domain.xml') as f:
domain_xml = f.read()
conn_mock = libvirt_mock.return_value
domain_mock = conn_mock.lookupByName.return_value
domain_mock.XMLDesc.return_value = domain_xml
nics = self.test_driver.get_nics('xxx-yyy-zzz')
self.assertEqual([], nics)
@@ -68,3 +68,61 @@ class EmulatorTestCase(base.BaseTestCase):
self.assertEqual('204 NO CONTENT', response.status)
driver_mock.reset_bios.assert_called_once_with('xxxx-yyyy-zzzz')
def test_ethernet_interfaces_collection(self, driver_mock):
driver_mock.get_nics.return_value = [{'id': 'nic1',
'mac': '52:54:00:4e:5d:37'},
{'id': 'nic2',
'mac': '00:11:22:33:44:55'}]
response = self.app.get('redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces')
self.assertEqual('200 OK', response.status)
self.assertEqual('Ethernet Interface Collection',
response.json['Name'])
self.assertEqual(2, response.json['Members@odata.count'])
self.assertEqual(['/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic1',
'/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic2'],
[m['@odata.id'] for m in response.json['Members']])
def test_ethernet_interfaces_collection_empty(self, driver_mock):
driver_mock.get_nics.return_value = []
response = self.app.get('redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces')
self.assertEqual('200 OK', response.status)
self.assertEqual('Ethernet Interface Collection',
response.json['Name'])
self.assertEqual(0, response.json['Members@odata.count'])
self.assertEqual([], response.json['Members'])
def test_ethernet_interface(self, driver_mock):
driver_mock.get_nics.return_value = [{'id': 'nic1',
'mac': '52:54:00:4e:5d:37'},
{'id': 'nic2',
'mac': '00:11:22:33:44:55'}]
response = self.app.get('/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic2')
self.assertEqual('200 OK', response.status)
self.assertEqual('nic2', response.json['Id'])
self.assertEqual('VNIC nic2', response.json['Name'])
self.assertEqual('00:11:22:33:44:55',
response.json['PermanentMACAddress'])
self.assertEqual('00:11:22:33:44:55',
response.json['MACAddress'])
self.assertEqual('/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic2',
response.json['@odata.id'])
def test_ethernet_interface_not_found(self, driver_mock):
driver_mock.get_nics.return_value = [{'id': 'nic1',
'mac': '52:54:00:4e:5d:37'},
{'id': 'nic2',
'mac': '00:11:22:33:44:55'}]
response = self.app.get('/redfish/v1/Systems/xxx-yyy-zzz/'
'EthernetInterfaces/nic3')
self.assertEqual('404 NOT FOUND', response.status)
@@ -15,6 +15,7 @@
import os
from munch import Munch
from oslotest import base
from six.moves import mock
@@ -182,3 +183,65 @@ class EmulatorTestCase(base.BaseTestCase):
NotImplementedError,
test_driver.reset_bios,
'xxx-yyy-zzz')
def test_get_nics(self, nova_mock):
addresses = Munch(
{u'public': [
Munch({u'OS-EXT-IPS-MAC:mac_addr': u'fa:16:3e:46:e3:ac',
u'version': 6,
u'addr': u'2001:db8::7',
u'OS-EXT-IPS:type': u'fixed'}),
Munch({u'OS-EXT-IPS-MAC:mac_addr': u'fa:16:3e:46:e3:ac',
u'version': 4,
u'addr': u'172.24.4.4',
u'OS-EXT-IPS:type': u'fixed'})],
u'private': [
Munch({u'OS-EXT-IPS-MAC:mac_addr': u'fa:16:3e:22:18:31',
u'version': 6,
u'addr': u'fdc2:e509:41b8:0:f816:3eff:fe22:1831',
u'OS-EXT-IPS:type': u'fixed'}),
Munch({u'OS-EXT-IPS-MAC:mac_addr': u'fa:16:3e:22:18:31',
u'version': 4,
u'addr': u'10.0.0.10',
u'OS-EXT-IPS:type': u'fixed'})]})
server = mock.Mock(addresses=addresses)
nova_mock.return_value.get_server.return_value = server
test_driver = OpenStackDriver('fake-cloud')
nics = test_driver.get_nics('xxxx-yyyy-zzzz')
self.assertEqual([{'id': 'fa:16:3e:22:18:31',
'mac': 'fa:16:3e:22:18:31'},
{'id': 'fa:16:3e:46:e3:ac',
'mac': 'fa:16:3e:46:e3:ac'}],
sorted(nics, key=lambda k: k['id']))
def test_get_nics_empty(self, nova_mock):
server = mock.Mock(addresses=None)
nova_mock.return_value.get_server.return_value = server
test_driver = OpenStackDriver('fake-cloud')
nics = test_driver.get_nics('xxxx-yyyy-zzzz')
self.assertEqual(set(), nics)
def test_get_nics_error(self, nova_mock):
addresses = Munch(
{u'public': [
Munch({u'version': 6,
u'addr': u'2001:db8::7'}),
Munch({u'version': 4,
u'addr': u'172.24.4.4'})],
u'private': [
Munch({u'OS-EXT-IPS-MAC:mac_addr': u'fa:16:3e:22:18:31',
u'version': 6,
u'addr': u'fdc2:e509:41b8:0:f816:3eff:fe22:1831',
u'OS-EXT-IPS:type': u'fixed'}),
Munch({u'OS-EXT-IPS-MAC:mac_addr': u'fa:16:3e:22:18:31',
u'version': 4,
u'addr': u'10.0.0.10',
u'OS-EXT-IPS:type': u'fixed'})]})
server = mock.Mock(addresses=addresses)
nova_mock.return_value.get_server.return_value = server
test_driver = OpenStackDriver('fake-cloud')
nics = test_driver.get_nics('xxxx-yyyy-zzzz')
self.assertEqual([{'id': 'fa:16:3e:22:18:31',
'mac': 'fa:16:3e:22:18:31'}],
nics)
+1
View File
@@ -12,3 +12,4 @@ oslotest>=3.2.0 # Apache-2.0
stestr>=1.0.0 # Apache-2.0
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=2.2.0 # MIT
munch>=2.1.0 # MIT