diff options
author | Jenkins <jenkins@review.openstack.org> | 2016-03-01 15:11:11 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2016-03-01 15:11:12 +0000 |
commit | 3a3a5c8ac6c2e767cd30f93401226f5c64717553 (patch) | |
tree | 2cc2dd2c4fea5aaf06b9f4edbee81760d23dd167 | |
parent | eb461f082ba622dbc3b431b3d3deba5b950d60f6 (diff) | |
parent | e0c7d2c6731744374ea83385305624254454b0ed (diff) | |
download | python-novaclient-3a3a5c8ac6c2e767cd30f93401226f5c64717553.tar.gz |
Merge "Add two server-migration commands and bump migration-list command"
-rw-r--r-- | novaclient/__init__.py | 2 | ||||
-rw-r--r-- | novaclient/tests/unit/fixture_data/server_migrations.py | 51 | ||||
-rw-r--r-- | novaclient/tests/unit/v2/contrib/test_migrations.py | 12 | ||||
-rw-r--r-- | novaclient/tests/unit/v2/fakes.py | 95 | ||||
-rw-r--r-- | novaclient/tests/unit/v2/test_server_migrations.py | 49 | ||||
-rw-r--r-- | novaclient/tests/unit/v2/test_shell.py | 14 | ||||
-rw-r--r-- | novaclient/v2/contrib/migrations.py | 15 | ||||
-rw-r--r-- | novaclient/v2/server_migrations.py | 27 | ||||
-rw-r--r-- | novaclient/v2/shell.py | 36 |
9 files changed, 279 insertions, 22 deletions
diff --git a/novaclient/__init__.py b/novaclient/__init__.py index 509d2a20..c7bff335 100644 --- a/novaclient/__init__.py +++ b/novaclient/__init__.py @@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1") # when client supported the max version, and bumped sequentially, otherwise # the client may break due to server side new version may include some # backward incompatible change. -API_MAX_VERSION = api_versions.APIVersion("2.22") +API_MAX_VERSION = api_versions.APIVersion("2.23") diff --git a/novaclient/tests/unit/fixture_data/server_migrations.py b/novaclient/tests/unit/fixture_data/server_migrations.py index 3aed49a5..93f299fb 100644 --- a/novaclient/tests/unit/fixture_data/server_migrations.py +++ b/novaclient/tests/unit/fixture_data/server_migrations.py @@ -25,3 +25,54 @@ class Fixture(base.Fixture): self.requests.register_uri('POST', url, status_code=202, headers=self.json_headers) + + get_migrations = {'migrations': [ + { + "created_at": "2016-01-29T13:42:02.000000", + "dest_compute": "compute2", + "dest_host": "1.2.3.4", + "dest_node": "node2", + "id": 1, + "server_uuid": "4cfba335-03d8-49b2-8c52-e69043d1e8fe", + "source_compute": "compute1", + "source_node": "node1", + "status": "running", + "memory_total_bytes": 123456, + "memory_processed_bytes": 12345, + "memory_remaining_bytes": 120000, + "disk_total_bytes": 234567, + "disk_processed_bytes": 23456, + "disk_remaining_bytes": 230000, + "updated_at": "2016-01-29T13:42:02.000000" + }]} + + url = self.url('1234', 'migrations') + self.requests.register_uri('GET', url, + status_code=200, + json=get_migrations, + headers=self.json_headers) + + get_migration = {'migration': { + "created_at": "2016-01-29T13:42:02.000000", + "dest_compute": "compute2", + "dest_host": "1.2.3.4", + "dest_node": "node2", + "id": 1, + "server_uuid": "4cfba335-03d8-49b2-8c52-e69043d1e8fe", + "source_compute": "compute1", + "source_node": "node1", + "status": "running", + "memory_total_bytes": 123456, + "memory_processed_bytes": 12345, + "memory_remaining_bytes": 120000, + "disk_total_bytes": 234567, + "disk_processed_bytes": 23456, + "disk_remaining_bytes": 230000, + "updated_at": "2016-01-29T13:42:02.000000" + }} + + url = self.url('1234', 'migrations', '1') + self.requests.register_uri('GET', url, + status_code=200, + json=get_migration, + headers=self.json_headers) diff --git a/novaclient/tests/unit/v2/contrib/test_migrations.py b/novaclient/tests/unit/v2/contrib/test_migrations.py index 29cac5d4..8d12633e 100644 --- a/novaclient/tests/unit/v2/contrib/test_migrations.py +++ b/novaclient/tests/unit/v2/contrib/test_migrations.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +from novaclient import api_versions from novaclient import extension from novaclient.tests.unit import utils from novaclient.tests.unit.v2 import fakes @@ -30,6 +31,17 @@ class MigrationsTest(utils.TestCase): cs.assert_called('GET', '/os-migrations') for m in ml: self.assertIsInstance(m, migrations.Migration) + self.assertRaises(AttributeError, getattr, m, "migration_type") + + def test_list_migrations_v223(self): + cs = fakes.FakeClient(extensions=extensions, + api_version=api_versions.APIVersion("2.23")) + ml = cs.migrations.list() + self.assert_request_id(ml, fakes.FAKE_REQUEST_ID_LIST) + cs.assert_called('GET', '/os-migrations') + for m in ml: + self.assertIsInstance(m, migrations.Migration) + self.assertEqual(m.migration_type, 'live-migration') def test_list_migrations_with_filters(self): ml = cs.migrations.list('host1', 'finished', 'child1') diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py index d3d1e405..85f4b74b 100644 --- a/novaclient/tests/unit/v2/fakes.py +++ b/novaclient/tests/unit/v2/fakes.py @@ -23,8 +23,10 @@ import six from six.moves.urllib import parse import novaclient +from novaclient import api_versions from novaclient import client as base_client from novaclient import exceptions +from novaclient.i18n import _ from novaclient.tests.unit import fakes from novaclient.tests.unit import utils from novaclient.v2 import client @@ -58,7 +60,8 @@ class FakeClient(fakes.FakeClient, client.Client): 'project_id', 'auth_url', extensions=kwargs.get('extensions'), direct_use=False) - self.api_version = api_version + self.api_version = api_version or api_versions.APIVersion("2.1") + kwargs["api_version"] = self.api_version self.client = FakeHTTPClient(**kwargs) @@ -91,6 +94,7 @@ class FakeHTTPClient(base_client.HTTPClient): self.http_log_debug = 'http_log_debug' self.last_request_id = None self.management_url = self.get_endpoint() + self.api_version = kwargs.get("api_version") def _cs_request(self, url, method, **kwargs): # Check that certain things are called correctly @@ -2367,21 +2371,26 @@ class FakeHTTPClient(base_client.HTTPClient): return self.get_os_cells_capacities() def get_os_migrations(self, **kw): - migrations = {'migrations': [ - { - "created_at": "2012-10-29T13:42:02.000000", - "dest_compute": "compute2", - "dest_host": "1.2.3.4", - "dest_node": "node2", - "id": 1234, - "instance_uuid": "instance_id_123", - "new_instance_type_id": 2, - "old_instance_type_id": 1, - "source_compute": "compute1", - "source_node": "node1", - "status": "Done", - "updated_at": "2012-10-29T13:42:02.000000" - }]} + migration = { + "created_at": "2012-10-29T13:42:02.000000", + "dest_compute": "compute2", + "dest_host": "1.2.3.4", + "dest_node": "node2", + "id": 1234, + "instance_uuid": "instance_id_123", + "new_instance_type_id": 2, + "old_instance_type_id": 1, + "source_compute": "compute1", + "source_node": "node1", + "status": "Done", + "updated_at": "2012-10-29T13:42:02.000000" + } + + if self.api_version >= api_versions.APIVersion("2.23"): + migration.update({"migration_type": "live-migration"}) + + migrations = {'migrations': [migration]} + return (200, FAKE_RESPONSE_HEADERS, migrations) def post_os_server_external_events(self, **kw): @@ -2435,6 +2444,57 @@ class FakeHTTPClient(base_client.HTTPClient): def post_servers_1234_migrations_1_action(self, body): return (202, {}, None) + def get_servers_1234_migrations_1(self, **kw): + # TODO(Shaohe Feng) this condition check can be a decorator + if self.api_version < api_versions.APIVersion("2.23"): + raise exceptions.UnsupportedVersion(_("Unsupport version %s") + % self.api_version) + migration = {"migration": { + "created_at": "2016-01-29T13:42:02.000000", + "dest_compute": "compute2", + "dest_host": "1.2.3.4", + "dest_node": "node2", + "id": 1, + "server_uuid": "4cfba335-03d8-49b2-8c52-e69043d1e8fe", + "source_compute": "compute1", + "source_node": "node1", + "status": "running", + "memory_total_bytes": 123456, + "memory_processed_bytes": 12345, + "memory_remaining_bytes": 120000, + "disk_total_bytes": 234567, + "disk_processed_bytes": 23456, + "disk_remaining_bytes": 230000, + "updated_at": "2016-01-29T13:42:02.000000" + }} + return (200, FAKE_RESPONSE_HEADERS, migration) + + def get_servers_1234_migrations(self, **kw): + # TODO(Shaohe Feng) this condition check can be a decorator + if self.api_version < api_versions.APIVersion("2.23"): + raise exceptions.UnsupportedVersion(_("Unsupport version %s") + % self.api_version) + migrations = {'migrations': [ + { + "created_at": "2016-01-29T13:42:02.000000", + "dest_compute": "compute2", + "dest_host": "1.2.3.4", + "dest_node": "node2", + "id": 1, + "server_uuid": "4cfba335-03d8-49b2-8c52-e69043d1e8fe", + "source_compute": "compute1", + "source_node": "node1", + "status": "running", + "memory_total_bytes": 123456, + "memory_processed_bytes": 12345, + "memory_remaining_bytes": 120000, + "disk_total_bytes": 234567, + "disk_processed_bytes": 23456, + "disk_remaining_bytes": 230000, + "updated_at": "2016-01-29T13:42:02.000000" + }]} + return (200, FAKE_RESPONSE_HEADERS, migrations) + class FakeSessionClient(fakes.FakeClient, client.Client): @@ -2443,6 +2503,7 @@ class FakeSessionClient(fakes.FakeClient, client.Client): 'project_id', 'auth_url', extensions=kwargs.get('extensions'), api_version=api_version, direct_use=False) + kwargs['api_version'] = api_version self.client = FakeSessionMockClient(**kwargs) @@ -2461,7 +2522,7 @@ class FakeSessionMockClient(base_client.SessionClient, FakeHTTPClient): self.interface = None self.region_name = None self.version = None - + self.api_version = kwargs.get('api_version') self.auth.get_auth_ref.return_value.project_id = 'tenant_id' def request(self, url, method, **kwargs): diff --git a/novaclient/tests/unit/v2/test_server_migrations.py b/novaclient/tests/unit/v2/test_server_migrations.py index 12c5a269..e4a2b4ba 100644 --- a/novaclient/tests/unit/v2/test_server_migrations.py +++ b/novaclient/tests/unit/v2/test_server_migrations.py @@ -14,9 +14,12 @@ # under the License. from novaclient import api_versions +from novaclient import base from novaclient.tests.unit.fixture_data import client from novaclient.tests.unit.fixture_data import server_migrations as data from novaclient.tests.unit import utils +from novaclient.tests.unit.v2 import fakes +from novaclient.v2 import server_migrations class ServerMigrationsTest(utils.FixturedTestCase): @@ -31,3 +34,49 @@ class ServerMigrationsTest(utils.FixturedTestCase): body = {'force_complete': None} self.cs.server_migrations.live_migrate_force_complete(1234, 1) self.assert_called('POST', '/servers/1234/migrations/1/action', body) + + +class ServerMigrationsTestV223(ServerMigrationsTest): + + migration = { + "created_at": "2016-01-29T13:42:02.000000", + "dest_compute": "compute2", + "dest_host": "1.2.3.4", + "dest_node": "node2", + "id": 1, + "server_uuid": "4cfba335-03d8-49b2-8c52-e69043d1e8fe", + "source_compute": "compute1", + "source_node": "node1", + "status": "running", + "memory_total_bytes": 123456, + "memory_processed_bytes": 12345, + "memory_remaining_bytes": 120000, + "disk_total_bytes": 234567, + "disk_processed_bytes": 23456, + "disk_remaining_bytes": 230000, + "updated_at": "2016-01-29T13:42:02.000000" + } + + def setUp(self): + super(ServerMigrationsTestV223, self).setUp() + self.cs.api_version = api_versions.APIVersion("2.23") + + def test_list_migrations(self): + ml = self.cs.server_migrations.list(1234) + + self.assertIsInstance(ml, base.ListWithMeta) + self.assert_request_id(ml, fakes.FAKE_REQUEST_ID_LIST) + for k in self.migration: + self.assertEqual(self.migration[k], getattr(ml[0], k)) + + self.assert_called('GET', '/servers/1234/migrations') + + def test_get_migration(self): + migration = self.cs.server_migrations.get(1234, 1) + + self.assertIsInstance(migration, server_migrations.ServerMigration) + for k in migration._info: + self.assertEqual(self.migration[k], migration._info[k]) + self.assert_request_id(migration, fakes.FAKE_REQUEST_ID_LIST) + + self.assert_called('GET', '/servers/1234/migrations/1') diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py index cb30ce40..7d1502eb 100644 --- a/novaclient/tests/unit/v2/test_shell.py +++ b/novaclient/tests/unit/v2/test_shell.py @@ -1687,6 +1687,16 @@ class ShellTest(utils.TestCase): self.assert_called('POST', '/servers/1234/migrations/1/action', {'force_complete': None}) + def test_list_migrations(self): + self.run_command('server-migration-list sample-server', + api_version='2.23') + self.assert_called('GET', '/servers/1234/migrations') + + def test_get_migration(self): + self.run_command('server-migration-show sample-server 1', + api_version='2.23') + self.assert_called('GET', '/servers/1234/migrations/1') + def test_host_evacuate_live_with_no_target_host(self): self.run_command('host-evacuate-live hyper') self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0) @@ -2501,6 +2511,10 @@ class ShellTest(utils.TestCase): self.run_command('migration-list') self.assert_called('GET', '/os-migrations') + def test_migration_list_v223(self): + self.run_command('migration-list', api_version="2.23") + self.assert_called('GET', '/os-migrations') + def test_migration_list_with_filters(self): self.run_command('migration-list --host host1 --cell_name child1 ' '--status finished') diff --git a/novaclient/v2/contrib/migrations.py b/novaclient/v2/contrib/migrations.py index 15959818..6af81318 100644 --- a/novaclient/v2/contrib/migrations.py +++ b/novaclient/v2/contrib/migrations.py @@ -16,6 +16,7 @@ migration interface from six.moves.urllib import parse +from novaclient import api_versions from novaclient import base from novaclient.i18n import _ from novaclient.openstack.common import cliutils @@ -71,11 +72,11 @@ class MigrationManager(base.ManagerWithFind): help=_('Fetch migrations for the given cell_name.')) def do_migration_list(cs, args): """Print a list of migrations.""" - _print_migrations(cs.migrations.list(args.host, args.status, - args.cell_name)) + migrations = cs.migrations.list(args.host, args.status, args.cell_name) + _print_migrations(cs, migrations) -def _print_migrations(migrations): +def _print_migrations(cs, migrations): fields = ['Source Node', 'Dest Node', 'Source Compute', 'Dest Compute', 'Dest Host', 'Status', 'Instance UUID', 'Old Flavor', 'New Flavor', 'Created At', 'Updated At'] @@ -86,6 +87,14 @@ def _print_migrations(migrations): def new_flavor(migration): return migration.new_instance_type_id + def migration_type(migration): + return migration.migration_type + formatters = {'Old Flavor': old_flavor, 'New Flavor': new_flavor} + if cs.api_version >= api_versions.APIVersion("2.23"): + fields.insert(0, "Id") + fields.append("Type") + formatters.update({"Type": migration_type}) + utils.print_list(migrations, fields, formatters) diff --git a/novaclient/v2/server_migrations.py b/novaclient/v2/server_migrations.py index 476c0a80..68ee94c9 100644 --- a/novaclient/v2/server_migrations.py +++ b/novaclient/v2/server_migrations.py @@ -22,7 +22,7 @@ class ServerMigration(base.Resource): return "<ServerMigration>" -class ServerMigrationsManager(base.Manager): +class ServerMigrationsManager(base.ManagerWithFind): resource_class = ServerMigration @api_versions.wraps("2.22") @@ -40,3 +40,28 @@ class ServerMigrationsManager(base.Manager): base.getid(migration)), body=body) return self.convert_into_with_meta(body, resp) + + @api_versions.wraps("2.23") + def get(self, server, migration): + """ + Get a migration of a specified server + + :param server: The :class:`Server` (or its ID) + :param migration: Migration id that will be gotten. + :returns: An instance of + novaclient.v2.server_migrations.ServerMigration + """ + return self._get('/servers/%s/migrations/%s' % + (base.getid(server), base.getid(migration)), + 'migration') + + @api_versions.wraps("2.23") + def list(self, server): + """ + Get a migrations list of a specified server + + :param server: The :class:`Server` (or its ID) + :returns: An instance of novaclient.base.ListWithMeta + """ + return self._list( + '/servers/%s/migrations' % base.getid(server), "migrations") diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py index 9693fc71..1dc728f8 100644 --- a/novaclient/v2/shell.py +++ b/novaclient/v2/shell.py @@ -3847,6 +3847,42 @@ def do_live_migration_force_complete(cs, args): cs.server_migrations.live_migrate_force_complete(server, args.migration) +@api_versions.wraps("2.23") +@cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.')) +def do_server_migration_list(cs, args): + """Get the migrations list of specified server.""" + server = _find_server(cs, args.server) + migrations = cs.server_migrations.list(server) + + fields = ['Id', 'Source Node', 'Dest Node', 'Source Compute', + 'Dest Compute', 'Dest Host', 'Status', 'Server UUID', + 'Created At', 'Updated At'] + + format_name = ["Total Memory Bytes", "Processed Memory Bytes", + "Remaining Memory Bytes", "Total Disk Bytes", + "Processed Disk Bytes", "Remaining Disk Bytes"] + + format_key = ["memory_total_bytes", "memory_processed_bytes", + "memory_remaining_bytes", "disk_total_bytes", + "disk_processed_bytes", "disk_remaining_bytes"] + + formatters = map(lambda field: utils._make_field_formatter(field)[1], + format_key) + formatters = dict(zip(format_name, formatters)) + + utils.print_list(migrations, fields + format_name, formatters) + + +@api_versions.wraps("2.23") +@cliutils.arg('server', metavar='<server>', help=_('Name or ID of server.')) +@cliutils.arg('migration', metavar='<migration>', help=_('ID of migration.')) +def do_server_migration_show(cs, args): + """Get the migration of specified server.""" + server = _find_server(cs, args.server) + migration = cs.server_migrations.get(server, args.migration) + utils.print_dict(migration._info) + + @cliutils.arg( '--all-tenants', action='store_const', |