Merge "Add attach a network to a container server side."
This commit is contained in:
commit
fe28a063f3
@ -774,3 +774,38 @@ This request does not return anything in the response body.
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- X-Openstack-Request-Id: request_id
|
||||
|
||||
|
||||
Attach a network to a container
|
||||
===============================
|
||||
|
||||
.. rest_method:: POST /v1/containers/{container_ident}/network_attach?network={network}
|
||||
|
||||
Attach a network to a container.
|
||||
|
||||
Response Codes
|
||||
--------------
|
||||
|
||||
.. rest_status_code:: success status.yaml
|
||||
|
||||
- 202
|
||||
|
||||
.. rest_status_code:: error status.yaml
|
||||
|
||||
- 401
|
||||
- 403
|
||||
- 404
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- container_ident: container_ident
|
||||
- network: network
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
This request does not return anything in the response body.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- X-Openstack-Request-Id: request_id
|
||||
|
@ -32,6 +32,7 @@
|
||||
"container:commit": "rule:default",
|
||||
"container:add_security_group": "rule:default",
|
||||
"container:network_detach": "rule:default",
|
||||
"container:network_attach": "rule:default",
|
||||
|
||||
"image:pull": "rule:default",
|
||||
"image:get_all": "rule:default",
|
||||
|
@ -114,7 +114,8 @@ class ContainersController(base.Controller):
|
||||
'stats': ['GET'],
|
||||
'commit': ['POST'],
|
||||
'add_security_group': ['POST'],
|
||||
'network_detach': ['POST']
|
||||
'network_detach': ['POST'],
|
||||
'network_attach': ['POST']
|
||||
}
|
||||
|
||||
@pecan.expose('json')
|
||||
@ -765,3 +766,17 @@ class ContainersController(base.Controller):
|
||||
neutron_net = neutron_api.get_neutron_network(kwargs.get('network'))
|
||||
compute_api.network_detach(context, container, neutron_net['id'])
|
||||
pecan.response.status = 202
|
||||
|
||||
@base.Controller.api_version("1.8")
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
@validation.validate_query_param(pecan.request, schema.network_attach)
|
||||
def network_attach(self, container_id, **kwargs):
|
||||
container = _get_container(container_id)
|
||||
check_policy_on_container(container.as_dict(),
|
||||
"container:network_attach")
|
||||
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_attach(context, container, neutron_net['id'])
|
||||
|
@ -180,3 +180,5 @@ network_detach = {
|
||||
'required': ['network'],
|
||||
'additionalProperties': False
|
||||
}
|
||||
|
||||
network_attach = copy.deepcopy(network_detach)
|
||||
|
@ -40,10 +40,11 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
* 1.5 - Add runtime to container
|
||||
* 1.6 - Support detach network from a container
|
||||
* 1.7 - Disallow non-admin users to force delete containers
|
||||
* 1.8 - Support attach a network to a container
|
||||
"""
|
||||
|
||||
BASE_VER = '1.1'
|
||||
CURRENT_MAX_VER = '1.7'
|
||||
CURRENT_MAX_VER = '1.8'
|
||||
|
||||
|
||||
class Version(object):
|
||||
|
@ -70,3 +70,9 @@ user documentation.
|
||||
|
||||
Disallow non-admin users to force delete containers
|
||||
Only Admin User can use "delete --force" to force delete a container.
|
||||
|
||||
1.8
|
||||
---
|
||||
|
||||
Add attach a network to a container.
|
||||
Users can use this api to attach a neutron network to a container.
|
||||
|
@ -134,3 +134,6 @@ class API(object):
|
||||
|
||||
def network_detach(self, context, container, *args):
|
||||
return self.rpcapi.network_detach(context, container, *args)
|
||||
|
||||
def network_attach(self, context, container, *args):
|
||||
return self.rpcapi.network_attach(context, container, *args)
|
||||
|
@ -722,3 +722,12 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception(reraise=False):
|
||||
LOG.exception("Unexpected exception: %s", six.text_type(e))
|
||||
|
||||
def network_attach(self, context, container, network):
|
||||
LOG.debug('Attach network: %(network)s to container: %(container)s.',
|
||||
{'container': container, 'network': network})
|
||||
try:
|
||||
self.driver.network_attach(context, container, network)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception(reraise=False):
|
||||
LOG.exception("Unexpected exception: %s", six.text_type(e))
|
||||
|
@ -181,3 +181,7 @@ class API(rpc_service.API):
|
||||
def network_detach(self, context, container, network):
|
||||
return self._call(container.host, 'network_detach',
|
||||
container=container, network=network)
|
||||
|
||||
def network_attach(self, context, container, network):
|
||||
return self._call(container.host, 'network_attach',
|
||||
container=container, network=network)
|
||||
|
@ -771,6 +771,35 @@ class DockerDriver(driver.ContainerDriver):
|
||||
container.addresses = update
|
||||
container.save(context)
|
||||
|
||||
def network_attach(self, context, container, network):
|
||||
with docker_utils.docker_client() as docker:
|
||||
network_api = zun_network.api(context,
|
||||
docker_api=docker)
|
||||
if network in container.addresses:
|
||||
raise exception.ZunException('Container %(container)s has'
|
||||
' alreay connected to the network'
|
||||
'%(network)s.'
|
||||
% {'container': container['uuid'],
|
||||
'network': network})
|
||||
self._get_or_create_docker_network(context, network_api, network)
|
||||
requested_network = {'network': network,
|
||||
'port': '',
|
||||
'v4-fixed-ip': '',
|
||||
'v6-fixed-ip': ''}
|
||||
docker_net_name = self._get_docker_network_name(context, network)
|
||||
addrs = network_api.connect_container_to_network(
|
||||
container, docker_net_name, requested_network,
|
||||
security_groups=None)
|
||||
if addrs is None:
|
||||
raise exception.ZunException(_(
|
||||
'Unexpected missing of addresses'))
|
||||
update = {}
|
||||
update[network] = addrs
|
||||
addresses = container.addresses
|
||||
addresses.update(update)
|
||||
container.addresses = addresses
|
||||
container.save(context)
|
||||
|
||||
|
||||
class NovaDockerDriver(DockerDriver):
|
||||
capabilities = {
|
||||
|
@ -231,3 +231,6 @@ class ContainerDriver(object):
|
||||
|
||||
def network_detach(self, context, container, network):
|
||||
raise NotImplementedError()
|
||||
|
||||
def network_attach(self, context, container, network):
|
||||
raise NotImplementedError()
|
||||
|
@ -17,7 +17,7 @@ import webtest
|
||||
from zun.api import app
|
||||
from zun.tests.unit.api import base as api_base
|
||||
|
||||
CURRENT_VERSION = "container 1.7"
|
||||
CURRENT_VERSION = "container 1.8"
|
||||
|
||||
|
||||
class TestRootController(api_base.FunctionalTest):
|
||||
@ -27,7 +27,7 @@ class TestRootController(api_base.FunctionalTest):
|
||||
'default_version':
|
||||
{'id': 'v1',
|
||||
'links': [{'href': 'http://localhost/v1/', 'rel': 'self'}],
|
||||
'max_version': '1.7',
|
||||
'max_version': '1.8',
|
||||
'min_version': '1.1',
|
||||
'status': 'CURRENT'},
|
||||
'description': 'Zun is an OpenStack project which '
|
||||
@ -35,7 +35,7 @@ class TestRootController(api_base.FunctionalTest):
|
||||
'versions': [{'id': 'v1',
|
||||
'links': [{'href': 'http://localhost/v1/',
|
||||
'rel': 'self'}],
|
||||
'max_version': '1.7',
|
||||
'max_version': '1.8',
|
||||
'min_version': '1.1',
|
||||
'status': 'CURRENT'}]}
|
||||
|
||||
|
@ -23,7 +23,7 @@ from zun.tests.unit.api import base as api_base
|
||||
from zun.tests.unit.db import utils
|
||||
from zun.tests.unit.objects import utils as obj_utils
|
||||
|
||||
CURRENT_VERSION = "container 1.7"
|
||||
CURRENT_VERSION = "container 1.8"
|
||||
|
||||
|
||||
class TestContainerController(api_base.FunctionalTest):
|
||||
|
@ -624,3 +624,8 @@ class TestManager(base.TestCase):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager.network_detach(self.context, container, 'network')
|
||||
mock_detach.assert_called_once_with(self.context, container, mock.ANY)
|
||||
|
||||
@mock.patch.object(fake_driver, 'network_attach')
|
||||
def test_container_network_attach(self, mock_attach):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager.network_attach(self.context, container, 'network')
|
||||
|
@ -475,6 +475,26 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
'network-fake_project',
|
||||
mock.ANY)
|
||||
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.connect_container_to_network')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.disconnect_container_from_network')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.list_networks')
|
||||
def test_network_attach(self, mock_list, mock_disconnect, mock_connect):
|
||||
mock_container = mock.MagicMock()
|
||||
mock_container.security_groups = None
|
||||
mock_list.return_value = {'network': 'network'}
|
||||
requested_network = [{'network': 'network',
|
||||
'port': '',
|
||||
'v4-fixed-ip': '',
|
||||
'v6-fixed-ip': ''}]
|
||||
self.driver.network_attach(self.context, mock_container, 'network')
|
||||
mock_connect.assert_called_once_with(mock_container,
|
||||
'network-fake_project',
|
||||
requested_network[0],
|
||||
security_groups=None)
|
||||
|
||||
|
||||
class TestNovaDockerDriver(base.DriverTestCase):
|
||||
def setUp(self):
|
||||
|
Loading…
Reference in New Issue
Block a user