summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarald Jensås <hjensas@redhat.com>2021-02-16 17:25:17 +0100
committerrabi <ramishra@redhat.com>2022-02-24 20:24:19 +0530
commit576e1d6f6247f633606b0f67fa0bb72274e1194a (patch)
tree5bba4e8e433718d96acb57d665824fe3fe35c7d4
parentcbe9be5e7625d374fc6cfbb63b7e3ef5335bf330 (diff)
downloadheat-576e1d6f6247f633606b0f67fa0bb72274e1194a.tar.gz
Use neutron client for server.addresses
The server.addresses (/servers/{server_id}/ips) endpoint can contain stale data causing attribute lookups to fail. This change replaces the use of server.addresses and instead uses the neutron client to list ports with 'device_id' matching the server id. Story: 2008632 Task: 41843 Related: RHBZ#1902230 Change-Id: I1b9293041f2ad92eac0e9bc9646e7b2d7c6f7fd0 (cherry picked from commit 45750c603ac9965afd5b4e53ecff65977b887b95)
-rw-r--r--heat/engine/resources/openstack/nova/server.py58
-rw-r--r--heat/tests/openstack/nova/test_server.py145
2 files changed, 131 insertions, 72 deletions
diff --git a/heat/engine/resources/openstack/nova/server.py b/heat/engine/resources/openstack/nova/server.py
index 0302514d9..7081c78c9 100644
--- a/heat/engine/resources/openstack/nova/server.py
+++ b/heat/engine/resources/openstack/nova/server.py
@@ -12,6 +12,7 @@
# under the License.
import copy
+import ipaddress
from oslo_config import cfg
from oslo_log import log as logging
@@ -955,8 +956,8 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
return result
def _get_live_networks(self, server, props):
- reality_nets = self._add_attrs_for_address(server,
- extend_networks=False)
+ reality_nets = self._get_server_addresses(server,
+ extend_networks=False)
reality_net_ids = {}
client_plugin = self.client_plugin('neutron')
for net_key in reality_nets:
@@ -1124,7 +1125,7 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
LOG.warning("Failed to fetch resource attributes: %s", ex)
return
- def _add_attrs_for_address(self, server, extend_networks=True):
+ def _get_server_addresses(self, server, extend_networks=True):
"""Adds port id, subnets and network attributes to addresses list.
This method is used only for resolving attributes.
@@ -1133,31 +1134,48 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
the net is returned without replacing name on
id.
"""
- nets = copy.deepcopy(server.addresses) or {}
- ifaces = server.interface_list()
- ip_mac_mapping_on_port_id = dict(((iface.fixed_ips[0]['ip_address'],
- iface.mac_addr), iface.port_id)
- for iface in ifaces)
- for net_name in nets:
- for addr in nets[net_name]:
- addr['port'] = ip_mac_mapping_on_port_id.get(
- (addr['addr'], addr['OS-EXT-IPS-MAC:mac_addr']))
+ nets = {}
+ ifaces = self.client('neutron').list_ports(device_id=server.id)
+ for port in ifaces['ports']:
+ net_label = self.client('neutron').list_networks(
+ id=port['network_id'])['networks'][0]['name']
+ net = nets.setdefault(net_label, [])
+ for fixed_ip in port['fixed_ips']:
+ addr = {'addr': fixed_ip.get('ip_address'),
+ 'OS-EXT-IPS-MAC:mac_addr': port['mac_address'],
+ 'OS-EXT-IPS:type': 'fixed',
+ 'port': port['id']}
+
+ try:
+ addr['version'] = ipaddress.ip_address(
+ addr['addr']).version,
+ except ValueError:
+ addr['version'] = None
+
+ if addr['addr']:
+ fips = self.client('neutron').list_floatingips(
+ fixed_ip_address=addr['addr'])
+ for fip in fips['floatingips']:
+ net.append({
+ 'addr': fip['floating_ip_address'],
+ 'version': addr['version'],
+ 'OS-EXT-IPS-MAC:mac_addr': port['mac_address'],
+ 'OS-EXT-IPS:type': 'floating',
+ 'port': None})
+
# _get_live_networks() uses this method to get reality_nets.
# We don't need to get subnets and network in that case. Only
# do the external calls if extend_networks is true, i.e called
# from _resolve_attribute()
if not extend_networks:
+ net.append(addr)
continue
- try:
- port = self.client('neutron').show_port(
- addr['port'])['port']
- except Exception as ex:
- addr['subnets'], addr['network'] = None, None
- LOG.warning("Failed to fetch resource attributes: %s", ex)
- continue
+
addr['subnets'] = self._get_subnets_attr(port['fixed_ips'])
addr['network'] = self._get_network_attr(port['network_id'])
+ net.append(addr)
+
if extend_networks:
return self._extend_networks(nets)
else:
@@ -1201,7 +1219,7 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
self.client_plugin().ignore_not_found(e)
return ''
if name == self.ADDRESSES:
- return self._add_attrs_for_address(server)
+ return self._get_server_addresses(server)
if name == self.NETWORKS_ATTR:
return self._extend_networks(server.networks)
if name == self.INSTANCE_NAME:
diff --git a/heat/tests/openstack/nova/test_server.py b/heat/tests/openstack/nova/test_server.py
index 47ab98963..42c40b57b 100644
--- a/heat/tests/openstack/nova/test_server.py
+++ b/heat/tests/openstack/nova/test_server.py
@@ -446,42 +446,48 @@ class ServersTest(common.HeatTestCase):
ip='5.6.9.8'),
create_fake_iface(port='1013',
mac='fa:16:3e:8c:44:cc',
- ip='10.13.12.13')]
+ ip='10.13.12.13',
+ subnet='private_subnet_id')]
+ ports = [dict(id=interfaces[0].port_id,
+ mac_address=interfaces[0].mac_addr,
+ fixed_ips=interfaces[0].fixed_ips,
+ network_id='public_id'),
+ dict(id=interfaces[1].port_id,
+ mac_address=interfaces[1].mac_addr,
+ fixed_ips=interfaces[1].fixed_ips,
+ network_id='public_id'),
+ dict(id=interfaces[2].port_id,
+ mac_address=interfaces[2].mac_addr,
+ fixed_ips=interfaces[2].fixed_ips,
+ network_id='private_id')]
+ public_net = dict(id='public_id',
+ name='public',
+ mtu=1500,
+ subnets=['public_subnet_id'])
+ private_net = dict(id='private_id',
+ name='private',
+ mtu=1500,
+ subnets=['private_subnet_id'])
+ private_subnet = dict(id='private_subnet_id',
+ name='private_subnet',
+ cidr='private_cidr',
+ allocation_pools=[{'start': 'start_addr',
+ 'end': 'end_addr'}],
+ gateway_ip='private_gateway',
+ network_id='private_id')
self.patchobject(self.fc.servers, 'get', return_value=return_server)
- self.patchobject(return_server, 'interface_list',
- return_value=interfaces)
+ self.patchobject(neutronclient.Client, 'list_ports',
+ return_value={'ports': ports})
+ self.patchobject(neutronclient.Client, 'list_networks',
+ side_effect=[{'networks': [public_net]},
+ {'networks': [public_net]},
+ {'networks': [private_net]}])
+ self.patchobject(neutronclient.Client, 'list_floatingips',
+ return_value={'floatingips': []})
self.patchobject(self.fc.servers, 'tag_list', return_value=['test'])
-
- self.port_show.return_value = {
- 'port': {'id': '1234',
- 'network_id': 'the_network',
- 'fixed_ips': [{
- 'ip_address': '4.5.6.7',
- 'subnet_id': 'the_subnet'}]
- }
- }
- subnet_dict = {
- 'subnet': {
- 'name': 'subnet_name',
- 'cidr': '10.0.0.0/24',
- 'allocation_pools': [{'start': '10.0.0.2',
- 'end': u'10.0.0.254'}],
- 'gateway_ip': '10.0.0.1',
- 'id': 'the_subnet',
- 'network_id': 'the_network'
- }
- }
- network_dict = {
- 'network': {
- 'name': 'network_name',
- 'mtu': 1500,
- 'subnets': [subnet_dict['subnet']['id']],
- 'id': 'the_network'
- }
- }
- self.subnet_show.return_value = subnet_dict
- self.network_show.return_value = network_dict
+ self.subnet_show.return_value = {'subnet': private_subnet}
+ self.network_show.return_value = {'network': private_net}
public_ip = return_server.networks['public'][0]
self.assertEqual('1234',
@@ -498,9 +504,9 @@ class ServersTest(common.HeatTestCase):
server.FnGetAtt('addresses')['private'][0]['port'])
self.assertEqual(private_ip,
server.FnGetAtt('addresses')['private'][0]['addr'])
- self.assertEqual([subnet_dict['subnet']],
+ self.assertEqual([private_subnet],
server.FnGetAtt('addresses')['private'][0]['subnets'])
- self.assertEqual(network_dict['network'],
+ self.assertEqual(private_net,
server.FnGetAtt('addresses')['private'][0]['network'])
self.assertEqual(private_ip,
server.FnGetAtt('networks')['private'][0])
@@ -521,21 +527,6 @@ class ServersTest(common.HeatTestCase):
self.assertIsNone(server.FnGetAtt('tags'))
self.assertEqual({}, server.FnGetAtt('os_collect_config'))
- def test_server_network_subnet_address_attr_port_not_found(self):
- return_server = self.fc.servers.list()[1]
- server_name = 'network-subnet-attr-server'
- server = self._create_test_server(return_server, server_name)
- interfaces = [create_fake_iface(port='1234',
- mac='fa:16:3e:8c:22:aa',
- ip='4.5.6.7')]
- self.patchobject(return_server, 'interface_list',
- return_value=interfaces)
- self.port_show.side_effect = neutron.exceptions.NotFound()
- self.assertEqual(None,
- server.FnGetAtt('addresses')['private'][0]['subnets'])
- self.assertEqual(None,
- server.FnGetAtt('addresses')['private'][0]['network'])
-
def test_server_create_metadata(self):
stack_name = 'create_metadata_test_stack'
self.patchobject(nova.NovaClientPlugin, 'client',
@@ -642,10 +633,30 @@ class ServersTest(common.HeatTestCase):
create_fake_iface(port='1013',
mac='fa:16:3e:8c:44:cc',
ip='10.13.12.13')]
+ ports = [dict(id=interfaces[0].port_id,
+ mac_address=interfaces[0].mac_addr,
+ fixed_ips=interfaces[0].fixed_ips,
+ network_id='public_id'),
+ dict(id=interfaces[1].port_id,
+ mac_address=interfaces[1].mac_addr,
+ fixed_ips=interfaces[1].fixed_ips,
+ network_id='public_id'),
+ dict(id=interfaces[2].port_id,
+ mac_address=interfaces[2].mac_addr,
+ fixed_ips=interfaces[2].fixed_ips,
+ network_id='private_id')]
+ public_net = dict(id='public_id', name='public')
+ private_net = dict(id='private_id', name='private')
self.patchobject(self.fc.servers, 'get', return_value=return_server)
- self.patchobject(return_server, 'interface_list',
- return_value=interfaces)
+ self.patchobject(neutronclient.Client, 'list_ports',
+ return_value={'ports': ports})
+ self.patchobject(neutronclient.Client, 'list_networks',
+ side_effect=[{'networks': [public_net]},
+ {'networks': [public_net]},
+ {'networks': [private_net]}])
+ self.patchobject(neutronclient.Client, 'list_floatingips',
+ return_value={'floatingips': []})
self.patchobject(return_server, 'interface_detach')
self.patchobject(return_server, 'interface_attach')
@@ -2038,20 +2049,42 @@ class ServersTest(common.HeatTestCase):
server.properties.data['networks'] = [{'network': 'public_id',
'fixed_ip': '5.6.9.8'}]
+ public_net = dict(id='public_id', name='public')
+ private_net = dict(id='private_id', name='private')
iface0 = create_fake_iface(port='aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
net='public',
ip='5.6.9.8',
mac='fa:16:3e:8c:33:aa')
+ port0 = dict(id=iface0.port_id,
+ network_id=iface0.net_id,
+ mac_address=iface0.mac_addr,
+ fixed_ips=iface0.fixed_ips)
iface1 = create_fake_iface(port='bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
net='public',
ip='4.5.6.7',
mac='fa:16:3e:8c:22:aa')
+ port1 = dict(id=iface1.port_id,
+ network_id=iface1.net_id,
+ mac_address=iface1.mac_addr,
+ fixed_ips=iface1.fixed_ips)
iface2 = create_fake_iface(port='cccccccc-cccc-cccc-cccc-cccccccccccc',
net='private',
ip='10.13.12.13',
mac='fa:16:3e:8c:44:cc')
+ port2 = dict(id=iface2.port_id,
+ network_id=iface2.net_id,
+ mac_address=iface2.mac_addr,
+ fixed_ips=iface2.fixed_ips)
self.patchobject(return_server, 'interface_list',
return_value=[iface0, iface1, iface2])
+ self.patchobject(neutronclient.Client, 'list_ports',
+ return_value={'ports': [port0, port1, port2]})
+ self.patchobject(neutronclient.Client, 'list_networks',
+ side_effect=[{'networks': [public_net]},
+ {'networks': [public_net]},
+ {'networks': [private_net]}])
+ self.patchobject(neutronclient.Client, 'list_floatingips',
+ return_value={'floatingips': []})
self.patchobject(neutron.NeutronClientPlugin,
'find_resourceid_by_name_or_id',
@@ -2674,6 +2707,14 @@ class ServersTest(common.HeatTestCase):
self.patchobject(neutron.NeutronClientPlugin,
'find_resourceid_by_name_or_id',
return_value=None)
+ self.patchobject(neutronclient.Client, 'list_ports',
+ return_value={'ports': [{'id': 'p_id',
+ 'name': 'p_name',
+ 'fixed_ips': [],
+ 'network_id': 'n_id'}]})
+ self.patchobject(neutronclient.Client, 'list_networks',
+ return_value={'networks': [{'id': 'n_id',
+ 'name': 'empty_net'}]})
self.patchobject(self.fc.servers, 'get', return_value=return_server)
self.patchobject(return_server, 'interface_list', return_value=[])
mock_detach = self.patchobject(return_server, 'interface_detach')