From bbc5cd7da5af18558859c6b3388142555888772e Mon Sep 17 00:00:00 2001 From: Julia Kreger Date: Wed, 12 Aug 2020 15:02:42 -0700 Subject: [PATCH] Fix URL parsing to enable redfish_address matching Fixes the ironic utilities logic to parse URLs in driver_info properly. Also adds ``redfish_address`` to the default list of fields to evaluate for host matching. Previously an operator could add the field to the list, but the matching logic would not match the URL as it did not know to decompose the url and identify the hostname portion of the url. Resolves: rhbz#1670336 Story: 2008010 Task: 40660 Change-Id: Ice86e9ab3efb98b649141bdf7e1e2febdc9203a8 --- ironic_inspector/common/ironic.py | 8 ++++ ironic_inspector/conf/default.py | 3 +- .../test/unit/test_common_ironic.py | 37 +++++++++++++++++++ ...port_redfish_address-94eae2c0d2879f53.yaml | 8 ++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/support_redfish_address-94eae2c0d2879f53.yaml diff --git a/ironic_inspector/common/ironic.py b/ironic_inspector/common/ironic.py index 6e44c35bc..7d8f4f922 100644 --- a/ironic_inspector/common/ironic.py +++ b/ironic_inspector/common/ironic.py @@ -12,6 +12,7 @@ # limitations under the License. import socket +import urllib import netaddr import openstack @@ -101,6 +102,9 @@ def get_ipmi_address(node): ipv4 = None ipv6 = None + if '//' in value: + url = urllib.parse.urlparse(value) + value = url.hostname try: addrinfo = socket.getaddrinfo(value, None, 0, 0, socket.SOL_TCP) for family, socket_type, proto, canon_name, sockaddr in addrinfo: @@ -234,6 +238,10 @@ def lookup_node_by_bmc_addresses(addresses, introspection_data=None, # FIXME(aarefiev): it's not effective to fetch all nodes, and may # impact on performance on big clusters + # TODO(TheJulia): We should likely first loop through nodes being + # inspected, i.e. inspect wait, and then fallback + # to the rest of the physical nodes so we limit + # overall-impact of the operation. nodes = ironic.nodes(fields=('id', 'driver_info'), limit=None) found = set() for node in nodes: diff --git a/ironic_inspector/conf/default.py b/ironic_inspector/conf/default.py index 921ac191d..91ac45ae8 100644 --- a/ironic_inspector/conf/default.py +++ b/ironic_inspector/conf/default.py @@ -79,7 +79,8 @@ _OPTS = [ 'applies when boot is managed by ironic-inspector (i.e. ' 'manage_boot==True).')), cfg.ListOpt('ipmi_address_fields', - default=['ilo_address', 'drac_host', 'drac_address'], + default=['redfish_address', 'ilo_address', 'drac_host', + 'drac_address'], help=_('Ironic driver_info fields that are equivalent ' 'to ipmi_address.')), cfg.StrOpt('rootwrap_config', diff --git a/ironic_inspector/test/unit/test_common_ironic.py b/ironic_inspector/test/unit/test_common_ironic.py index c3eaa8cab..d8c30dcd5 100644 --- a/ironic_inspector/test/unit/test_common_ironic.py +++ b/ironic_inspector/test/unit/test_common_ironic.py @@ -98,6 +98,43 @@ class TestGetIpmiAddress(base.BaseTest): self.assertEqual((None, None, None), ir_utils.get_ipmi_address(node)) + @mock.patch.object(socket, 'getaddrinfo', autospec=True) + def test_redfish_bmc_address(self, mock_socket): + self.cfg.config(ipmi_address_fields=['redfish_address']) + url = 'http://{}/path'.format(self.ipmi_address) + node = mock.Mock(spec=['driver_info', 'uuid'], + driver_info={'redfish_address': url}) + mock_socket.return_value = [ + (socket.AF_INET, None, None, None, (self.ipmi_ipv4,)), + (socket.AF_INET6, None, None, None, (self.ipmi_ipv6,))] + self.assertEqual((self.ipmi_address, self.ipmi_ipv4, self.ipmi_ipv6), + ir_utils.get_ipmi_address(node)) + mock_socket.assert_called_once_with(self.ipmi_address, None, 0, 0, 6) + + @mock.patch.object(socket, 'getaddrinfo', autospec=True) + def test_redfish_bmc_address_ipv4(self, mock_socket): + self.cfg.config(ipmi_address_fields=['redfish_address']) + url = 'http://{}:8080/path'.format(self.ipmi_ipv4) + node = mock.Mock(spec=['driver_info', 'uuid'], + driver_info={'redfish_address': url}) + mock_socket.return_value = [ + (socket.AF_INET, None, None, None, (self.ipmi_ipv4,))] + self.assertEqual((self.ipmi_ipv4, self.ipmi_ipv4, None), + ir_utils.get_ipmi_address(node)) + mock_socket.assert_called_once_with(self.ipmi_ipv4, None, 0, 0, 6) + + @mock.patch.object(socket, 'getaddrinfo', autospec=True) + def test_redfish_bmc_address_ipv6(self, mock_socket): + self.cfg.config(ipmi_address_fields=['redfish_address']) + url = 'https://[{}]::443/path'.format(self.ipmi_ipv6) + node = mock.Mock(spec=['driver_info', 'uuid'], + driver_info={'redfish_address': url}) + mock_socket.return_value = [ + (socket.AF_INET6, None, None, None, (self.ipmi_ipv6,))] + self.assertEqual((self.ipmi_ipv6, None, self.ipmi_ipv6), + ir_utils.get_ipmi_address(node)) + mock_socket.assert_called_once_with(self.ipmi_ipv6, None, 0, 0, 6) + class TestCapabilities(unittest.TestCase): diff --git a/releasenotes/notes/support_redfish_address-94eae2c0d2879f53.yaml b/releasenotes/notes/support_redfish_address-94eae2c0d2879f53.yaml new file mode 100644 index 000000000..3fa0a2f17 --- /dev/null +++ b/releasenotes/notes/support_redfish_address-94eae2c0d2879f53.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixes the node identification logic to enable a user to list + the ``redfish_address`` label for ``driver_info`` field values for + identification of a machine using the ``[DEFAULT]ipmi_address_fields`` + configuration option. Previously the host would just not be matched as + the full URL would be evaluated instead of what the URL may resolve to.