heat/heat/tests/openstack/neutron/test_neutron_subnet.py

763 lines
31 KiB
Python

#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import mock
from neutronclient.common import exceptions as qe
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.v2_0 import client as neutronclient
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 import node_data
from heat.engine import resource
from heat.engine.resources.openstack.neutron import subnet
from heat.engine import rsrc_defn
from heat.engine import scheduler
from heat.engine import stk_defn
from heat.tests import common
from heat.tests import utils
neutron_template = '''
heat_template_version: 2015-04-30
description: Template to test subnet Neutron resource
resources:
net:
type: OS::Neutron::Net
properties:
name: the_net
tenant_id: c1210485b2424d48804aad5d39c61b8f
shared: true
dhcp_agent_ids:
- 28c25a04-3f73-45a7-a2b4-59e183943ddc
sub_net:
type: OS::Neutron::Subnet
properties:
network: { get_resource : net}
tenant_id: c1210485b2424d48804aad5d39c61b8f
ip_version: 4
cidr: 10.0.3.0/24
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
dns_nameservers:
- 8.8.8.8
port:
type: OS::Neutron::Port
properties:
device_id: d6b4d3a5-c700-476f-b609-1493dd9dadc0
name: port1
network: { get_resource : net}
fixed_ips:
- subnet: { get_resource : sub_net }
ip_address: 10.0.3.21
port2:
type: OS::Neutron::Port
properties:
name: port2
network: { get_resource : net}
router:
type: OS::Neutron::Router
properties:
l3_agent_ids:
- 792ff887-6c85-4a56-b518-23f24fa65581
router_interface:
type: OS::Neutron::RouterInterface
properties:
router_id: { get_resource : router }
subnet: { get_resource : sub_net }
gateway:
type: OS::Neutron::RouterGateway
properties:
router_id: { get_resource : router }
network: { get_resource : net}
'''
neutron_template_deprecated = neutron_template.replace(
'neutron', 'neutron_id').replace('subnet', 'subnet_id')
class NeutronSubnetTest(common.HeatTestCase):
def setUp(self):
super(NeutronSubnetTest, self).setUp()
self.create_mock = self.patchobject(neutronclient.Client,
'create_subnet')
self.delete_mock = self.patchobject(neutronclient.Client,
'delete_subnet')
self.show_mock = self.patchobject(neutronclient.Client,
'show_subnet')
self.update_mock = self.patchobject(neutronclient.Client,
'update_subnet')
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')
def create_subnet(self, t, stack, resource_name):
resource_defns = stack.t.resource_definitions(stack)
rsrc = subnet.Subnet('test_subnet', resource_defns[resource_name],
stack)
return rsrc
def _setup_mock(self, stack_name=None, use_deprecated_templ=False,
tags=None):
if use_deprecated_templ:
t = template_format.parse(neutron_template_deprecated)
else:
t = template_format.parse(neutron_template)
if tags:
t['resources']['sub_net']['properties']['tags'] = tags
stack = utils.parse_stack(t, stack_name=stack_name)
sn = {
"subnet": {
"name": "name",
"network_id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766",
"tenant_id": "c1210485b2424d48804aad5d39c61b8f",
"allocation_pools": [
{"start": "10.0.3.20", "end": "10.0.3.150"}],
"gateway_ip": "10.0.3.1",
'host_routes': [
{'destination': u'10.0.4.0/24', 'nexthop': u'10.0.3.20'}],
"ip_version": 4,
"cidr": "10.0.3.0/24",
"dns_nameservers": ["8.8.8.8"],
"id": "91e47a57-7508-46fe-afc9-fc454e8580e1",
"enable_dhcp": True,
}
}
self.create_mock.return_value = sn
self.show_mock.side_effect = [
qe.NeutronClientException(status_code=404),
sn,
sn,
qe.NeutronClientException(status_code=404)
]
self.delete_mock.side_effect = [
None,
qe.NeutronClientException(status_code=404)
]
return t, stack
def test_subnet(self):
update_props = {'subnet': {
'dns_nameservers': ['8.8.8.8', '192.168.1.254'],
'name': 'mysubnet',
'enable_dhcp': True,
'host_routes': [{'destination': '192.168.1.0/24',
'nexthop': '194.168.1.2'}],
'gateway_ip': '10.0.3.105',
'tags': ['tag2', 'tag3'],
'allocation_pools': [
{'start': '10.0.3.20', 'end': '10.0.3.100'},
{'start': '10.0.3.110', 'end': '10.0.3.200'}]}}
t, stack = self._setup_mock(tags=['tag1', 'tag2'])
create_props = {'subnet': {
'name': utils.PhysName(stack.name, 'test_subnet'),
'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
'dns_nameservers': [u'8.8.8.8'],
'allocation_pools': [
{'start': u'10.0.3.20', 'end': u'10.0.3.150'}],
'host_routes': [
{'destination': u'10.0.4.0/24', 'nexthop': u'10.0.3.20'}],
'ip_version': 4,
'cidr': u'10.0.3.0/24',
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
'enable_dhcp': True}}
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
set_tag_mock = self.patchobject(neutronclient.Client, 'replace_tag')
rsrc = self.create_subnet(t, stack, 'sub_net')
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
self.create_mock.assert_called_once_with(create_props)
set_tag_mock.assert_called_once_with(
'subnets',
rsrc.resource_id,
{'tags': ['tag1', 'tag2']}
)
rsrc.validate()
ref_id = rsrc.FnGetRefId()
self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', ref_id)
self.assertIsNone(rsrc.FnGetAtt('network_id'))
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766',
rsrc.FnGetAtt('network_id'))
self.assertEqual('8.8.8.8', rsrc.FnGetAtt('dns_nameservers')[0])
# assert the dependency (implicit or explicit) between the ports
# and the subnet
self.assertIn(stack['port'], stack.dependencies[stack['sub_net']])
self.assertIn(stack['port2'], stack.dependencies[stack['sub_net']])
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
update_props['subnet'])
rsrc.handle_update(update_snippet, {}, update_props['subnet'])
self.update_mock.assert_called_once_with(
'91e47a57-7508-46fe-afc9-fc454e8580e1',
update_props)
set_tag_mock.assert_called_with(
'subnets',
rsrc.resource_id,
{'tags': ['tag2', 'tag3']}
)
# with name None
del update_props['subnet']['name']
rsrc.handle_update(update_snippet, {}, update_props['subnet'])
self.update_mock.assert_called_with(
'91e47a57-7508-46fe-afc9-fc454e8580e1',
update_props)
# with no prop_diff
rsrc.handle_update(update_snippet, {}, {})
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
def test_update_subnet_with_value_specs(self):
update_props = {'subnet': {
'name': 'mysubnet',
'value_specs': {
'enable_dhcp': True,
}
}}
update_props_merged = copy.deepcopy(update_props)
update_props_merged['subnet']['enable_dhcp'] = True
del update_props_merged['subnet']['value_specs']
t, stack = self._setup_mock()
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)
rsrc.validate()
ref_id = rsrc.FnGetRefId()
self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', ref_id)
self.assertIsNone(rsrc.FnGetAtt('network_id'))
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766',
rsrc.FnGetAtt('network_id'))
self.assertEqual('8.8.8.8', rsrc.FnGetAtt('dns_nameservers')[0])
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
update_props['subnet'])
rsrc.handle_update(update_snippet, {}, update_props['subnet'])
self.update_mock.assert_called_once_with(
'91e47a57-7508-46fe-afc9-fc454e8580e1',
update_props
)
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
def test_update_subnet_with_no_name(self):
stack_name = utils.random_name()
update_props = {'subnet': {
'name': None,
}}
update_props_name = {'subnet': {
'name': utils.PhysName(stack_name, 'test_subnet'),
}}
t, stack = self._setup_mock(stack_name)
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)
rsrc.validate()
ref_id = rsrc.FnGetRefId()
self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', ref_id)
self.assertIsNone(rsrc.FnGetAtt('network_id'))
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766',
rsrc.FnGetAtt('network_id'))
self.assertEqual('8.8.8.8', rsrc.FnGetAtt('dns_nameservers')[0])
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
update_props['subnet'])
rsrc.handle_update(update_snippet, {}, update_props['subnet'])
self.update_mock.assert_called_once_with(
'91e47a57-7508-46fe-afc9-fc454e8580e1',
update_props_name
)
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
def test_subnet_with_subnetpool(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"}],
"subnetpool_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'][
'subnetpool'] = '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_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',
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)
rsrc.validate()
ref_id = rsrc.FnGetRefId()
self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', ref_id)
self.assertIsNone(rsrc.FnGetAtt('network_id'))
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766',
rsrc.FnGetAtt('network_id'))
self.assertEqual('8.8.8.8', rsrc.FnGetAtt('dns_nameservers')[0])
# assert the dependency (implicit or explicit) between the ports
# and the subnet
self.assertIn(stack['port'], stack.dependencies[stack['sub_net']])
self.assertIn(stack['port2'], stack.dependencies[stack['sub_net']])
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
def test_subnet_disable_dhcp(self):
t = template_format.parse(neutron_template)
t['resources']['sub_net']['properties']['enable_dhcp'] = 'False'
stack = utils.parse_stack(t)
subnet_info = {
"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"}],
"cidr": "10.0.3.0/24",
"dns_nameservers": ["8.8.8.8"],
"enable_dhcp": False,
"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_info
self.show_mock.side_effect = [
subnet_info,
qe.NeutronClientException(status_code=404)
]
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)
rsrc.validate()
ref_id = rsrc.FnGetRefId()
self.assertEqual('91e47a57-7508-46fe-afc9-fc454e8580e1', ref_id)
self.assertIs(False, rsrc.FnGetAtt('enable_dhcp'))
scheduler.TaskRunner(rsrc.delete)()
def test_null_gateway_ip(self):
p = {}
subnet.Subnet._null_gateway_ip(p)
self.assertEqual({}, p)
p = {'foo': 'bar'}
subnet.Subnet._null_gateway_ip(p)
self.assertEqual({'foo': 'bar'}, p)
p = {
'foo': 'bar',
'gateway_ip': '198.51.100.0'
}
subnet.Subnet._null_gateway_ip(p)
self.assertEqual({
'foo': 'bar',
'gateway_ip': '198.51.100.0'
}, p)
p = {
'foo': 'bar',
'gateway_ip': ''
}
subnet.Subnet._null_gateway_ip(p)
self.assertEqual({
'foo': 'bar',
'gateway_ip': None
}, p)
# This should not happen as prepare_properties
# strips out None values, but testing anyway
p = {
'foo': 'bar',
'gateway_ip': None
}
subnet.Subnet._null_gateway_ip(p)
self.assertEqual({
'foo': 'bar',
'gateway_ip': None
}, p)
def test_ipv6_subnet(self):
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
props.pop('allocation_pools')
props.pop('host_routes')
props['ip_version'] = 6
props['ipv6_address_mode'] = 'slaac'
props['ipv6_ra_mode'] = 'slaac'
props['cidr'] = 'fdfa:6a50:d22b::/64'
props['dns_nameservers'] = ['2001:4860:4860::8844']
stack = utils.parse_stack(t)
create_info = {
'subnet': {
'name': utils.PhysName(stack.name, 'test_subnet'),
'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
'dns_nameservers': [u'2001:4860:4860::8844'],
'ip_version': 6,
'enable_dhcp': True,
'cidr': u'fdfa:6a50:d22b::/64',
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
'ipv6_address_mode': 'slaac',
'ipv6_ra_mode': 'slaac'
}
}
subnet_info = copy.deepcopy(create_info)
subnet_info['subnet']['id'] = "91e47a57-7508-46fe-afc9-fc454e8580e1"
self.create_mock.return_value = subnet_info
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.create_mock.assert_called_once_with(create_info)
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
rsrc.validate()
def test_host_routes_validate_destination(self):
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
props['host_routes'] = [{'destination': 'invalid_cidr',
'nexthop': '10.0.3.20'}]
stack = utils.parse_stack(t)
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
rsrc = stack['sub_net']
ex = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
msg = ("Property error: "
"resources.sub_net.properties.host_routes[0].destination: "
"Error validating value 'invalid_cidr': Invalid net cidr "
"invalid IPNetwork invalid_cidr ")
self.assertEqual(msg, six.text_type(ex))
def test_ipv6_validate_ra_mode(self):
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
props['ipv6_address_mode'] = 'dhcpv6-stateful'
props['ipv6_ra_mode'] = 'slaac'
props['ip_version'] = 6
stack = utils.parse_stack(t)
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
rsrc = stack['sub_net']
ex = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertEqual("When both ipv6_ra_mode and ipv6_address_mode are "
"set, they must be equal.", six.text_type(ex))
def test_ipv6_validate_ip_version(self):
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
props['ipv6_address_mode'] = 'slaac'
props['ipv6_ra_mode'] = 'slaac'
props['ip_version'] = 4
stack = utils.parse_stack(t)
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
rsrc = stack['sub_net']
ex = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertEqual("ipv6_ra_mode and ipv6_address_mode are not "
"supported for ipv4.", six.text_type(ex))
def test_validate_both_subnetpool_cidr(self):
self.patchobject(neutronV20, 'find_resourceid_by_name_or_id',
return_value='new_pool')
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
props['subnetpool'] = 'new_pool'
stack = utils.parse_stack(t)
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
rsrc = stack['sub_net']
ex = self.assertRaises(exception.ResourcePropertyConflict,
rsrc.validate)
msg = ("Cannot define the following properties at the same time: "
"subnetpool, cidr.")
self.assertEqual(msg, six.text_type(ex))
def test_validate_none_subnetpool_cidr(self):
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
del props['cidr']
stack = utils.parse_stack(t)
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
rsrc = stack['sub_net']
ex = self.assertRaises(exception.PropertyUnspecifiedError,
rsrc.validate)
msg = ("At least one of the following properties must be specified: "
"subnetpool, cidr.")
self.assertEqual(msg, six.text_type(ex))
def test_validate_subnetpool_ref_with_cidr(self):
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
props['subnetpool'] = {'get_resource': 'subnetpool'}
props = t['resources']['sub_net']['properties']
stack = utils.parse_stack(t)
snippet = rsrc_defn.ResourceDefinition('subnetpool',
'OS::Neutron::SubnetPool')
res = resource.Resource('subnetpool', snippet, stack)
stack.add_resource(res)
self.patchobject(stack['subnetpool'], 'FnGetRefId',
return_value=None)
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
rsrc = stack['sub_net']
ex = self.assertRaises(exception.ResourcePropertyConflict,
rsrc.validate)
msg = ("Cannot define the following properties at the same time: "
"subnetpool, cidr.")
self.assertEqual(msg, six.text_type(ex))
def test_validate_subnetpool_ref_no_cidr(self):
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
del props['cidr']
props['subnetpool'] = {'get_resource': 'subnetpool'}
props = t['resources']['sub_net']['properties']
stack = utils.parse_stack(t)
snippet = rsrc_defn.ResourceDefinition('subnetpool',
'OS::Neutron::SubnetPool')
res = resource.Resource('subnetpool', snippet, stack)
stack.add_resource(res)
self.patchobject(stack['subnetpool'], 'FnGetRefId',
return_value=None)
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
rsrc = stack['sub_net']
self.assertIsNone(rsrc.validate())
def test_validate_both_prefixlen_cidr(self):
t = template_format.parse(neutron_template)
props = t['resources']['sub_net']['properties']
props['prefixlen'] = '24'
stack = utils.parse_stack(t)
self.patchobject(stack['net'], 'FnGetRefId',
return_value='fc68ea2c-b60b-4b4f-bd82-94ec81110766')
rsrc = stack['sub_net']
ex = self.assertRaises(exception.ResourcePropertyConflict,
rsrc.validate)
msg = ("Cannot define the following properties at the same time: "
"prefixlen, cidr.")
self.assertEqual(msg, six.text_type(ex))
def test_deprecated_network_id(self):
template = """
heat_template_version: 2015-04-30
resources:
net:
type: OS::Neutron::Net
properties:
name: test
subnet:
type: OS::Neutron::Subnet
properties:
network_id: { get_resource: net }
cidr: 10.0.0.0/24
"""
t = template_format.parse(template)
stack = utils.parse_stack(t)
rsrc = stack['subnet']
nd = {'reference_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'}
stk_defn.update_resource_data(stack.defn, 'net',
node_data.NodeData.from_dict(nd))
self.create_mock.return_value = {
"subnet": {
"id": "91e47a57-7508-46fe-afc9-fc454e8580e1",
"ip_version": 4,
"name": "name",
"network_id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766",
"tenant_id": "c1210485b2424d48804aad5d39c61b8f"
}
}
stack.create()
self.assertEqual(hot_funcs.GetResource(stack.defn, 'get_resource',
'net'),
rsrc.properties.get('network'))
self.assertIsNone(rsrc.properties.get('network_id'))
def test_subnet_get_live_state(self):
template = """
heat_template_version: 2015-04-30
resources:
net:
type: OS::Neutron::Net
properties:
name: test
subnet:
type: OS::Neutron::Subnet
properties:
network_id: { get_resource: net }
cidr: 10.0.0.0/25
value_specs:
test_value_spec: value_spec_value
"""
t = template_format.parse(template)
stack = utils.parse_stack(t)
rsrc = stack['subnet']
stack.create()
subnet_resp = {'subnet': {
'name': 'subnet-subnet-la5usdgifhrd',
'enable_dhcp': True,
'network_id': 'dffd43b3-6206-4402-87e6-8a16ddf3bd68',
'tenant_id': '30f466e3d14b4251853899f9c26e2b66',
'dns_nameservers': [],
'ipv6_ra_mode': None,
'allocation_pools': [{'start': '10.0.0.2', 'end': '10.0.0.126'}],
'gateway_ip': '10.0.0.1',
'ipv6_address_mode': None,
'ip_version': 4,
'host_routes': [],
'prefixlen': None,
'cidr': '10.0.0.0/25',
'id': 'b255342b-31b7-4674-8ea4-a144bca658b0',
'subnetpool_id': None,
'test_value_spec': 'value_spec_value'}
}
rsrc.client().show_subnet = mock.MagicMock(return_value=subnet_resp)
rsrc.resource_id = '1234'
reality = rsrc.get_live_state(rsrc.properties)
expected = {
'enable_dhcp': True,
'dns_nameservers': [],
'allocation_pools': [{'start': '10.0.0.2', 'end': '10.0.0.126'}],
'gateway_ip': '10.0.0.1',
'host_routes': [],
'value_specs': {'test_value_spec': 'value_spec_value'}
}
self.assertEqual(set(expected.keys()), set(reality.keys()))
for key in expected:
self.assertEqual(expected[key], reality[key])