Skip to content

Commit 8e833a3

Browse files
committed
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
1 parent 6ce7da8 commit 8e833a3

3 files changed

Lines changed: 235 additions & 20 deletions

File tree

openstackclient/compute/v2/server.py

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,18 @@ def get_parser(self, prog_name):
11541154
'(supported by --os-compute-api-version 2.52 or above)'
11551155
),
11561156
)
1157+
parser.add_argument(
1158+
'--hostname',
1159+
metavar='<hostname>',
1160+
help=_(
1161+
'Hostname configured for the server in the metadata service. '
1162+
'If unset, a hostname will be automatically generated from '
1163+
'the server name. '
1164+
'A utility such as cloud-init is required to propagate the '
1165+
'hostname in the metadata service to the guest OS itself. '
1166+
'(supported by --os-compute-api-version 2.90 or above)'
1167+
),
1168+
)
11571169
parser.add_argument(
11581170
'--wait',
11591171
action='store_true',
@@ -1618,6 +1630,16 @@ def _match_image(image_api, wanted_properties):
16181630
boot_kwargs['hypervisor_hostname'] = (
16191631
parsed_args.hypervisor_hostname)
16201632

1633+
if parsed_args.hostname:
1634+
if compute_client.api_version < api_versions.APIVersion("2.90"):
1635+
msg = _(
1636+
'--os-compute-api-version 2.90 or greater is required to '
1637+
'support the --hostname option'
1638+
)
1639+
raise exceptions.CommandError(msg)
1640+
1641+
boot_kwargs['hostname'] = parsed_args.hostname
1642+
16211643
LOG.debug('boot_args: %s', boot_args)
16221644
LOG.debug('boot_kwargs: %s', boot_kwargs)
16231645

@@ -3273,6 +3295,16 @@ def get_parser(self, prog_name):
32733295
'(supported by --os-compute-api-version 2.63 or above)'
32743296
),
32753297
)
3298+
parser.add_argument(
3299+
'--hostname',
3300+
metavar='<hostname>',
3301+
help=_(
3302+
'Hostname configured for the server in the metadata service. '
3303+
'A separate utility running in the guest is required to '
3304+
'propagate changes to this value to the guest OS itself. '
3305+
'(supported by --os-compute-api-version 2.90 or above)'
3306+
),
3307+
)
32763308
parser.add_argument(
32773309
'--wait',
32783310
action='store_true',
@@ -3390,6 +3422,16 @@ def _show_progress(progress):
33903422

33913423
kwargs['trusted_image_certificates'] = None
33923424

3425+
if parsed_args.hostname:
3426+
if compute_client.api_version < api_versions.APIVersion('2.90'):
3427+
msg = _(
3428+
'--os-compute-api-version 2.90 or greater is required to '
3429+
'support the --hostname option'
3430+
)
3431+
raise exceptions.CommandError(msg)
3432+
3433+
kwargs['hostname'] = parsed_args.hostname
3434+
33933435
try:
33943436
server = server.rebuild(image, parsed_args.password, **kwargs)
33953437
finally:
@@ -4076,6 +4118,16 @@ def get_parser(self, prog_name):
40764118
'(supported by --os-compute-api-version 2.26 or above)'
40774119
),
40784120
)
4121+
parser.add_argument(
4122+
'--hostname',
4123+
metavar='<hostname>',
4124+
help=_(
4125+
'Hostname configured for the server in the metadata service. '
4126+
'A separate utility running in the guest is required to '
4127+
'propagate changes to this value to the guest OS itself. '
4128+
'(supported by --os-compute-api-version 2.90 or above)'
4129+
),
4130+
)
40794131
return parser
40804132

40814133
def take_action(self, parsed_args):
@@ -4102,8 +4154,27 @@ def take_action(self, parsed_args):
41024154
)
41034155
raise exceptions.CommandError(msg)
41044156

4157+
if parsed_args.hostname:
4158+
if server.api_version < api_versions.APIVersion('2.90'):
4159+
msg = _(
4160+
'--os-compute-api-version 2.90 or greater is required to '
4161+
'support the --hostname option'
4162+
)
4163+
raise exceptions.CommandError(msg)
4164+
4165+
update_kwargs = {}
4166+
41054167
if parsed_args.name:
4106-
server.update(name=parsed_args.name)
4168+
update_kwargs['name'] = parsed_args.name
4169+
4170+
if parsed_args.description:
4171+
update_kwargs['description'] = parsed_args.description
4172+
4173+
if parsed_args.hostname:
4174+
update_kwargs['hostname'] = parsed_args.hostname
4175+
4176+
if update_kwargs:
4177+
server.update(**update_kwargs)
41074178

