Support opening container's port
Introduce an option to expose container's port(s). In particular, it introduces a parameter 'exposed_ports' on creating container. The value is in the form: ``{"<port>/<protocol>": {}}``. For example, it can be ``{"80": {}}`` or ``{"80/tcp": {}}``. The format is designed to align with docker's option 'ExposedPorts'. If this parameter is provided, Zun will create a security group for the container. The security group will be populated a set of rules to open those exposed ports. This feature is a managed security group feature (Zun manages the security group of the container). Obviously, it cannot be used with the 'security_groups' parameter, in which users are responsible to manage the security group. Change-Id: Id713ce602dca8e74089d4a5eea8df41ea8784db4 Partial-Implements: blueprint support-port-bindings
This commit is contained in:
parent
1efb2b9645
commit
44dc51f8df
@ -60,6 +60,7 @@ Request
|
||||
- mounts: mounts
|
||||
- privileged: privileged-request
|
||||
- healthcheck: healthcheck-request
|
||||
- exposed_ports: exposed_ports
|
||||
|
||||
Request Example
|
||||
----------------
|
||||
|
@ -482,6 +482,18 @@ exec_url:
|
||||
The URL to start an exec instance.
|
||||
in: body
|
||||
type: dict
|
||||
exposed_ports:
|
||||
description: |
|
||||
A list of dictionary data to specify how to expose container's ports.
|
||||
If this parameter is specified, Zun will create a security group with
|
||||
a set of rules to open the ports that should be exposed, and associate
|
||||
the security group to the container. The value is in the form of
|
||||
``{"<port>/<protocol>: {}"}``, where the ``port`` is the container's
|
||||
port and ``protocol`` is either ``tcp`` or ``udp``. If ``protocol``
|
||||
is not provided, ``tcp`` will be used.
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
fixed_ips:
|
||||
description: |
|
||||
A list of fixed IP addresses with subnet IDs and other detailed
|
||||
|
@ -398,6 +398,12 @@ class ContainersController(base.Controller):
|
||||
if container_dict.get('restart_policy'):
|
||||
utils.check_for_restart_policy(container_dict)
|
||||
|
||||
exposed_ports = container_dict.pop('exposed_ports', None)
|
||||
if exposed_ports is not None:
|
||||
api_utils.version_check('exposed_ports', '1.24')
|
||||
exposed_ports = utils.build_exposed_ports(exposed_ports)
|
||||
container_dict['exposed_ports'] = exposed_ports
|
||||
|
||||
container_dict['status'] = consts.CREATING
|
||||
extra_spec = {}
|
||||
extra_spec['hints'] = container_dict.get('hints', None)
|
||||
|
@ -39,6 +39,7 @@ _legacy_container_properties = {
|
||||
'auto_heal': parameter_types.boolean,
|
||||
'privileged': parameter_types.boolean,
|
||||
'healthcheck': parameter_types.healthcheck,
|
||||
'exposed_ports': parameter_types.exposed_ports,
|
||||
}
|
||||
|
||||
legacy_container_create = {
|
||||
@ -54,7 +55,14 @@ _container_properties['command'] = parameter_types.command_list
|
||||
container_create = {
|
||||
'type': 'object',
|
||||
'properties': _container_properties,
|
||||
'required': ['image'],
|
||||
'allOf': [
|
||||
{
|
||||
'required': ['image'],
|
||||
},
|
||||
{
|
||||
'not': {'required': ['security_groups', 'exposed_ports']}
|
||||
}
|
||||
],
|
||||
'additionalProperties': False
|
||||
}
|
||||
|
||||
|
@ -196,6 +196,10 @@ healthcheck = {
|
||||
}
|
||||
}
|
||||
|
||||
exposed_ports = {
|
||||
'type': ['object', 'null']
|
||||
}
|
||||
|
||||
mounts = {
|
||||
'type': ['array', 'null'],
|
||||
'items': {
|
||||
|
@ -56,10 +56,11 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
* 1.21 - Add support privileged
|
||||
* 1.22 - Add healthcheck to container create
|
||||
* 1.23 - Add attribute 'type' to parameter 'mounts'
|
||||
* 1.24 - Add exposed_ports to container
|
||||
"""
|
||||
|
||||
BASE_VER = '1.1'
|
||||
CURRENT_MAX_VER = '1.23'
|
||||
CURRENT_MAX_VER = '1.24'
|
||||
|
||||
|
||||
class Version(object):
|
||||
|
@ -188,3 +188,17 @@ user documentation.
|
||||
|
||||
Add support for file injection when creating a container.
|
||||
The content of the file is sent to Zun server via parameter 'mounts'.
|
||||
|
||||
1.24
|
||||
----
|
||||
|
||||
Add a parameter 'exposed_ports' to the request of creating a container.
|
||||
This parameter is of the following form:
|
||||
|
||||
"exposed_ports": { "<port>/<protocol>: {}" }
|
||||
|
||||
where 'port' is the container's port and 'protocol' is either 'tcp' or 'udp'.
|
||||
If this parameter is specified, Zun will create a security group and open
|
||||
the exposed port. This parameter cannot be used together with the
|
||||
'security_groups' parameter because Zun will manage the security groups of
|
||||
the container.
|
||||
|
@ -487,6 +487,36 @@ def check_for_restart_policy(container_dict):
|
||||
container_dict.get('restart_policy')['MaximumRetryCount'] = '0'
|
||||
|
||||
|
||||
def build_exposed_ports(ports):
|
||||
|
||||
def validate_protocol(protocol):
|
||||
if protocol not in ('tcp', 'udp'):
|
||||
raise exception.InvalidValue(_(
|
||||
"value %s is an invalid protocol") % protocol)
|
||||
|
||||
def validate_port(port):
|
||||
try:
|
||||
int(port)
|
||||
except ValueError:
|
||||
msg = _("value %s is invalid as publish port.") % port
|
||||
raise exception.InvalidValue(msg)
|
||||
|
||||
exposed_ports = {}
|
||||
for key, value in ports.items():
|
||||
try:
|
||||
port, protocol = key.split('/')
|
||||
except ValueError:
|
||||
port, protocol = key, 'tcp'
|
||||
|
||||
validate_protocol(protocol)
|
||||
validate_port(port)
|
||||
|
||||
key = '/'.join([port, protocol])
|
||||
exposed_ports[key] = value
|
||||
|
||||
return exposed_ports
|
||||
|
||||
|
||||
def build_requested_networks(context, nets):
|
||||
"""Build requested networks by calling neutron client
|
||||
|
||||
|
@ -17,6 +17,7 @@ import functools
|
||||
import types
|
||||
|
||||
from docker import errors
|
||||
from neutronclient.common import exceptions as n_exc
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
@ -285,6 +286,7 @@ class DockerDriver(driver.ContainerDriver):
|
||||
# host_config['pid_mode'] = 'container:%s' % sandbox_id
|
||||
host_config['ipc_mode'] = 'container:%s' % sandbox_id
|
||||
else:
|
||||
self._process_exposed_ports(network_api.neutron_api, container)
|
||||
self._process_networking_config(
|
||||
context, container, requested_networks, host_config,
|
||||
kwargs, docker)
|
||||
@ -343,6 +345,16 @@ class DockerDriver(driver.ContainerDriver):
|
||||
def get_host_default_base_size(self):
|
||||
return self.base_device_size
|
||||
|
||||
def _process_exposed_ports(self, neutron_api, container):
|
||||
if not container.exposed_ports:
|
||||
return
|
||||
|
||||
secgroup_name = self._get_secgorup_name(container.uuid)
|
||||
secgroup_id = neutron_api.create_security_group({'security_group': {
|
||||
"name": secgroup_name}})['security_group']['id']
|
||||
neutron_api.expose_ports(secgroup_id, container.exposed_ports)
|
||||
container.security_groups = [secgroup_id]
|
||||
|
||||
def _process_networking_config(self, context, container,
|
||||
requested_networks, host_config,
|
||||
container_kwargs, docker):
|
||||
@ -380,6 +392,9 @@ class DockerDriver(driver.ContainerDriver):
|
||||
self._get_or_create_docker_network(
|
||||
context, network_api, rq_network['network'])
|
||||
|
||||
def _get_secgorup_name(self, container_uuid):
|
||||
return consts.NAME_PREFIX + container_uuid
|
||||
|
||||
def _get_binds(self, context, requested_volumes):
|
||||
binds = {}
|
||||
for volume in requested_volumes:
|
||||
@ -419,6 +434,8 @@ class DockerDriver(driver.ContainerDriver):
|
||||
network_api = zun_network.api(context=context,
|
||||
docker_api=docker)
|
||||
self._cleanup_network_for_container(container, network_api)
|
||||
self._cleanup_exposed_ports(network_api.neutron_api,
|
||||
container)
|
||||
if container.container_id:
|
||||
docker.remove_container(container.container_id,
|
||||
force=force)
|
||||
@ -438,6 +455,15 @@ class DockerDriver(driver.ContainerDriver):
|
||||
network_api.disconnect_container_from_network(
|
||||
container, docker_net, neutron_network_id=neutron_net)
|
||||
|
||||
def _cleanup_exposed_ports(self, neutron_api, container):
|
||||
if not container.exposed_ports:
|
||||
return
|
||||
|
||||
try:
|
||||
neutron_api.delete_security_group(container.security_groups[0])
|
||||
except n_exc.NeutronClientException:
|
||||
LOG.exception("Failed to delete security group")
|
||||
|
||||
def check_container_exist(self, container):
|
||||
with docker_utils.docker_client() as docker:
|
||||
docker_containers = [c['Id']
|
||||
@ -975,6 +1001,7 @@ class DockerDriver(driver.ContainerDriver):
|
||||
'hostname': name[:63],
|
||||
'volumes': volumes,
|
||||
}
|
||||
self._process_exposed_ports(network_api.neutron_api, container)
|
||||
self._process_networking_config(
|
||||
context, container, requested_networks, host_config,
|
||||
kwargs, docker)
|
||||
@ -1042,6 +1069,7 @@ class DockerDriver(driver.ContainerDriver):
|
||||
with docker_utils.docker_client() as docker:
|
||||
network_api = zun_network.api(context=context, docker_api=docker)
|
||||
self._cleanup_network_for_container(container, network_api)
|
||||
self._cleanup_exposed_ports(network_api.neutron_api, container)
|
||||
try:
|
||||
docker.remove_container(sandbox_id, force=True)
|
||||
except errors.APIError as api_error:
|
||||
|
@ -0,0 +1,37 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""add_exposed_ports_to_container
|
||||
|
||||
Revision ID: 02134de8e7d3
|
||||
Revises: a019998b09b5
|
||||
Create Date: 2018-08-19 19:29:51.636559
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '02134de8e7d3'
|
||||
down_revision = 'a019998b09b5'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
import zun
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('container',
|
||||
sa.Column('exposed_ports',
|
||||
zun.db.sqlalchemy.models.JSONEncodedDict(),
|
||||
nullable=True))
|
@ -172,6 +172,7 @@ class Container(Base):
|
||||
started_at = Column(DateTime)
|
||||
privileged = Column(Boolean, default=False)
|
||||
healthcheck = Column(JSONEncodedDict)
|
||||
exposed_ports = Column(JSONEncodedDict)
|
||||
|
||||
|
||||
class VolumeMapping(Base):
|
||||
|
@ -189,18 +189,6 @@ class KuryrNetwork(network.Network):
|
||||
if requested_network.get('port'):
|
||||
neutron_port_id = requested_network.get('port')
|
||||
neutron_port = self.neutron_api.get_neutron_port(neutron_port_id)
|
||||
# NOTE(hongbin): If existing port is specified, security_group_ids
|
||||
# is ignored because existing port already has security groups.
|
||||
# We might revisit this behaviour later. Alternatively, we could
|
||||
# either throw an exception or overwrite the port's security
|
||||
# groups.
|
||||
if not container.security_groups:
|
||||
container.security_groups = []
|
||||
if neutron_port.get('security_groups'):
|
||||
for sg in neutron_port['security_groups']:
|
||||
if sg not in container.security_groups:
|
||||
container.security_groups += [sg]
|
||||
|
||||
# update device_id in port
|
||||
port_req_body = {'port': {'device_id': container.uuid}}
|
||||
self.neutron_api.update_port(neutron_port_id, port_req_body)
|
||||
|
@ -11,7 +11,9 @@
|
||||
# under the License.
|
||||
|
||||
from neutron_lib import constants as n_const
|
||||
from neutronclient.common import exceptions as n_exceptions
|
||||
from neutronclient.neutron import v2_0 as neutronv20
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from zun.common import clients
|
||||
@ -19,6 +21,9 @@ from zun.common import exception
|
||||
from zun.common.i18n import _
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NeutronAPI(object):
|
||||
|
||||
def __init__(self, context):
|
||||
@ -98,3 +103,26 @@ class NeutronAPI(object):
|
||||
binding_vif_type = port.get('binding:vif_type')
|
||||
if binding_vif_type == 'binding_failed':
|
||||
raise exception.PortBindingFailed(port=port['id'])
|
||||
|
||||
def expose_ports(self, secgroup_id, ports):
|
||||
for port in ports:
|
||||
port, proto = port.split('/')
|
||||
secgroup_rule = {
|
||||
'security_group_id': secgroup_id,
|
||||
'direction': 'ingress',
|
||||
'port_range_min': port,
|
||||
'port_range_max': port,
|
||||
'protocol': proto
|
||||
}
|
||||
|
||||
try:
|
||||
self.create_security_group_rule({
|
||||
'security_group_rule': secgroup_rule})
|
||||
except n_exceptions.NeutronClientException as ex:
|
||||
LOG.error("Error happened during creating a "
|
||||
"Neutron security group "
|
||||
"rule: %s", ex)
|
||||
self.delete_security_group(secgroup_id)
|
||||
raise exception.ZunException(_(
|
||||
"Could not create required security group rules %s "
|
||||
"for setting up exported port.") % secgroup_rule)
|
||||
|
@ -67,7 +67,8 @@ class Container(base.ZunPersistentObject, base.ZunObject):
|
||||
# Version 1.34: Add privileged to container
|
||||
# Version 1.35: Add 'healthcheck' attribute
|
||||
# Version 1.36: Add 'get_count' method
|
||||
VERSION = '1.36'
|
||||
# Version 1.37: Add 'exposed_ports' attribute
|
||||
VERSION = '1.37'
|
||||
|
||||
fields = {
|
||||
'id': fields.IntegerField(),
|
||||
@ -107,6 +108,7 @@ class Container(base.ZunPersistentObject, base.ZunObject):
|
||||
'auto_heal': fields.BooleanField(nullable=True),
|
||||
'capsule_id': fields.IntegerField(nullable=True),
|
||||
'started_at': fields.DateTimeField(tzinfo_aware=False, nullable=True),
|
||||
'exposed_ports': z_fields.JsonField(nullable=True),
|
||||
'exec_instances': fields.ListOfObjectsField('ExecInstance',
|
||||
nullable=True),
|
||||
'privileged': fields.BooleanField(nullable=True),
|
||||
|
@ -26,7 +26,7 @@ from zun.tests.unit.db import base
|
||||
|
||||
|
||||
PATH_PREFIX = '/v1'
|
||||
CURRENT_VERSION = "container 1.23"
|
||||
CURRENT_VERSION = "container 1.24"
|
||||
|
||||
|
||||
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.23',
|
||||
'max_version': '1.24',
|
||||
'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.23',
|
||||
'max_version': '1.24',
|
||||
'min_version': '1.1',
|
||||
'status': 'CURRENT'}]}
|
||||
|
||||
|
@ -87,6 +87,24 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
self.post('/v1/containers?run=true', params=params,
|
||||
content_type='application/json')
|
||||
|
||||
@patch('zun.network.neutron.NeutronAPI.get_available_network')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
def test_run_container_wrong_exposed_ports(
|
||||
self, mock_container_create, mock_mock_neutron_get_network):
|
||||
params = ('{"name": "MyDocker", "image": "ubuntu",'
|
||||
'"exposed_ports": {"foo": {}}}')
|
||||
with self.assertRaisesRegex(AppError,
|
||||
"value foo is invalid as publish port"):
|
||||
self.post('/v1/containers?run=true', params=params,
|
||||
content_type='application/json')
|
||||
|
||||
params = ('{"name": "MyDocker", "image": "ubuntu",'
|
||||
'"exposed_ports": {"80/foo": {}}}')
|
||||
with self.assertRaisesRegex(AppError,
|
||||
"value foo is an invalid protocol"):
|
||||
self.post('/v1/containers?run=true', params=params,
|
||||
content_type='application/json')
|
||||
|
||||
def test_run_container_runtime_wrong_api_version(self):
|
||||
params = ('{"name": "MyDocker", "image": "ubuntu",'
|
||||
'"command": "env", "memory": "512",'
|
||||
@ -282,6 +300,7 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
'"runtime": "runc", "hostname": "testhost",'
|
||||
'"disk": 20, "restart_policy": {"Name": "no"},'
|
||||
'"nets": [{"network": "testpublicnet"}],'
|
||||
'"exposed_ports": {"80/tcp": {}, "22": {}},'
|
||||
'"mounts": [{"source": "s", "destination": "d"}]}')
|
||||
response = self.post('/v1/containers/',
|
||||
params=params,
|
||||
@ -311,6 +330,10 @@ class TestContainerController(api_base.FunctionalTest):
|
||||
mock_container_create.call_args[1]['requested_volumes']
|
||||
self.assertEqual(1, len(requested_volumes))
|
||||
self.assertEqual(fake_volume_id, requested_volumes[0].volume_id)
|
||||
exposed_ports = mock_container_create.call_args[0][1].exposed_ports
|
||||
self.assertEqual(2, len(exposed_ports))
|
||||
self.assertIn("80/tcp", exposed_ports)
|
||||
self.assertIn("22/tcp", exposed_ports)
|
||||
|
||||
# Delete the container we created
|
||||
def side_effect(*args, **kwargs):
|
||||
|
@ -94,6 +94,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self.driver.images(repo='test')
|
||||
self.mock_docker.images.assert_called_once_with('test', False)
|
||||
|
||||
@mock.patch('neutronclient.v2_0.client.Client.create_security_group')
|
||||
@mock.patch('zun.network.neutron.NeutronAPI.expose_ports')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.connect_container_to_network')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
@ -104,7 +106,9 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self, mock_save,
|
||||
mock_get_security_group_ids,
|
||||
mock_create_or_update_port,
|
||||
mock_connect):
|
||||
mock_connect,
|
||||
mock_expose_ports,
|
||||
mock_create_security_group):
|
||||
self.mock_docker.create_host_config = mock.Mock(
|
||||
return_value={'Id1': 'val1', 'key2': 'val2'})
|
||||
self.mock_docker.create_container = mock.Mock(
|
||||
@ -122,6 +126,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
volumes = []
|
||||
fake_port = {'mac_address': 'fake_mac'}
|
||||
mock_create_or_update_port.return_value = ([], fake_port)
|
||||
mock_create_security_group.return_value = {
|
||||
'security_group': {'id': 'fake-id'}}
|
||||
# DockerDriver with supported storage driver - overlay2
|
||||
self.driver._host.sp_disk_quota = True
|
||||
self.driver._host.storage_driver = 'overlay2'
|
||||
@ -161,6 +167,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self.assertEqual(result_container.status,
|
||||
consts.CREATED)
|
||||
|
||||
@mock.patch('neutronclient.v2_0.client.Client.create_security_group')
|
||||
@mock.patch('zun.network.neutron.NeutronAPI.expose_ports')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.connect_container_to_network')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
@ -171,7 +179,9 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self, mock_save,
|
||||
mock_get_security_group_ids,
|
||||
mock_create_or_update_port,
|
||||
mock_connect):
|
||||
mock_connect,
|
||||
mock_expose_ports,
|
||||
mock_create_security_group):
|
||||
self.mock_docker.create_host_config = mock.Mock(
|
||||
return_value={'Id1': 'val1', 'key2': 'val2'})
|
||||
self.mock_docker.create_container = mock.Mock(
|
||||
@ -189,6 +199,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
volumes = []
|
||||
fake_port = {'mac_address': 'fake_mac'}
|
||||
mock_create_or_update_port.return_value = ([], fake_port)
|
||||
mock_create_security_group.return_value = {
|
||||
'security_group': {'id': 'fake-id'}}
|
||||
# DockerDriver with supported storage driver - overlay2
|
||||
self.driver._host.sp_disk_quota = True
|
||||
self.driver._host.storage_driver = 'devicemapper'
|
||||
@ -229,6 +241,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self.assertEqual(result_container.status,
|
||||
consts.CREATED)
|
||||
|
||||
@mock.patch('neutronclient.v2_0.client.Client.create_security_group')
|
||||
@mock.patch('zun.network.neutron.NeutronAPI.expose_ports')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.connect_container_to_network')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
@ -239,7 +253,9 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self, mock_save,
|
||||
mock_get_security_group_ids,
|
||||
mock_create_or_update_port,
|
||||
mock_connect):
|
||||
mock_connect,
|
||||
mock_expose_ports,
|
||||
mock_create_security_group):
|
||||
CONF.set_override("docker_remote_api_version", "1.24", "docker")
|
||||
self.mock_docker.create_host_config = mock.Mock(
|
||||
return_value={'Id1': 'val1', 'key2': 'val2'})
|
||||
@ -259,6 +275,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
volumes = []
|
||||
fake_port = {'mac_address': 'fake_mac'}
|
||||
mock_create_or_update_port.return_value = ([], fake_port)
|
||||
mock_create_security_group.return_value = {
|
||||
'security_group': {'id': 'fake-id'}}
|
||||
result_container = self.driver.create(self.context, mock_container,
|
||||
image, networks, volumes)
|
||||
host_config = {}
|
||||
@ -335,11 +353,15 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
|
||||
@mock.patch('zun.container.docker.driver.DockerDriver'
|
||||
'._cleanup_network_for_container')
|
||||
def test_delete_success(self, mock_cleanup_network_for_container):
|
||||
@mock.patch('zun.container.docker.driver.DockerDriver'
|
||||
'._cleanup_exposed_ports')
|
||||
def test_delete_success(self, mock_cleanup_network_for_container,
|
||||
mock_cleanup_exposed_ports):
|
||||
self.mock_docker.remove_container = mock.Mock()
|
||||
mock_container = self.mock_default_container
|
||||
self.driver.delete(self.context, mock_container, True)
|
||||
self.assertTrue(mock_cleanup_network_for_container.called)
|
||||
self.assertTrue(mock_cleanup_exposed_ports.called)
|
||||
self.mock_docker.remove_container.assert_called_once_with(
|
||||
mock_container.container_id, force=True)
|
||||
|
||||
@ -714,6 +736,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self.mock_docker.commit.assert_called_once_with(
|
||||
mock_container.container_id, "repo", "tag")
|
||||
|
||||
@mock.patch('neutronclient.v2_0.client.Client.create_security_group')
|
||||
@mock.patch('zun.network.neutron.NeutronAPI.expose_ports')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.connect_container_to_network')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
@ -722,7 +746,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
@mock.patch('zun.common.utils.get_security_group_ids')
|
||||
def test_create_sandbox(self, mock_get_security_group_ids,
|
||||
mock_get_sandbox_name, mock_create_or_update_port,
|
||||
mock_connect):
|
||||
mock_connect, mock_expose_ports,
|
||||
mock_create_security_group):
|
||||
sandbox_name = 'my_test_sandbox'
|
||||
mock_get_sandbox_name.return_value = sandbox_name
|
||||
self.mock_docker.create_container = mock.Mock(
|
||||
@ -747,6 +772,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
networking_config={'Id': 'val1', 'key1': 'val2'})
|
||||
self.assertEqual(result_sandbox_id, 'val1')
|
||||
|
||||
@mock.patch('neutronclient.v2_0.client.Client.create_security_group')
|
||||
@mock.patch('zun.network.neutron.NeutronAPI.expose_ports')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.connect_container_to_network')
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
@ -756,7 +783,9 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
def test_create_sandbox_with_long_name(self, mock_get_security_group_ids,
|
||||
mock_get_sandbox_name,
|
||||
mock_create_or_update_port,
|
||||
mock_connect):
|
||||
mock_connect,
|
||||
mock_expose_ports,
|
||||
mock_create_security_group):
|
||||
sandbox_name = 'x' * 100
|
||||
mock_get_sandbox_name.return_value = sandbox_name
|
||||
self.mock_docker.create_container = mock.Mock(
|
||||
@ -780,7 +809,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
networking_config={'Id': 'val1', 'key1': 'val2'})
|
||||
self.assertEqual(result_sandbox_id, 'val1')
|
||||
|
||||
def test_delete_sandbox(self):
|
||||
@mock.patch('neutronclient.v2_0.client.Client.delete_security_group')
|
||||
def test_delete_sandbox(self, mock_delete_security_group):
|
||||
self.mock_docker.remove_container = mock.Mock()
|
||||
mock_container = mock.MagicMock()
|
||||
mock_container.get_sandbox_id.return_value = 'test_sandbox_id'
|
||||
|
@ -107,6 +107,7 @@ def get_test_container(**kwargs):
|
||||
{"retries": "2", "timeout": 3,
|
||||
"test": "stat /etc/passwd || exit 1",
|
||||
"interval": 3}),
|
||||
'exposed_ports': kwargs.get('exposed_ports', {"80/tcp": {}}),
|
||||
}
|
||||
|
||||
|
||||
|
@ -344,7 +344,7 @@ class TestObject(test_base.TestCase, _TestObject):
|
||||
# For more information on object version testing, read
|
||||
# https://docs.openstack.org/zun/latest/
|
||||
object_data = {
|
||||
'Container': '1.36-ad2bacdaa51afd0047e96003f93ff181',
|
||||
'Container': '1.37-cdc1537de5adf3570b598da1a3728a68',
|
||||
'VolumeMapping': '1.3-14e3f9fc64e7afd751727c6ad3f32a94',
|
||||
'Image': '1.2-80504fdd797e9dd86128a91680e876ad',
|
||||
'MyObj': '1.0-34c4b1aadefd177b13f9a2f894cc23cd',
|
||||
|
Loading…
Reference in New Issue
Block a user