Merge "Allow creating a Neutron port without fixed ips"
This commit is contained in:
commit
af0dd44dab
|
@ -14,6 +14,7 @@
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
|
from heat.common import exception
|
||||||
from heat.common.i18n import _
|
from heat.common.i18n import _
|
||||||
from heat.engine import attributes
|
from heat.engine import attributes
|
||||||
from heat.engine import constraints
|
from heat.engine import constraints
|
||||||
|
@ -53,11 +54,11 @@ class Port(neutron.NeutronResource):
|
||||||
EXTRA_PROPERTIES = (
|
EXTRA_PROPERTIES = (
|
||||||
VALUE_SPECS, ADMIN_STATE_UP, MAC_ADDRESS,
|
VALUE_SPECS, ADMIN_STATE_UP, MAC_ADDRESS,
|
||||||
ALLOWED_ADDRESS_PAIRS, VNIC_TYPE, QOS_POLICY,
|
ALLOWED_ADDRESS_PAIRS, VNIC_TYPE, QOS_POLICY,
|
||||||
PORT_SECURITY_ENABLED, PROPAGATE_UPLINK_STATUS,
|
PORT_SECURITY_ENABLED, PROPAGATE_UPLINK_STATUS, NO_FIXED_IPS,
|
||||||
) = (
|
) = (
|
||||||
'value_specs', 'admin_state_up', 'mac_address',
|
'value_specs', 'admin_state_up', 'mac_address',
|
||||||
'allowed_address_pairs', 'binding:vnic_type', 'qos_policy',
|
'allowed_address_pairs', 'binding:vnic_type', 'qos_policy',
|
||||||
'port_security_enabled', 'propagate_uplink_status',
|
'port_security_enabled', 'propagate_uplink_status', 'no_fixed_ips',
|
||||||
)
|
)
|
||||||
|
|
||||||
_FIXED_IP_KEYS = (
|
_FIXED_IP_KEYS = (
|
||||||
|
@ -313,6 +314,13 @@ class Port(neutron.NeutronResource):
|
||||||
update_allowed=True,
|
update_allowed=True,
|
||||||
support_status=support.SupportStatus(version='15.0.0')
|
support_status=support.SupportStatus(version='15.0.0')
|
||||||
),
|
),
|
||||||
|
NO_FIXED_IPS: properties.Schema(
|
||||||
|
properties.Schema.BOOLEAN,
|
||||||
|
_('Flag to disable all fixed ips on the port.'),
|
||||||
|
update_allowed=True,
|
||||||
|
support_status=support.SupportStatus(version='16.0.0'),
|
||||||
|
default=False
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Need to update properties_schema with other properties before
|
# Need to update properties_schema with other properties before
|
||||||
|
@ -442,6 +450,14 @@ class Port(neutron.NeutronResource):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
super(Port, self).validate()
|
||||||
|
fixed_ips = self.properties.get(self.FIXED_IPS)
|
||||||
|
no_fixed_ips = self.properties.get(self.NO_FIXED_IPS, False)
|
||||||
|
if fixed_ips and no_fixed_ips:
|
||||||
|
raise exception.ResourcePropertyConflict(self.FIXED_IPS,
|
||||||
|
self.NO_FIXED_IPS)
|
||||||
|
|
||||||
def add_dependencies(self, deps):
|
def add_dependencies(self, deps):
|
||||||
super(Port, self).add_dependencies(deps)
|
super(Port, self).add_dependencies(deps)
|
||||||
# Depend on any Subnet in this template with the same
|
# Depend on any Subnet in this template with the same
|
||||||
|
@ -480,24 +496,28 @@ class Port(neutron.NeutronResource):
|
||||||
self.set_tags(tags)
|
self.set_tags(tags)
|
||||||
|
|
||||||
def _prepare_port_properties(self, props, prepare_for_update=False):
|
def _prepare_port_properties(self, props, prepare_for_update=False):
|
||||||
if self.FIXED_IPS in props:
|
if not props.pop(self.NO_FIXED_IPS, False):
|
||||||
fixed_ips = props[self.FIXED_IPS]
|
if self.FIXED_IPS in props:
|
||||||
if fixed_ips:
|
fixed_ips = props[self.FIXED_IPS]
|
||||||
for fixed_ip in fixed_ips:
|
if fixed_ips:
|
||||||
for key, value in list(fixed_ip.items()):
|
for fixed_ip in fixed_ips:
|
||||||
if value is None:
|
for key, value in list(fixed_ip.items()):
|
||||||
fixed_ip.pop(key)
|
if value is None:
|
||||||
if self.FIXED_IP_SUBNET in fixed_ip:
|
fixed_ip.pop(key)
|
||||||
fixed_ip[
|
if self.FIXED_IP_SUBNET in fixed_ip:
|
||||||
'subnet_id'] = fixed_ip.pop(self.FIXED_IP_SUBNET)
|
fixed_ip['subnet_id'] = \
|
||||||
else:
|
fixed_ip.pop(self.FIXED_IP_SUBNET)
|
||||||
# Passing empty list would have created a port without
|
else:
|
||||||
# fixed_ips during CREATE and released the existing
|
# Passing empty list would have created a port without
|
||||||
# fixed_ips during UPDATE (default neutron behaviour).
|
# fixed_ips during CREATE and released the existing
|
||||||
# However, for backward compatibility we will let neutron
|
# fixed_ips during UPDATE (default neutron behaviour).
|
||||||
# assign ip for CREATE and leave the assigned ips during
|
# However, for backward compatibility we will let neutron
|
||||||
# UPDATE by not passing it. ref bug #1538473.
|
# assign ip for CREATE and leave the assigned ips during
|
||||||
del props[self.FIXED_IPS]
|
# UPDATE by not passing it. ref bug #1538473.
|
||||||
|
del props[self.FIXED_IPS]
|
||||||
|
else:
|
||||||
|
props[self.FIXED_IPS] = []
|
||||||
|
|
||||||
# delete empty MAC addresses so that Neutron validation code
|
# delete empty MAC addresses so that Neutron validation code
|
||||||
# wouldn't fail as it not accepts Nones
|
# wouldn't fail as it not accepts Nones
|
||||||
if self.ALLOWED_ADDRESS_PAIRS in props:
|
if self.ALLOWED_ADDRESS_PAIRS in props:
|
||||||
|
|
|
@ -56,6 +56,17 @@ resources:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
neutron_port_with_no_fixed_ips_template = '''
|
||||||
|
heat_template_version: 2015-04-30
|
||||||
|
description: Template to test port Neutron resource
|
||||||
|
resources:
|
||||||
|
port:
|
||||||
|
type: OS::Neutron::Port
|
||||||
|
properties:
|
||||||
|
network: abcd1234
|
||||||
|
no_fixed_ips: true
|
||||||
|
'''
|
||||||
|
|
||||||
neutron_port_security_template = '''
|
neutron_port_security_template = '''
|
||||||
heat_template_version: 2015-04-30
|
heat_template_version: 2015-04-30
|
||||||
description: Template to test port Neutron resource
|
description: Template to test port Neutron resource
|
||||||
|
@ -224,6 +235,34 @@ class NeutronPortTest(common.HeatTestCase):
|
||||||
'device_owner': ''
|
'device_owner': ''
|
||||||
}})
|
}})
|
||||||
|
|
||||||
|
def test_no_fixed_ips(self):
|
||||||
|
t = template_format.parse(neutron_port_with_no_fixed_ips_template)
|
||||||
|
stack = utils.parse_stack(t)
|
||||||
|
|
||||||
|
self.find_mock.return_value = 'abcd1234'
|
||||||
|
|
||||||
|
self.create_mock.return_value = {'port': {
|
||||||
|
"status": "BUILD",
|
||||||
|
"id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766"
|
||||||
|
}}
|
||||||
|
|
||||||
|
self.port_show_mock.return_value = {'port': {
|
||||||
|
"status": "ACTIVE",
|
||||||
|
"id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766",
|
||||||
|
}}
|
||||||
|
|
||||||
|
port = stack['port']
|
||||||
|
scheduler.TaskRunner(port.create)()
|
||||||
|
self.create_mock.assert_called_once_with({'port': {
|
||||||
|
'network_id': u'abcd1234',
|
||||||
|
'name': utils.PhysName(stack.name, 'port'),
|
||||||
|
'fixed_ips': [],
|
||||||
|
'admin_state_up': True,
|
||||||
|
'binding:vnic_type': 'normal',
|
||||||
|
'device_id': '',
|
||||||
|
'device_owner': ''
|
||||||
|
}})
|
||||||
|
|
||||||
def test_port_security_enabled(self):
|
def test_port_security_enabled(self):
|
||||||
t = template_format.parse(neutron_port_security_template)
|
t = template_format.parse(neutron_port_security_template)
|
||||||
stack = utils.parse_stack(t)
|
stack = utils.parse_stack(t)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Now the ``OS::Neutron::Port`` type supports the ``no_fixed_ips`` property,
|
||||||
|
which allows users to create a network port without any fixed ips.
|
Loading…
Reference in New Issue