compute: Add support for microversion 2.90
Allow configuring hostname when creating a new server or updating or rebuilding an existing server. Change-Id: Ibe603eab78bbbec43605f56de62a20493b6aa93d Signed-off-by: Stephen Finucane <sfinucan@redhat.com> Depends-On: https://review.opendev.org/c/openstack/python-novaclient/+/806917
This commit is contained in:
parent
6ce7da8aeb
commit
8e833a3ed2
@ -1154,6 +1154,18 @@ class CreateServer(command.ShowOne):
|
|||||||
'(supported by --os-compute-api-version 2.52 or above)'
|
'(supported by --os-compute-api-version 2.52 or above)'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--hostname',
|
||||||
|
metavar='<hostname>',
|
||||||
|
help=_(
|
||||||
|
'Hostname configured for the server in the metadata service. '
|
||||||
|
'If unset, a hostname will be automatically generated from '
|
||||||
|
'the server name. '
|
||||||
|
'A utility such as cloud-init is required to propagate the '
|
||||||
|
'hostname in the metadata service to the guest OS itself. '
|
||||||
|
'(supported by --os-compute-api-version 2.90 or above)'
|
||||||
|
),
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--wait',
|
'--wait',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@ -1618,6 +1630,16 @@ class CreateServer(command.ShowOne):
|
|||||||
boot_kwargs['hypervisor_hostname'] = (
|
boot_kwargs['hypervisor_hostname'] = (
|
||||||
parsed_args.hypervisor_hostname)
|
parsed_args.hypervisor_hostname)
|
||||||
|
|
||||||
|
if parsed_args.hostname:
|
||||||
|
if compute_client.api_version < api_versions.APIVersion("2.90"):
|
||||||
|
msg = _(
|
||||||
|
'--os-compute-api-version 2.90 or greater is required to '
|
||||||
|
'support the --hostname option'
|
||||||
|
)
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
boot_kwargs['hostname'] = parsed_args.hostname
|
||||||
|
|
||||||
LOG.debug('boot_args: %s', boot_args)
|
LOG.debug('boot_args: %s', boot_args)
|
||||||
LOG.debug('boot_kwargs: %s', boot_kwargs)
|
LOG.debug('boot_kwargs: %s', boot_kwargs)
|
||||||
|
|
||||||
@ -3273,6 +3295,16 @@ class RebuildServer(command.ShowOne):
|
|||||||
'(supported by --os-compute-api-version 2.63 or above)'
|
'(supported by --os-compute-api-version 2.63 or above)'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--hostname',
|
||||||
|
metavar='<hostname>',
|
||||||
|
help=_(
|
||||||
|
'Hostname configured for the server in the metadata service. '
|
||||||
|
'A separate utility running in the guest is required to '
|
||||||
|
'propagate changes to this value to the guest OS itself. '
|
||||||
|
'(supported by --os-compute-api-version 2.90 or above)'
|
||||||
|
),
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--wait',
|
'--wait',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@ -3390,6 +3422,16 @@ class RebuildServer(command.ShowOne):
|
|||||||
|
|
||||||
kwargs['trusted_image_certificates'] = None
|
kwargs['trusted_image_certificates'] = None
|
||||||
|
|
||||||
|
if parsed_args.hostname:
|
||||||
|
if compute_client.api_version < api_versions.APIVersion('2.90'):
|
||||||
|
msg = _(
|
||||||
|
'--os-compute-api-version 2.90 or greater is required to '
|
||||||
|
'support the --hostname option'
|
||||||
|
)
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
kwargs['hostname'] = parsed_args.hostname
|
||||||
|
|
||||||
try:
|
try:
|
||||||
server = server.rebuild(image, parsed_args.password, **kwargs)
|
server = server.rebuild(image, parsed_args.password, **kwargs)
|
||||||
finally:
|
finally:
|
||||||
@ -4076,6 +4118,16 @@ class SetServer(command.Command):
|
|||||||
'(supported by --os-compute-api-version 2.26 or above)'
|
'(supported by --os-compute-api-version 2.26 or above)'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--hostname',
|
||||||
|
metavar='<hostname>',
|
||||||
|
help=_(
|
||||||
|
'Hostname configured for the server in the metadata service. '
|
||||||
|
'A separate utility running in the guest is required to '
|
||||||
|
'propagate changes to this value to the guest OS itself. '
|
||||||
|
'(supported by --os-compute-api-version 2.90 or above)'
|
||||||
|
),
|
||||||
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
@ -4102,8 +4154,27 @@ class SetServer(command.Command):
|
|||||||
)
|
)
|
||||||
raise exceptions.CommandError(msg)
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
if parsed_args.hostname:
|
||||||
|
if server.api_version < api_versions.APIVersion('2.90'):
|
||||||
|
msg = _(
|
||||||
|
'--os-compute-api-version 2.90 or greater is required to '
|
||||||
|
'support the --hostname option'
|
||||||
|
)
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
|
||||||
|
update_kwargs = {}
|
||||||
|
|
||||||
if parsed_args.name:
|
if parsed_args.name:
|
||||||
server.update(name=parsed_args.name)
|
update_kwargs['name'] = parsed_args.name
|
||||||
|
|
||||||
|
if parsed_args.description:
|
||||||
|
update_kwargs['description'] = parsed_args.description
|
||||||
|
|
||||||
|
if parsed_args.hostname:
|
||||||
|
update_kwargs['hostname'] = parsed_args.hostname
|
||||||
|
|
||||||
|
if update_kwargs:
|
||||||
|
server.update(**update_kwargs)
|
||||||
|
|
||||||
if parsed_args.properties:
|
if parsed_args.properties:
|
||||||
compute_client.servers.set_meta(server, parsed_args.properties)
|
compute_client.servers.set_meta(server, parsed_args.properties)
|
||||||
@ -4124,9 +4195,6 @@ class SetServer(command.Command):
|
|||||||
elif parsed_args.no_password:
|
elif parsed_args.no_password:
|
||||||
server.clear_password()
|
server.clear_password()
|
||||||
|
|
||||||
if parsed_args.description:
|
|
||||||
server.update(description=parsed_args.description)
|
|
||||||
|
|
||||||
if parsed_args.tags:
|
if parsed_args.tags:
|
||||||
for tag in parsed_args.tags:
|
for tag in parsed_args.tags:
|
||||||
server.add_tag(tag=tag)
|
server.add_tag(tag=tag)
|
||||||
|
@ -3554,6 +3554,76 @@ class TestServerCreate(TestServer):
|
|||||||
self.assertFalse(self.images_mock.called)
|
self.assertFalse(self.images_mock.called)
|
||||||
self.assertFalse(self.flavors_mock.called)
|
self.assertFalse(self.flavors_mock.called)
|
||||||
|
|
||||||
|
def test_server_create_with_hostname_v290(self):
|
||||||
|
self.app.client_manager.compute.api_version = \
|
||||||
|
api_versions.APIVersion('2.90')
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
'--image', 'image1',
|
||||||
|
'--flavor', 'flavor1',
|
||||||
|
'--hostname', 'hostname',
|
||||||
|
self.new_server.name,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('image', 'image1'),
|
||||||
|
('flavor', 'flavor1'),
|
||||||
|
('hostname', 'hostname'),
|
||||||
|
('config_drive', False),
|
||||||
|
('server_name', self.new_server.name),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# ServerManager.create(name, image, flavor, **kwargs)
|
||||||
|
self.servers_mock.create.assert_called_with(
|
||||||
|
self.new_server.name,
|
||||||
|
self.image,
|
||||||
|
self.flavor,
|
||||||
|
meta=None,
|
||||||
|
files={},
|
||||||
|
reservation_id=None,
|
||||||
|
min_count=1,
|
||||||
|
max_count=1,
|
||||||
|
security_groups=[],
|
||||||
|
userdata=None,
|
||||||
|
key_name=None,
|
||||||
|
availability_zone=None,
|
||||||
|
admin_pass=None,
|
||||||
|
block_device_mapping_v2=[],
|
||||||
|
nics='auto',
|
||||||
|
scheduler_hints={},
|
||||||
|
config_drive=None,
|
||||||
|
hostname='hostname',
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(self.columns, columns)
|
||||||
|
self.assertEqual(self.datalist(), data)
|
||||||
|
self.assertFalse(self.images_mock.called)
|
||||||
|
self.assertFalse(self.flavors_mock.called)
|
||||||
|
|
||||||
|
def test_server_create_with_hostname_pre_v290(self):
|
||||||
|
self.app.client_manager.compute.api_version = \
|
||||||
|
api_versions.APIVersion('2.89')
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
'--image', 'image1',
|
||||||
|
'--flavor', 'flavor1',
|
||||||
|
'--hostname', 'hostname',
|
||||||
|
self.new_server.name,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('image', 'image1'),
|
||||||
|
('flavor', 'flavor1'),
|
||||||
|
('hostname', 'hostname'),
|
||||||
|
('config_drive', False),
|
||||||
|
('server_name', self.new_server.name),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestServerDelete(TestServer):
|
class TestServerDelete(TestServer):
|
||||||
|
|
||||||
@ -6235,6 +6305,46 @@ class TestServerRebuild(TestServer):
|
|||||||
self.cmd.take_action,
|
self.cmd.take_action,
|
||||||
parsed_args)
|
parsed_args)
|
||||||
|
|
||||||
|
def test_rebuild_with_hostname(self):
|
||||||
|
self.app.client_manager.compute.api_version = \
|
||||||
|
api_versions.APIVersion('2.90')
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
self.server.id,
|
||||||
|
'--hostname', 'new-hostname'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('server', self.server.id),
|
||||||
|
('hostname', 'new-hostname')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.servers_mock.get.assert_called_with(self.server.id)
|
||||||
|
self.get_image_mock.assert_called_with(self.image.id)
|
||||||
|
self.server.rebuild.assert_called_with(
|
||||||
|
self.image, None, hostname='new-hostname')
|
||||||
|
|
||||||
|
def test_rebuild_with_hostname_pre_v290(self):
|
||||||
|
self.app.client_manager.compute.api_version = \
|
||||||
|
api_versions.APIVersion('2.89')
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
self.server.id,
|
||||||
|
'--hostname', 'new-hostname',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('server', self.server.id),
|
||||||
|
('hostname', 'new-hostname')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestEvacuateServer(TestServer):
|
class TestEvacuateServer(TestServer):
|
||||||
|
|
||||||
@ -7340,10 +7450,10 @@ class TestServerSet(TestServer):
|
|||||||
mock.sentinel.fake_pass)
|
mock.sentinel.fake_pass)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
|
|
||||||
def test_server_set_with_description_api_newer(self):
|
def test_server_set_with_description(self):
|
||||||
|
|
||||||
# Description is supported for nova api version 2.19 or above
|
# Description is supported for nova api version 2.19 or above
|
||||||
self.fake_servers[0].api_version = 2.19
|
self.fake_servers[0].api_version = api_versions.APIVersion('2.19')
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
'--description', 'foo_description',
|
'--description', 'foo_description',
|
||||||
@ -7354,18 +7464,15 @@ class TestServerSet(TestServer):
|
|||||||
('server', 'foo_vm'),
|
('server', 'foo_vm'),
|
||||||
]
|
]
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
with mock.patch.object(api_versions,
|
|
||||||
'APIVersion',
|
|
||||||
return_value=2.19):
|
|
||||||
result = self.cmd.take_action(parsed_args)
|
result = self.cmd.take_action(parsed_args)
|
||||||
self.fake_servers[0].update.assert_called_once_with(
|
self.fake_servers[0].update.assert_called_once_with(
|
||||||
description='foo_description')
|
description='foo_description')
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
|
|
||||||
def test_server_set_with_description_api_older(self):
|
def test_server_set_with_description_pre_v219(self):
|
||||||
|
|
||||||
# Description is not supported for nova api version below 2.19
|
# Description is not supported for nova api version below 2.19
|
||||||
self.fake_servers[0].api_version = 2.18
|
self.fake_servers[0].api_version = api_versions.APIVersion('2.18')
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
'--description', 'foo_description',
|
'--description', 'foo_description',
|
||||||
@ -7376,9 +7483,6 @@ class TestServerSet(TestServer):
|
|||||||
('server', 'foo_vm'),
|
('server', 'foo_vm'),
|
||||||
]
|
]
|
||||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
with mock.patch.object(api_versions,
|
|
||||||
'APIVersion',
|
|
||||||
return_value=2.19):
|
|
||||||
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
parsed_args)
|
parsed_args)
|
||||||
|
|
||||||
@ -7426,6 +7530,41 @@ class TestServerSet(TestServer):
|
|||||||
'--os-compute-api-version 2.26 or greater is required',
|
'--os-compute-api-version 2.26 or greater is required',
|
||||||
str(ex))
|
str(ex))
|
||||||
|
|
||||||
|
def test_server_set_with_hostname(self):
|
||||||
|
|
||||||
|
self.fake_servers[0].api_version = api_versions.APIVersion('2.90')
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
'--hostname', 'foo-hostname',
|
||||||
|
'foo_vm',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('hostname', 'foo-hostname'),
|
||||||
|
('server', 'foo_vm'),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
result = self.cmd.take_action(parsed_args)
|
||||||
|
self.fake_servers[0].update.assert_called_once_with(
|
||||||
|
hostname='foo-hostname')
|
||||||
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
def test_server_set_with_hostname_pre_v290(self):
|
||||||
|
|
||||||
|
self.fake_servers[0].api_version = api_versions.APIVersion('2.89')
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
'--hostname', 'foo-hostname',
|
||||||
|
'foo_vm',
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('hostname', 'foo-hostname'),
|
||||||
|
('server', 'foo_vm'),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestServerShelve(TestServer):
|
class TestServerShelve(TestServer):
|
||||||
|
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The ``server create``, ``server set`` and ``server rebuild`` commands now
|
||||||
|
accept an optional ``--hostname HOSTNAME`` option. This can be used to
|
||||||
|
configure the hostname stored in the metadata service and/or config drive.
|
||||||
|
Utilities such as ``cloud-init`` can then consume this information to set
|
||||||
|
the hostname within the guest OS.
|
Loading…
x
Reference in New Issue
Block a user