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)