diff --git a/api-ref/source/containers.inc b/api-ref/source/containers.inc index 56bf898f3..57d2c7fb4 100644 --- a/api-ref/source/containers.inc +++ b/api-ref/source/containers.inc @@ -941,10 +941,14 @@ Response Codes - 403 - 404 +Request +------- + .. rest_parameters:: parameters.yaml - container_ident: container_ident - - network: network + - network: network-query + - port: port-query Response -------- @@ -1023,6 +1027,9 @@ Response Codes - 403 - 404 +Request +------- + .. rest_parameters:: parameters.yaml - container_ident: container_ident diff --git a/zun/api/controllers/v1/containers.py b/zun/api/controllers/v1/containers.py index 16e395194..4f9582b60 100644 --- a/zun/api/controllers/v1/containers.py +++ b/zun/api/controllers/v1/containers.py @@ -1013,8 +1013,13 @@ class ContainersController(base.Controller): context = pecan.request.context compute_api = pecan.request.compute_api neutron_api = neutron.NeutronAPI(context) - neutron_net = neutron_api.get_neutron_network(kwargs.get('network')) - compute_api.network_detach(context, container, neutron_net['id']) + if kwargs.get('port'): + port = neutron_api.get_neutron_port(kwargs['port']) + net_id = port['network_id'] + else: + network = neutron_api.get_neutron_network(kwargs.get('network')) + net_id = network['id'] + compute_api.network_detach(context, container, net_id) pecan.response.status = 202 @base.Controller.api_version("1.8") diff --git a/zun/api/controllers/v1/schemas/containers.py b/zun/api/controllers/v1/schemas/containers.py index 5cf49aa85..952956552 100644 --- a/zun/api/controllers/v1/schemas/containers.py +++ b/zun/api/controllers/v1/schemas/containers.py @@ -177,10 +177,24 @@ network_detach = { 'type': 'object', 'properties': { 'network': { - 'type': 'string' + 'type': 'string', + 'minLength': 1, + 'maxLength': 255, + }, + 'port': { + 'type': 'string', + 'minLength': 1, + 'maxLength': 255, } }, - 'required': ['network'], + 'oneOf': [ + { + 'required': ['network'] + }, + { + 'required': ['port'] + } + ], 'additionalProperties': False } diff --git a/zun/api/controllers/versions.py b/zun/api/controllers/versions.py index 979a1ef03..d4e8c7d02 100644 --- a/zun/api/controllers/versions.py +++ b/zun/api/controllers/versions.py @@ -49,10 +49,11 @@ REST_API_VERSION_HISTORY = """REST API Version History: * 1.14 - Add support to rename the container from update api * 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 """ BASE_VER = '1.1' -CURRENT_MAX_VER = '1.16' +CURRENT_MAX_VER = '1.17' class Version(object): diff --git a/zun/api/rest_api_version_history.rst b/zun/api/rest_api_version_history.rst index 644076968..669c1391f 100644 --- a/zun/api/rest_api_version_history.rst +++ b/zun/api/rest_api_version_history.rst @@ -134,3 +134,9 @@ user documentation. ---- Modify restart_policy to capsule spec content to align with Kubernetes. + +1.17 +---- + + Add parameter ``port`` to the network_detach API. This allow users to + detach a container from a neutron port. diff --git a/zun/tests/unit/api/controllers/test_root.py b/zun/tests/unit/api/controllers/test_root.py index d81aa2126..9d15cc953 100644 --- a/zun/tests/unit/api/controllers/test_root.py +++ b/zun/tests/unit/api/controllers/test_root.py @@ -28,7 +28,7 @@ class TestRootController(api_base.FunctionalTest): 'default_version': {'id': 'v1', 'links': [{'href': 'http://localhost/v1/', 'rel': 'self'}], - 'max_version': '1.16', + 'max_version': '1.17', '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.16', + 'max_version': '1.17', 'min_version': '1.1', 'status': 'CURRENT'}]} diff --git a/zun/tests/unit/api/controllers/v1/test_containers.py b/zun/tests/unit/api/controllers/v1/test_containers.py index acf968fa2..4ccc905d7 100644 --- a/zun/tests/unit/api/controllers/v1/test_containers.py +++ b/zun/tests/unit/api/controllers/v1/test_containers.py @@ -1902,7 +1902,26 @@ class TestContainerController(api_base.FunctionalTest): response = self.post(url) self.assertEqual(202, response.status_int) mock_detach.assert_called_once_with(mock.ANY, test_container_obj, - mock.ANY) + 'private') + + @patch('zun.network.neutron.NeutronAPI.get_neutron_port') + @patch('zun.compute.api.API.network_detach') + @patch('zun.objects.Container.get_by_uuid') + def test_network_detach_with_port(self, mock_by_uuid, mock_detach, + mock_get_port): + test_container = utils.get_test_container() + test_container_obj = objects.Container(self.context, **test_container) + mock_by_uuid.return_value = test_container_obj + container_uuid = test_container.get('uuid') + mock_get_port.return_value = {'network_id': 'fake-net-id'} + mock_detach.return_value = None + url = '/v1/containers/%s/%s?port=%s' % (container_uuid, + 'network_detach', + 'fake-port') + response = self.post(url) + self.assertEqual(202, response.status_int) + mock_detach.assert_called_once_with(mock.ANY, test_container_obj, + 'fake-net-id') @patch('zun.objects.Container.get_by_uuid') def test_network_list(self, mock_container_get_by_uuid):