Add validation for connections

This patch its about to add all connections validation
for flat and neutron network interface and if the user
its using the OneView ml2 Driver.

Change-Id: I6c47f6b09d22b530da8eeac189ff54f603850723
This commit is contained in:
Andre 2016-09-26 21:27:41 +00:00 committed by Hugo Nicodemos
parent 2605032944
commit abd32cbdfe
7 changed files with 348 additions and 103 deletions

View File

@ -610,6 +610,84 @@ class Client(BaseClient):
return complete_task.get('associatedResource').get('resourceUri')
# ---- Node Validate ----
@auditing.audit
def validate_connections(self, oneview_info, ports, network_interface):
if network_interface != 'neutron':
self._is_node_port_mac_compatible_with_server_hardware(
oneview_info, ports)
self._validate_server_profile_template_mac_type(oneview_info)
elif oneview_info.get('use_oneview_ml2_driver'):
valid_ports = utils.get_oneview_connection_ports(ports)
self._validate_node_and_port_server_hardware_uri(
oneview_info, valid_ports)
self._validate_connection_mac(oneview_info, valid_ports)
@auditing.audit
def _is_node_port_mac_compatible_with_server_hardware(
self, node_info, ports
):
server_hardware = self.get_server_hardware(node_info)
try:
mac = server_hardware.get_mac(nic_index=0)
except exceptions.OneViewException:
mac = self.get_sh_mac_from_ilo(server_hardware.uuid, nic_index=0)
for port in ports:
if port.address.lower() == mac:
return
message = (
"The ports of the node are not compatible with its "
"server hardware %(server_hardware_uri)s." %
{'server_hardware_uri': server_hardware.uri}
)
raise exceptions.OneViewInconsistentResource(message)
@auditing.audit
def _validate_server_profile_template_mac_type(self, oneview_info):
server_profile_template = self.get_server_profile_template(
oneview_info
)
if server_profile_template.mac_type != 'Physical':
message = (
"The server profile template %s is not set to use "
"physical MAC." % server_profile_template.uri
)
raise exceptions.OneViewInconsistentResource(message)
@auditing.audit
def _validate_node_and_port_server_hardware_uri(self, oneview_info, ports):
node_hardware_id = utils.get_uuid_from_uri(
oneview_info.get('server_hardware_uri')
)
for port in ports:
switch_info = utils.get_switch_info(port)
port_hardware_id = switch_info.get('server_hardware_id')
if port_hardware_id.lower() != node_hardware_id.lower():
raise exceptions.OneViewInconsistentResource(
"The Server Hardware ID of the port %(port_id)s "
"doesn't match the Server Hardware ID %(server_hardware)s "
"of the node." % {
'port_id': port.uuid,
'server_hardware': node_hardware_id
}
)
@auditing.audit
def _validate_connection_mac(self, oneview_info, ports):
server_hardware = self.get_server_hardware(oneview_info)
for port in ports:
if port.address.lower() not in utils.get_all_macs(server_hardware):
raise exceptions.OneViewInconsistentResource(
"The MAC address %(mac)s of the port %(port_id)s doesn't"
" have a corresponding MAC address in the Server Hardware"
" %(server_hardware_uri)s" % {
'mac': port.address,
'port_id': port.uuid,
'server_hardware_uri': server_hardware.uri
}
)
@auditing.audit
def validate_node_server_hardware(
self, node_info, node_memorymb, node_cpus
@ -697,48 +775,16 @@ class Client(BaseClient):
server_hardware = self.get_server_hardware(node_info)
mac = self.get_sh_mac_from_ilo(server_hardware.uuid, nic_index=0)
is_mac_address_compatible = True
for port in ports:
port_address = port.__dict__.get('_obj_address')
if port_address is None:
port_address = port.__dict__.get('_address')
if port_address.lower() != mac.lower():
is_mac_address_compatible = False
if port.address.lower() == mac.lower():
return
if (not is_mac_address_compatible) or len(ports) == 0:
message = (
"The ports of the node are not compatible with its"
" server profile %(server_profile_uri)s." %
{'server_profile_uri': server_profile.uri}
)
raise exceptions.OneViewInconsistentResource(message)
@auditing.audit
def is_node_port_mac_compatible_with_server_hardware(
self, node_info, ports
):
server_hardware = self.get_server_hardware(node_info)
try:
mac = server_hardware.get_mac(nic_index=0)
except exceptions.OneViewException:
mac = self.get_sh_mac_from_ilo(server_hardware.uuid, nic_index=0)
is_mac_address_compatible = True
for port in ports:
port_address = port.__dict__.get('_obj_address')
if port_address is None:
port_address = port.__dict__.get('_address')
if port_address.lower() != mac:
is_mac_address_compatible = False
if (not is_mac_address_compatible) or len(ports) == 0:
message = (
"The ports of the node are not compatible with its"
" server hardware %(server_hardware_uri)s." %
{'server_hardware_uri': server_hardware.uri}
)
raise exceptions.OneViewInconsistentResource(message)
message = (
"The ports of the node are not compatible with its"
" server profile %(server_profile_uri)s." %
{'server_profile_uri': server_profile.uri}
)
raise exceptions.OneViewInconsistentResource(message)
@auditing.audit
def validate_node_server_profile_template(self, node_info):
@ -813,16 +859,3 @@ class Client(BaseClient):
" template %s." % server_profile_template.uri
)
raise exceptions.OneViewInconsistentResource(message)
@auditing.audit
def validate_server_profile_template_mac_type(self, uuid):
server_profile_template = self.get_server_profile_template_by_uuid(
uuid
)
if server_profile_template.mac_type != 'Physical':
message = (
"The server profile template %s is not set to use"
" physical MAC." % server_profile_template.uri
)
raise exceptions.OneViewInconsistentResource(message)

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
#
# (c) Copyright 2015 Hewlett Packard Enterprise Development LP
# Copyright 2015 Universidade Federal de Campina Grande
#
@ -17,7 +15,6 @@
import json
SERVER_HARDWARE_JSON = {
"type": "server-hardware-1",
"name": "Encl2, bay 16",
@ -6705,3 +6702,17 @@ PROPERTIES_DICT = {"cpu_arch": "x86_64",
DRIVER_INFO_DICT = {'server_hardware_uri': 'fake_sh_uri',
'server_profile_template_uri': 'fake_spt_uri'}
class TestablePort(object):
def __init__(
self, obj_address, bootable=False, pxe_enabled=False, sh_id=''
):
self.address = obj_address
self.local_link_connection = {
'switch_info': {'bootable': str(bootable),
'server_hardware_id': sh_id}
}
self.pxe_enabled = pxe_enabled
self.uuid = 'port-uuid'

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
#
# (c) Copyright 2015 Hewlett Packard Enterprise Development LP
# Copyright 2015 Universidade Federal de Campina Grande
#
@ -27,7 +25,6 @@ from oneview_client import exceptions
from oneview_client import ilo_utils
from oneview_client import models
from oneview_client.tests import fixtures
from oneview_client import utils
class OneViewClientAuthTestCase(unittest.TestCase):
@ -575,14 +572,15 @@ class OneViewClientTestCase(unittest.TestCase):
)
mock_get.return_value = response
spt_uuid = utils.get_uuid_from_uri(
server_profile_template_virtual_mac.get("uri")
)
oneview_info = {
'server_profile_template_uri':
server_profile_template_virtual_mac.get("uri")
}
self.assertRaises(
exceptions.OneViewInconsistentResource,
oneview_client.validate_server_profile_template_mac_type,
spt_uuid
oneview_client._validate_server_profile_template_mac_type,
oneview_info
)
@mock.patch.object(requests, 'get', autospec=True)
@ -603,11 +601,12 @@ class OneViewClientTestCase(unittest.TestCase):
)
mock_get.return_value = response
spt_uuid = utils.get_uuid_from_uri(
server_profile_template_physical_mac.get("uri")
)
oneview_info = {
'server_profile_template_uri':
server_profile_template_physical_mac.get("uri")
}
oneview_client.validate_server_profile_template_mac_type(spt_uuid)
oneview_client._validate_server_profile_template_mac_type(oneview_info)
@mock.patch.object(client.ClientV2, '_authenticate', autospec=True)
@ -927,7 +926,3 @@ class OneViewClientV2TestCase(unittest.TestCase):
headers=mock.ANY,
verify=True
)
if __name__ == '__main__':
unittest.main()

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
#
# (c) Copyright 2015 Hewlett Packard Enterprise Development LP
# Copyright 2015 Universidade Federal de Campina Grande
#
@ -29,13 +27,7 @@ from oneview_client import exceptions
from oneview_client import models
from oneview_client import states
from oneview_client.tests import fixtures
class TestablePort(object):
def __init__(self, obj_address):
self.obj_address = obj_address
self._obj_address = obj_address
from oneview_client import utils
class OneViewClientAuthTestCase(unittest.TestCase):
@ -542,6 +534,73 @@ class OneViewClientTestCase(unittest.TestCase):
)
self.assertEqual(mock_get.call_count, 2)
def test__validate_node_and_port_server_hardware_uri_without_ports(self):
driver_info = {"server_hardware_uri": "/rest/server-hardware/uri"}
self.oneview_client._validate_node_and_port_server_hardware_uri(
driver_info, []
)
def test__validate_node_and_port_server_hardware_uri(self):
sh_id = 'sh-id'
driver_info = {"server_hardware_uri": sh_id}
port1 = fixtures.TestablePort('AA:BB:CC:DD:EE:FA', sh_id=sh_id)
ports = [port1]
self.oneview_client._validate_node_and_port_server_hardware_uri(
driver_info, ports
)
def test__dont_validate_node_and_port_server_hardware_uri(self):
sh_id = 'sh-id'
wrong_sh_id = 'wrong-id'
driver_info = {"server_hardware_uri": sh_id}
port1 = fixtures.TestablePort('AA:BB:CC:DD:EE:FA', sh_id=sh_id)
port2 = fixtures.TestablePort('AA:BB:CC:DD:EE:FA', sh_id=wrong_sh_id)
ports = [port1, port2]
with self.assertRaises(exceptions.OneViewInconsistentResource):
self.oneview_client._validate_node_and_port_server_hardware_uri(
driver_info, ports
)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
@mock.patch.object(utils, 'get_all_macs', autospec=True)
def test__validate_connection_mac(
self, mock_get_macs, mock_get_server_hardware
):
sh_id = 'sh-id'
sh_uri = "/rest/server-hardware/" + sh_id
port1 = fixtures.TestablePort('AA:BB:CC:DD:EE:FA', sh_id=sh_id)
ports = [port1]
driver_info = {"server_hardware_uri": sh_uri}
server_hardware_mock = models.ServerHardware()
setattr(server_hardware_mock, "uri", "uri")
mock_get_server_hardware.return_value = server_hardware_mock
mock_get_macs.return_value = {'aa:bb:cc:dd:ee:fa'}
self.oneview_client._validate_connection_mac(driver_info, ports)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
@mock.patch.object(utils, 'get_all_macs', autospec=True)
def test__dont_validate_connection_mac(
self, mock_get_macs, mock_get_server_hardware
):
sh_id = 'sh-id'
sh_uri = "/rest/server-hardware/" + sh_id
port1 = fixtures.TestablePort('AA:BB:CC:DD:EE:FA', sh_id=sh_id)
port2 = fixtures.TestablePort('AA:BB:CC:DD:EE:FB', sh_id=sh_id)
ports = [port1, port2]
driver_info = {"server_hardware_uri": sh_uri}
server_hardware_mock = models.ServerHardware()
setattr(server_hardware_mock, "uri", "uri")
mock_get_server_hardware.return_value = server_hardware_mock
mock_get_macs.return_value = {'aa:bb:cc:dd:ee:fb'}
with self.assertRaises(exceptions.OneViewInconsistentResource):
self.oneview_client._validate_connection_mac(driver_info, ports)
@mock.patch.object(client.Client, 'get_server_hardware', autospec=True)
def test_validate_node_server_hardware_inconsistent_memorymb_value(
self, mock_get_server_hardware
@ -668,9 +727,9 @@ class OneViewClientTestCase(unittest.TestCase):
mock_server_hardware.return_value = server_hardware_mock
mock_server_hardware_by_uuid.return_value = server_hardware_mock
self.oneview_client.is_node_port_mac_compatible_with_server_hardware(
self.oneview_client._is_node_port_mac_compatible_with_server_hardware(
{},
[type('obj', (object,), {'_address': 'D8:9D:67:73:54:00'})]
[type('obj', (object,), {'address': 'D8:9D:67:73:54:00'})]
)
mock_server_hardware.assert_called_once_with(self.oneview_client, {})
@ -702,9 +761,9 @@ class OneViewClientTestCase(unittest.TestCase):
exceptions.OneViewInconsistentResource,
exc_expected_msg,
self.oneview_client
.is_node_port_mac_compatible_with_server_hardware,
._is_node_port_mac_compatible_with_server_hardware,
{},
[type('obj', (object,), {'_address': 'AA:BB:CC:DD:EE:FF'})]
[type('obj', (object,), {'address': 'AA:BB:CC:DD:EE:FF'})]
)
@mock.patch.object(client.Client, 'get_server_profile_from_hardware',
@ -886,35 +945,38 @@ class OneViewClientTestCase(unittest.TestCase):
server_profile_template
)
@mock.patch.object(client.Client, 'get_server_profile_template_by_uuid',
@mock.patch.object(client.Client, 'get_server_profile_template',
autospec=True)
def test_validate_server_profile_template_mac_type(
self, server_template_mock):
uuid = 123
profile_template_mock = models.ServerProfileTemplate()
setattr(profile_template_mock, "mac_type", "Physical")
setattr(profile_template_mock, "uri",
"/rest/server-profile-templates/%s" % '111-222-333')
oneview_info = {'server_profile_template_uri': '/rest/111-222-333'}
server_template_mock.return_value = profile_template_mock
self.oneview_client.validate_server_profile_template_mac_type(uuid)
self.oneview_client._validate_server_profile_template_mac_type(
oneview_info
)
@mock.patch.object(client.Client, 'get_server_profile_template_by_uuid',
@mock.patch.object(client.Client, 'get_server_profile_template',
autospec=True)
def test_validate_server_profile_template_mac_type_negative(
self, server_template_mock):
uuid = 123
# Negative case
profile_template_mock = models.ServerProfileTemplate()
setattr(profile_template_mock, "mac_type", "Virtual")
setattr(profile_template_mock, "uri",
"/rest/server-profile-templates/%s" % uuid)
"/rest/server-profile-templates/%s" % '123')
oneview_info = {'server_profile_template_uri': '/rest/123'}
server_template_mock.return_value = profile_template_mock
self.assertRaises(
exceptions.OneViewInconsistentResource,
self.oneview_client.validate_server_profile_template_mac_type,
uuid)
self.oneview_client._validate_server_profile_template_mac_type,
oneview_info
)
@mock.patch.object(client.Client, 'get_oneview_version')
def test_verify_oneview_version(self, mock_get_oneview_version):
@ -1030,7 +1092,7 @@ class OneViewClientTestCase(unittest.TestCase):
mock_get_server_profile_from_hardware.return_value = \
server_profile_mock
port = TestablePort('AA:BB:CC:DD:EE:FF')
port = fixtures.TestablePort('AA:BB:CC:DD:EE:FF')
node_info = None
ports = [port]
self.oneview_client.is_node_port_mac_compatible_with_server_profile(
@ -1100,7 +1162,7 @@ class OneViewClientTestCase(unittest.TestCase):
mock_get_sh_mac_from_ilo.return_value = 'aa:bb:cc:dd:ee'
node_info = {'server_hardware_uri': '/rest/111-222-333'}
ports = [TestablePort('aa:bb:cc:dd:ee')]
ports = [fixtures.TestablePort('aa:bb:cc:dd:ee')]
self.oneview_client.is_node_port_mac_compatible_with_server_profile(
node_info,
ports
@ -1322,6 +1384,3 @@ class OneViewClientTestCase(unittest.TestCase):
self.assertTrue(mock__prepare_do_request.called)
self.assertTrue(mock__wait_for_task.called)
if __name__ == '__main__':
unittest.main()

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
#
# (c) Copyright 2016 Hewlett Packard Enterprise Development LP
# Copyright 2016 Universidade Federal de Campina Grande
#
@ -17,6 +15,8 @@
import unittest
from oneview_client import exceptions
from oneview_client.tests import fixtures
from oneview_client import utils
@ -47,3 +47,57 @@ class UtilsTestCase(unittest.TestCase):
prefix = '/rest/resource/'
uuid = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa?'
self.assertEqual(None, utils.get_uri_from_uuid(prefix, uuid))
def test__get_empty_bootable_ports(self):
port = fixtures.TestablePort('AA:BB:CC:DD:EE:FF', bootable=False)
ports = [port]
with self.assertRaises(exceptions.OneViewInconsistentResource):
utils.get_bootable_ports(ports, bootable='true')
def test__get_empty_not_bootable_ports(self):
port = fixtures.TestablePort('AA:BB:CC:DD:EE:FF', bootable=True)
ports = [port]
with self.assertRaises(exceptions.OneViewInconsistentResource):
utils.get_bootable_ports(ports, bootable='false')
def test__get_multiple_bootable_ports(self):
port1 = fixtures.TestablePort('AA:BB:CC:DD:EE:FA', bootable=True)
port2 = fixtures.TestablePort('AA:BB:CC:DD:EE:FB', bootable=False)
port3 = fixtures.TestablePort('AA:BB:CC:DD:EE:FC', bootable=True)
ports = [port1, port2, port3]
self.assertEqual(
[port1, port3],
utils.get_bootable_ports(ports)
)
def test__get_multiple_not_bootable_ports(self):
port1 = fixtures.TestablePort('AA:BB:CC:DD:EE:FA', bootable=False)
port2 = fixtures.TestablePort('AA:BB:CC:DD:EE:FB', bootable=True)
port3 = fixtures.TestablePort('AA:BB:CC:DD:EE:FC', bootable=False)
ports = [port1, port2, port3]
self.assertEqual(
[port1, port3],
utils.get_bootable_ports(ports, bootable='false')
)
def test__get_no_pxe_enabled_ports(self):
port = fixtures.TestablePort('AA:BB:CC:DD:EE:FF', pxe_enabled=False)
ports = [port]
with self.assertRaises(exceptions.OneViewInconsistentResource):
utils.get_ports_with_llc_and_pxe_enabled(ports)
def test__get_pxe_enabled_ports(self):
port = fixtures.TestablePort('AA:BB:CC:DD:EE:FF', pxe_enabled=True)
ports = [port]
self.assertEqual(
ports, utils.get_ports_with_llc_and_pxe_enabled(ports)
)
def test__get_multiple_pxe_enabled_ports(self):
port1 = fixtures.TestablePort('AA:BB:CC:DD:EE:FA', pxe_enabled=True)
port2 = fixtures.TestablePort('AA:BB:CC:DD:EE:FB', pxe_enabled=False)
port3 = fixtures.TestablePort('AA:BB:CC:DD:EE:FC', pxe_enabled=True)
ports = [port1, port2, port3]
self.assertEqual(
[port1, port3], utils.get_ports_with_llc_and_pxe_enabled(ports)
)

View File

@ -14,6 +14,11 @@
# limitations under the License.
import re
import six
from oslo_serialization import jsonutils
from oneview_client import exceptions
UUID_PATTERN = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-" +\
"[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
@ -33,3 +38,90 @@ def get_uuid_from_uri(uri):
def get_uri_from_uuid(resource_prefix, uuid):
if uuid and _is_uuid_valid(uuid):
return str(resource_prefix) + str(uuid)
def get_oneview_connection_ports(ports):
llc_pxe_ports = get_ports_with_llc_and_pxe_enabled(ports)
bootable_ports = get_bootable_ports(llc_pxe_ports)
return bootable_ports
def get_ports_with_llc_and_pxe_enabled(ports):
llc_pxe_ports = [port for port in ports if (
port.local_link_connection and port.pxe_enabled)
]
if not llc_pxe_ports:
raise exceptions.OneViewInconsistentResource(
"There must exist at least one port with local link "
"connection information and pxe_enabled = True at the node."
)
return llc_pxe_ports
def get_bootable_ports(ports, bootable='true'):
bootable_ports = []
for port in ports:
switch_info = get_switch_info(port)
if switch_info and switch_info.get('bootable').lower() == bootable:
bootable_ports.append(port)
if not bootable_ports:
raise exceptions.OneViewInconsistentResource(
"In the local_link_connection of the port must exist "
"the switch_info with bootable = true"
)
return bootable_ports
def get_switch_info(port):
switch_info = port.local_link_connection.get('switch_info')
if switch_info and isinstance(switch_info, six.text_type):
switch_info = jsonutils.loads(switch_info)
return switch_info
def get_all_macs(server_hardware):
macs = []
device_slots = server_hardware.port_map.get('deviceSlots')
physical_ports = get_physical_ports(device_slots)
virtual_ports = get_virtual_ports(physical_ports)
macs.extend(get_physical_macs(physical_ports))
macs.extend(get_virtual_macs(virtual_ports))
return set(macs)
def get_physical_ports(device_slots):
physical_ports = []
for device_slot in device_slots:
if device_slot and device_slot.get('physicalPorts'):
physical_ports.extend(device_slot.get('physicalPorts'))
return physical_ports
def get_virtual_ports(physical_ports):
virtual_ports = []
for physical_port in physical_ports:
if physical_port and physical_port.get('virtualPorts'):
virtual_ports.extend(physical_port.get('virtualPorts'))
return virtual_ports
def get_physical_macs(physical_ports):
physical_macs = []
for physical_port in physical_ports:
if physical_port and physical_port.get('mac'):
physical_macs.append(physical_port.get('mac').lower())
return physical_macs
def get_virtual_macs(virtual_ports):
virtual_macs = []
for virtual_port in virtual_ports:
if virtual_port and virtual_port.get('mac'):
virtual_macs.append(virtual_port.get('mac').lower())
return virtual_macs

View File

@ -4,5 +4,6 @@
pbr>=1.6 # Apache-2.0
Babel>=2.3.4 # BSD
oslo.serialization>=1.10.0 # Apache-2.0
retrying!=1.3.0,>=1.2.3 # Apache-2.0
six>=1.9.0 # MIT