OS::Nova::Server: Extend addresses attr to include network

This change adds 'network' to the addresses attribute of the
OS::Nova::Server resource. This enables resolving the
properties of the neutron network for the server resource.

Story: 1766946
Task: 19690
Change-Id: I5bef751982919103ecbefeee64bf0f2cbede0cd0
This commit is contained in:
Harald Jensås 2018-05-16 22:16:27 +02:00
parent 42aab2095a
commit 30d63c5b63
3 changed files with 64 additions and 10 deletions

View File

@ -638,13 +638,16 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
'through the following expression: ``{get_attr: [<server>, ' 'through the following expression: ``{get_attr: [<server>, '
'addresses, <network name_or_id>, 0, port]}``. The subnets may ' 'addresses, <network name_or_id>, 0, port]}``. The subnets may '
'be obtained trough the following expression: ``{get_attr: ' 'be obtained trough the following expression: ``{get_attr: '
'[<server>, addresses, <network name_or_id>, 0, subnets]}``.'), '[<server>, addresses, <network name_or_id>, 0, subnets]}``. '
'The network may be obtained through the following expression: '
'``{get_attr: [<server>, addresses, <network name_or_id>, 0, '
'network]}``.'),
type=attributes.Schema.MAP, type=attributes.Schema.MAP,
support_status=support.SupportStatus( support_status=support.SupportStatus(
version='11.0.0', version='11.0.0',
status=support.SUPPORTED, status=support.SUPPORTED,
message=_('The attribute was extended to include subnets with ' message=_('The attribute was extended to include subnets and '
'version 11.0.0.'), 'network with version 11.0.0.'),
previous_status=support.SupportStatus( previous_status=support.SupportStatus(
status=support.SUPPORTED status=support.SUPPORTED
) )
@ -1072,11 +1075,9 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
return bdm_v2_list return bdm_v2_list
def _get_port_subnets_attr(self, port_id): def _get_subnets_attr(self, fixed_ips):
subnets = [] subnets = []
try: try:
fixed_ips = self.client('neutron').show_port(
port_id)['port']['fixed_ips']
for fixed_ip in fixed_ips: for fixed_ip in fixed_ips:
if fixed_ip.get('subnet_id'): if fixed_ip.get('subnet_id'):
subnets.append(self.client('neutron').show_subnet( subnets.append(self.client('neutron').show_subnet(
@ -1086,8 +1087,15 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
return return
return subnets return subnets
def _get_network_attr(self, network_id):
try:
return self.client('neutron').show_network(network_id)['network']
except Exception as ex:
LOG.warning("Failed to fetch resource attributes: %s", ex)
return
def _add_attrs_for_address(self, server, extend_networks=True): def _add_attrs_for_address(self, server, extend_networks=True):
"""Method adds port id and subnets attributes to list of addresses. """Adds port id, subnets and network attributes to addresses list.
This method is used only for resolving attributes. This method is used only for resolving attributes.
:param server: The server resource :param server: The server resource
@ -1108,8 +1116,17 @@ class Server(server_base.BaseServer, sh.SchedulerHintsMixin,
# We don't need to get subnets and network in that case. Only # 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 # do the external calls if extend_networks is true, i.e called
# from _resolve_attribute() # from _resolve_attribute()
if extend_networks: if not extend_networks:
addr['subnets'] = self._get_port_subnets_attr(addr['port']) 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'])
if extend_networks: if extend_networks:
return self._extend_networks(nets) return self._extend_networks(nets)

View File

@ -253,6 +253,8 @@ class ServersTest(common.HeatTestCase):
'show_port') 'show_port')
self.subnet_show = self.patchobject(neutronclient.Client, self.subnet_show = self.patchobject(neutronclient.Client,
'show_subnet') 'show_subnet')
self.network_show = self.patchobject(neutronclient.Client,
'show_network')
def _limits_absolute(self): def _limits_absolute(self):
max_personality = mock.Mock() max_personality = mock.Mock()
@ -441,6 +443,7 @@ class ServersTest(common.HeatTestCase):
self.port_show.return_value = { self.port_show.return_value = {
'port': {'id': '1234', 'port': {'id': '1234',
'network_id': 'the_network',
'fixed_ips': [{ 'fixed_ips': [{
'ip_address': '4.5.6.7', 'ip_address': '4.5.6.7',
'subnet_id': 'the_subnet'}] 'subnet_id': 'the_subnet'}]
@ -453,10 +456,20 @@ class ServersTest(common.HeatTestCase):
'allocation_pools': [{'start': '10.0.0.2', 'allocation_pools': [{'start': '10.0.0.2',
'end': u'10.0.0.254'}], 'end': u'10.0.0.254'}],
'gateway_ip': '10.0.0.1', 'gateway_ip': '10.0.0.1',
'id': 'the_subnet' '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.subnet_show.return_value = subnet_dict
self.network_show.return_value = network_dict
public_ip = return_server.networks['public'][0] public_ip = return_server.networks['public'][0]
self.assertEqual('1234', self.assertEqual('1234',
@ -475,6 +488,8 @@ class ServersTest(common.HeatTestCase):
server.FnGetAtt('addresses')['private'][0]['addr']) server.FnGetAtt('addresses')['private'][0]['addr'])
self.assertEqual([subnet_dict['subnet']], self.assertEqual([subnet_dict['subnet']],
server.FnGetAtt('addresses')['private'][0]['subnets']) server.FnGetAtt('addresses')['private'][0]['subnets'])
self.assertEqual(network_dict['network'],
server.FnGetAtt('addresses')['private'][0]['network'])
self.assertEqual(private_ip, self.assertEqual(private_ip,
server.FnGetAtt('networks')['private'][0]) server.FnGetAtt('networks')['private'][0])
@ -494,6 +509,21 @@ class ServersTest(common.HeatTestCase):
self.assertIsNone(server.FnGetAtt('tags')) self.assertIsNone(server.FnGetAtt('tags'))
self.assertEqual({}, server.FnGetAtt('os_collect_config')) 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): def test_server_create_metadata(self):
stack_name = 'create_metadata_test_stack' stack_name = 'create_metadata_test_stack'
self.patchobject(nova.NovaClientPlugin, 'client', self.patchobject(nova.NovaClientPlugin, 'client',

View File

@ -0,0 +1,7 @@
---
features:
- |
Adds ``network`` to the ``addresses`` attribute of
``OS::Nova::Server`` resource. This enables resolving the network
properties for the server resource.