Introduce 'fixed_ips' to network_list
Modify the response of network_list API. Add a 'fixed_ips' field that contains the list of IP addresses and their subnet IDs. This change is primarily for aligning the format with nova and neutron so that API consumers can use the same parsing code. The first use case is from Heat. Heat would be able to use the same code for parsing nova's interface_list and zun's network_list. Change-Id: Id1e652d944be852697f18958899e395918ab0885
This commit is contained in:
parent
4db4adf6e5
commit
53c7f6bb9c
@ -1276,6 +1276,7 @@ Response
|
||||
- port_id: port_id
|
||||
- version: version
|
||||
- ip_address: ip_address
|
||||
- fixed_ips: fixed_ips
|
||||
|
||||
Response Example
|
||||
----------------
|
||||
|
@ -427,6 +427,13 @@ exec_url:
|
||||
The URL to start an exec instance.
|
||||
in: body
|
||||
type: dict
|
||||
fixed_ips:
|
||||
description: |
|
||||
A list of fixed IP addresses with subnet IDs and other detailed
|
||||
information.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
forced_down:
|
||||
description: |
|
||||
Whether or not this service was forced down manually by an
|
||||
@ -608,7 +615,7 @@ interactive-request:
|
||||
type: boolean
|
||||
ip_address:
|
||||
description: |
|
||||
The IP address of the port.
|
||||
The IP address.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
@ -834,7 +841,7 @@ status_reason:
|
||||
type: string
|
||||
subnet_id:
|
||||
description: |
|
||||
The UUID of subnet of a container.
|
||||
The UUID of subnet.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
|
@ -1,11 +1,13 @@
|
||||
{
|
||||
"networks": [
|
||||
{
|
||||
"subnet_id": "ae8d7cce-859e-432f-8a33-d7d8834ccd14",
|
||||
"port_id": "5be06e49-70dc-4984-94a2-1b946bb136fb",
|
||||
"version": 4,
|
||||
"ip_address": "30.30.30.10",
|
||||
"net_id": "7e6b5e1b-9b44-4f55-b4e3-16a1ead98161"
|
||||
"net_id": "7e6b5e1b-9b44-4f55-b4e3-16a1ead98161",
|
||||
"fixed_ips": {
|
||||
"ip_address": "30.30.30.10",
|
||||
"version": 4,
|
||||
"subnet_id": "ae8d7cce-859e-432f-8a33-d7d8834ccd14"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1039,7 +1039,32 @@ class ContainersController(base.Controller):
|
||||
requested_networks = utils.build_requested_networks(context, [kwargs])
|
||||
compute_api.network_attach(context, container, requested_networks[0])
|
||||
|
||||
@base.Controller.api_version("1.13")
|
||||
@base.Controller.api_version("1.13", "1.17")
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def network_list(self, container_ident):
|
||||
"""Retrieve a list of networks of the container.
|
||||
|
||||
:param container_ident: UUID or Name of a container.
|
||||
"""
|
||||
container = utils.get_container(container_ident)
|
||||
container_networks = self._get_container_networks_legacy(container)
|
||||
return {'networks': container_networks}
|
||||
|
||||
def _get_container_networks_legacy(self, container):
|
||||
container_networks = []
|
||||
for net_id, net_infos in container.addresses.items():
|
||||
for net_info in net_infos:
|
||||
container_networks.append({
|
||||
'net_id': net_id,
|
||||
'subnet_id': net_info.get("subnet_id"),
|
||||
'port_id': net_info.get("port"),
|
||||
'version': net_info.get("version"),
|
||||
'ip_address': net_info.get("addr")
|
||||
})
|
||||
return container_networks
|
||||
|
||||
@base.Controller.api_version("1.18") # noqa
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def network_list(self, container_ident):
|
||||
@ -1054,12 +1079,19 @@ class ContainersController(base.Controller):
|
||||
def _get_container_networks(self, container):
|
||||
container_networks = []
|
||||
for net_id, net_infos in container.addresses.items():
|
||||
addresses = {}
|
||||
for net_info in net_infos:
|
||||
container_networks.append({
|
||||
'net_id': net_id,
|
||||
port_id = net_info["port"]
|
||||
addresses.setdefault(port_id, [])
|
||||
addresses[port_id].append({
|
||||
'subnet_id': net_info.get("subnet_id"),
|
||||
'port_id': net_info.get("port"),
|
||||
'version': net_info.get("version"),
|
||||
'ip_address': net_info.get("addr")
|
||||
})
|
||||
for port_id, fixed_ips in addresses.items():
|
||||
container_networks.append({
|
||||
'net_id': net_id,
|
||||
'port_id': port_id,
|
||||
'fixed_ips': fixed_ips,
|
||||
})
|
||||
return container_networks
|
||||
|
@ -50,10 +50,11 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
* 1.15 - Remove add_security_group and remove_security_group
|
||||
* 1.16 - Modify restart_policy to capsule spec content
|
||||
* 1.17 - Add support for detaching ports
|
||||
* 1.18 - Modify the response of network list
|
||||
"""
|
||||
|
||||
BASE_VER = '1.1'
|
||||
CURRENT_MAX_VER = '1.17'
|
||||
CURRENT_MAX_VER = '1.18'
|
||||
|
||||
|
||||
class Version(object):
|
||||
|
@ -140,3 +140,24 @@ user documentation.
|
||||
|
||||
Add parameter ``port`` to the network_detach API. This allow users to
|
||||
detach a container from a neutron port.
|
||||
|
||||
1.18
|
||||
----
|
||||
|
||||
Modify the response of network_list
|
||||
(GET /v1/containers/{container_ident}/network_list) API. The normal response
|
||||
will be something like::
|
||||
|
||||
{
|
||||
"networks": [
|
||||
{
|
||||
"port_id": "5be06e49-70dc-4984-94a2-1b946bb136fb",
|
||||
"net_id": "7e6b5e1b-9b44-4f55-b4e3-16a1ead98161",
|
||||
"fixed_ips" [
|
||||
"ip_address": "30.30.30.10",
|
||||
"version": 4,
|
||||
"subnet_id": "ae8d7cce-859e-432f-8a33-d7d8834ccd14"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ from zun.tests.unit.db import base
|
||||
|
||||
|
||||
PATH_PREFIX = '/v1'
|
||||
CURRENT_VERSION = "container 1.14"
|
||||
CURRENT_VERSION = "container 1.18"
|
||||
|
||||
|
||||
class FunctionalTest(base.DbTestCase):
|
||||
|
@ -28,7 +28,7 @@ class TestRootController(api_base.FunctionalTest):
|
||||
'default_version':
|
||||
{'id': 'v1',
|
||||
'links': [{'href': 'http://localhost/v1/', 'rel': 'self'}],
|
||||
'max_version': '1.17',
|
||||
'max_version': '1.18',
|
||||
'min_version': '1.1',
|
||||
'status': 'CURRENT'},
|
||||
'description': 'Zun is an OpenStack project which '
|
||||
@ -37,7 +37,7 @@ class TestRootController(api_base.FunctionalTest):
|
||||
'versions': [{'id': 'v1',
|
||||
'links': [{'href': 'http://localhost/v1/',
|
||||
'rel': 'self'}],
|
||||
'max_version': '1.17',
|
||||
'max_version': '1.18',
|
||||
'min_version': '1.1',
|
||||
'status': 'CURRENT'}]}
|
||||
|
||||
|
@ -1749,6 +1749,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
def test_add_security_group_by_uuid(self, mock_get_resource,
|
||||
mock_find_resourceid,
|
||||
mock_add_security_group):
|
||||
headers = {"OpenStack-API-Version": "container 1.14"}
|
||||
test_container = utils.get_test_container()
|
||||
test_container_obj = objects.Container(self.context, **test_container)
|
||||
mock_get_resource.return_value = test_container_obj
|
||||
@ -1758,7 +1759,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
url = '/v1/containers/%s/%s?name=%s' % (container_name,
|
||||
'add_security_group',
|
||||
security_group_id_to_add)
|
||||
response = self.post(url)
|
||||
response = self.post(url, headers=headers)
|
||||
self.assertEqual(202, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
mock_find_resourceid.assert_called_once_with(
|
||||
@ -1772,6 +1773,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
def test_add_security_group_not_found(self, mock_get_resource,
|
||||
mock_find_resourceid,
|
||||
mock_add_security_group):
|
||||
headers = {"OpenStack-API-Version": "container 1.14"}
|
||||
test_container = utils.get_test_container()
|
||||
test_container_obj = objects.Container(self.context, **test_container)
|
||||
mock_get_resource.return_value = test_container_obj
|
||||
@ -1781,7 +1783,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
url = '/v1/containers/%s/%s?name=%s' % (container_name,
|
||||
'add_security_group',
|
||||
security_group_to_add)
|
||||
response = self.post(url, expect_errors=True)
|
||||
response = self.post(url, expect_errors=True, headers=headers)
|
||||
self.assertEqual(400, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(
|
||||
@ -1794,6 +1796,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
def test_add_security_group_not_unique_match(self, mock_get_resource,
|
||||
mock_find_resourceid,
|
||||
mock_add_security_group):
|
||||
headers = {"OpenStack-API-Version": "container 1.14"}
|
||||
test_container = utils.get_test_container()
|
||||
test_container_obj = objects.Container(self.context, **test_container)
|
||||
mock_get_resource.return_value = test_container_obj
|
||||
@ -1803,7 +1806,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
url = '/v1/containers/%s/%s?name=%s' % (container_name,
|
||||
'add_security_group',
|
||||
security_group_to_add)
|
||||
response = self.post(url, expect_errors=True)
|
||||
response = self.post(url, expect_errors=True, headers=headers)
|
||||
self.assertEqual(409, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(
|
||||
@ -1935,8 +1938,23 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
mock_container_get_by_uuid.assert_called_once_with(
|
||||
mock.ANY,
|
||||
test_container['uuid'])
|
||||
self.assertEqual(test_container['addresses']['private'][0]['port'],
|
||||
response.json['networks'][0]['port_id'])
|
||||
self._assert_networks(test_container['addresses'],
|
||||
response.json['networks'])
|
||||
|
||||
def _assert_networks(self, addresses, networks):
|
||||
self.assertEqual(len(addresses), len(networks))
|
||||
for network in networks:
|
||||
address_list = addresses[network['net_id']]
|
||||
self.assertEqual(len(address_list), len(network['fixed_ips']))
|
||||
for address in address_list:
|
||||
matched = 0
|
||||
for fixed_ip in network['fixed_ips']:
|
||||
if (address['addr'] == fixed_ip['ip_address'] and
|
||||
address['version'] == fixed_ip['version'] and
|
||||
address['subnet_id'] == fixed_ip['subnet_id'] and
|
||||
address['port'] == network['port_id']):
|
||||
matched += 1
|
||||
self.assertEqual(1, matched)
|
||||
|
||||
@mock.patch('zun.compute.api.API.remove_security_group')
|
||||
@mock.patch('zun.network.neutron.NeutronAPI.find_resourceid_by_name_or_id')
|
||||
@ -1944,6 +1962,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
def test_remove_security_group_by_uuid(self, mock_get_resource,
|
||||
mock_find_resourceid,
|
||||
mock_remove_security_group):
|
||||
headers = {"OpenStack-API-Version": "container 1.14"}
|
||||
test_container = utils.get_test_container(
|
||||
security_groups=['affb9021-964d-4b1b-80a8-9b9db60497e4'])
|
||||
test_container_obj = objects.Container(self.context, **test_container)
|
||||
@ -1955,7 +1974,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
url = '/v1/containers/%s/%s?name=%s' % (container_name,
|
||||
'remove_security_group',
|
||||
security_group_id_to_remove)
|
||||
response = self.post(url)
|
||||
response = self.post(url, headers=headers)
|
||||
self.assertEqual(202, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
mock_find_resourceid.assert_called_once_with(
|
||||
|
Loading…
Reference in New Issue
Block a user