From 4a9cb8eea8e47950cb30ecaa7572a23d80d5bfcd Mon Sep 17 00:00:00 2001
From: Hongbin Lu <hongbin034@gmail.com>
Date: Tue, 9 Jan 2018 21:24:08 +0000
Subject: [PATCH] Support filtering port with IP address substring

Change-Id: I9559f1c0a6db943705bd32aefb60d7ea7054dd1b
Related-Bug: #1718605
---
 doc/source/cli/command-objects/port.rst        |  9 +++++----
 openstackclient/network/v2/port.py             | 11 ++++++++---
 .../tests/unit/network/v2/test_port.py         | 18 ++++++++++++++++++
 ...ith-ip-address-substr-14c5805b241e402f.yaml |  7 +++++++
 4 files changed, 38 insertions(+), 7 deletions(-)
 create mode 100644 releasenotes/notes/allow-port-list-with-ip-address-substr-14c5805b241e402f.yaml

diff --git a/doc/source/cli/command-objects/port.rst b/doc/source/cli/command-objects/port.rst
index 335c22707a..bb037fa3e5 100644
--- a/doc/source/cli/command-objects/port.rst
+++ b/doc/source/cli/command-objects/port.rst
@@ -179,7 +179,7 @@ List ports
         [--router <router> | --server <server> | --device-id <device-id>]
         [--network <network>]
         [--mac-address <mac-address>]
-        [--fixed-ip subnet=<subnet>,ip-address=<ip-address>]
+        [--fixed-ip subnet=<subnet>,ip-address=<ip-address>,ip-substring=<ip-substring>]
         [--long]
         [--project <project> [--project-domain <project-domain>]]
         [--tags <tag>[,<tag>,...]] [--any-tags <tag>[,<tag>,...]]
@@ -210,10 +210,11 @@ List ports
 
     List only ports with this MAC address
 
-.. option:: --fixed-ip subnet=<subnet>,ip-address=<ip-address>
+.. option:: --fixed-ip subnet=<subnet>,ip-address=<ip-address>,ip-substring=<ip-substring>
 
-    Desired IP and/or subnet for filtering ports (name or ID):
-    subnet=<subnet>,ip-address=<ip-address>
+    Desired IP address, IP address substring and/or subnet (name or ID) for
+    filtering ports:
+    subnet=<subnet>,ip-address=<ip-address>,ip-substring=<ip-substring>
     (repeat option to set multiple fixed IP addresses)
 
 .. option:: --long
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index f13ee7b90b..af6efa9d0a 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -215,6 +215,9 @@ def _prepare_filter_fixed_ips(client_manager, parsed_args):
 
         if 'ip-address' in ip_spec:
             ips.append('ip_address=%s' % ip_spec['ip-address'])
+
+        if 'ip-substring' in ip_spec:
+            ips.append('ip_address_substr=%s' % ip_spec['ip-substring'])
     return ips
 
 
@@ -531,11 +534,13 @@ class ListPort(command.Lister):
         identity_common.add_project_domain_option_to_parser(parser)
         parser.add_argument(
             '--fixed-ip',
-            metavar='subnet=<subnet>,ip-address=<ip-address>',
+            metavar=('subnet=<subnet>,ip-address=<ip-address>,'
+                     'ip-substring=<ip-substring>'),
             action=parseractions.MultiKeyValueAction,
-            optional_keys=['subnet', 'ip-address'],
+            optional_keys=['subnet', 'ip-address', 'ip-substring'],
             help=_("Desired IP and/or subnet for filtering ports "
-                   "(name or ID): subnet=<subnet>,ip-address=<ip-address> "
+                   "(name or ID): subnet=<subnet>,ip-address=<ip-address>,"
+                   "ip-substring=<ip-substring> "
                    "(repeat option to set multiple fixed IP addresses)"),
         )
         _tag.add_tag_filtering_option_to_parser(parser, _('ports'))
diff --git a/openstackclient/tests/unit/network/v2/test_port.py b/openstackclient/tests/unit/network/v2/test_port.py
index 03e1d841bd..78d7fd6ca1 100644
--- a/openstackclient/tests/unit/network/v2/test_port.py
+++ b/openstackclient/tests/unit/network/v2/test_port.py
@@ -867,6 +867,24 @@ class TestListPort(TestPort):
         self.assertEqual(self.columns, columns)
         self.assertEqual(self.data, list(data))
 
+    def test_port_list_fixed_ip_opt_ip_address_substr(self):
+        ip_address_ss = self._ports[0].fixed_ips[0]['ip_address'][:-1]
+        arglist = [
+            '--fixed-ip', "ip-substring=%s" % ip_address_ss,
+        ]
+        verifylist = [
+            ('fixed_ip', [{'ip-substring': ip_address_ss}])
+        ]
+
+        parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+        columns, data = self.cmd.take_action(parsed_args)
+
+        self.network.ports.assert_called_once_with(**{
+            'fixed_ips': ['ip_address_substr=%s' % ip_address_ss]})
+        self.assertEqual(self.columns, columns)
+        self.assertEqual(self.data, list(data))
+
     def test_port_list_fixed_ip_opt_subnet_id(self):
         subnet_id = self._ports[0].fixed_ips[0]['subnet_id']
         arglist = [
diff --git a/releasenotes/notes/allow-port-list-with-ip-address-substr-14c5805b241e402f.yaml b/releasenotes/notes/allow-port-list-with-ip-address-substr-14c5805b241e402f.yaml
new file mode 100644
index 0000000000..bbb0af6ba0
--- /dev/null
+++ b/releasenotes/notes/allow-port-list-with-ip-address-substr-14c5805b241e402f.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    Add an ``ip-substring`` key to the ``--fixed-ip`` option of the
+    ``port list`` command.  This allows filtering ports by a substring
+    match of an IP address.
+    [Bug `1718605 <https://bugs.launchpad.net/bugs/1718605>`_]
\ No newline at end of file