From 92d0fbeafd146126897934a7ec57ebf2ccef8580 Mon Sep 17 00:00:00 2001
From: Richard Theis <rtheis@us.ibm.com>
Date: Wed, 29 Jun 2016 09:48:04 -0500
Subject: [PATCH] Add port security option to network commands

Add the "--enable-port-security" and "--disable-port-security" options
to the "network create" and "network set" commands. This supports setting
the default port security for ports created on a network.

Change-Id: I1deb505bd77cef2e4bc3c2dbbb0c450665136f47
Implements: blueprint neutron-client
---
 doc/source/command-objects/network.rst        | 26 ++++++++++++++++
 openstackclient/network/v2/network.py         | 30 +++++++++++++++++++
 openstackclient/tests/network/v2/fakes.py     |  3 ++
 .../tests/network/v2/test_network.py          | 18 +++++++++++
 .../bp-neutron-client-a0552f8ca909b665.yaml   |  5 ++++
 5 files changed, 82 insertions(+)

diff --git a/doc/source/command-objects/network.rst b/doc/source/command-objects/network.rst
index 0c472e7f18..5d9a5ca860 100644
--- a/doc/source/command-objects/network.rst
+++ b/doc/source/command-objects/network.rst
@@ -24,6 +24,7 @@ Create new network
         [--enable | --disable]
         [--share | --no-share]
         [--availability-zone-hint <availability-zone>]
+        [--enable-port-security | --disable-port-security]
         [--external [--default | --no-default] | --internal]
         [--provider-network-type <provider-network-type>]
         [--provider-physical-network <provider-physical-network>]
@@ -72,6 +73,20 @@ Create new network
 
     *Network version 2 only*
 
+.. option:: --enable-port-security
+
+    Enable port security by default for ports created on
+    this network (default)
+
+    *Network version 2 only*
+
+.. option:: --disable-port-security
+
+    Disable port security by default for ports created on
+    this network
+
+    *Network version 2 only*
+
 .. option:: --subnet <subnet>
 
     IPv4 subnet for fixed IPs (in CIDR notation)
@@ -191,6 +206,7 @@ Set network properties
         [--name <name>]
         [--enable | --disable]
         [--share | --no-share]
+        [--enable-port-security | --disable-port-security]
         [--external [--default | --no-default] | --internal]
         [--provider-network-type <provider-network-type>]
         [--provider-physical-network <provider-physical-network>]
@@ -218,6 +234,16 @@ Set network properties
 
     Do not share the network between projects
 
+.. option:: --enable-port-security
+
+    Enable port security by default for ports created on
+    this network
+
+.. option:: --disable-port-security
+
+    Disable port security by default for ports created on
+    this network
+
 .. option:: --external
 
     Set this network as an external network.
diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py
index 31dfc7983b..ccc02fd8e6 100644
--- a/openstackclient/network/v2/network.py
+++ b/openstackclient/network/v2/network.py
@@ -58,6 +58,10 @@ def _get_attrs(client_manager, parsed_args):
         attrs['shared'] = True
     if parsed_args.no_share:
         attrs['shared'] = False
+    if parsed_args.enable_port_security:
+        attrs['port_security_enabled'] = True
+    if parsed_args.disable_port_security:
+        attrs['port_security_enabled'] = False
 
     # "network set" command doesn't support setting project.
     if 'project' in parsed_args and parsed_args.project is not None:
@@ -197,6 +201,19 @@ class CreateNetwork(common.NetworkAndComputeShowOne):
                    "(Network Availability Zone extension required, "
                    "repeat option to set multiple availability zones)")
         )
+        port_security_group = parser.add_mutually_exclusive_group()
+        port_security_group.add_argument(
+            '--enable-port-security',
+            action='store_true',
+            help=_("Enable port security by default for ports created on "
+                   "this network (default)")
+        )
+        port_security_group.add_argument(
+            '--disable-port-security',
+            action='store_true',
+            help=_("Disable port security by default for ports created on "
+                   "this network")
+        )
         external_router_grp = parser.add_mutually_exclusive_group()
         external_router_grp.add_argument(
             '--external',
@@ -403,6 +420,19 @@ class SetNetwork(command.Command):
             action='store_true',
             help=_("Do not share the network between projects")
         )
+        port_security_group = parser.add_mutually_exclusive_group()
+        port_security_group.add_argument(
+            '--enable-port-security',
+            action='store_true',
+            help=_("Enable port security by default for ports created on "
+                   "this network")
+        )
+        port_security_group.add_argument(
+            '--disable-port-security',
+            action='store_true',
+            help=_("Disable port security by default for ports created on "
+                   "this network")
+        )
         external_router_grp = parser.add_mutually_exclusive_group()
         external_router_grp.add_argument(
             '--external',
diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py
index 50d9899cb0..8d5efe1456 100644
--- a/openstackclient/tests/network/v2/fakes.py
+++ b/openstackclient/tests/network/v2/fakes.py
@@ -285,6 +285,7 @@ class FakeNetwork(object):
             'availability_zones': [],
             'availability_zone_hints': [],
             'is_default': False,
+            'port_security_enabled': True,
         }
 
         # Overwrite default attributes.
@@ -296,6 +297,8 @@ class FakeNetwork(object):
         # Set attributes with special mapping in OpenStack SDK.
         network.project_id = network_attrs['tenant_id']
         network.is_router_external = network_attrs['router:external']
+        network.is_port_security_enabled = \
+            network_attrs['port_security_enabled']
 
         return network
 
