262 lines
12 KiB
Python
262 lines
12 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.
|
|
|
|
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.resources.openstack.neutron import subnetpool
|
|
from heat.engine import rsrc_defn
|
|
from heat.engine import scheduler
|
|
from heat.tests import common
|
|
from heat.tests.openstack.neutron import inline_templates
|
|
from heat.tests import utils
|
|
|
|
|
|
class NeutronSubnetPoolTest(common.HeatTestCase):
|
|
|
|
def setUp(self):
|
|
super(NeutronSubnetPoolTest, self).setUp()
|
|
self.patchobject(neutron.NeutronClientPlugin, 'has_extension',
|
|
return_value=True)
|
|
self.find_resource = self.patchobject(neutronV20,
|
|
'find_resourceid_by_name_or_id',
|
|
return_value='new_test')
|
|
|
|
def create_subnetpool(self, status='COMPLETE'):
|
|
self.t = template_format.parse(inline_templates.SPOOL_TEMPLATE)
|
|
self.stack = utils.parse_stack(self.t)
|
|
resource_defns = self.stack.t.resource_definitions(self.stack)
|
|
rsrc = subnetpool.SubnetPool('sub_pool', resource_defns['sub_pool'],
|
|
self.stack)
|
|
if status == 'FAILED':
|
|
self.patchobject(neutronclient.Client, 'create_subnetpool',
|
|
side_effect=qe.NeutronClientException(
|
|
status_code=500))
|
|
error = self.assertRaises(exception.ResourceFailure,
|
|
scheduler.TaskRunner(rsrc.create))
|
|
self.assertEqual(
|
|
'NeutronClientException: resources.sub_pool: '
|
|
'An unknown exception occurred.',
|
|
six.text_type(error))
|
|
else:
|
|
self.patchobject(neutronclient.Client, 'create_subnetpool',
|
|
return_value={'subnetpool': {
|
|
'id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'
|
|
}})
|
|
scheduler.TaskRunner(rsrc.create)()
|
|
|
|
self.assertEqual((rsrc.CREATE, status), rsrc.state)
|
|
return rsrc
|
|
|
|
def test_validate_prefixlen_min_gt_max(self):
|
|
self.t = template_format.parse(inline_templates.SPOOL_TEMPLATE)
|
|
props = self.t['resources']['sub_pool']['properties']
|
|
props['min_prefixlen'] = 28
|
|
props['max_prefixlen'] = 24
|
|
self.stack = utils.parse_stack(self.t)
|
|
rsrc = self.stack['sub_pool']
|
|
errMessage = ('Illegal prefix bounds: max_prefixlen=24, '
|
|
'min_prefixlen=28.')
|
|
error = self.assertRaises(exception.StackValidationFailed,
|
|
rsrc.validate)
|
|
self.assertEqual(errMessage, six.text_type(error))
|
|
|
|
def test_validate_prefixlen_default_gt_max(self):
|
|
self.t = template_format.parse(inline_templates.SPOOL_TEMPLATE)
|
|
props = self.t['resources']['sub_pool']['properties']
|
|
props['default_prefixlen'] = 28
|
|
props['max_prefixlen'] = 24
|
|
self.stack = utils.parse_stack(self.t)
|
|
rsrc = self.stack['sub_pool']
|
|
errMessage = ('Illegal prefix bounds: max_prefixlen=24, '
|
|
'default_prefixlen=28.')
|
|
error = self.assertRaises(exception.StackValidationFailed,
|
|
rsrc.validate)
|
|
self.assertEqual(errMessage, six.text_type(error))
|
|
|
|
def test_validate_prefixlen_min_gt_default(self):
|
|
self.t = template_format.parse(inline_templates.SPOOL_TEMPLATE)
|
|
props = self.t['resources']['sub_pool']['properties']
|
|
props['min_prefixlen'] = 28
|
|
props['default_prefixlen'] = 24
|
|
self.stack = utils.parse_stack(self.t)
|
|
rsrc = self.stack['sub_pool']
|
|
errMessage = ('Illegal prefix bounds: min_prefixlen=28, '
|
|
'default_prefixlen=24.')
|
|
error = self.assertRaises(exception.StackValidationFailed,
|
|
rsrc.validate)
|
|
self.assertEqual(errMessage, six.text_type(error))
|
|
|
|
def test_validate_minimal(self):
|
|
self.t = template_format.parse(inline_templates.SPOOL_MINIMAL_TEMPLATE)
|
|
self.stack = utils.parse_stack(self.t)
|
|
rsrc = self.stack['sub_pool']
|
|
self.assertIsNone(rsrc.validate())
|
|
|
|
def test_create_subnetpool(self):
|
|
rsrc = self.create_subnetpool()
|
|
ref_id = rsrc.FnGetRefId()
|
|
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id)
|
|
|
|
def test_create_subnetpool_failed(self):
|
|
self.create_subnetpool('FAILED')
|
|
|
|
def test_delete_subnetpool(self):
|
|
self.patchobject(neutronclient.Client, 'delete_subnetpool')
|
|
rsrc = self.create_subnetpool()
|
|
ref_id = rsrc.FnGetRefId()
|
|
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id)
|
|
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
|
|
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
|
|
|
def test_delete_subnetpool_not_found(self):
|
|
self.patchobject(neutronclient.Client, 'delete_subnetpool',
|
|
side_effect=qe.NotFound(status_code=404))
|
|
rsrc = self.create_subnetpool()
|
|
ref_id = rsrc.FnGetRefId()
|
|
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id)
|
|
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
|
|
self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state)
|
|
|
|
def test_delete_subnetpool_resource_id_none(self):
|
|
delete_pool = self.patchobject(neutronclient.Client,
|
|
'delete_subnetpool')
|
|
rsrc = self.create_subnetpool()
|
|
rsrc.resource_id = None
|
|
self.assertIsNone(scheduler.TaskRunner(rsrc.delete)())
|
|
delete_pool.assert_not_called()
|
|
|
|
def test_update_subnetpool(self):
|
|
update_subnetpool = self.patchobject(neutronclient.Client,
|
|
'update_subnetpool')
|
|
rsrc = self.create_subnetpool()
|
|
ref_id = rsrc.FnGetRefId()
|
|
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id)
|
|
props = {
|
|
'name': 'the_new_sp',
|
|
'prefixes': [
|
|
'10.1.0.0/16',
|
|
'10.2.0.0/16'],
|
|
'address_scope': 'new_test',
|
|
'default_quota': '16',
|
|
'default_prefixlen': '24',
|
|
'min_prefixlen': '24',
|
|
'max_prefixlen': '28',
|
|
'is_default': False,
|
|
}
|
|
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
|
|
props)
|
|
self.assertIsNone(rsrc.handle_update(update_snippet, {}, props))
|
|
self.assertEqual(1, update_subnetpool.call_count)
|
|
|
|
def test_update_subnetpool_no_prop_diff(self):
|
|
update_subnetpool = self.patchobject(neutronclient.Client,
|
|
'update_subnetpool')
|
|
rsrc = self.create_subnetpool()
|
|
ref_id = rsrc.FnGetRefId()
|
|
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id)
|
|
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
|
|
rsrc.t)
|
|
self.assertIsNone(rsrc.handle_update(update_snippet, {}, {}))
|
|
update_subnetpool.assert_not_called()
|
|
|
|
def test_update_subnetpool_validate_prefixes(self):
|
|
update_subnetpool = self.patchobject(neutronclient.Client,
|
|
'update_subnetpool')
|
|
rsrc = self.create_subnetpool()
|
|
ref_id = rsrc.FnGetRefId()
|
|
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id)
|
|
prefix_old = rsrc.properties['prefixes']
|
|
props = {
|
|
'name': 'the_new_sp',
|
|
'prefixes': ['10.5.0.0/16']
|
|
}
|
|
prefix_new = props['prefixes']
|
|
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
|
|
props)
|
|
errMessage = ('Property prefixes updated value %(value1)s '
|
|
'should be superset of existing value %(value2)s.'
|
|
% dict(value1=sorted(prefix_new),
|
|
value2=sorted(prefix_old)))
|
|
|
|
error = self.assertRaises(exception.StackValidationFailed,
|
|
rsrc.handle_update,
|
|
update_snippet, {}, props)
|
|
|
|
self.assertEqual(errMessage, six.text_type(error))
|
|
update_subnetpool.assert_not_called()
|
|
|
|
props = {
|
|
'name': 'the_new_sp',
|
|
'prefixes': ['10.0.0.0/8',
|
|
'10.6.0.0/16'],
|
|
}
|
|
|
|
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
|
|
props)
|
|
self.assertIsNone(rsrc.handle_update(update_snippet, {}, props))
|
|
update_subnetpool.assert_called_once_with(
|
|
'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
|
|
{'subnetpool': props})
|
|
|
|
def test_update_subnetpool_update_address_scope(self):
|
|
update_subnetpool = self.patchobject(neutronclient.Client,
|
|
'update_subnetpool')
|
|
rsrc = self.create_subnetpool()
|
|
ref_id = rsrc.FnGetRefId()
|
|
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id)
|
|
props = {
|
|
'name': 'the_new_sp',
|
|
'address_scope': 'new_test',
|
|
'prefixes': ['10.0.0.0/8',
|
|
'10.6.0.0/16'],
|
|
}
|
|
update_dict = {
|
|
'name': 'the_new_sp',
|
|
'address_scope_id': 'new_test',
|
|
'prefixes': ['10.0.0.0/8',
|
|
'10.6.0.0/16'],
|
|
}
|
|
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
|
|
props)
|
|
self.assertIsNone(rsrc.handle_update(update_snippet, {}, props))
|
|
self.assertEqual(3, self.find_resource.call_count)
|
|
update_subnetpool.assert_called_once_with(
|
|
'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
|
|
{'subnetpool': update_dict})
|
|
|
|
def test_update_subnetpool_remove_address_scope(self):
|
|
update_subnetpool = self.patchobject(neutronclient.Client,
|
|
'update_subnetpool')
|
|
rsrc = self.create_subnetpool()
|
|
ref_id = rsrc.FnGetRefId()
|
|
self.assertEqual('fc68ea2c-b60b-4b4f-bd82-94ec81110766', ref_id)
|
|
props = {
|
|
'name': 'the_new_sp',
|
|
'prefixes': ['10.0.0.0/8',
|
|
'10.6.0.0/16'],
|
|
}
|
|
props_diff = {'address_scope': None}
|
|
update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(),
|
|
props)
|
|
self.assertIsNone(rsrc.handle_update(update_snippet, {}, props_diff))
|
|
self.assertEqual(2, self.find_resource.call_count)
|
|
update_subnetpool.assert_called_once_with(
|
|
'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
|
|
{'subnetpool': props_diff})
|