From cdde2f527263dc4a1aa6be4b86179e7e1b8bb210 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Mon, 4 May 2015 18:19:06 -0700 Subject: [PATCH] Add port_security_enabled for Neutron In Kilo cycle, Neutron introduced a new attribute to port, port_security_enabled which isn't supported by HEAT yet. This patch adds its support. OS::Neutron::Port support port_security_enabled OS::Neutron::Net support port_security_enabled Change-Id: I0f33afe9fac835da9041ff48695bb8cd18660383 Closes-Bug: #1451629 Co-Authored-By: Yalei Wang --- .../engine/resources/openstack/neutron/net.py | 21 ++++++- .../resources/openstack/neutron/port.py | 18 ++++++ heat/tests/neutron/test_neutron.py | 1 + .../tests/neutron/test_neutron_floating_ip.py | 4 ++ heat/tests/neutron/test_neutron_net.py | 5 +- heat/tests/neutron/test_neutron_port.py | 57 +++++++++++++++++++ 6 files changed, 103 insertions(+), 3 deletions(-) diff --git a/heat/engine/resources/openstack/neutron/net.py b/heat/engine/resources/openstack/neutron/net.py index 896fd01f89..9264c202f8 100644 --- a/heat/engine/resources/openstack/neutron/net.py +++ b/heat/engine/resources/openstack/neutron/net.py @@ -15,21 +15,24 @@ from heat.common.i18n import _ from heat.engine import attributes from heat.engine import properties from heat.engine.resources.openstack.neutron import neutron +from heat.engine import support class Net(neutron.NeutronResource): PROPERTIES = ( NAME, VALUE_SPECS, ADMIN_STATE_UP, TENANT_ID, SHARED, - DHCP_AGENT_IDS, + DHCP_AGENT_IDS, PORT_SECURITY_ENABLED, ) = ( 'name', 'value_specs', 'admin_state_up', 'tenant_id', 'shared', - 'dhcp_agent_ids', + 'dhcp_agent_ids', 'port_security_enabled', ) ATTRIBUTES = ( STATUS, NAME_ATTR, SUBNETS, ADMIN_STATE_UP_ATTR, TENANT_ID_ATTR, SHOW, + PORT_SECURITY_ENABLED_ATTR, ) = ( "status", "name", "subnets", "admin_state_up", "tenant_id", "show", + "port_security_enabled", ) properties_schema = { @@ -75,6 +78,15 @@ class Net(neutron.NeutronResource): 'property to administrative users only.'), update_allowed=True ), + PORT_SECURITY_ENABLED: properties.Schema( + properties.Schema.BOOLEAN, + _('Flag to enable/disable port security on the network. It ' + 'provides the default value for the attribute of the ports ' + 'created on this network'), + default=True, + update_allowed=True, + support_status=support.SupportStatus(version='5.0.0') + ), } attributes_schema = { @@ -102,6 +114,11 @@ class Net(neutron.NeutronResource): _("All attributes."), type=attributes.Schema.MAP ), + PORT_SECURITY_ENABLED_ATTR: attributes.Schema( + _("Port security enabled of the network."), + support_status=support.SupportStatus(version='5.0.0'), + type=attributes.Schema.BOOLEAN + ), } def handle_create(self): diff --git a/heat/engine/resources/openstack/neutron/port.py b/heat/engine/resources/openstack/neutron/port.py index adebae3566..98ac867003 100644 --- a/heat/engine/resources/openstack/neutron/port.py +++ b/heat/engine/resources/openstack/neutron/port.py @@ -34,11 +34,13 @@ class Port(neutron.NeutronResource): ADMIN_STATE_UP, FIXED_IPS, MAC_ADDRESS, DEVICE_ID, SECURITY_GROUPS, ALLOWED_ADDRESS_PAIRS, DEVICE_OWNER, REPLACEMENT_POLICY, VNIC_TYPE, + PORT_SECURITY_ENABLED, ) = ( 'network_id', 'network', 'name', 'value_specs', 'admin_state_up', 'fixed_ips', 'mac_address', 'device_id', 'security_groups', 'allowed_address_pairs', 'device_owner', 'replacement_policy', 'binding:vnic_type', + 'port_security_enabled', ) _FIXED_IP_KEYS = ( @@ -57,10 +59,12 @@ class Port(neutron.NeutronResource): ADMIN_STATE_UP_ATTR, DEVICE_ID_ATTR, DEVICE_OWNER_ATTR, FIXED_IPS_ATTR, MAC_ADDRESS_ATTR, NAME_ATTR, NETWORK_ID_ATTR, SECURITY_GROUPS_ATTR, STATUS, TENANT_ID, ALLOWED_ADDRESS_PAIRS_ATTR, SHOW, SUBNETS_ATTR, + PORT_SECURITY_ENABLED_ATTR, ) = ( 'admin_state_up', 'device_id', 'device_owner', 'fixed_ips', 'mac_address', 'name', 'network_id', 'security_groups', 'status', 'tenant_id', 'allowed_address_pairs', 'show', 'subnets', + 'port_security_enabled', ) properties_schema = { @@ -217,6 +221,15 @@ class Port(neutron.NeutronResource): support_status=support.SupportStatus(version='2015.1'), update_allowed=True ), + PORT_SECURITY_ENABLED: properties.Schema( + properties.Schema.BOOLEAN, + _('Flag to enable/disable port security on the port. ' + 'When disable this feature(set it to False), there will be no ' + 'packages filtering, like security-group and address-pairs.'), + default=True, + update_allowed=True, + support_status=support.SupportStatus(version='5.0.0') + ), } attributes_schema = { @@ -273,6 +286,11 @@ class Port(neutron.NeutronResource): _("A list of all subnet attributes for the port."), type=attributes.Schema.LIST ), + PORT_SECURITY_ENABLED_ATTR: attributes.Schema( + _("Port security enabled of the port."), + support_status=support.SupportStatus(version='5.0.0'), + type=attributes.Schema.BOOLEAN + ), } def validate(self): diff --git a/heat/tests/neutron/test_neutron.py b/heat/tests/neutron/test_neutron.py index 1699af95dc..2642ca1c0d 100644 --- a/heat/tests/neutron/test_neutron.py +++ b/heat/tests/neutron/test_neutron.py @@ -84,6 +84,7 @@ class NeutronTest(common.HeatTestCase): self.assertEqual({'name': 'resource_name', 'router:external': True, 'admin_state_up': False, + 'port_security_enabled': True, 'shared': False}, props) def test_is_built(self): diff --git a/heat/tests/neutron/test_neutron_floating_ip.py b/heat/tests/neutron/test_neutron_floating_ip.py index b75105126a..e9d9c43b76 100644 --- a/heat/tests/neutron/test_neutron_floating_ip.py +++ b/heat/tests/neutron/test_neutron_floating_ip.py @@ -246,6 +246,7 @@ class NeutronFloatingIPTest(common.HeatTestCase): {'subnet_id': u'sub1234', 'ip_address': u'10.0.0.10'} ], 'name': utils.PhysName('test_stack', 'port_floating'), + 'port_security_enabled': True, 'admin_state_up': True}} ).AndReturn({'port': { "status": "BUILD", @@ -283,6 +284,7 @@ class NeutronFloatingIPTest(common.HeatTestCase): 'name': 'test_port', 'device_id': 'd6b4d3a5-c700-476f-b609-1493dd9dadc2', 'device_owner': 'network:floatingip', + 'port_security_enabled': True, 'security_groups': [ '8a2f582a-e1cd-480f-b85d-b02631c10656'] } @@ -356,6 +358,7 @@ class NeutronFloatingIPTest(common.HeatTestCase): {'subnet_id': u'sub1234', 'ip_address': u'10.0.0.10'} ], 'name': utils.PhysName('test_stack', 'port_floating'), + 'port_security_enabled': True, 'admin_state_up': True}} ).AndReturn({'port': { "status": "BUILD", @@ -602,6 +605,7 @@ class NeutronFloatingIPTest(common.HeatTestCase): {'subnet_id': u'sub1234', 'ip_address': u'10.0.0.10'} ], 'name': utils.PhysName('test_stack', 'port_floating'), + 'port_security_enabled': True, 'admin_state_up': True}} ).AndReturn({'port': { "status": "BUILD", diff --git a/heat/tests/neutron/test_neutron_net.py b/heat/tests/neutron/test_neutron_net.py index 576d79fb51..fa3b335e92 100644 --- a/heat/tests/neutron/test_neutron_net.py +++ b/heat/tests/neutron/test_neutron_net.py @@ -37,6 +37,7 @@ resources: shared: true dhcp_agent_ids: - 28c25a04-3f73-45a7-a2b4-59e183943ddc + port_security_enabled: False subnet: type: OS::Neutron::Subnet @@ -102,6 +103,7 @@ class NeutronNetTest(common.HeatTestCase): 'name': u'the_network', 'admin_state_up': True, 'tenant_id': 'c1210485b2424d48804aad5d39c61b8f', + 'port_security_enabled': False, 'shared': True} }).AndReturn({"network": { "status": "BUILD", @@ -215,7 +217,8 @@ class NeutronNetTest(common.HeatTestCase): {'network': { 'shared': True, 'name': 'mynet', - 'admin_state_up': True + 'admin_state_up': True, + 'port_security_enabled': False }}).AndReturn(None) # Delete script diff --git a/heat/tests/neutron/test_neutron_port.py b/heat/tests/neutron/test_neutron_port.py index 32a6e47741..d795c7b054 100644 --- a/heat/tests/neutron/test_neutron_port.py +++ b/heat/tests/neutron/test_neutron_port.py @@ -54,6 +54,18 @@ resources: ''' +neutron_port_security_template = ''' +heat_template_version: 2015-04-30 +description: Template to test port Neutron resource +resources: + port: + type: OS::Neutron::Port + properties: + network: abcd1234 + port_security_enabled: False +''' + + class NeutronPortTest(common.HeatTestCase): def setUp(self): @@ -77,6 +89,7 @@ class NeutronPortTest(common.HeatTestCase): ], 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'}} ).AndReturn({'port': { "status": "BUILD", @@ -119,6 +132,7 @@ class NeutronPortTest(common.HeatTestCase): ], 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'}} ).AndReturn({'port': { "status": "BUILD", @@ -151,6 +165,7 @@ class NeutronPortTest(common.HeatTestCase): 'network_id': u'net1234', 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'}} ).AndReturn({'port': { "status": "BUILD", @@ -190,6 +205,7 @@ class NeutronPortTest(common.HeatTestCase): 'mac_address': u'00-B0-D0-86-BB-F7' }], 'name': utils.PhysName('test_stack', 'port'), + 'port_security_enabled': True, 'admin_state_up': True}} ).AndReturn({'port': { "status": "BUILD", @@ -211,6 +227,39 @@ class NeutronPortTest(common.HeatTestCase): scheduler.TaskRunner(port.create)() self.m.VerifyAll() + def test_port_security_enabled(self): + neutronV20.find_resourceid_by_name_or_id( + mox.IsA(neutronclient.Client), + 'network', + 'abcd1234' + ).MultipleTimes().AndReturn('abcd1234') + + neutronclient.Client.create_port({'port': { + 'network_id': u'abcd1234', + 'port_security_enabled': False, + 'name': utils.PhysName('test_stack', 'port'), + 'admin_state_up': True}} + ).AndReturn({'port': { + "status": "BUILD", + "id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766" + }}) + + neutronclient.Client.show_port( + 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' + ).AndReturn({'port': { + "status": "ACTIVE", + "id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766", + }}) + + self.m.ReplayAll() + + t = template_format.parse(neutron_port_security_template) + stack = utils.parse_stack(t) + + port = stack['port'] + scheduler.TaskRunner(port.create)() + self.m.VerifyAll() + def test_missing_mac_address(self): neutronV20.find_resourceid_by_name_or_id( mox.IsA(neutronclient.Client), @@ -223,6 +272,7 @@ class NeutronPortTest(common.HeatTestCase): 'ip_address': u'10.0.3.21', }], 'name': utils.PhysName('test_stack', 'port'), + 'port_security_enabled': True, 'admin_state_up': True}} ).AndReturn({'port': { "status": "BUILD", @@ -281,6 +331,7 @@ class NeutronPortTest(common.HeatTestCase): ], 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'} self._mock_create_with_security_groups(port_prop) @@ -305,6 +356,7 @@ class NeutronPortTest(common.HeatTestCase): ], 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'} self._mock_create_with_security_groups(port_prop) @@ -322,6 +374,7 @@ class NeutronPortTest(common.HeatTestCase): props = {'network_id': u'net1234', 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'} new_props = props.copy() new_props['name'] = "new_name" @@ -406,6 +459,7 @@ class NeutronPortTest(common.HeatTestCase): props = {'network_id': u'net1234', 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'} neutronV20.find_resourceid_by_name_or_id( @@ -479,6 +533,7 @@ class NeutronPortTest(common.HeatTestCase): 'network_id': u'net1234', 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'}} ).AndReturn({'port': { 'status': 'BUILD', @@ -541,6 +596,7 @@ class NeutronPortTest(common.HeatTestCase): 'network_id': u'net1234', 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': u'network:dhcp'}} ).AndReturn({'port': { 'status': 'BUILD', @@ -587,6 +643,7 @@ class NeutronPortTest(common.HeatTestCase): ], 'name': utils.PhysName('test_stack', 'port'), 'admin_state_up': True, + 'port_security_enabled': True, 'device_owner': 'network:dhcp', 'binding:vnic_type': 'direct' }