From a5267772186add4e37c454c5a97d0ea3a1c88a81 Mon Sep 17 00:00:00 2001
From: David Moreau Simard <dms@redhat.com>
Date: Wed, 9 Dec 2015 16:18:54 -0500
Subject: [PATCH] Make --image parameter optional in "server rebuild"

The command will now default to the image currently in-use by
the server, effectively making the --image parameter optional.

This commit also adds basic tests for ServerRebuild since there
wasn't any. Will add more full tests for it.

Change-Id: I733fd3ad5a825f06563c72aa430122e1a0e3b3b0
Closes-bug: #1524406
Co-Authored-By: David Moreau Simard <dms@redhat.com>
Co-Authored-By: Tang Chen <tangchen@cn.fujitsu.com>
---
 doc/source/command-objects/server.rst         |  5 +-
 openstackclient/compute/v2/server.py          | 11 +--
 .../tests/compute/v2/test_server.py           | 70 +++++++++++++++++++
 3 files changed, 79 insertions(+), 7 deletions(-)

diff --git a/doc/source/command-objects/server.rst b/doc/source/command-objects/server.rst
index fd487b8ea4..fc27597125 100644
--- a/doc/source/command-objects/server.rst
+++ b/doc/source/command-objects/server.rst
@@ -375,14 +375,15 @@ Rebuild server
 .. code:: bash
 
     os server rebuild
-        --image <image>
+        [--image <image>]
         [--password <password>]
         [--wait]
         <server>
 
 .. option:: --image <image>
 
-    Recreate server from this image
+    Recreate server from the specified image (name or ID). Defaults to the
+    currently used one.
 
 .. option:: --password <password>
 
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index 9e2721fb67..6dce8ed546 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -1096,8 +1096,8 @@ class RebuildServer(show.ShowOne):
         parser.add_argument(
             '--image',
             metavar='<image>',
-            required=True,
-            help=_('Recreate server from this image'),
+            help=_('Recreate server from the specified image (name or ID).'
+                   ' Defaults to the currently used one.'),
         )
         parser.add_argument(
             '--password',
@@ -1115,12 +1115,13 @@ class RebuildServer(show.ShowOne):
     def take_action(self, parsed_args):
         compute_client = self.app.client_manager.compute
 
-        # Lookup parsed_args.image
-        image = utils.find_resource(compute_client.images, parsed_args.image)
-
         server = utils.find_resource(
             compute_client.servers, parsed_args.server)
 
+        # If parsed_args.image is not set, default to the currently used one.
+        image_id = parsed_args.image or server._info.get('image', {}).get('id')
+        image = utils.find_resource(compute_client.images, image_id)
+
         server = server.rebuild(image, parsed_args.password)
         if parsed_args.wait:
             if utils.wait_for_status(
diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py
index 73d3cc6193..02eae4241e 100644
--- a/openstackclient/tests/compute/v2/test_server.py
+++ b/openstackclient/tests/compute/v2/test_server.py
@@ -736,6 +736,76 @@ class TestServerPause(TestServer):
         self.run_method_with_servers('pause', 3)
 
 
+class TestServerRebuild(TestServer):
+
+    def setUp(self):
+        super(TestServerRebuild, self).setUp()
+
+        # Return value for utils.find_resource for image
+        self.image = image_fakes.FakeImage.create_one_image()
+        self.cimages_mock.get.return_value = self.image
+
+        # Fake the rebuilt new server.
+        new_server = compute_fakes.FakeServer.create_one_server()
+
+        # Fake the server to be rebuilt. The IDs of them should be the same.
+        attrs = {
+            'id': new_server.id,
+            'image': {
+                'id': self.image.id
+            },
+            'networks': {},
+            'adminPass': 'passw0rd',
+        }
+        methods = {
+            'rebuild': new_server,
+        }
+        self.server = compute_fakes.FakeServer.create_one_server(
+            attrs=attrs,
+            methods=methods
+        )
+
+        # Return value for utils.find_resource for server.
+        self.servers_mock.get.return_value = self.server
+
+        self.cmd = server.RebuildServer(self.app, None)
+
+    def test_rebuild_with_current_image(self):
+        arglist = [
+            self.server.id,
+        ]
+        verifylist = [
+            ('server', self.server.id)
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # Get the command object to test.
+        self.cmd.take_action(parsed_args)
+
+        self.servers_mock.get.assert_called_with(self.server.id)
+        self.cimages_mock.get.assert_called_with(self.image.id)
+        self.server.rebuild.assert_called_with(self.image, None)
+
+    def test_rebuild_with_current_image_and_password(self):
+        password = 'password-xxx'
+        arglist = [
+            self.server.id,
+            '--password', password
+        ]
+        verifylist = [
+            ('server', self.server.id),
+            ('password', password)
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        # Get the command object to test
+        self.cmd.take_action(parsed_args)
+
+        self.servers_mock.get.assert_called_with(self.server.id)
+        self.cimages_mock.get.assert_called_with(self.image.id)
+        self.server.rebuild.assert_called_with(self.image, password)
+
+
 class TestServerResize(TestServer):
 
     def setUp(self):