Fix GET for conductors with a port or IPv6 address

Our validation does not expect a host-port pair, not having colons in
the hostname. We don't need to verify all possible cases: we will return
404 for a conductor that does not exist.

Change-Id: Iea65575f540a89a0de280fb730e430647c5733dc
This commit is contained in:
Dmitry Tantsur 2023-12-06 17:00:00 +01:00
parent dcea5f5a1d
commit e67f716063
No known key found for this signature in database
GPG Key ID: 315B2AF9FD216C60
4 changed files with 37 additions and 4 deletions

View File

@ -102,9 +102,9 @@ class ConductorsController(rest.RestController):
@METRICS.timer('ConductorsController.get_all')
@method.expose()
@args.validate(marker=args.name, limit=args.integer, sort_key=args.string,
sort_dir=args.string, fields=args.string_list,
detail=args.boolean)
@args.validate(marker=args.host_port, limit=args.integer,
sort_key=args.string, sort_dir=args.string,
fields=args.string_list, detail=args.boolean)
def get_all(self, marker=None, limit=None, sort_key='id', sort_dir='asc',
fields=None, detail=None):
"""Retrieve a list of conductors.
@ -139,7 +139,7 @@ class ConductorsController(rest.RestController):
@METRICS.timer('ConductorsController.get_one')
@method.expose()
@args.validate(hostname=args.name, fields=args.string_list)
@args.validate(hostname=args.host_port, fields=args.string_list)
def get_one(self, hostname, fields=None):
"""Retrieve information about the given conductor.

View File

@ -14,6 +14,7 @@ import functools
import inspect
import jsonschema
from oslo_utils import netutils
from oslo_utils import strutils
from oslo_utils import uuidutils
@ -88,6 +89,18 @@ def name(name, value):
return value
def host_port(name, value):
if value is None:
return
try:
host, port = netutils.parse_host_port(value)
except (ValueError, TypeError) as exc:
raise exception.InvalidParameterValue(f'{name}: {exc}')
if not host:
raise exception.InvalidParameterValue(_('Missing host in %s') % name)
return value
def uuid_or_name(name, value):
"""Validate that the value is a UUID or logical name

View File

@ -85,6 +85,19 @@ class TestListConductors(test_api_base.BaseApiTest):
self.assertEqual(data['hostname'], 'rocky.rocks')
self.assertTrue(data['alive'])
def test_get_one_with_port_and_v6(self):
obj_utils.create_test_conductor(self.context, hostname='[::1]:8090')
data = self.get_json(
'/conductors/[::1]:8090',
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertIn('hostname', data)
self.assertIn('drivers', data)
self.assertIn('conductor_group', data)
self.assertIn('alive', data)
self.assertIn('drivers', data)
self.assertEqual(data['hostname'], '[::1]:8090')
self.assertTrue(data['alive'])
@mock.patch.object(timeutils, 'utcnow', autospec=True)
def test_get_one_conductor_offline(self, mock_utcnow):
self.config(heartbeat_timeout=10, group='conductor')

View File

@ -0,0 +1,7 @@
---
fixes:
- |
Fixes getting details of a conductor if it uses a non-standard JSON RPC
port or an IPv6 address as the name, e.g.
``GET /v1/conductors/[2001:db8::1]:8090``. Previously, it would result in
a HTTP error 400.