From 5fdb861ad4835513c0cb78251cce85ac73f51dd4 Mon Sep 17 00:00:00 2001
From: Matt Riedemann <mriedem@us.ibm.com>
Date: Wed, 10 Jun 2015 13:40:05 -0700
Subject: [PATCH] Show reserved status for a fixed_ip if available

Commit 8886590f30daf736ae30a95b3e4a77cb586d4f02 adds the v2.4
microversion to nova so that we can get back the reserved value of a
fixed IP.

This change adds support to novaclient to display the reserved status
from the fixed_ip resource if it's available in the response.

Related blueprint show-reserved-status-in-os-fixed-ips-api

Change-Id: Idf3df1728ba87006d1b0f82a1c01712202670e0a
---
 novaclient/tests/functional/base.py          | 33 ++++++++++
 novaclient/tests/functional/test_fixedips.py | 67 ++++++++++++++++++++
 novaclient/v2/shell.py                       | 14 +++-
 3 files changed, 113 insertions(+), 1 deletion(-)
 create mode 100644 novaclient/tests/functional/test_fixedips.py

diff --git a/novaclient/tests/functional/base.py b/novaclient/tests/functional/base.py
index 8b0e17266..0f73aff17 100644
--- a/novaclient/tests/functional/base.py
+++ b/novaclient/tests/functional/base.py
@@ -243,3 +243,36 @@ class ClientTestBase(testtools.TestCase):
                 if l_property.strip() == key:
                     return l_value.strip()
         raise ValueError("Property '%s' is missing from the table." % key)
+
+    def _get_column_value_from_single_row_table(self, table, column):
+        """Get the value for the column in the single-row table
+
+        Example table:
+
+        +----------+-------------+----------+----------+
+        | address  | cidr        | hostname | host     |
+        +----------+-------------+----------+----------+
+        | 10.0.0.3 | 10.0.0.0/24 | test     | myhost   |
+        +----------+-------------+----------+----------+
+
+        :param table: newline-separated table with |-separated cells
+        :param column: name of the column to look for
+        :raises: ValueError if the column value is not found
+        """
+        lines = table.split("\n")
+        # Determine the column header index first.
+        column_index = -1
+        for line in lines:
+            if "|" in line:
+                if column_index == -1:
+                    headers = line.split("|")[1:-1]
+                    for index, header in enumerate(headers):
+                        if header.strip() == column:
+                            column_index = index
+                            break
+                else:
+                    # We expect a single-row table so we should be able to get
+                    # the value now using the column index.
+                    return line.split("|")[1:-1][column_index].strip()
+
+        raise ValueError("Unable to find value for column '%s'.")
diff --git a/novaclient/tests/functional/test_fixedips.py b/novaclient/tests/functional/test_fixedips.py
new file mode 100644
index 000000000..f6983070f
--- /dev/null
+++ b/novaclient/tests/functional/test_fixedips.py
@@ -0,0 +1,67 @@
+# Copyright 2015 IBM Corp.
+#    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 oslo_utils import strutils
+
+from novaclient.tests.functional import base
+from novaclient.v2 import shell
+
+
+class TestFixedIPsNovaClient(base.ClientTestBase):
+    """FixedIPs functional tests."""
+
+    API_VERSION = '2.1'
+
+    def nova(self, *args, **kwargs):
+        flags = '--os-compute-api-version %s ' % self.API_VERSION
+        return self.cli_clients.nova(flags=flags, *args, **kwargs)
+
+    def _create_server(self):
+        name = self.name_generate(prefix='server')
+        server = self.client.servers.create(name, self.image, self.flavor)
+        shell._poll_for_status(
+            self.client.servers.get, server.id,
+            'building', ['active'])
+        self.addCleanup(server.delete)
+        return server
+
+    def _test_fixedip_get(self, expect_reserved=False):
+        server = self._create_server()
+        networks = server.networks
+        self.assertIn('private', networks)
+        fixed_ip = networks['private'][0]
+        table = self.nova('fixed-ip-get %s' % fixed_ip)
+        addr = self._get_column_value_from_single_row_table(table, 'address')
+        self.assertEqual(fixed_ip, addr)
+        if expect_reserved:
+            reserved = self._get_column_value_from_single_row_table(table,
+                                                                    'reserved')
+            # By default the fixed IP should not be reserved.
+            self.assertEqual(False, strutils.bool_from_string(reserved,
+                                                              strict=True))
+        else:
+            self.assertRaises(ValueError,
+                              self._get_column_value_from_single_row_table,
+                              table, 'reserved')
+
+    def test_fixedip_get(self):
+        self._test_fixedip_get()
+
+
+class TestFixedIPsNovaClientV24(TestFixedIPsNovaClient):
+    """FixedIPs functional tests for v2.4 nova-api microversion."""
+
+    API_VERSION = '2.4'
+
+    def test_fixedip_get(self):
+        self._test_fixedip_get(expect_reserved=True)
diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py
index 6a2d3dad5..dcd27843e 100644
--- a/novaclient/v2/shell.py
+++ b/novaclient/v2/shell.py
@@ -3621,11 +3621,23 @@ def do_service_delete(cs, args):
     cs.services.delete(args.id)
 
 
+@api_versions.wraps("2.0", "2.3")
+def _print_fixed_ip(cs, fixed_ip):
+    fields = ['address', 'cidr', 'hostname', 'host']
+    utils.print_list([fixed_ip], fields)
+
+
+@api_versions.wraps("2.4")
+def _print_fixed_ip(cs, fixed_ip):
+    fields = ['address', 'cidr', 'hostname', 'host', 'reserved']
+    utils.print_list([fixed_ip], fields)
+
+
 @cliutils.arg('fixed_ip', metavar='<fixed_ip>', help=_('Fixed IP Address.'))
 def do_fixed_ip_get(cs, args):
     """Retrieve info on a fixed IP."""
     result = cs.fixed_ips.get(args.fixed_ip)
-    utils.print_list([result], ['address', 'cidr', 'hostname', 'host'])
+    _print_fixed_ip(cs, result)
 
 
 @cliutils.arg('fixed_ip', metavar='<fixed_ip>', help=_('Fixed IP Address.'))