From 8cceaddaac43729c068f0f99675967ee3a7b228a Mon Sep 17 00:00:00 2001
From: Rui Chen <chenrui.momo@gmail.com>
Date: Wed, 8 Jun 2016 18:23:01 +0800
Subject: [PATCH] Fix console url show command broken in microversion case

The response data of nova get_xxx_console API is changed
from "console" to "remote_console" in microversion 2.6, and nova
server side API schema verify the spice vnc type to "spice-html5",
update OSC code to apply these change so that OSC can work in
different nova microversion cases.

Change-Id: I3bb4fe057e656209d00d2bb308ac3f7f837cb03f
Closes-Bug: #1590318
---
 openstackclient/compute/v2/console.py         |  12 +-
 .../tests/compute/v2/test_console.py          | 149 ++++++++++++++++++
 2 files changed, 158 insertions(+), 3 deletions(-)
 create mode 100644 openstackclient/tests/compute/v2/test_console.py

diff --git a/openstackclient/compute/v2/console.py b/openstackclient/compute/v2/console.py
index 97d3f318f8..4179fa5c1e 100644
--- a/openstackclient/compute/v2/console.py
+++ b/openstackclient/compute/v2/console.py
@@ -93,7 +93,7 @@ class ShowConsoleURL(command.ShowOne):
             '--spice',
             dest='url_type',
             action='store_const',
-            const='spice',
+            const='spice-html5',
             help=_("Show SPICE console URL")
         )
         return parser
@@ -105,14 +105,20 @@ class ShowConsoleURL(command.ShowOne):
             parsed_args.server,
         )
 
+        data = None
         if parsed_args.url_type in ['novnc', 'xvpvnc']:
             data = server.get_vnc_console(parsed_args.url_type)
-        if parsed_args.url_type in ['spice']:
+        if parsed_args.url_type in ['spice-html5']:
             data = server.get_spice_console(parsed_args.url_type)
 
         if not data:
             return ({}, {})
 
         info = {}
-        info.update(data['console'])
+        # NOTE(Rui Chen): Return 'remote_console' in compute microversion API
+        #                 2.6 and later, return 'console' in compute
+        #                 microversion API from 2.0 to 2.5, do compatibility
+        #                 handle for different microversion API.
+        console_data = data.get('remote_console', data.get('console'))
+        info.update(console_data)
         return zip(*sorted(six.iteritems(info)))
diff --git a/openstackclient/tests/compute/v2/test_console.py b/openstackclient/tests/compute/v2/test_console.py
new file mode 100644
index 0000000000..6be081263c
--- /dev/null
+++ b/openstackclient/tests/compute/v2/test_console.py
@@ -0,0 +1,149 @@
+#   Copyright 2016 Huawei, Inc. All rights reserved.
+#
+#   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.
+#
+
+import mock
+
+from openstackclient.compute.v2 import console
+from openstackclient.tests.compute.v2 import fakes as compute_fakes
+
+
+class TestConsole(compute_fakes.TestComputev2):
+
+    def setUp(self):
+        super(TestConsole, self).setUp()
+        self.servers_mock = self.app.client_manager.compute.servers
+        self.servers_mock.reset_mock()
+
+
+class TestConsoleUrlShow(TestConsole):
+
+    def setUp(self):
+        super(TestConsoleUrlShow, self).setUp()
+        fake_console_data = {'remote_console': {'url': 'http://localhost',
+                                                'protocol': 'fake_protocol',
+                                                'type': 'fake_type'}}
+        methods = {
+            'get_vnc_console': fake_console_data,
+            'get_spice_console': fake_console_data,
+            'get_serial_console': fake_console_data,
+            'get_rdp_console': fake_console_data,
+            'get_mks_console': fake_console_data,
+        }
+        self.fake_server = compute_fakes.FakeServer.create_one_server(
+            methods=methods)
+        self.servers_mock.get.return_value = self.fake_server
+
+        self.columns = (
+            'protocol',
+            'type',
+            'url',
+        )
+        self.data = (
+            fake_console_data['remote_console']['protocol'],
+            fake_console_data['remote_console']['type'],
+            fake_console_data['remote_console']['url']
+        )
+
+        self.cmd = console.ShowConsoleURL(self.app, None)
+
+    def test_console_url_show_by_default(self):
+        arglist = [
+            'foo_vm',
+        ]
+        verifylist = [
+            ('url_type', 'novnc'),
+            ('server', 'foo_vm'),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+        columns, data = self.cmd.take_action(parsed_args)
+        self.fake_server.get_vnc_console.assert_called_once_with('novnc')
+        self.assertEqual(self.columns, columns)
+        self.assertEqual(self.data, data)
+
+    def test_console_url_show_with_novnc(self):
+        arglist = [
+            '--novnc',
+            'foo_vm',
+        ]
+        verifylist = [
+            ('url_type', 'novnc'),
+            ('server', 'foo_vm'),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+        columns, data = self.cmd.take_action(parsed_args)
+        self.fake_server.get_vnc_console.assert_called_once_with('novnc')
+        self.assertEqual(self.columns, columns)
+        self.assertEqual(self.data, data)
+
+    def test_console_url_show_with_xvpvnc(self):
+        arglist = [
+            '--xvpvnc',
+            'foo_vm',
+        ]
+        verifylist = [
+            ('url_type', 'xvpvnc'),
+            ('server', 'foo_vm'),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+        columns, data = self.cmd.take_action(parsed_args)
+        self.fake_server.get_vnc_console.assert_called_once_with('xvpvnc')
+        self.assertEqual(self.columns, columns)
+        self.assertEqual(self.data, data)
+
+    def test_console_url_show_with_spice(self):
+        arglist = [
+            '--spice',
+            'foo_vm',
+        ]
+        verifylist = [
+            ('url_type', 'spice-html5'),
+            ('server', 'foo_vm'),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+        columns, data = self.cmd.take_action(parsed_args)
+        self.fake_server.get_spice_console.assert_called_once_with(
+            'spice-html5')
+        self.assertEqual(self.columns, columns)
+        self.assertEqual(self.data, data)
+
+    def test_console_url_show_compatible(self):
+        methods = {
+            'get_vnc_console': {'console': {'url': 'http://localhost',
+                                            'type': 'fake_type'}},
+        }
+        old_fake_server = compute_fakes.FakeServer.create_one_server(
+            methods=methods)
+        old_columns = (
+            'type',
+            'url',
+        )
+        old_data = (
+            methods['get_vnc_console']['console']['type'],
+            methods['get_vnc_console']['console']['url']
+        )
+        arglist = [
+            'foo_vm',
+        ]
+        verifylist = [
+            ('url_type', 'novnc'),
+            ('server', 'foo_vm'),
+        ]
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+        with mock.patch.object(self.servers_mock, 'get',
+                               return_value=old_fake_server):
+            columns, data = self.cmd.take_action(parsed_args)
+            old_fake_server.get_vnc_console.assert_called_once_with('novnc')
+            self.assertEqual(old_columns, columns)
+            self.assertEqual(old_data, data)