Add server migration list CLI
Add ``openstack server migration list`` to fetch server migrations. Part of blueprint add-user-id-field-to-the-migrations-table Change-Id: I15b4a5aca8d0dee59dd293e7b1c7272cdfbeea20
This commit is contained in:
parent
51aee432d9
commit
b77c28d295
12
doc/source/cli/command-objects/server-migration.rst
Normal file
12
doc/source/cli/command-objects/server-migration.rst
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
================
|
||||||
|
server migration
|
||||||
|
================
|
||||||
|
|
||||||
|
A server migration provides a way to move an instance from one
|
||||||
|
host to another. There are four types of migration operation
|
||||||
|
supported: live migration, cold migration, resize and evacuation.
|
||||||
|
|
||||||
|
Compute v2
|
||||||
|
|
||||||
|
.. autoprogram-cliff:: openstack.compute.v2
|
||||||
|
:command: server migration list
|
@ -1768,6 +1768,167 @@ revert to release the new server and restart the old one.""")
|
|||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
|
||||||
|
|
||||||
|
class ListMigration(command.Command):
|
||||||
|
_description = _("""List server migrations.""")
|
||||||
|
|
||||||
|
def get_parser(self, prog_name):
|
||||||
|
parser = super(ListMigration, self).get_parser(prog_name)
|
||||||
|
parser.add_argument(
|
||||||
|
"--server",
|
||||||
|
metavar="<server>",
|
||||||
|
dest='server',
|
||||||
|
default=None,
|
||||||
|
help=_('Server to show migration details (name or ID).')
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--host",
|
||||||
|
metavar="<host>",
|
||||||
|
default=None,
|
||||||
|
help=_('Fetch migrations for the given host.')
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--status",
|
||||||
|
metavar="<status>",
|
||||||
|
default=None,
|
||||||
|
help=_('Fetch migrations for the given status.')
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--marker",
|
||||||
|
metavar="<marker>",
|
||||||
|
dest='marker',
|
||||||
|
default=None,
|
||||||
|
help=_("The last migration of the previous page; displays list "
|
||||||
|
"of migrations after 'marker'. Note that the marker is "
|
||||||
|
"the migration UUID. (Supported with "
|
||||||
|
"``--os-compute-api-version`` 2.59 or greater.)")
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--limit",
|
||||||
|
metavar="<limit>",
|
||||||
|
dest='limit',
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
help=_("Maximum number of migrations to display. Note that there "
|
||||||
|
"is a configurable max limit on the server, and the limit "
|
||||||
|
"that is used will be the minimum of what is requested "
|
||||||
|
"here and what is configured in the server. "
|
||||||
|
"(Supported with ``--os-compute-api-version`` 2.59 "
|
||||||
|
"or greater.)")
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--changes-since',
|
||||||
|
dest='changes_since',
|
||||||
|
metavar='<changes-since>',
|
||||||
|
default=None,
|
||||||
|
help=_("List only migrations changed later or equal to a certain "
|
||||||
|
"point of time. The provided time should be an ISO 8061 "
|
||||||
|
"formatted time, e.g. ``2016-03-04T06:27:59Z``. "
|
||||||
|
"(Supported with ``--os-compute-api-version`` 2.59 "
|
||||||
|
"or greater.)")
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--changes-before',
|
||||||
|
dest='changes_before',
|
||||||
|
metavar='<changes-before>',
|
||||||
|
default=None,
|
||||||
|
help=_("List only migrations changed earlier or equal to a "
|
||||||
|
"certain point of time. The provided time should be an ISO "
|
||||||
|
"8061 formatted time, e.g. ``2016-03-04T06:27:59Z``. "
|
||||||
|
"(Supported with ``--os-compute-api-version`` 2.66 or "
|
||||||
|
"greater.)")
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--project',
|
||||||
|
metavar='<project>',
|
||||||
|
dest='project_id',
|
||||||
|
default=None,
|
||||||
|
help=_("Filter the migrations by the given project ID. "
|
||||||
|
"(Supported with ``--os-compute-api-version`` 2.80 "
|
||||||
|
"or greater.)"),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--user',
|
||||||
|
metavar='<user>',
|
||||||
|
dest='user_id',
|
||||||
|
default=None,
|
||||||
|
help=_("Filter the migrations by the given user ID. "
|
||||||
|
"(Supported with ``--os-compute-api-version`` 2.80 "
|
||||||
|
"or greater.)"),
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def print_migrations(self, parsed_args, compute_client, migrations):
|
||||||
|
columns = ['Source Node', 'Dest Node', 'Source Compute',
|
||||||
|
'Dest Compute', 'Dest Host', 'Status',
|
||||||
|
'Server UUID', 'Old Flavor', 'New Flavor',
|
||||||
|
'Created At', 'Updated At']
|
||||||
|
|
||||||
|
# Insert migrations UUID after ID
|
||||||
|
if compute_client.api_version >= api_versions.APIVersion("2.59"):
|
||||||
|
columns.insert(0, "UUID")
|
||||||
|
|
||||||
|
# TODO(brinzhang): It also suppports filter migrations by type
|
||||||
|
# since 2.1. https://review.opendev.org/#/c/675117 supported
|
||||||
|
# filtering the migrations by 'migration_type' and 'source_compute'
|
||||||
|
# in novaclient, that will be added in OSC by follow-up.
|
||||||
|
if compute_client.api_version >= api_versions.APIVersion("2.23"):
|
||||||
|
columns.insert(0, "Id")
|
||||||
|
columns.insert(len(columns) - 2, "Type")
|
||||||
|
|
||||||
|
if compute_client.api_version >= api_versions.APIVersion("2.80"):
|
||||||
|
if parsed_args.project_id:
|
||||||
|
columns.insert(len(columns) - 2, "Project")
|
||||||
|
if parsed_args.user_id:
|
||||||
|
columns.insert(len(columns) - 2, "User")
|
||||||
|
|
||||||
|
columns_header = columns
|
||||||
|
return (columns_header, (utils.get_item_properties(
|
||||||
|
mig, columns) for mig in migrations))
|
||||||
|
|
||||||
|
def take_action(self, parsed_args):
|
||||||
|
compute_client = self.app.client_manager.compute
|
||||||
|
|
||||||
|
search_opts = {
|
||||||
|
"host": parsed_args.host,
|
||||||
|
"server": parsed_args.server,
|
||||||
|
"status": parsed_args.status,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed_args.marker or parsed_args.limit or
|
||||||
|
parsed_args.changes_since):
|
||||||
|
if compute_client.api_version < api_versions.APIVersion("2.59"):
|
||||||
|
msg = _("marker, limit and/or changes_since is not supported "
|
||||||
|
"for --os-compute-api-version less than 2.59")
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
if parsed_args.marker:
|
||||||
|
search_opts['marker'] = parsed_args.marker
|
||||||
|
if parsed_args.limit:
|
||||||
|
search_opts['limit'] = parsed_args.limit
|
||||||
|
if parsed_args.changes_since:
|
||||||
|
search_opts['changes_since'] = parsed_args.changes_since
|
||||||
|
|
||||||
|
if parsed_args.changes_before:
|
||||||
|
if compute_client.api_version < api_versions.APIVersion("2.66"):
|
||||||
|
msg = _("changes_before is not supported for "
|
||||||
|
"--os-compute-api-version less than 2.66")
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
search_opts['changes_before'] = parsed_args.changes_before
|
||||||
|
|
||||||
|
if parsed_args.project_id or parsed_args.user_id:
|
||||||
|
if compute_client.api_version < api_versions.APIVersion("2.80"):
|
||||||
|
msg = _("Project and/or user is not supported for "
|
||||||
|
"--os-compute-api-version less than 2.80")
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
if parsed_args.project_id:
|
||||||
|
search_opts['project_id'] = parsed_args.project_id
|
||||||
|
if parsed_args.user_id:
|
||||||
|
search_opts['user_id'] = parsed_args.user_id
|
||||||
|
|
||||||
|
migrations = compute_client.migrations.list(**search_opts)
|
||||||
|
|
||||||
|
return self.print_migrations(parsed_args, compute_client, migrations)
|
||||||
|
|
||||||
|
|
||||||
class PauseServer(command.Command):
|
class PauseServer(command.Command):
|
||||||
_description = _("Pause server(s)")
|
_description = _("Pause server(s)")
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import random
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@ -198,6 +199,9 @@ class FakeComputev2Client(object):
|
|||||||
self.instance_action = mock.Mock()
|
self.instance_action = mock.Mock()
|
||||||
self.instance_action.resource_class = fakes.FakeResource(None, {})
|
self.instance_action.resource_class = fakes.FakeResource(None, {})
|
||||||
|
|
||||||
|
self.migrations = mock.Mock()
|
||||||
|
self.migrations.resource_class = fakes.FakeResource(None, {})
|
||||||
|
|
||||||
self.auth_token = kwargs['token']
|
self.auth_token = kwargs['token']
|
||||||
|
|
||||||
self.management_url = kwargs['endpoint']
|
self.management_url = kwargs['endpoint']
|
||||||
@ -1539,3 +1543,89 @@ class FakeRateLimit(object):
|
|||||||
self.remain = remain
|
self.remain = remain
|
||||||
self.unit = unit
|
self.unit = unit
|
||||||
self.next_available = next_available
|
self.next_available = next_available
|
||||||
|
|
||||||
|
|
||||||
|
class FakeServerMigration(object):
|
||||||
|
"""Fake one or more server migrations."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_one_server_migration(attrs=None, methods=None):
|
||||||
|
"""Create a fake server migration.
|
||||||
|
|
||||||
|
:param Dictionary attrs:
|
||||||
|
A dictionary with all attributes
|
||||||
|
:param Dictionary methods:
|
||||||
|
A dictionary with all methods
|
||||||
|
:return:
|
||||||
|
A FakeResource object, with id, type, and so on
|
||||||
|
"""
|
||||||
|
attrs = attrs or {}
|
||||||
|
methods = methods or {}
|
||||||
|
|
||||||
|
# Set default attributes.
|
||||||
|
migration_info = {
|
||||||
|
"dest_host": "10.0.2.15",
|
||||||
|
"status": "migrating",
|
||||||
|
"type": "migration",
|
||||||
|
"updated_at": "2017-01-31T08:03:25.000000",
|
||||||
|
"created_at": "2017-01-31T08:03:21.000000",
|
||||||
|
"dest_compute": "compute-" + uuid.uuid4().hex,
|
||||||
|
"id": random.randint(1, 999),
|
||||||
|
"source_node": "node-" + uuid.uuid4().hex,
|
||||||
|
"server": uuid.uuid4().hex,
|
||||||
|
"dest_node": "node-" + uuid.uuid4().hex,
|
||||||
|
"source_compute": "compute-" + uuid.uuid4().hex,
|
||||||
|
"uuid": uuid.uuid4().hex,
|
||||||
|
"old_instance_type_id": uuid.uuid4().hex,
|
||||||
|
"new_instance_type_id": uuid.uuid4().hex,
|
||||||
|
"project": uuid.uuid4().hex,
|
||||||
|
"user": uuid.uuid4().hex
|
||||||
|
}
|
||||||
|
|
||||||
|
# Overwrite default attributes.
|
||||||
|
migration_info.update(attrs)
|
||||||
|
|
||||||
|
migration = fakes.FakeResource(info=copy.deepcopy(migration_info),
|
||||||
|
methods=methods,
|
||||||
|
loaded=True)
|
||||||
|
return migration
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_server_migrations(attrs=None, methods=None, count=2):
|
||||||
|
"""Create multiple fake server migrations.
|
||||||
|
|
||||||
|
:param Dictionary attrs:
|
||||||
|
A dictionary with all attributes
|
||||||
|
:param Dictionary methods:
|
||||||
|
A dictionary with all methods
|
||||||
|
:param int count:
|
||||||
|
The number of server migrations to fake
|
||||||
|
:return:
|
||||||
|
A list of FakeResource objects faking the server migrations
|
||||||
|
"""
|
||||||
|
migrations = []
|
||||||
|
for i in range(0, count):
|
||||||
|
migrations.append(
|
||||||
|
FakeServerMigration.create_one_server_migration(
|
||||||
|
attrs, methods))
|
||||||
|
|
||||||
|
return migrations
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_server_migrations(migrations=None, count=2):
|
||||||
|
"""Get an iterable MagicMock object with a list of faked migrations.
|
||||||
|
|
||||||
|
If server migrations list is provided, then initialize the Mock object
|
||||||
|
with the list. Otherwise create one.
|
||||||
|
|
||||||
|
:param List migrations:
|
||||||
|
A list of FakeResource objects faking server migrations
|
||||||
|
:param int count:
|
||||||
|
The number of server migrations to fake
|
||||||
|
:return:
|
||||||
|
An iterable Mock object with side_effect set to a list of faked
|
||||||
|
server migrations
|
||||||
|
"""
|
||||||
|
if migrations is None:
|
||||||
|
migrations = FakeServerMigration.create_server_migrations(count)
|
||||||
|
return mock.Mock(side_effect=migrations)
|
||||||
|
@ -3523,6 +3523,490 @@ class TestServerMigrate(TestServer):
|
|||||||
self.assertNotCalled(self.servers_mock.live_migrate)
|
self.assertNotCalled(self.servers_mock.live_migrate)
|
||||||
|
|
||||||
|
|
||||||
|
class TestServerMigration(TestServer):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestServerMigration, self).setUp()
|
||||||
|
|
||||||
|
# Get a shortcut to the compute client ServerManager Mock
|
||||||
|
self.servers_mock = self.app.client_manager.compute.servers
|
||||||
|
self.servers_mock.reset_mock()
|
||||||
|
|
||||||
|
self.migrations_mock = (
|
||||||
|
self.app.client_manager.compute.migrations)
|
||||||
|
self.migrations_mock.reset_mock()
|
||||||
|
|
||||||
|
self.server = self.setup_servers_mock(1)[0]
|
||||||
|
|
||||||
|
def setup_servers_mock(self, count):
|
||||||
|
servers = compute_fakes.FakeServer.create_servers(count=count)
|
||||||
|
|
||||||
|
# This is the return value for utils.find_resource()
|
||||||
|
self.servers_mock.get = compute_fakes.FakeServer.get_servers(servers)
|
||||||
|
return servers
|
||||||
|
|
||||||
|
def setup_server_migrations_mock(self, count):
|
||||||
|
return compute_fakes.FakeServerMigration.create_server_migrations(
|
||||||
|
count=count)
|
||||||
|
|
||||||
|
|
||||||
|
class TestListMigration(TestServerMigration):
|
||||||
|
"""Test fetch all migrations."""
|
||||||
|
|
||||||
|
MIGRATION_COLUMNS = [
|
||||||
|
'Source Node', 'Dest Node', 'Source Compute',
|
||||||
|
'Dest Compute', 'Dest Host', 'Status', 'Server UUID',
|
||||||
|
'Old Flavor', 'New Flavor', 'Created At', 'Updated At'
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestListMigration, self).setUp()
|
||||||
|
|
||||||
|
self.cmd = server.ListMigration(self.app, None)
|
||||||
|
self.migrations = self.setup_server_migrations_mock(3)
|
||||||
|
self.migrations_mock.list.return_value = self.migrations
|
||||||
|
self.setup_server_migrations_data(self.migrations)
|
||||||
|
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.20')
|
||||||
|
|
||||||
|
def setup_server_migrations_data(self, migrations):
|
||||||
|
self.data = (common_utils.get_item_properties(
|
||||||
|
s, self.MIGRATION_COLUMNS) for s in migrations)
|
||||||
|
|
||||||
|
def test_server_migraton_list(self):
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'status': 'migrating',
|
||||||
|
'host': None,
|
||||||
|
'server': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.migrations_mock.list.assert_called_with(**kwargs)
|
||||||
|
|
||||||
|
self.assertEqual(self.MIGRATION_COLUMNS, columns)
|
||||||
|
self.assertEqual(tuple(self.data), tuple(data))
|
||||||
|
|
||||||
|
|
||||||
|
class TestListMigrationV223(TestListMigration):
|
||||||
|
"""Test fetch all migrations. """
|
||||||
|
|
||||||
|
MIGRATION_COLUMNS = [
|
||||||
|
'Source Node', 'Dest Node', 'Source Compute',
|
||||||
|
'Dest Compute', 'Dest Host', 'Status', 'Server UUID',
|
||||||
|
'Old Flavor', 'New Flavor', 'Created At', 'Updated At'
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestListMigrationV223, self).setUp()
|
||||||
|
self.cmd = server.ListMigration(self.app, None)
|
||||||
|
self.migrations = self.setup_server_migrations_mock(3)
|
||||||
|
self.migrations_mock.list.return_value = self.migrations
|
||||||
|
self.setup_server_migrations_data(self.migrations)
|
||||||
|
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.23')
|
||||||
|
|
||||||
|
def test_server_migraton_list(self):
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'status': 'migrating',
|
||||||
|
'host': None,
|
||||||
|
'server': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.migrations_mock.list.assert_called_with(**kwargs)
|
||||||
|
|
||||||
|
self.MIGRATION_COLUMNS.insert(0, "Id")
|
||||||
|
self.MIGRATION_COLUMNS.insert(
|
||||||
|
len(self.MIGRATION_COLUMNS) - 2, 'Type')
|
||||||
|
self.assertEqual(self.MIGRATION_COLUMNS, columns)
|
||||||
|
self.assertEqual(tuple(self.data), tuple(data))
|
||||||
|
|
||||||
|
|
||||||
|
class TestListMigrationV259(TestListMigration):
|
||||||
|
"""Test fetch all migrations. """
|
||||||
|
|
||||||
|
MIGRATION_COLUMNS = [
|
||||||
|
'Id', 'UUID', 'Source Node', 'Dest Node', 'Source Compute',
|
||||||
|
'Dest Compute', 'Dest Host', 'Status', 'Server UUID',
|
||||||
|
'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At'
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestListMigrationV259, self).setUp()
|
||||||
|
self.cmd = server.ListMigration(self.app, None)
|
||||||
|
self.migrations = self.setup_server_migrations_mock(3)
|
||||||
|
self.migrations_mock.list.return_value = self.migrations
|
||||||
|
self.setup_server_migrations_data(self.migrations)
|
||||||
|
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.59')
|
||||||
|
|
||||||
|
def test_server_migraton_list(self):
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--limit', '1',
|
||||||
|
'--marker', 'test_kp',
|
||||||
|
'--changes-since', '2019-08-09T08:03:25Z'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('limit', 1),
|
||||||
|
('marker', 'test_kp'),
|
||||||
|
('changes_since', '2019-08-09T08:03:25Z')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'status': 'migrating',
|
||||||
|
'limit': 1,
|
||||||
|
'marker': 'test_kp',
|
||||||
|
'host': None,
|
||||||
|
'server': None,
|
||||||
|
'changes_since': '2019-08-09T08:03:25Z',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.migrations_mock.list.assert_called_with(**kwargs)
|
||||||
|
|
||||||
|
self.assertEqual(self.MIGRATION_COLUMNS, columns)
|
||||||
|
self.assertEqual(tuple(self.data), tuple(data))
|
||||||
|
|
||||||
|
def test_server_migraton_list_with_limit_pre_v259(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.58')
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--limit', '1'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('limit', 1)
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
def test_server_migraton_list_with_marker_pre_v259(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.58')
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--marker', 'test_kp'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('marker', 'test_kp')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
def test_server_migraton_list_with_changes_since_pre_v259(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.58')
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--changes-since', '2019-08-09T08:03:25Z'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('changes_since', '2019-08-09T08:03:25Z')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
|
||||||
|
class TestListMigrationV266(TestListMigration):
|
||||||
|
"""Test fetch all migrations by changes-before. """
|
||||||
|
|
||||||
|
MIGRATION_COLUMNS = [
|
||||||
|
'Id', 'UUID', 'Source Node', 'Dest Node', 'Source Compute',
|
||||||
|
'Dest Compute', 'Dest Host', 'Status', 'Server UUID',
|
||||||
|
'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At'
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestListMigrationV266, self).setUp()
|
||||||
|
self.cmd = server.ListMigration(self.app, None)
|
||||||
|
self.migrations = self.setup_server_migrations_mock(3)
|
||||||
|
self.migrations_mock.list.return_value = self.migrations
|
||||||
|
self.setup_server_migrations_data(self.migrations)
|
||||||
|
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.66')
|
||||||
|
|
||||||
|
def test_server_migraton_list_with_changes_before(self):
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--limit', '1',
|
||||||
|
'--marker', 'test_kp',
|
||||||
|
'--changes-since', '2019-08-07T08:03:25Z',
|
||||||
|
'--changes-before', '2019-08-09T08:03:25Z'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('limit', 1),
|
||||||
|
('marker', 'test_kp'),
|
||||||
|
('changes_since', '2019-08-07T08:03:25Z'),
|
||||||
|
('changes_before', '2019-08-09T08:03:25Z')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'status': 'migrating',
|
||||||
|
'limit': 1,
|
||||||
|
'marker': 'test_kp',
|
||||||
|
'host': None,
|
||||||
|
'server': None,
|
||||||
|
'changes_since': '2019-08-07T08:03:25Z',
|
||||||
|
'changes_before': '2019-08-09T08:03:25Z',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.migrations_mock.list.assert_called_with(**kwargs)
|
||||||
|
|
||||||
|
self.assertEqual(self.MIGRATION_COLUMNS, columns)
|
||||||
|
self.assertEqual(tuple(self.data), tuple(data))
|
||||||
|
|
||||||
|
def test_server_migraton_list_with_changes_before_pre_v266(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.65')
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--changes-before', '2019-08-09T08:03:25Z'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('changes_before', '2019-08-09T08:03:25Z')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
|
||||||
|
class TestListMigrationV280(TestListMigration):
|
||||||
|
"""Test fetch all migrations by user-id and/or project-id. """
|
||||||
|
|
||||||
|
MIGRATION_COLUMNS = [
|
||||||
|
'Id', 'UUID', 'Source Node', 'Dest Node', 'Source Compute',
|
||||||
|
'Dest Compute', 'Dest Host', 'Status', 'Server UUID',
|
||||||
|
'Old Flavor', 'New Flavor', 'Type', 'Created At', 'Updated At'
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestListMigrationV280, self).setUp()
|
||||||
|
self.cmd = server.ListMigration(self.app, None)
|
||||||
|
self.migrations = self.setup_server_migrations_mock(3)
|
||||||
|
self.migrations_mock.list.return_value = self.migrations
|
||||||
|
self.setup_server_migrations_data(self.migrations)
|
||||||
|
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.80')
|
||||||
|
|
||||||
|
def test_server_migraton_list_with_project(self):
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--limit', '1',
|
||||||
|
'--marker', 'test_kp',
|
||||||
|
'--changes-since', '2019-08-07T08:03:25Z',
|
||||||
|
'--changes-before', '2019-08-09T08:03:25Z',
|
||||||
|
'--project', '0c2accde-644a-45fa-8c10-e76debc7fbc3'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('limit', 1),
|
||||||
|
('marker', 'test_kp'),
|
||||||
|
('changes_since', '2019-08-07T08:03:25Z'),
|
||||||
|
('changes_before', '2019-08-09T08:03:25Z'),
|
||||||
|
('project_id', '0c2accde-644a-45fa-8c10-e76debc7fbc3')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'status': 'migrating',
|
||||||
|
'limit': 1,
|
||||||
|
'marker': 'test_kp',
|
||||||
|
'host': None,
|
||||||
|
'server': None,
|
||||||
|
'project_id': '0c2accde-644a-45fa-8c10-e76debc7fbc3',
|
||||||
|
'changes_since': '2019-08-07T08:03:25Z',
|
||||||
|
'changes_before': "2019-08-09T08:03:25Z",
|
||||||
|
}
|
||||||
|
|
||||||
|
self.migrations_mock.list.assert_called_with(**kwargs)
|
||||||
|
|
||||||
|
self.MIGRATION_COLUMNS.insert(
|
||||||
|
len(self.MIGRATION_COLUMNS) - 2, "Project")
|
||||||
|
self.assertEqual(self.MIGRATION_COLUMNS, columns)
|
||||||
|
self.assertEqual(tuple(self.data), tuple(data))
|
||||||
|
# Clean up global variables MIGRATION_COLUMNS
|
||||||
|
self.MIGRATION_COLUMNS.remove('Project')
|
||||||
|
|
||||||
|
def test_get_migrations_with_project_pre_v280(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.79')
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--changes-before', '2019-08-09T08:03:25Z',
|
||||||
|
'--project', '0c2accde-644a-45fa-8c10-e76debc7fbc3'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('changes_before', '2019-08-09T08:03:25Z'),
|
||||||
|
('project_id', '0c2accde-644a-45fa-8c10-e76debc7fbc3')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
def test_server_migraton_list_with_user(self):
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--limit', '1',
|
||||||
|
'--marker', 'test_kp',
|
||||||
|
'--changes-since', '2019-08-07T08:03:25Z',
|
||||||
|
'--changes-before', '2019-08-09T08:03:25Z',
|
||||||
|
'--user', 'dd214878-ca12-40fb-b035-fa7d2c1e86d6'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('limit', 1),
|
||||||
|
('marker', 'test_kp'),
|
||||||
|
('changes_since', '2019-08-07T08:03:25Z'),
|
||||||
|
('changes_before', '2019-08-09T08:03:25Z'),
|
||||||
|
('user_id', 'dd214878-ca12-40fb-b035-fa7d2c1e86d6')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'status': 'migrating',
|
||||||
|
'limit': 1,
|
||||||
|
'marker': 'test_kp',
|
||||||
|
'host': None,
|
||||||
|
'server': None,
|
||||||
|
'user_id': 'dd214878-ca12-40fb-b035-fa7d2c1e86d6',
|
||||||
|
'changes_since': '2019-08-07T08:03:25Z',
|
||||||
|
'changes_before': "2019-08-09T08:03:25Z",
|
||||||
|
}
|
||||||
|
|
||||||
|
self.migrations_mock.list.assert_called_with(**kwargs)
|
||||||
|
|
||||||
|
self.MIGRATION_COLUMNS.insert(
|
||||||
|
len(self.MIGRATION_COLUMNS) - 2, "User")
|
||||||
|
self.assertEqual(self.MIGRATION_COLUMNS, columns)
|
||||||
|
self.assertEqual(tuple(self.data), tuple(data))
|
||||||
|
# Clean up global variables MIGRATION_COLUMNS
|
||||||
|
self.MIGRATION_COLUMNS.remove('User')
|
||||||
|
|
||||||
|
def test_get_migrations_with_user_pre_v280(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.79')
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--changes-before', '2019-08-09T08:03:25Z',
|
||||||
|
'--user', 'dd214878-ca12-40fb-b035-fa7d2c1e86d6'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('changes_before', '2019-08-09T08:03:25Z'),
|
||||||
|
('user_id', 'dd214878-ca12-40fb-b035-fa7d2c1e86d6')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
def test_server_migraton_list_with_project_and_user(self):
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--limit', '1',
|
||||||
|
'--changes-since', '2019-08-07T08:03:25Z',
|
||||||
|
'--changes-before', '2019-08-09T08:03:25Z',
|
||||||
|
'--project', '0c2accde-644a-45fa-8c10-e76debc7fbc3',
|
||||||
|
'--user', 'dd214878-ca12-40fb-b035-fa7d2c1e86d6'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('limit', 1),
|
||||||
|
('changes_since', '2019-08-07T08:03:25Z'),
|
||||||
|
('changes_before', '2019-08-09T08:03:25Z'),
|
||||||
|
('project_id', '0c2accde-644a-45fa-8c10-e76debc7fbc3'),
|
||||||
|
('user_id', 'dd214878-ca12-40fb-b035-fa7d2c1e86d6')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Set expected values
|
||||||
|
kwargs = {
|
||||||
|
'status': 'migrating',
|
||||||
|
'limit': 1,
|
||||||
|
'host': None,
|
||||||
|
'server': None,
|
||||||
|
'project_id': '0c2accde-644a-45fa-8c10-e76debc7fbc3',
|
||||||
|
'user_id': 'dd214878-ca12-40fb-b035-fa7d2c1e86d6',
|
||||||
|
'changes_since': '2019-08-07T08:03:25Z',
|
||||||
|
'changes_before': "2019-08-09T08:03:25Z",
|
||||||
|
}
|
||||||
|
|
||||||
|
self.migrations_mock.list.assert_called_with(**kwargs)
|
||||||
|
|
||||||
|
self.MIGRATION_COLUMNS.insert(
|
||||||
|
len(self.MIGRATION_COLUMNS) - 2, "Project")
|
||||||
|
self.MIGRATION_COLUMNS.insert(
|
||||||
|
len(self.MIGRATION_COLUMNS) - 2, "User")
|
||||||
|
self.assertEqual(self.MIGRATION_COLUMNS, columns)
|
||||||
|
self.assertEqual(tuple(self.data), tuple(data))
|
||||||
|
# Clean up global variables MIGRATION_COLUMNS
|
||||||
|
self.MIGRATION_COLUMNS.remove('Project')
|
||||||
|
self.MIGRATION_COLUMNS.remove('User')
|
||||||
|
|
||||||
|
def test_get_migrations_with_project_and_user_pre_v280(self):
|
||||||
|
self.app.client_manager.compute.api_version = api_versions.APIVersion(
|
||||||
|
'2.79')
|
||||||
|
arglist = [
|
||||||
|
'--status', 'migrating',
|
||||||
|
'--changes-before', '2019-08-09T08:03:25Z',
|
||||||
|
'--project', '0c2accde-644a-45fa-8c10-e76debc7fbc3',
|
||||||
|
'--user', 'dd214878-ca12-40fb-b035-fa7d2c1e86d6'
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('status', 'migrating'),
|
||||||
|
('changes_before', '2019-08-09T08:03:25Z'),
|
||||||
|
('project_id', '0c2accde-644a-45fa-8c10-e76debc7fbc3'),
|
||||||
|
('user_id', 'dd214878-ca12-40fb-b035-fa7d2c1e86d6')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
|
||||||
|
parsed_args)
|
||||||
|
|
||||||
|
|
||||||
class TestServerPause(TestServer):
|
class TestServerPause(TestServer):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add ``server migration list`` command. This command allows
|
||||||
|
users to list the status of ongoing server migrations.
|
@ -108,6 +108,7 @@ openstack.compute.v2 =
|
|||||||
server_migrate = openstackclient.compute.v2.server:MigrateServer
|
server_migrate = openstackclient.compute.v2.server:MigrateServer
|
||||||
server_migrate_confirm = openstackclient.compute.v2.server:MigrateConfirm
|
server_migrate_confirm = openstackclient.compute.v2.server:MigrateConfirm
|
||||||
server_migrate_revert = openstackclient.compute.v2.server:MigrateRevert
|
server_migrate_revert = openstackclient.compute.v2.server:MigrateRevert
|
||||||
|
server_migration_list = openstackclient.compute.v2.server:ListMigration
|
||||||
server_pause = openstackclient.compute.v2.server:PauseServer
|
server_pause = openstackclient.compute.v2.server:PauseServer
|
||||||
server_reboot = openstackclient.compute.v2.server:RebootServer
|
server_reboot = openstackclient.compute.v2.server:RebootServer
|
||||||
server_rebuild = openstackclient.compute.v2.server:RebuildServer
|
server_rebuild = openstackclient.compute.v2.server:RebuildServer
|
||||||
|
Loading…
Reference in New Issue
Block a user