compute: Migrate 'server rebuild' to SDK

Change-Id: Ic7cdb05327a4a74364f08451e531d02c631b7633
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
Depends-on: https://review.opendev.org/c/openstack/openstacksdk/+/918730
This commit is contained in:
Stephen Finucane 2024-05-17 12:24:14 +01:00
parent 2057462120
commit 8d904a9efb
2 changed files with 327 additions and 205 deletions

View File

@ -16,6 +16,7 @@
"""Compute v2 Server action implementations""" """Compute v2 Server action implementations"""
import argparse import argparse
import base64
import getpass import getpass
import json import json
import logging import logging
@ -3505,11 +3506,11 @@ class RebuildServer(command.ShowOne):
self.app.stdout.write('\rProgress: %s' % progress) self.app.stdout.write('\rProgress: %s' % progress)
self.app.stdout.flush() self.app.stdout.flush()
compute_client = self.app.client_manager.compute compute_client = self.app.client_manager.sdk_connection.compute
image_client = self.app.client_manager.image image_client = self.app.client_manager.image
server = utils.find_resource( server = compute_client.find_server(
compute_client.servers, parsed_args.server parsed_args.server, ignore_missing=False
) )
# If parsed_args.image is not set and if the instance is image backed, # If parsed_args.image is not set and if the instance is image backed,
@ -3521,7 +3522,7 @@ class RebuildServer(command.ShowOne):
parsed_args.image, ignore_missing=False parsed_args.image, ignore_missing=False
) )
else: else:
if not server.image: if not server.image or not server.image.id:
msg = _( msg = _(
'The --image option is required when rebuilding a ' 'The --image option is required when rebuilding a '
'volume-backed server' 'volume-backed server'
@ -3538,10 +3539,10 @@ class RebuildServer(command.ShowOne):
kwargs['preserve_ephemeral'] = parsed_args.preserve_ephemeral kwargs['preserve_ephemeral'] = parsed_args.preserve_ephemeral
if parsed_args.properties: if parsed_args.properties:
kwargs['meta'] = parsed_args.properties kwargs['metadata'] = parsed_args.properties
if parsed_args.description: if parsed_args.description:
if compute_client.api_version < api_versions.APIVersion('2.19'): if not sdk_utils.supports_microversion(compute_client, '2.19'):
msg = _( msg = _(
'--os-compute-api-version 2.19 or greater is required to ' '--os-compute-api-version 2.19 or greater is required to '
'support the --description option' 'support the --description option'
@ -3551,7 +3552,7 @@ class RebuildServer(command.ShowOne):
kwargs['description'] = parsed_args.description kwargs['description'] = parsed_args.description
if parsed_args.key_name: if parsed_args.key_name:
if compute_client.api_version < api_versions.APIVersion('2.54'): if not sdk_utils.supports_microversion(compute_client, '2.54'):
msg = _( msg = _(
'--os-compute-api-version 2.54 or greater is required to ' '--os-compute-api-version 2.54 or greater is required to '
'support the --key-name option' 'support the --key-name option'
@ -3560,7 +3561,7 @@ class RebuildServer(command.ShowOne):
kwargs['key_name'] = parsed_args.key_name kwargs['key_name'] = parsed_args.key_name
elif parsed_args.no_key_name: elif parsed_args.no_key_name:
if compute_client.api_version < api_versions.APIVersion('2.54'): if not sdk_utils.supports_microversion(compute_client, '2.54'):
msg = _( msg = _(
'--os-compute-api-version 2.54 or greater is required to ' '--os-compute-api-version 2.54 or greater is required to '
'support the --no-key-name option' 'support the --no-key-name option'
@ -3569,9 +3570,8 @@ class RebuildServer(command.ShowOne):
kwargs['key_name'] = None kwargs['key_name'] = None
userdata = None
if parsed_args.user_data: if parsed_args.user_data:
if compute_client.api_version < api_versions.APIVersion('2.54'): if not sdk_utils.supports_microversion(compute_client, '2.54'):
msg = _( msg = _(
'--os-compute-api-version 2.54 or greater is required to ' '--os-compute-api-version 2.54 or greater is required to '
'support the --user-data option' 'support the --user-data option'
@ -3579,27 +3579,29 @@ class RebuildServer(command.ShowOne):
raise exceptions.CommandError(msg) raise exceptions.CommandError(msg)
try: try:
userdata = open(parsed_args.user_data) with open(parsed_args.user_data, 'rb') as fh:
# TODO(stephenfin): SDK should do this for us
user_data = base64.b64encode(fh.read()).decode('utf-8')
except OSError as e: except OSError as e:
msg = _("Can't open '%(data)s': %(exception)s") msg = _("Can't open '%(data)s': %(exception)s")
raise exceptions.CommandError( raise exceptions.CommandError(
msg % {'data': parsed_args.user_data, 'exception': e} msg % {'data': parsed_args.user_data, 'exception': e}
) )
kwargs['userdata'] = userdata kwargs['user_data'] = user_data
elif parsed_args.no_user_data: elif parsed_args.no_user_data:
if compute_client.api_version < api_versions.APIVersion('2.54'): if not sdk_utils.supports_microversion(compute_client, '2.54'):
msg = _( msg = _(
'--os-compute-api-version 2.54 or greater is required to ' '--os-compute-api-version 2.54 or greater is required to '
'support the --no-user-data option' 'support the --no-user-data option'
) )
raise exceptions.CommandError(msg) raise exceptions.CommandError(msg)
kwargs['userdata'] = None kwargs['user_data'] = None
# TODO(stephenfin): Handle OS_TRUSTED_IMAGE_CERTIFICATE_IDS # TODO(stephenfin): Handle OS_TRUSTED_IMAGE_CERTIFICATE_IDS
if parsed_args.trusted_image_certs: if parsed_args.trusted_image_certs:
if compute_client.api_version < api_versions.APIVersion('2.63'): if not sdk_utils.supports_microversion(compute_client, '2.63'):
msg = _( msg = _(
'--os-compute-api-version 2.63 or greater is required to ' '--os-compute-api-version 2.63 or greater is required to '
'support the --trusted-certs option' 'support the --trusted-certs option'
@ -3609,7 +3611,7 @@ class RebuildServer(command.ShowOne):
certs = parsed_args.trusted_image_certs certs = parsed_args.trusted_image_certs
kwargs['trusted_image_certificates'] = certs kwargs['trusted_image_certificates'] = certs
elif parsed_args.no_trusted_image_certs: elif parsed_args.no_trusted_image_certs:
if compute_client.api_version < api_versions.APIVersion('2.63'): if not sdk_utils.supports_microversion(compute_client, '2.63'):
msg = _( msg = _(
'--os-compute-api-version 2.63 or greater is required to ' '--os-compute-api-version 2.63 or greater is required to '
'support the --no-trusted-certs option' 'support the --no-trusted-certs option'
@ -3619,7 +3621,7 @@ class RebuildServer(command.ShowOne):
kwargs['trusted_image_certificates'] = None kwargs['trusted_image_certificates'] = None
if parsed_args.hostname: if parsed_args.hostname:
if compute_client.api_version < api_versions.APIVersion('2.90'): if not sdk_utils.supports_microversion(compute_client, '2.90'):
msg = _( msg = _(
'--os-compute-api-version 2.90 or greater is required to ' '--os-compute-api-version 2.90 or greater is required to '
'support the --hostname option' 'support the --hostname option'
@ -3628,9 +3630,8 @@ class RebuildServer(command.ShowOne):
kwargs['hostname'] = parsed_args.hostname kwargs['hostname'] = parsed_args.hostname
v2_93 = api_versions.APIVersion('2.93')
if parsed_args.reimage_boot_volume: if parsed_args.reimage_boot_volume:
if compute_client.api_version < v2_93: if not sdk_utils.supports_microversion(compute_client, '2.93'):
msg = _( msg = _(
'--os-compute-api-version 2.93 or greater is required to ' '--os-compute-api-version 2.93 or greater is required to '
'support the --reimage-boot-volume option' 'support the --reimage-boot-volume option'
@ -3639,8 +3640,8 @@ class RebuildServer(command.ShowOne):
else: else:
# force user to explicitly request reimaging of volume-backed # force user to explicitly request reimaging of volume-backed
# server # server
if not server.image: if not server.image or not server.image.id:
if compute_client.api_version >= v2_93: if sdk_utils.supports_microversion(compute_client, '2.93'):
msg = ( msg = (
'--reimage-boot-volume is required to rebuild a ' '--reimage-boot-volume is required to rebuild a '
'volume-backed server' 'volume-backed server'
@ -3672,15 +3673,13 @@ class RebuildServer(command.ShowOne):
msg = _("The server status is not ACTIVE, SHUTOFF or ERROR.") msg = _("The server status is not ACTIVE, SHUTOFF or ERROR.")
raise exceptions.CommandError(msg) raise exceptions.CommandError(msg)
try: server = compute_client.rebuild_server(
server = server.rebuild(image, parsed_args.password, **kwargs) server, image, admin_password=parsed_args.password, **kwargs
finally: )
if userdata and hasattr(userdata, 'close'):
userdata.close()
if parsed_args.wait: if parsed_args.wait:
if utils.wait_for_status( if utils.wait_for_status(
compute_client.servers.get, compute_client.get_server,
server.id, server.id,
callback=_show_progress, callback=_show_progress,
success_status=success_status, success_status=success_status,
@ -3690,8 +3689,6 @@ class RebuildServer(command.ShowOne):
msg = _('Error rebuilding server: %s') % server.id msg = _('Error rebuilding server: %s') % server.id
raise exceptions.CommandError(msg) raise exceptions.CommandError(msg)
# TODO(stephenfin): Remove when the whole command is using SDK
compute_client = self.app.client_manager.sdk_connection.compute
data = _prep_server_detail( data = _prep_server_detail(
compute_client, image_client, server, refresh=False compute_client, image_client, server, refresh=False
) )

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import base64
import collections import collections
import copy import copy
import getpass import getpass
@ -6227,59 +6228,47 @@ class TestServerRebuild(TestServer):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# Return value for utils.find_resource for image
self.image = image_fakes.create_one_image() self.image = image_fakes.create_one_image()
self.image_client.get_image.return_value = self.image self.image_client.get_image.return_value = self.image
# Fake the rebuilt new server.
attrs = { attrs = {
'status': 'ACTIVE',
'image': {'id': self.image.id}, 'image': {'id': self.image.id},
'networks': {},
'adminPass': 'passw0rd',
} }
new_server = compute_fakes.create_one_server(attrs=attrs) self.server = compute_fakes.create_one_sdk_server(attrs=attrs)
self.compute_sdk_client.find_server.return_value = self.server
# Fake the server to be rebuilt. The IDs of them should be the same. self.compute_sdk_client.rebuild_server.return_value = self.server
attrs['id'] = new_server.id
attrs['status'] = 'ACTIVE'
methods = {
'rebuild': new_server,
}
self.server = compute_fakes.create_one_server(
attrs=attrs, methods=methods
)
# Return value for utils.find_resource for server.
self.servers_mock.get.return_value = self.server
self.cmd = server.RebuildServer(self.app, None) self.cmd = server.RebuildServer(self.app, None)
def test_rebuild_with_image_name(self): def test_rebuild_with_image_name(self):
image_name = 'my-custom-image' image_name = 'my-custom-image'
user_image = image_fakes.create_one_image(attrs={'name': image_name}) image = image_fakes.create_one_image(attrs={'name': image_name})
self.image_client.find_image.return_value = user_image self.image_client.find_image.return_value = image
attrs = { arglist = [
'image': {'id': user_image.id}, self.server.id,
'networks': {}, '--image',
'adminPass': 'passw0rd', image_name,
} ]
new_server = compute_fakes.create_one_server(attrs=attrs) verifylist = [
self.server.rebuild.return_value = new_server ('server', self.server.id),
('image', image_name),
]
arglist = [self.server.id, '--image', image_name]
verifylist = [('server', self.server.id), ('image', image_name)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Get the command object to test.
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_called_with( self.image_client.find_image.assert_called_with(
image_name, ignore_missing=False image_name, ignore_missing=False
) )
self.image_client.get_image.assert_called_with(user_image.id) self.image_client.get_image.assert_called_with(self.image.id)
self.server.rebuild.assert_called_with(user_image, None) self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server, image, admin_password=None
)
def test_rebuild_with_current_image(self): def test_rebuild_with_current_image(self):
arglist = [ arglist = [
@ -6291,10 +6280,16 @@ class TestServerRebuild(TestServer):
# Get the command object to test. # Get the command object to test.
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_not_called() self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_called_with(self.image.id) self.image_client.get_image.assert_has_calls(
self.server.rebuild.assert_called_with(self.image, None) [mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server, self.image, admin_password=None
)
def test_rebuild_with_volume_backed_server_no_image(self): def test_rebuild_with_volume_backed_server_no_image(self):
# the volume-backed server will have the image attribute set to an # the volume-backed server will have the image attribute set to an
@ -6307,8 +6302,8 @@ class TestServerRebuild(TestServer):
verifylist = [ verifylist = [
('server', self.server.id), ('server', self.server.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
exc = self.assertRaises( exc = self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args exceptions.CommandError, self.cmd.take_action, parsed_args
) )
@ -6325,14 +6320,20 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('name', name), ('name', name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Get the command object to test parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with(self.image, None, name=name) )
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server, self.image, admin_password=None, name=name
)
def test_rebuild_with_preserve_ephemeral(self): def test_rebuild_with_preserve_ephemeral(self):
arglist = [ arglist = [
@ -6343,15 +6344,22 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('preserve_ephemeral', True), ('preserve_ephemeral', True),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Get the command object to test parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with( )
self.image, None, preserve_ephemeral=True self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
preserve_ephemeral=True,
) )
def test_rebuild_with_no_preserve_ephemeral(self): def test_rebuild_with_no_preserve_ephemeral(self):
@ -6368,24 +6376,40 @@ class TestServerRebuild(TestServer):
# Get the command object to test # Get the command object to test
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with( )
self.image, None, preserve_ephemeral=False self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
preserve_ephemeral=False,
) )
def test_rebuild_with_password(self): def test_rebuild_with_password(self):
password = 'password-xxx' password = 'password-xxx'
arglist = [self.server.id, '--password', password] arglist = [self.server.id, '--password', password]
verifylist = [('server', self.server.id), ('password', password)] verifylist = [('server', self.server.id), ('password', password)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Get the command object to test parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with(self.image, password) )
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=password,
)
def test_rebuild_with_description(self): def test_rebuild_with_description(self):
self.set_compute_api_version('2.19') self.set_compute_api_version('2.19')
@ -6393,14 +6417,22 @@ class TestServerRebuild(TestServer):
description = 'description1' description = 'description1'
arglist = [self.server.id, '--description', description] arglist = [self.server.id, '--description', description]
verifylist = [('server', self.server.id), ('description', description)] verifylist = [('server', self.server.id), ('description', description)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with( )
self.image, None, description=description self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
description=description,
) )
def test_rebuild_with_description_pre_v219(self): def test_rebuild_with_description_pre_v219(self):
@ -6409,8 +6441,8 @@ class TestServerRebuild(TestServer):
description = 'description1' description = 'description1'
arglist = [self.server.id, '--description', description] arglist = [self.server.id, '--description', description]
verifylist = [('server', self.server.id), ('description', description)] verifylist = [('server', self.server.id), ('description', description)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises( self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args exceptions.CommandError, self.cmd.take_action, parsed_args
) )
@ -6425,25 +6457,30 @@ class TestServerRebuild(TestServer):
('wait', True), ('wait', True),
('server', self.server.id), ('server', self.server.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Get the command object to test. parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
# kwargs = dict(success_status=['active', 'verify_resize'],) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
)
mock_wait_for_status.assert_called_once_with( mock_wait_for_status.assert_called_once_with(
self.servers_mock.get, self.compute_sdk_client.get_server,
self.server.id, self.server.id,
callback=mock.ANY, callback=mock.ANY,
success_status=['active'], success_status=['active'],
# **kwargs
) )
self.servers_mock.get.assert_called_with(self.server.id)
self.image_client.get_image.assert_called_with(self.image.id)
self.server.rebuild.assert_called_with(self.image, None)
@mock.patch.object(common_utils, 'wait_for_status', return_value=False) @mock.patch.object(common_utils, 'wait_for_status', return_value=False)
def test_rebuild_with_wait_fails(self, mock_wait_for_status): def test_rebuild_with_wait_fails(self, mock_wait_for_status):
arglist = [ arglist = [
@ -6454,23 +6491,30 @@ class TestServerRebuild(TestServer):
('wait', True), ('wait', True),
('server', self.server.id), ('server', self.server.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises( self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args exceptions.CommandError, self.cmd.take_action, parsed_args
) )
self.compute_sdk_client.find_server.assert_called_once_with(
self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_called_once_with(self.image.id)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
)
mock_wait_for_status.assert_called_once_with( mock_wait_for_status.assert_called_once_with(
self.servers_mock.get, self.compute_sdk_client.get_server,
self.server.id, self.server.id,
callback=mock.ANY, callback=mock.ANY,
success_status=['active'], success_status=['active'],
) )
self.servers_mock.get.assert_called_with(self.server.id)
self.image_client.get_image.assert_called_with(self.image.id)
self.server.rebuild.assert_called_with(self.image, None)
@mock.patch.object(common_utils, 'wait_for_status', return_value=True) @mock.patch.object(common_utils, 'wait_for_status', return_value=True)
def test_rebuild_with_wait_shutoff_status(self, mock_wait_for_status): def test_rebuild_with_wait_shutoff_status(self, mock_wait_for_status):
self.server.status = 'SHUTOFF' self.server.status = 'SHUTOFF'
@ -6482,25 +6526,30 @@ class TestServerRebuild(TestServer):
('wait', True), ('wait', True),
('server', self.server.id), ('server', self.server.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Get the command object to test. parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
# kwargs = dict(success_status=['active', 'verify_resize'],) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
)
mock_wait_for_status.assert_called_once_with( mock_wait_for_status.assert_called_once_with(
self.servers_mock.get, self.compute_sdk_client.get_server,
self.server.id, self.server.id,
callback=mock.ANY, callback=mock.ANY,
success_status=['shutoff'], success_status=['shutoff'],
# **kwargs
) )
self.servers_mock.get.assert_called_with(self.server.id)
self.image_client.get_image.assert_called_with(self.image.id)
self.server.rebuild.assert_called_with(self.image, None)
@mock.patch.object(common_utils, 'wait_for_status', return_value=True) @mock.patch.object(common_utils, 'wait_for_status', return_value=True)
def test_rebuild_with_wait_error_status(self, mock_wait_for_status): def test_rebuild_with_wait_error_status(self, mock_wait_for_status):
self.server.status = 'ERROR' self.server.status = 'ERROR'
@ -6512,25 +6561,30 @@ class TestServerRebuild(TestServer):
('wait', True), ('wait', True),
('server', self.server.id), ('server', self.server.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Get the command object to test. parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
# kwargs = dict(success_status=['active', 'verify_resize'],) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
)
mock_wait_for_status.assert_called_once_with( mock_wait_for_status.assert_called_once_with(
self.servers_mock.get, self.compute_sdk_client.get_server,
self.server.id, self.server.id,
callback=mock.ANY, callback=mock.ANY,
success_status=['active'], success_status=['active'],
# **kwargs
) )
self.servers_mock.get.assert_called_with(self.server.id)
self.image_client.get_image.assert_called_with(self.image.id)
self.server.rebuild.assert_called_with(self.image, None)
def test_rebuild_wrong_status_fails(self): def test_rebuild_wrong_status_fails(self):
self.server.status = 'SHELVED' self.server.status = 'SHELVED'
arglist = [ arglist = [
@ -6539,15 +6593,18 @@ class TestServerRebuild(TestServer):
verifylist = [ verifylist = [
('server', self.server.id), ('server', self.server.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises( self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args exceptions.CommandError, self.cmd.take_action, parsed_args
) )
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_not_called() )
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_called_once_with(self.image.id)
self.compute_sdk_client.rebuild_server.assert_not_called()
def test_rebuild_with_property(self): def test_rebuild_with_property(self):
arglist = [ arglist = [
@ -6562,15 +6619,22 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('properties', expected_properties), ('properties', expected_properties),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# Get the command object to test parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with( )
self.image, None, meta=expected_properties self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
metadata=expected_properties,
) )
def test_rebuild_with_keypair_name(self): def test_rebuild_with_keypair_name(self):
@ -6586,14 +6650,22 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('key_name', self.server.key_name), ('key_name', self.server.key_name),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with( )
self.image, None, key_name=self.server.key_name self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
key_name=self.server.key_name,
) )
def test_rebuild_with_keypair_name_pre_v254(self): def test_rebuild_with_keypair_name_pre_v254(self):
@ -6626,12 +6698,23 @@ class TestServerRebuild(TestServer):
verifylist = [ verifylist = [
('server', self.server.id), ('server', self.server.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id)
self.image_client.get_image.assert_called_with(self.image.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.rebuild.assert_called_with(self.image, None, key_name=None) self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
key_name=None,
)
def test_rebuild_with_keypair_name_and_unset(self): def test_rebuild_with_keypair_name_and_unset(self):
self.server.key_name = 'mykey' self.server.key_name = 'mykey'
@ -6653,14 +6736,10 @@ class TestServerRebuild(TestServer):
verifylist, verifylist,
) )
@mock.patch('openstackclient.compute.v2.server.open') def test_rebuild_with_user_data(self):
def test_rebuild_with_user_data(self, mock_open):
self.set_compute_api_version('2.57') self.set_compute_api_version('2.57')
mock_file = mock.Mock(name='File') user_data = b'#!/bin/sh'
mock_open.return_value = mock_file
mock_open.read.return_value = '#!/bin/sh'
arglist = [ arglist = [
self.server.id, self.server.id,
'--user-data', '--user-data',
@ -6670,22 +6749,29 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('user_data', 'userdata.sh'), ('user_data', 'userdata.sh'),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
with mock.patch(
'openstackclient.compute.v2.server.open',
mock.mock_open(read_data=user_data),
) as mock_file:
self.cmd.take_action(parsed_args)
# Ensure the userdata file is opened # Ensure the userdata file is opened
mock_open.assert_called_with('userdata.sh') mock_file.assert_called_with('userdata.sh', 'rb')
# Ensure the userdata file is closed self.compute_sdk_client.find_server.assert_called_once_with(
mock_file.close.assert_called_with() self.server.id, ignore_missing=False
)
self.servers_mock.get.assert_called_with(self.server.id) self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_called_with(self.image.id) self.image_client.get_image.assert_has_calls(
self.server.rebuild.assert_called_with( [mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image, self.image,
None, admin_password=None,
userdata=mock_file, user_data=base64.b64encode(user_data).decode('utf-8'),
) )
def test_rebuild_with_user_data_pre_v257(self): def test_rebuild_with_user_data_pre_v257(self):
@ -6700,8 +6786,8 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('user_data', 'userdata.sh'), ('user_data', 'userdata.sh'),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises( self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args exceptions.CommandError, self.cmd.take_action, parsed_args
) )
@ -6718,12 +6804,23 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('no_user_data', True), ('no_user_data', True),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id)
self.image_client.get_image.assert_called_with(self.image.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.rebuild.assert_called_with(self.image, None, userdata=None) self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
user_data=None,
)
def test_rebuild_with_no_user_data_pre_v254(self): def test_rebuild_with_no_user_data_pre_v254(self):
self.set_compute_api_version('2.53') self.set_compute_api_version('2.53')
@ -6736,8 +6833,8 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('no_user_data', True), ('no_user_data', True),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises( self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args exceptions.CommandError, self.cmd.take_action, parsed_args
) )
@ -6771,14 +6868,22 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('trusted_image_certs', ['foo', 'bar']), ('trusted_image_certs', ['foo', 'bar']),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with( )
self.image, None, trusted_image_certificates=['foo', 'bar'] self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
trusted_image_certificates=['foo', 'bar'],
) )
def test_rebuild_with_trusted_image_cert_pre_v263(self): def test_rebuild_with_trusted_image_cert_pre_v263(self):
@ -6795,8 +6900,8 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('trusted_image_certs', ['foo', 'bar']), ('trusted_image_certs', ['foo', 'bar']),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises( self.assertRaises(
exceptions.CommandError, self.cmd.take_action, parsed_args exceptions.CommandError, self.cmd.take_action, parsed_args
) )
@ -6812,13 +6917,22 @@ class TestServerRebuild(TestServer):
('server', self.server.id), ('server', self.server.id),
('no_trusted_image_certs', True), ('no_trusted_image_certs', True),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id)
self.image_client.get_image.assert_called_with(self.image.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.rebuild.assert_called_with( self.server.id, ignore_missing=False
self.image, None, trusted_image_certificates=None )
self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
trusted_image_certificates=None,
) )
def test_rebuild_with_no_trusted_image_cert_pre_v263(self): def test_rebuild_with_no_trusted_image_cert_pre_v263(self):
@ -6841,16 +6955,31 @@ class TestServerRebuild(TestServer):
def test_rebuild_with_hostname(self): def test_rebuild_with_hostname(self):
self.set_compute_api_version('2.90') self.set_compute_api_version('2.90')
arglist = [self.server.id, '--hostname', 'new-hostname'] arglist = [
verifylist = [('server', self.server.id), ('hostname', 'new-hostname')] self.server.id,
parsed_args = self.check_parser(self.cmd, arglist, verifylist) '--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.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.image_client.get_image.assert_called_with(self.image.id) self.server.id, ignore_missing=False
self.server.rebuild.assert_called_with( )
self.image, None, hostname='new-hostname' self.image_client.find_image.assert_not_called()
self.image_client.get_image.assert_has_calls(
[mock.call(self.image.id), mock.call(self.image.id)]
)
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server,
self.image,
admin_password=None,
hostname='new-hostname',
) )
def test_rebuild_with_hostname_pre_v290(self): def test_rebuild_with_hostname_pre_v290(self):
@ -6877,24 +7006,12 @@ class TestServerRebuildVolumeBacked(TestServer):
self.image_client.find_image.return_value = self.new_image self.image_client.find_image.return_value = self.new_image
attrs = { attrs = {
'status': 'ACTIVE',
'image': '', 'image': '',
'networks': {},
'adminPass': 'passw0rd',
} }
new_server = compute_fakes.create_one_server(attrs=attrs) self.server = compute_fakes.create_one_sdk_server(attrs=attrs)
self.compute_sdk_client.find_server.return_value = self.server
# Fake the server to be rebuilt. The IDs of them should be the same. self.compute_sdk_client.rebuild_server.return_value = self.server
attrs['id'] = new_server.id
attrs['status'] = 'ACTIVE'
methods = {
'rebuild': new_server,
}
self.server = compute_fakes.create_one_server(
attrs=attrs, methods=methods
)
# Return value for utils.find_resource for server.
self.servers_mock.get.return_value = self.server
self.cmd = server.RebuildServer(self.app, None) self.cmd = server.RebuildServer(self.app, None)
@ -6912,12 +7029,20 @@ class TestServerRebuildVolumeBacked(TestServer):
('reimage_boot_volume', True), ('reimage_boot_volume', True),
('image', self.new_image.id), ('image', self.new_image.id),
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.servers_mock.get.assert_called_with(self.server.id) self.compute_sdk_client.find_server.assert_called_once_with(
self.server.rebuild.assert_called_with(self.new_image, None) self.server.id, ignore_missing=False
)
self.image_client.find_image.assert_called_with(
self.new_image.id, ignore_missing=False
)
self.image_client.get_image.assert_not_called()
self.compute_sdk_client.rebuild_server.assert_called_once_with(
self.server, self.new_image, admin_password=None
)
def test_rebuild_with_no_reimage_boot_volume(self): def test_rebuild_with_no_reimage_boot_volume(self):
self.set_compute_api_version('2.93') self.set_compute_api_version('2.93')