Add segment property for subnet
Change-Id: I662e47c618ece613d4cc9b2a2bd340c0cf64adbb Partially-Implements: blueprint neutron-routed-networks
This commit is contained in:
parent
889c1c774e
commit
a466f2a56f
|
@ -16,6 +16,9 @@ from openstack import exceptions
|
|||
from openstack import profile
|
||||
|
||||
from heat.engine.clients import client_plugin
|
||||
from heat.engine import constraints
|
||||
|
||||
CLIENT_NAME = 'openstack'
|
||||
|
||||
|
||||
class OpenStackSDKPlugin(client_plugin.ClientPlugin):
|
||||
|
@ -43,3 +46,16 @@ class OpenStackSDKPlugin(client_plugin.ClientPlugin):
|
|||
|
||||
def is_not_found(self, ex):
|
||||
return isinstance(ex, exceptions.ResourceNotFound)
|
||||
|
||||
def find_network_segment(self, value):
|
||||
return self.client().network.find_segment(value).id
|
||||
|
||||
|
||||
class SegmentConstraint(constraints.BaseCustomConstraint):
|
||||
|
||||
expected_exceptions = (exceptions.ResourceNotFound,
|
||||
exceptions.DuplicateResource)
|
||||
|
||||
def validate_with_client(self, client, value):
|
||||
sdk_plugin = client.client_plugin(CLIENT_NAME)
|
||||
sdk_plugin.find_network_segment(value)
|
||||
|
|
|
@ -38,12 +38,12 @@ class Subnet(neutron.NeutronResource):
|
|||
NETWORK_ID, NETWORK, SUBNETPOOL, PREFIXLEN, CIDR,
|
||||
VALUE_SPECS, NAME, IP_VERSION, DNS_NAMESERVERS, GATEWAY_IP,
|
||||
ENABLE_DHCP, ALLOCATION_POOLS, TENANT_ID, HOST_ROUTES,
|
||||
IPV6_RA_MODE, IPV6_ADDRESS_MODE,
|
||||
IPV6_RA_MODE, IPV6_ADDRESS_MODE, SEGMENT
|
||||
) = (
|
||||
'network_id', 'network', 'subnetpool', 'prefixlen', 'cidr',
|
||||
'value_specs', 'name', 'ip_version', 'dns_nameservers', 'gateway_ip',
|
||||
'enable_dhcp', 'allocation_pools', 'tenant_id', 'host_routes',
|
||||
'ipv6_ra_mode', 'ipv6_address_mode',
|
||||
'ipv6_ra_mode', 'ipv6_address_mode', 'segment'
|
||||
)
|
||||
|
||||
_ALLOCATION_POOL_KEYS = (
|
||||
|
@ -236,6 +236,14 @@ class Subnet(neutron.NeutronResource):
|
|||
],
|
||||
support_status=support.SupportStatus(version='2015.1')
|
||||
),
|
||||
SEGMENT: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('The name/ID of the segment to associate.'),
|
||||
constraints=[
|
||||
constraints.CustomConstraint('neutron.segment')
|
||||
],
|
||||
support_status=support.SupportStatus(version='9.0.0')
|
||||
),
|
||||
}
|
||||
|
||||
attributes_schema = {
|
||||
|
@ -303,6 +311,13 @@ class Subnet(neutron.NeutronResource):
|
|||
client_plugin=self.client_plugin(),
|
||||
finder='find_resourceid_by_name_or_id',
|
||||
entity='subnetpool'
|
||||
),
|
||||
translation.TranslationRule(
|
||||
props,
|
||||
translation.TranslationRule.RESOLVE,
|
||||
[self.SEGMENT],
|
||||
client_plugin=self.client_plugin('openstack'),
|
||||
finder='find_network_segment'
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -357,6 +372,8 @@ class Subnet(neutron.NeutronResource):
|
|||
self.properties,
|
||||
self.physical_resource_name())
|
||||
props['network_id'] = props.pop(self.NETWORK)
|
||||
if self.SEGMENT in props and props[self.SEGMENT]:
|
||||
props['segment_id'] = props.pop(self.SEGMENT)
|
||||
if self.SUBNETPOOL in props and props[self.SUBNETPOOL]:
|
||||
props['subnetpool_id'] = props.pop('subnetpool')
|
||||
self._null_gateway_ip(props)
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from openstack import exceptions
|
||||
|
||||
from heat.engine.clients.os import openstacksdk
|
||||
from heat.tests import common
|
||||
from heat.tests import utils
|
||||
|
||||
|
@ -22,3 +27,22 @@ class OpenStackSDKPluginTest(common.HeatTestCase):
|
|||
plugin = context.clients.client_plugin('openstack')
|
||||
client = plugin.client()
|
||||
self.assertIsNotNone(client.network.segments)
|
||||
|
||||
|
||||
class SegmentConstraintTest(common.HeatTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SegmentConstraintTest, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
self.mock_find_segment = mock.Mock()
|
||||
self.ctx.clients.client_plugin(
|
||||
'openstack').find_network_segment = self.mock_find_segment
|
||||
self.constraint = openstacksdk.SegmentConstraint()
|
||||
|
||||
def test_validation(self):
|
||||
self.mock_find_segment.side_effect = [
|
||||
"seg1", exceptions.ResourceNotFound(),
|
||||
exceptions.DuplicateResource()]
|
||||
self.assertTrue(self.constraint.validate("foo", self.ctx))
|
||||
self.assertFalse(self.constraint.validate("bar", self.ctx))
|
||||
self.assertFalse(self.constraint.validate("baz", self.ctx))
|
||||
|
|
|
@ -20,6 +20,7 @@ import six
|
|||
from heat.common import exception
|
||||
from heat.common import template_format
|
||||
from heat.engine.clients.os import neutron
|
||||
from heat.engine.clients.os import openstacksdk
|
||||
from heat.engine.hot import functions as hot_funcs
|
||||
from heat.engine.resources.openstack.neutron import subnet
|
||||
from heat.engine import rsrc_defn
|
||||
|
@ -111,6 +112,9 @@ class NeutronSubnetTest(common.HeatTestCase):
|
|||
|
||||
self.patchobject(neutron.NeutronClientPlugin, 'has_extension',
|
||||
return_value=True)
|
||||
self.patchobject(openstacksdk.OpenStackSDKPlugin,
|
||||
'find_network_segment',
|
||||
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
|
||||
self.patchobject(neutronV20, 'find_resourceid_by_name_or_id',
|
||||
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
|
||||
|
||||
|
@ -333,6 +337,46 @@ class NeutronSubnetTest(common.HeatTestCase):
|
|||
self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', ref_id)
|
||||
scheduler.TaskRunner(rsrc.delete)()
|
||||
|
||||
def test_subnet_with_segment(self):
|
||||
subnet_dict = {
|
||||
"subnet": {
|
||||
"allocation_pools": [
|
||||
{"start": "10.0.3.20", "end": "10.0.3.150"}],
|
||||
"host_routes": [
|
||||
{"destination": "10.0.4.0/24", "nexthop": "10.0.3.20"}],
|
||||
"segment_id": 'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
|
||||
"prefixlen": 24,
|
||||
"dns_nameservers": ["8.8.8.8"],
|
||||
"enable_dhcp": True,
|
||||
"gateway_ip": "10.0.3.1",
|
||||
"id": "91e47a57-7508-46fe-afc9-fc454e8580e1",
|
||||
"ip_version": 4,
|
||||
"name": "name",
|
||||
"network_id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766",
|
||||
"tenant_id": "c1210485b2424d48804aad5d39c61b8f"
|
||||
}
|
||||
}
|
||||
self.create_mock.return_value = subnet_dict
|
||||
self.show_mock.side_effect = [
|
||||
qe.NeutronClientException(status_code=404)]
|
||||
t = template_format.parse(neutron_template)
|
||||
del t['resources']['sub_net']['properties']['cidr']
|
||||
t['resources']['sub_net']['properties'][
|
||||
'segment'] = 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
|
||||
t['resources']['sub_net']['properties'][
|
||||
'prefixlen'] = 24
|
||||
t['resources']['sub_net']['properties'][
|
||||
'name'] = 'mysubnet'
|
||||
stack = utils.parse_stack(t)
|
||||
self.patchobject(stack['net'], 'FnGetRefId',
|
||||
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
|
||||
rsrc = self.create_subnet(t, stack, 'sub_net')
|
||||
scheduler.TaskRunner(rsrc.create)()
|
||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||
ref_id = rsrc.FnGetRefId()
|
||||
self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', ref_id)
|
||||
scheduler.TaskRunner(rsrc.delete)()
|
||||
|
||||
def test_subnet_deprecated(self):
|
||||
t, stack = self._setup_mock(use_deprecated_templ=True)
|
||||
self.patchobject(stack['net'], 'FnGetRefId',
|
||||
|
|
|
@ -132,6 +132,7 @@ heat.constraints =
|
|||
neutron.qos_policy = heat.engine.clients.os.neutron.neutron_constraints:QoSPolicyConstraint
|
||||
neutron.router = heat.engine.clients.os.neutron.neutron_constraints:RouterConstraint
|
||||
neutron.security_group = heat.engine.clients.os.neutron.neutron_constraints:SecurityGroupConstraint
|
||||
neutron.segment = heat.engine.clients.os.openstacksdk:SegmentConstraint
|
||||
neutron.subnet = heat.engine.clients.os.neutron.neutron_constraints:SubnetConstraint
|
||||
neutron.subnetpool = heat.engine.clients.os.neutron.neutron_constraints:SubnetPoolConstraint
|
||||
nova.flavor = heat.engine.clients.os.nova:FlavorConstraint
|
||||
|
|
Loading…
Reference in New Issue