diff --git a/heat/engine/resources/openstack/manila/share_network.py b/heat/engine/resources/openstack/manila/share_network.py index 2b5d98b866..5d0e4bb72f 100644 --- a/heat/engine/resources/openstack/manila/share_network.py +++ b/heat/engine/resources/openstack/manila/share_network.py @@ -128,6 +128,21 @@ class ManilaShareNetwork(resource.Resource): raise exception.ResourcePropertyConflict(self.NEUTRON_SUBNET, self.NOVA_NETWORK) + if (self.properties[self.NEUTRON_NETWORK] and + self.properties[self.NEUTRON_SUBNET]): + plg = self.client_plugin('neutron') + subnet_id = plg.find_resourceid_by_name_or_id( + 'subnet', self.properties[self.NEUTRON_SUBNET]) + net_id = plg.network_id_from_subnet_id(subnet_id) + provided_net_id = plg.find_resourceid_by_name_or_id( + 'network', self.properties[self.NEUTRON_NETWORK]) + if net_id != provided_net_id: + msg = (_('Provided %(subnet)s does not belong ' + 'to provided %(network)s.') + % {'subnet': self.NEUTRON_SUBNET, + 'network': self.NEUTRON_NETWORK}) + raise exception.StackValidationFailed(message=msg) + def translation_rules(self, props): if self.is_using_neutron(): translation_rules = [ @@ -162,10 +177,15 @@ class ManilaShareNetwork(resource.Resource): return translation_rules def handle_create(self): + neutron_subnet_id = self.properties[self.NEUTRON_SUBNET] + neutron_net_id = self.properties[self.NEUTRON_NETWORK] + if neutron_subnet_id and not neutron_net_id: + neutron_net_id = self.client_plugin( + 'neutron').network_id_from_subnet_id(neutron_subnet_id) network = self.client().share_networks.create( name=self.properties[self.NAME], - neutron_net_id=self.properties[self.NEUTRON_NETWORK], - neutron_subnet_id=self.properties[self.NEUTRON_SUBNET], + neutron_net_id=neutron_net_id, + neutron_subnet_id=neutron_subnet_id, nova_net_id=self.properties[self.NOVA_NETWORK], description=self.properties[self.DESCRIPTION]) self.resource_id_set(network.id) @@ -191,11 +211,17 @@ class ManilaShareNetwork(resource.Resource): self.resource_id, service) if prop_diff: + neutron_subnet_id = prop_diff.get(self.NEUTRON_SUBNET) + neutron_net_id = prop_diff.get(self.NEUTRON_NETWORK) + if neutron_subnet_id and not neutron_net_id: + neutron_net_id = self.client_plugin( + 'neutron').network_id_from_subnet_id(neutron_subnet_id) + self.client().share_networks.update( self.resource_id, name=prop_diff.get(self.NAME), - neutron_net_id=prop_diff.get(self.NEUTRON_NETWORK), - neutron_subnet_id=prop_diff.get(self.NEUTRON_SUBNET), + neutron_net_id=neutron_net_id, + neutron_subnet_id=neutron_subnet_id, nova_net_id=prop_diff.get(self.NOVA_NETWORK), description=prop_diff.get(self.DESCRIPTION)) diff --git a/heat/tests/openstack/manila/test_share_network.py b/heat/tests/openstack/manila/test_share_network.py index 50a53d3203..3190a65fe6 100644 --- a/heat/tests/openstack/manila/test_share_network.py +++ b/heat/tests/openstack/manila/test_share_network.py @@ -83,6 +83,13 @@ class ManilaShareNetworkTest(common.HeatTestCase): self.patchobject(share_network.ManilaShareNetwork, 'client_plugin', return_value=self.client_plugin) + + def return_network(name): + return '3' + + self.client_plugin.network_id_from_subnet_id.side_effect = ( + return_network + ) self.stub_NetworkConstraint_validate() self.stub_NovaNetworkConstraint() self.stub_SubnetConstraint_validate() @@ -139,6 +146,22 @@ class ManilaShareNetworkTest(common.HeatTestCase): calls, any_order=True) self.assertEqual('share_networks', net.entity) + def test_create_without_network(self): + t = template_format.parse(stack_template) + del t['resources']['share_network']['properties']['neutron_network'] + stack = utils.parse_stack(t) + rsrc_defn = stack.t.resource_definitions(stack)['share_network'] + net = self._create_network('share_network', rsrc_defn, stack) + self.assertEqual((net.CREATE, net.COMPLETE), net.state) + self.assertEqual('42', net.resource_id) + net.client().share_networks.create.assert_called_with( + name='1', description='2', neutron_net_id='3', + neutron_subnet_id='4', nova_net_id=None) + calls = [mock.call('42', '6'), mock.call('42', '7')] + net.client().share_networks.add_security_service.assert_has_calls( + calls, any_order=True) + self.assertEqual('share_networks', net.entity) + def test_create_fail(self): self.client.share_networks.add_security_service.side_effect = ( Exception()) @@ -146,6 +169,18 @@ class ManilaShareNetworkTest(common.HeatTestCase): exception.ResourceFailure, self._create_network, 'share_network', self.rsrc_defn, self.stack) + def test_validate_conflicting_net_subnet(self): + t = template_format.parse(stack_template) + t['resources']['share_network']['properties']['neutron_network'] = '5' + stack = utils.parse_stack(t) + rsrc_defn = stack.t.resource_definitions(stack)['share_network'] + net = self._create_network('share_network', rsrc_defn, stack) + net.is_using_neutron = mock.Mock(return_value=True) + msg = ('Provided neutron_subnet does not belong ' + 'to provided neutron_network.') + self.assertRaisesRegexp(exception.StackValidationFailed, msg, + net.validate) + def test_update(self): net = self._create_network('share_network', self.rsrc_defn, self.stack) props = self.tmpl['resources']['share_network']['properties'].copy()