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
This commit is contained in:
Julia Kreger 2020-08-12 15:02:42 -07:00
parent e5841dfd2b
commit bbc5cd7da5
4 changed files with 55 additions and 1 deletions

View File

@ -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:

View File

@ -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',

View File

@ -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):

View File

@ -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.