diff --git a/openstackclient/tests/network/v2/test_network.py b/openstackclient/tests/network/v2/test_network.py
index 8fc9dadf8f..ffe6c973dc 100644
--- a/openstackclient/tests/network/v2/test_network.py
+++ b/openstackclient/tests/network/v2/test_network.py
@@ -55,6 +55,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
         'id',
         'is_default',
         'name',
+        'port_security_enabled',
         'project_id',
         'provider_network_type',
         'router:external',
@@ -70,6 +71,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
         _network.id,
         _network.is_default,
         _network.name,
+        _network.is_port_security_enabled,
         _network.project_id,
         _network.provider_network_type,
         network._format_router_external(_network.is_router_external),
@@ -151,6 +153,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
             "--provider-physical-network", "physnet1",
             "--provider-segment", "400",
             "--transparent-vlan",
+            "--enable-port-security",
             self._network.name,
         ]
         verifylist = [
@@ -165,6 +168,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
             ('physical_network', 'physnet1'),
             ('segmentation_id', '400'),
             ('transparent_vlan', True),
+            ('enable_port_security', True),
             ('name', self._network.name),
         ]
 
@@ -183,6 +187,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
             'provider:physical_network': 'physnet1',
             'provider:segmentation_id': '400',
             'vlan_transparent': True,
+            'port_security_enabled': True,
         })
         self.assertEqual(self.columns, columns)
         self.assertEqual(self.data, data)
@@ -191,6 +196,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
         arglist = [
             "--enable",
             "--no-share",
+            "--disable-port-security",
             self._network.name,
         ]
         verifylist = [
@@ -198,6 +204,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
             ('no_share', True),
             ('name', self._network.name),
             ('external', False),
+            ('disable_port_security', True),
         ]
 
         parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -207,6 +214,7 @@ class TestCreateNetworkIdentityV3(TestNetwork):
             'admin_state_up': True,
             'name': self._network.name,
             'shared': False,
+            'port_security_enabled': False,
         })
         self.assertEqual(self.columns, columns)
         self.assertEqual(self.data, data)
@@ -226,6 +234,7 @@ class TestCreateNetworkIdentityV2(TestNetwork):
         'id',
         'is_default',
         'name',
+        'port_security_enabled',
         'project_id',
         'provider_network_type',
         'router:external',
@@ -241,6 +250,7 @@ class TestCreateNetworkIdentityV2(TestNetwork):
         _network.id,
         _network.is_default,
         _network.name,
+        _network.is_port_security_enabled,
         _network.project_id,
         _network.provider_network_type,
         network._format_router_external(_network.is_router_external),
@@ -547,6 +557,7 @@ class TestSetNetwork(TestNetwork):
             '--provider-physical-network', 'physnet1',
             '--provider-segment', '400',
             '--no-transparent-vlan',
+            '--enable-port-security',
         ]
         verifylist = [
             ('network', self._network.name),
@@ -559,6 +570,7 @@ class TestSetNetwork(TestNetwork):
             ('physical_network', 'physnet1'),
             ('segmentation_id', '400'),
             ('no_transparent_vlan', True),
+            ('enable_port_security', True),
         ]
 
         parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -574,6 +586,7 @@ class TestSetNetwork(TestNetwork):
             'provider:physical_network': 'physnet1',
             'provider:segmentation_id': '400',
             'vlan_transparent': False,
+            'port_security_enabled': True,
         }
         self.network.update_network.assert_called_once_with(
             self._network, **attrs)
@@ -585,12 +598,14 @@ class TestSetNetwork(TestNetwork):
             '--disable',
             '--no-share',
             '--internal',
+            '--disable-port-security',
         ]
         verifylist = [
             ('network', self._network.name),
             ('disable', True),
             ('no_share', True),
             ('internal', True),
+            ('disable_port_security', True),
         ]
 
         parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -600,6 +615,7 @@ class TestSetNetwork(TestNetwork):
             'admin_state_up': False,
             'shared': False,
             'router:external': False,
+            'port_security_enabled': False,
         }
         self.network.update_network.assert_called_once_with(
             self._network, **attrs)
@@ -630,6 +646,7 @@ class TestShowNetwork(TestNetwork):
         'id',
         'is_default',
         'name',
+        'port_security_enabled',
         'project_id',
         'provider_network_type',
         'router:external',
@@ -645,6 +662,7 @@ class TestShowNetwork(TestNetwork):
         _network.id,
         _network.is_default,
         _network.name,
+        _network.is_port_security_enabled,
         _network.project_id,
         _network.provider_network_type,
         network._format_router_external(_network.is_router_external),
diff --git a/releasenotes/notes/bp-neutron-client-a0552f8ca909b665.yaml b/releasenotes/notes/bp-neutron-client-a0552f8ca909b665.yaml
index 8402e2c9c3..9224a46240 100644
--- a/releasenotes/notes/bp-neutron-client-a0552f8ca909b665.yaml
+++ b/releasenotes/notes/bp-neutron-client-a0552f8ca909b665.yaml
@@ -4,6 +4,11 @@ features:
     ``port set`` commands to support JSON input for more advanced
     binding profile data.
     [Blueprint :oscbp:`neutron-client`]
+  - Add ``--enable-port-security`` and ``--disable-port-security``
+    options on the ``network create`` and ``network set`` commands.
+    This supports setting the default port security for ports created
+    on a network.
+    [Blueprint :oscbp:`neutron-client`]
   - Add ``geneve`` choice to the  ``network create`` command
     ``--provider-network-type`` option.
     [Blueprint :oscbp:`neutron-client`]