41084179
if parsed_args.properties:
41094180
compute_client.servers.set_meta(server, parsed_args.properties)
@@ -4124,9 +4195,6 @@ def take_action(self, parsed_args):
41244195
elif parsed_args.no_password:
41254196
server.clear_password()
41264197

4127-
if parsed_args.description:
4128-
server.update(description=parsed_args.description)
4129-
41304198
if parsed_args.tags:
41314199
for tag in parsed_args.tags:
41324200
server.add_tag(tag=tag)

openstackclient/tests/unit/compute/v2/test_server.py

Lines changed: 155 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3554,6 +3554,76 @@ def test_server_create_with_host_and_hypervisor_hostname_v274(self):
35543554
self.assertFalse(self.images_mock.called)
35553555
self.assertFalse(self.flavors_mock.called)
35563556

3557+
def test_server_create_with_hostname_v290(self):
3558+
self.app.client_manager.compute.api_version = \
3559+
api_versions.APIVersion('2.90')
3560+
3561+
arglist = [
3562+
'--image', 'image1',
3563+
'--flavor', 'flavor1',
3564+
'--hostname', 'hostname',
3565+
self.new_server.name,
3566+
]
3567+
verifylist = [
3568+
('image', 'image1'),
3569+
('flavor', 'flavor1'),
3570+
('hostname', 'hostname'),
3571+
('config_drive', False),
3572+
('server_name', self.new_server.name),
3573+
]
3574+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
3575+
columns, data = self.cmd.take_action(parsed_args)
3576+
3577+
# ServerManager.create(name, image, flavor, **kwargs)
3578+
self.servers_mock.create.assert_called_with(
3579+
self.new_server.name,
3580+
self.image,
3581+
self.flavor,
3582+
meta=None,
3583+
files={},
3584+
reservation_id=None,
3585+
min_count=1,
3586+
max_count=1,
3587+
security_groups=[],
3588+
userdata=None,
3589+
key_name=None,
3590+
availability_zone=None,
3591+
admin_pass=None,
3592+
block_device_mapping_v2=[],
3593+
nics='auto',
3594+
scheduler_hints={},
3595+
config_drive=None,
3596+
hostname='hostname',
3597+
)
3598+
3599+
self.assertEqual(self.columns, columns)
3600+
self.assertEqual(self.datalist(), data)
3601+
self.assertFalse(self.images_mock.called)
3602+
self.assertFalse(self.flavors_mock.called)
3603+
3604+
def test_server_create_with_hostname_pre_v290(self):
3605+
self.app.client_manager.compute.api_version = \
3606+
api_versions.APIVersion('2.89')
3607+
3608+
arglist = [
3609+
'--image', 'image1',
3610+
'--flavor', 'flavor1',
3611+
'--hostname', 'hostname',
3612+
self.new_server.name,
3613+
]
3614+
verifylist = [
3615+
('image', 'image1'),
3616+
('flavor', 'flavor1'),
3617+
('hostname', 'hostname'),
3618+
('config_drive', False),
3619+
('server_name', self.new_server.name),
3620+
]
3621+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
3622+
3623+
self.assertRaises(
3624+
exceptions.CommandError, self.cmd.take_action,
3625+
parsed_args)
3626+
35573627

35583628
class TestServerDelete(TestServer):
35593629

@@ -6235,6 +6305,46 @@ def test_rebuild_with_no_trusted_image_cert_pre_257(self):
62356305
self.cmd.take_action,
62366306
parsed_args)
62376307

6308+
def test_rebuild_with_hostname(self):
6309+
self.app.client_manager.compute.api_version = \
6310+
api_versions.APIVersion('2.90')
6311+
6312+
arglist = [
6313+
self.server.id,
6314+
'--hostname', 'new-hostname'
6315+
]
6316+
verifylist = [
6317+
('server', self.server.id),
6318+
('hostname', 'new-hostname')
6319+
]
6320+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
6321+
6322+
self.cmd.take_action(parsed_args)
6323+
6324+
self.servers_mock.get.assert_called_with(self.server.id)
6325+
self.get_image_mock.assert_called_with(self.image.id)
6326+
self.server.rebuild.assert_called_with(
6327+
self.image, None, hostname='new-hostname')
6328+
6329+
def test_rebuild_with_hostname_pre_v290(self):
6330+
self.app.client_manager.compute.api_version = \
6331+
api_versions.APIVersion('2.89')
6332+
6333+
arglist = [
6334+
self.server.id,
6335+
'--hostname', 'new-hostname',
6336+
]
6337+
verifylist = [
6338+
('server', self.server.id),
6339+
('hostname', 'new-hostname')
6340+
]
6341+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
6342+
6343+
self.assertRaises(
6344+
exceptions.CommandError,
6345+
self.cmd.take_action,
6346+
parsed_args)
6347+
62386348

