From 1c3cf11331a5734700e1c333c98928ab933c0e92 Mon Sep 17 00:00:00 2001
From: hackertron <jayadityagupta11@gmail.com>
Date: Thu, 2 Apr 2020 13:47:02 +0200
Subject: [PATCH] Add 'server migration abort' command

This is equivalent to nova client's 'live-migration-abort' command.

Change-Id: I0ff520ccfdf2de52c427affad7bef4554c86a06f
Story: 2007489
Task: 39210
---
 openstackclient/compute/v2/server.py          | 38 +++++++++++++
 .../tests/unit/compute/v2/fakes.py            |  3 +
 .../tests/unit/compute/v2/test_server.py      | 56 +++++++++++++++++++
 .../notes/bug-2007489-42e41b14e42128ce.yaml   |  4 ++
 setup.cfg                                     |  1 +
 5 files changed, 102 insertions(+)
 create mode 100644 releasenotes/notes/bug-2007489-42e41b14e42128ce.yaml

diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index f8d6aad0e8..0a96eb86de 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -2026,6 +2026,44 @@ class ListMigration(command.Command):
         return self.print_migrations(parsed_args, compute_client, migrations)
 
 
+class AbortMigration(command.Command):
+    """Cancel an ongoing live migration.
+
+    This command requires ``--os-compute-api-version`` 2.24 or greater.
+    """
+
+    def get_parser(self, prog_name):
+        parser = super(AbortMigration, self).get_parser(prog_name)
+        parser.add_argument(
+            'server',
+            metavar='<server>',
+            help=_('Server (name or ID)'),
+        )
+        parser.add_argument(
+            'migration',
+            metavar='<migration>',
+            help=_("Migration (ID)"),
+        )
+        return parser
+
+    def take_action(self, parsed_args):
+        compute_client = self.app.client_manager.compute
+
+        if compute_client.api_version < api_versions.APIVersion('2.24'):
+            msg = _(
+                '--os-compute-api-version 2.24 or greater is required to '
+                'support the server migration abort command'
+            )
+            raise exceptions.CommandError(msg)
+
+        server = utils.find_resource(
+            compute_client.servers,
+            parsed_args.server,
+        )
+        compute_client.server_migrations.live_migration_abort(
+            server.id, parsed_args.migration)
+
+
 class PauseServer(command.Command):
     _description = _("Pause server(s)")
 
diff --git a/openstackclient/tests/unit/compute/v2/fakes.py b/openstackclient/tests/unit/compute/v2/fakes.py
index 6aeb5da72f..ce556fa6cd 100644
--- a/openstackclient/tests/unit/compute/v2/fakes.py
+++ b/openstackclient/tests/unit/compute/v2/fakes.py
@@ -196,6 +196,9 @@ class FakeComputev2Client(object):
         self.server_groups = mock.Mock()
         self.server_groups.resource_class = fakes.FakeResource(None, {})
 
+        self.server_migrations = mock.Mock()
+        self.server_migrations.resource_class = fakes.FakeResource(None, {})
+
         self.instance_action = mock.Mock()
         self.instance_action.resource_class = fakes.FakeResource(None, {})
 
diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py
index a9f72cf6da..9ac2935236 100644
--- a/openstackclient/tests/unit/compute/v2/test_server.py
+++ b/openstackclient/tests/unit/compute/v2/test_server.py
@@ -42,6 +42,11 @@ class TestServer(compute_fakes.TestComputev2):
         self.servers_mock = self.app.client_manager.compute.servers
         self.servers_mock.reset_mock()
 
+        # Get a shortcut to the compute client ServerMigrationsManager Mock
+        self.server_migrations_mock = \
+            self.app.client_manager.compute.server_migrations
+        self.server_migrations_mock.reset_mock()
+
         # Get a shortcut to the compute client volumeManager Mock
         self.servers_volumes_mock = self.app.client_manager.compute.volumes
         self.servers_volumes_mock.reset_mock()
@@ -4207,6 +4212,57 @@ class TestListMigrationV280(TestListMigration):
                           parsed_args)
 
 
+class TestServerMigrationAbort(TestServer):
+
+    def setUp(self):
+        super(TestServerMigrationAbort, self).setUp()
+
+        self.server = compute_fakes.FakeServer.create_one_server()
+
+        # Return value for utils.find_resource for server.
+        self.servers_mock.get.return_value = self.server
+
+        # Get the command object to test
+        self.cmd = server.AbortMigration(self.app, None)
+
+    def test_migration_abort(self):
+        self.app.client_manager.compute.api_version = api_versions.APIVersion(
+            '2.24')
+
+        arglist = [
+            self.server.id,
+            '2',  # arbitrary migration ID
+        ]
+        verifylist = []
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        result = self.cmd.take_action(parsed_args)
+
+        self.servers_mock.get.assert_called_with(self.server.id)
+        self.server_migrations_mock.live_migration_abort.assert_called_with(
+            self.server.id, '2',)
+        self.assertIsNone(result)
+
+    def test_migration_abort_pre_v224(self):
+        self.app.client_manager.compute.api_version = api_versions.APIVersion(
+            '2.23')
+
+        arglist = [
+            self.server.id,
+            '2',  # arbitrary migration ID
+        ]
+        verifylist = []
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        ex = self.assertRaises(
+            exceptions.CommandError,
+            self.cmd.take_action,
+            parsed_args)
+        self.assertIn(
+            '--os-compute-api-version 2.24 or greater is required',
+            str(ex))
+
+
 class TestServerPause(TestServer):
 
     def setUp(self):
diff --git a/releasenotes/notes/bug-2007489-42e41b14e42128ce.yaml b/releasenotes/notes/bug-2007489-42e41b14e42128ce.yaml
new file mode 100644
index 0000000000..99dd5062b0
--- /dev/null
+++ b/releasenotes/notes/bug-2007489-42e41b14e42128ce.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Add ``server migration abort`` command to abort ongoing live migrations.
diff --git a/setup.cfg b/setup.cfg
index 6cf18cc29b..56934a192b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -109,6 +109,7 @@ openstack.compute.v2 =
     server_migrate_confirm = openstackclient.compute.v2.server:MigrateConfirm
     server_migrate_revert = openstackclient.compute.v2.server:MigrateRevert
     server_migration_list = openstackclient.compute.v2.server:ListMigration
+    server_migration_abort = openstackclient.compute.v2.server:AbortMigration
     server_pause = openstackclient.compute.v2.server:PauseServer
     server_reboot = openstackclient.compute.v2.server:RebootServer
     server_rebuild = openstackclient.compute.v2.server:RebuildServer