From 3c2a817efcb6954f3c8246c32ce997b9e3a4d000 Mon Sep 17 00:00:00 2001 From: Mahesh Panchaksharaiah <maheshp@thoughtworks.com> Date: Fri, 19 Jul 2013 14:55:23 +0530 Subject: [PATCH] Added 'nova migration-list' command This command lets Admin's list migrations by applying filters Implements: blueprint list-resizes-through-admin-api Change-Id: I587c62dab537186cfc8b387fbc46cdb56fb9976c --- .../tests/v1_1/contrib/test_migrations.py | 42 ++++++++++ novaclient/tests/v1_1/fakes.py | 18 ++++ novaclient/tests/v1_1/test_shell.py | 11 +++ novaclient/v1_1/contrib/migrations.py | 84 +++++++++++++++++++ 4 files changed, 155 insertions(+) create mode 100644 novaclient/tests/v1_1/contrib/test_migrations.py create mode 100644 novaclient/v1_1/contrib/migrations.py diff --git a/novaclient/tests/v1_1/contrib/test_migrations.py b/novaclient/tests/v1_1/contrib/test_migrations.py new file mode 100644 index 000000000..7b49c4cc7 --- /dev/null +++ b/novaclient/tests/v1_1/contrib/test_migrations.py @@ -0,0 +1,42 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from novaclient import extension +from novaclient.tests import utils +from novaclient.tests.v1_1 import fakes +from novaclient.v1_1.contrib import migrations + +extensions = [ + extension.Extension(migrations.__name__.split(".")[-1], + migrations), +] +cs = fakes.FakeClient(extensions=extensions) + + +class MigrationsTest(utils.TestCase): + + def test_list_migrations(self): + ml = cs.migrations.list() + cs.assert_called('GET', '/os-migrations') + for m in ml: + self.assertTrue(isinstance(m, migrations.Migration)) + + def test_list_migrations_with_filters(self): + ml = cs.migrations.list('host1', 'finished', 'child1') + + cs.assert_called('GET', + '/os-migrations?status=finished&host=host1' + '&cell_name=child1') + for m in ml: + self.assertTrue(isinstance(m, migrations.Migration)) diff --git a/novaclient/tests/v1_1/fakes.py b/novaclient/tests/v1_1/fakes.py index 3e1e955a2..03e2c4847 100644 --- a/novaclient/tests/v1_1/fakes.py +++ b/novaclient/tests/v1_1/fakes.py @@ -1843,3 +1843,21 @@ class FakeHTTPClient(base_client.HTTPClient): def get_os_cells_child_cell_capacities(self, **kw): 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" + }]} + return (200, {}, migrations) diff --git a/novaclient/tests/v1_1/test_shell.py b/novaclient/tests/v1_1/test_shell.py index 1a08c0bb8..625b17789 100644 --- a/novaclient/tests/v1_1/test_shell.py +++ b/novaclient/tests/v1_1/test_shell.py @@ -1607,3 +1607,14 @@ class ShellTest(utils.TestCase): def test_cell_capacities_without_cell_name(self): self.run_command('cell-capacities') self.assert_called('GET', '/os-cells/capacities') + + def test_migration_list(self): + self.run_command('migration-list') + 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') + self.assert_called('GET', + '/os-migrations?status=finished&host=host1' + '&cell_name=child1') diff --git a/novaclient/v1_1/contrib/migrations.py b/novaclient/v1_1/contrib/migrations.py new file mode 100644 index 000000000..ee2f49963 --- /dev/null +++ b/novaclient/v1_1/contrib/migrations.py @@ -0,0 +1,84 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +migration interface +""" + +import urllib + +from novaclient import base +from novaclient import utils + + +class Migration(base.Resource): + def __repr__(self): + return "<Migration: %s>" % self.id + + +class MigrationManager(base.ManagerWithFind): + resource_class = Migration + + def list(self, host=None, status=None, cell_name=None): + """ + Get a list of migrations. + :param host: (optional) filter migrations by host name. + :param status: (optional) filter migrations by status. + :param cell_name: (optional) filter migrations for a cell. + """ + opts = {} + if host: + opts['host'] = host + if status: + opts['status'] = status + if cell_name: + opts['cell_name'] = cell_name + + query_string = "?%s" % urllib.urlencode(opts) if opts else "" + + return self._list("/os-migrations%s" % query_string, "migrations") + + +@utils.arg('--host', + dest='host', + metavar='<host>', + help='Fetch migrations for the given host.') +@utils.arg('--status', + dest='status', + metavar='<status>', + help='Fetch migrations for the given status.') +@utils.arg('--cell_name', + dest='cell_name', + metavar='<cell_name>', + 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)) + + +def _print_migrations(migrations): + fields = ['Source Node', 'Dest Node', 'Source Compute', 'Dest Compute', + 'Dest Host', 'Status', 'Instance UUID', 'Old Flavor', + 'New Flavor', 'Created At', 'Updated At'] + + def old_flavor(migration): + return migration.old_instance_type_id + + def new_flavor(migration): + return migration.new_instance_type_id + + formatters = {'Old Flavor': old_flavor, 'New Flavor': new_flavor} + + utils.print_list(migrations, fields, formatters)