62396349
class TestEvacuateServer(TestServer):
62406350

@@ -7340,10 +7450,10 @@ def test_server_set_with_root_password(self, mock_getpass):
73407450
mock.sentinel.fake_pass)
73417451
self.assertIsNone(result)
73427452

7343-
def test_server_set_with_description_api_newer(self):
7453+
def test_server_set_with_description(self):
73447454

73457455
# Description is supported for nova api version 2.19 or above
7346-
self.fake_servers[0].api_version = 2.19
7456+
self.fake_servers[0].api_version = api_versions.APIVersion('2.19')
73477457

73487458
arglist = [
73497459
'--description', 'foo_description',
@@ -7354,18 +7464,15 @@ def test_server_set_with_description_api_newer(self):
73547464
('server', 'foo_vm'),
73557465
]
73567466
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
7357-
with mock.patch.object(api_versions,
7358-
'APIVersion',
7359-
return_value=2.19):
7360-
result = self.cmd.take_action(parsed_args)
7361-
self.fake_servers[0].update.assert_called_once_with(
7362-
description='foo_description')
7363-
self.assertIsNone(result)
7467+
result = self.cmd.take_action(parsed_args)
7468+
self.fake_servers[0].update.assert_called_once_with(
7469+
description='foo_description')
7470+
self.assertIsNone(result)
73647471

7365-
def test_server_set_with_description_api_older(self):
7472+
def test_server_set_with_description_pre_v219(self):
73667473

73677474
# Description is not supported for nova api version below 2.19
7368-
self.fake_servers[0].api_version = 2.18
7475+
self.fake_servers[0].api_version = api_versions.APIVersion('2.18')
73697476

73707477
arglist = [
73717478
'--description', 'foo_description',
@@ -7376,11 +7483,8 @@ def test_server_set_with_description_api_older(self):
73767483
('server', 'foo_vm'),
73777484
]
73787485
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
7379-
with mock.patch.object(api_versions,
7380-
'APIVersion',
7381-
return_value=2.19):
7382-
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
7383-
parsed_args)
7486+
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
7487+
parsed_args)
73847488

73857489
def test_server_set_with_tag(self):
73867490
self.fake_servers[0].api_version = api_versions.APIVersion('2.26')
@@ -7426,6 +7530,41 @@ def test_server_set_with_tag_pre_v226(self):
74267530
'--os-compute-api-version 2.26 or greater is required',
74277531
str(ex))
74287532

7533+
def test_server_set_with_hostname(self):
7534+
7535+
self.fake_servers[0].api_version = api_versions.APIVersion('2.90')
7536+
7537+
arglist = [
7538+
'--hostname', 'foo-hostname',
7539+
'foo_vm',
7540+
]
7541+
verifylist = [
7542+
('hostname', 'foo-hostname'),
7543+
('server', 'foo_vm'),
7544+
]
7545+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
7546+
result = self.cmd.take_action(parsed_args)
7547+
self.fake_servers[0].update.assert_called_once_with(
7548+
hostname='foo-hostname')
7549+
self.assertIsNone(result)
7550+
7551+
def test_server_set_with_hostname_pre_v290(self):
7552+
7553+
self.fake_servers[0].api_version = api_versions.APIVersion('2.89')
7554+
7555+
arglist = [
7556+
'--hostname', 'foo-hostname',
7557+
'foo_vm',
7558+
]
7559+
verifylist = [
7560+
('hostname', 'foo-hostname'),
7561+
('server', 'foo_vm'),
7562+
]
7563+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
7564+
self.assertRaises(
7565+
exceptions.CommandError, self.cmd.take_action,
7566+
parsed_args)
7567+
74297568

74307569
class TestServerShelve(TestServer):
74317570

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
features:
3+
- |
4+
The ``server create``, ``server set`` and ``server rebuild`` commands now
5+
accept an optional ``--hostname HOSTNAME`` option. This can be used to
6+
configure the hostname stored in the metadata service and/or config drive.
7+
Utilities such as ``cloud-init`` can then consume this information to set
8+
the hostname within the guest OS.

0 commit comments

Comments
 (0)