Implement GroupSet updatable for AWS::EC2::NetworkInterface
Implement the 'GroupSet' updatable for AWS::EC2::NetworkInterface resource to be compatible with AWSCloudFormation. Change-Id: Ia92c6d2732fdafc659d1a9a1db01cb66be9a9bc0 Closes-Bug: #1334212
This commit is contained in:
parent
945f3fe95a
commit
ac45f3b6e9
@ -46,7 +46,7 @@ class NetworkInterface(resource.Resource):
|
||||
GROUP_SET: properties.Schema(
|
||||
properties.Schema.LIST,
|
||||
_('List of security group IDs associated with this interface.'),
|
||||
default=[]
|
||||
update_allowed=True
|
||||
),
|
||||
PRIVATE_IP_ADDRESS: properties.Schema(
|
||||
properties.Schema.STRING
|
||||
@ -115,8 +115,11 @@ class NetworkInterface(resource.Resource):
|
||||
'network_id': network_id,
|
||||
'fixed_ips': [fixed_ip]
|
||||
}
|
||||
|
||||
if self.properties[self.GROUP_SET]:
|
||||
# if without group_set, don't set the 'security_groups' property,
|
||||
# neutron will create the port with the 'default' securityGroup,
|
||||
# if has the group_set and the value is [], which means to create the
|
||||
# port without securityGroup(same as the behavior of neutron)
|
||||
if self.properties[self.GROUP_SET] is not None:
|
||||
sgs = self.client_plugin().get_secgroup_uuids(
|
||||
self.properties.get(self.GROUP_SET))
|
||||
props['security_groups'] = sgs
|
||||
@ -124,12 +127,34 @@ class NetworkInterface(resource.Resource):
|
||||
self.resource_id_set(port['id'])
|
||||
|
||||
def handle_delete(self):
|
||||
if self.resource_id is None:
|
||||
return
|
||||
|
||||
client = self.neutron()
|
||||
try:
|
||||
client.delete_port(self.resource_id)
|
||||
except Exception as ex:
|
||||
self.client_plugin().ignore_not_found(ex)
|
||||
|
||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||
if prop_diff:
|
||||
update_props = {}
|
||||
if self.GROUP_SET in prop_diff:
|
||||
group_set = prop_diff.get(self.GROUP_SET)
|
||||
# update should keep the same behavior as creation,
|
||||
# if without the GroupSet in update template, we should
|
||||
# update the security_groups property to referent
|
||||
# the 'default' security group
|
||||
if group_set is not None:
|
||||
sgs = self.client_plugin().get_secgroup_uuids(group_set)
|
||||
else:
|
||||
sgs = self.client_plugin().get_secgroup_uuids(['default'])
|
||||
|
||||
update_props['security_groups'] = sgs
|
||||
|
||||
self.neutron().update_port(self.resource_id,
|
||||
{'port': update_props})
|
||||
|
||||
def _get_fixed_ip_address(self, ):
|
||||
if self.fixed_ip_address is None:
|
||||
client = self.neutron()
|
||||
|
145
heat/tests/test_network_interface.py
Normal file
145
heat/tests/test_network_interface.py
Normal file
@ -0,0 +1,145 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
from heat.engine import rsrc_defn
|
||||
from heat.engine import scheduler
|
||||
from heat.tests.common import HeatTestCase
|
||||
from heat.tests import utils
|
||||
|
||||
try:
|
||||
from neutronclient.v2_0 import client as neutronclient
|
||||
except ImportError:
|
||||
neutronclient = None
|
||||
|
||||
test_template = {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'resources': {
|
||||
'my_nic': {
|
||||
'type': 'AWS::EC2::NetworkInterface',
|
||||
'properties': {
|
||||
'SubnetId': 'ssss'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NetworkInterfaceTest(HeatTestCase):
|
||||
def setUp(self):
|
||||
super(NetworkInterfaceTest, self).setUp()
|
||||
self.ctx = utils.dummy_context()
|
||||
self.m.StubOutWithMock(neutronclient.Client, 'show_subnet')
|
||||
self.m.StubOutWithMock(neutronclient.Client, 'create_port')
|
||||
self.m.StubOutWithMock(neutronclient.Client, 'delete_port')
|
||||
self.m.StubOutWithMock(neutronclient.Client, 'update_port')
|
||||
self.stub_keystoneclient()
|
||||
|
||||
def mock_show_subnet(self):
|
||||
neutronclient.Client.show_subnet('ssss').AndReturn({
|
||||
'subnet': {
|
||||
'name': 'my_subnet',
|
||||
'network_id': 'nnnn',
|
||||
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f',
|
||||
'allocation_pools': [{'start': '10.0.0.2',
|
||||
'end': '10.0.0.254'}],
|
||||
'gateway_ip': '10.0.0.1',
|
||||
'ip_version': 4,
|
||||
'cidr': '10.0.0.0/24',
|
||||
'id': 'ssss',
|
||||
'enable_dhcp': False,
|
||||
}})
|
||||
|
||||
def mock_create_network_interface(self, stack_name='my_stack',
|
||||
resource_name='my_nic',
|
||||
security_groups=None):
|
||||
self.nic_name = utils.PhysName(stack_name, resource_name)
|
||||
port = {'network_id': 'nnnn',
|
||||
'fixed_ips': [{
|
||||
'subnet_id': u'ssss'
|
||||
}],
|
||||
'name': self.nic_name,
|
||||
'admin_state_up': True}
|
||||
|
||||
port_info = {
|
||||
'port': {
|
||||
'admin_state_up': True,
|
||||
'device_id': '',
|
||||
'device_owner': '',
|
||||
'fixed_ips': [
|
||||
{
|
||||
'ip_address': '10.0.0.100',
|
||||
'subnet_id': 'ssss'
|
||||
}
|
||||
],
|
||||
'id': 'pppp',
|
||||
'mac_address': 'fa:16:3e:25:32:5d',
|
||||
'name': self.nic_name,
|
||||
'network_id': 'nnnn',
|
||||
'status': 'ACTIVE',
|
||||
'tenant_id': 'c1210485b2424d48804aad5d39c61b8f'
|
||||
}
|
||||
}
|
||||
|
||||
if security_groups is not None:
|
||||
port['security_groups'] = security_groups
|
||||
port_info['security_groups'] = security_groups
|
||||
else:
|
||||
port_info['security_groups'] = ['default']
|
||||
|
||||
neutronclient.Client.create_port({'port': port}).AndReturn(port_info)
|
||||
|
||||
def mock_update_network_interface(self, update_props, port_id='pppp'):
|
||||
neutronclient.Client.update_port(
|
||||
port_id,
|
||||
{'port': update_props}).AndReturn(None)
|
||||
|
||||
def mock_delete_network_interface(self, port_id='pppp'):
|
||||
neutronclient.Client.delete_port(port_id).AndReturn(None)
|
||||
|
||||
def test_network_interface_create_update_delete(self):
|
||||
my_stack = utils.parse_stack(test_template, stack_name='my_stack')
|
||||
nic_rsrc = my_stack['my_nic']
|
||||
|
||||
self.mock_show_subnet()
|
||||
self.mock_create_network_interface()
|
||||
|
||||
update_props = {}
|
||||
update_sg_ids = ['0389f747-7785-4757-b7bb-2ab07e4b09c3']
|
||||
update_props['security_groups'] = update_sg_ids
|
||||
|
||||
self.mock_update_network_interface(update_props)
|
||||
self.mock_delete_network_interface()
|
||||
|
||||
self.m.ReplayAll()
|
||||
# create the nic without GroupSet
|
||||
self.assertIsNone(nic_rsrc.validate())
|
||||
scheduler.TaskRunner(nic_rsrc.create)()
|
||||
self.assertEqual((nic_rsrc.CREATE, my_stack.COMPLETE),
|
||||
nic_rsrc.state)
|
||||
|
||||
# update the nic with GroupSet
|
||||
props = copy.deepcopy(nic_rsrc.properties.data)
|
||||
props['GroupSet'] = update_sg_ids
|
||||
update_snippet = rsrc_defn.ResourceDefinition(nic_rsrc.name,
|
||||
nic_rsrc.type(),
|
||||
props)
|
||||
scheduler.TaskRunner(nic_rsrc.update, update_snippet)()
|
||||
self.assertEqual((nic_rsrc.UPDATE, nic_rsrc.COMPLETE), nic_rsrc.state)
|
||||
|
||||
# delete the nic
|
||||
scheduler.TaskRunner(nic_rsrc.delete)()
|
||||
self.assertEqual((nic_rsrc.DELETE, nic_rsrc.COMPLETE), nic_rsrc.state)
|
||||
|
||||
self.m.VerifyAll()
|
Loading…
Reference in New Issue
Block a user