From 15de8c8c91437c525b5922c8f11c850df546b42c Mon Sep 17 00:00:00 2001 From: Simon Pasquier Date: Tue, 26 Nov 2013 10:04:53 +0100 Subject: [PATCH] Implement PrivateIpAddress attribute The PrivateIpAddress attribute maps to the private IP address of the AWS::EC2::NetworkInterface resource. Change-Id: I471e9ab9ea6fed8bc09a6339d11bcf1f1e4528f8 Closes-Bug: #1254675 --- heat/engine/resources/network_interface.py | 26 ++++++++++++++++++++++ heat/tests/test_vpc.py | 26 ++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/heat/engine/resources/network_interface.py b/heat/engine/resources/network_interface.py index 36347eced1..5eb9075919 100644 --- a/heat/engine/resources/network_interface.py +++ b/heat/engine/resources/network_interface.py @@ -52,11 +52,18 @@ class NetworkInterface(resource.Resource): 'Description': _('List of tags associated with this interface.')}} } + attributes_schema = {'PrivateIpAddress': _('Private IP address of the ' + 'network interface.')} + @staticmethod def network_id_from_subnet_id(neutronclient, subnet_id): subnet_info = neutronclient.show_subnet(subnet_id) return subnet_info['subnet']['network_id'] + def __init__(self, name, json_snippet, stack): + super(NetworkInterface, self).__init__(name, json_snippet, stack) + self.fixed_ip_address = None + def handle_create(self): client = self.neutron() @@ -91,6 +98,25 @@ class NetworkInterface(resource.Resource): if ex.status_code != 404: raise ex + def _get_fixed_ip_address(self, ): + if self.fixed_ip_address is None: + from neutronclient.common.exceptions import NeutronClientException + + client = self.neutron() + try: + port = client.show_port(self.resource_id)['port'] + if port['fixed_ips'] and len(port['fixed_ips']) > 0: + self.fixed_ip_address = port['fixed_ips'][0]['ip_address'] + except NeutronClientException as ex: + if ex.status_code != 404: + raise ex + + return self.fixed_ip_address + + def _resolve_attribute(self, name): + if name == 'PrivateIpAddress': + return self._get_fixed_ip_address() + def resource_mapping(): if clients.neutronclient is None: diff --git a/heat/tests/test_vpc.py b/heat/tests/test_vpc.py index 13983dc676..cf1df01bbb 100644 --- a/heat/tests/test_vpc.py +++ b/heat/tests/test_vpc.py @@ -53,6 +53,7 @@ class VPCTestBase(HeatTestCase): self.m.StubOutWithMock(neutronclient.Client, 'remove_interface_router') self.m.StubOutWithMock(neutronclient.Client, 'show_subnet') self.m.StubOutWithMock(neutronclient.Client, 'show_network') + self.m.StubOutWithMock(neutronclient.Client, 'show_port') self.m.StubOutWithMock(neutronclient.Client, 'show_router') self.m.StubOutWithMock(neutronclient.Client, 'create_security_group') self.m.StubOutWithMock(neutronclient.Client, 'show_security_group') @@ -563,6 +564,29 @@ Resources: } }) + def mock_show_network_interface(self): + self.nic_name = utils.PhysName('test_stack', 'the_nic') + neutronclient.Client.show_port('dddd').AndReturn({ + 'port': { + 'admin_state_up': True, + 'device_id': '', + 'device_owner': '', + 'fixed_ips': [ + { + 'ip_address': '10.0.0.100', + 'subnet_id': 'cccc' + } + ], + 'id': 'dddd', + 'mac_address': 'fa:16:3e:25:32:5d', + 'name': self.nic_name, + 'network_id': 'aaaa', + 'security_groups': ['0389f747-7785-4757-b7bb-2ab07e4b09c3'], + 'status': 'ACTIVE', + 'tenant_id': 'c1210485b2424d48804aad5d39c61b8f' + } + }) + def mock_delete_network_interface(self): neutronclient.Client.delete_port('dddd').AndReturn(None) @@ -573,6 +597,7 @@ Resources: self.mock_create_subnet() self.mock_show_subnet() self.mock_create_network_interface() + self.mock_show_network_interface() self.mock_delete_network_interface() self.mock_delete_subnet() self.mock_delete_network() @@ -585,6 +610,7 @@ Resources: self.assertEqual((stack.CREATE, stack.COMPLETE), stack.state) rsrc = stack['the_nic'] self.assertResourceState(rsrc, 'dddd') + self.assertEqual(rsrc.FnGetAtt('PrivateIpAddress'), '10.0.0.100') self.assertRaises(resource.UpdateReplace, rsrc.handle_update, {}, {}, {})