Merge "Make sandbox container optional"
This commit is contained in:
commit
080f4fb00f
@ -40,6 +40,10 @@ class Manager(object):
|
||||
self.driver = driver.load_container_driver(container_driver)
|
||||
self.host = CONF.host
|
||||
self._resource_tracker = None
|
||||
if self._use_sandbox():
|
||||
self.use_sandbox = True
|
||||
else:
|
||||
self.use_sandbox = False
|
||||
|
||||
def _fail_container(self, context, container, error, unset_host=False):
|
||||
container.status = consts.ERROR
|
||||
@ -66,9 +70,13 @@ class Manager(object):
|
||||
if created_container:
|
||||
self._do_container_start(context, created_container)
|
||||
|
||||
def _do_sandbox_cleanup(self, context, container, sandbox_id):
|
||||
def _do_sandbox_cleanup(self, context, container):
|
||||
sandbox_id = container.get_sandbox_id()
|
||||
if sandbox_id is None:
|
||||
return
|
||||
|
||||
try:
|
||||
self.driver.delete_sandbox(context, container, sandbox_id)
|
||||
self.driver.delete_sandbox(context, container)
|
||||
except Exception as e:
|
||||
LOG.error("Error occurred while deleting sandbox: %s",
|
||||
six.text_type(e))
|
||||
@ -90,10 +98,12 @@ class Manager(object):
|
||||
self._fail_container(self, context, container, msg)
|
||||
return
|
||||
|
||||
sandbox_id = self._create_sandbox(context, container,
|
||||
requested_networks, reraise)
|
||||
if sandbox_id is None:
|
||||
return
|
||||
sandbox_id = None
|
||||
if self.use_sandbox:
|
||||
sandbox_id = self._create_sandbox(context, container,
|
||||
requested_networks, reraise)
|
||||
if sandbox_id is None:
|
||||
return
|
||||
|
||||
self._update_task_state(context, container, consts.IMAGE_PULLING)
|
||||
repo, tag = utils.parse_image_name(container.image)
|
||||
@ -108,21 +118,21 @@ class Manager(object):
|
||||
except exception.ImageNotFound as e:
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.error(six.text_type(e))
|
||||
self._do_sandbox_cleanup(context, container, sandbox_id)
|
||||
self._do_sandbox_cleanup(context, container)
|
||||
self._fail_container(context, container, six.text_type(e))
|
||||
return
|
||||
except exception.DockerError as e:
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.error("Error occurred while calling Docker image API: %s",
|
||||
six.text_type(e))
|
||||
self._do_sandbox_cleanup(context, container, sandbox_id)
|
||||
self._do_sandbox_cleanup(context, container)
|
||||
self._fail_container(context, container, six.text_type(e))
|
||||
return
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.exception("Unexpected exception: %s",
|
||||
six.text_type(e))
|
||||
self._do_sandbox_cleanup(context, container, sandbox_id)
|
||||
self._do_sandbox_cleanup(context, container)
|
||||
self._fail_container(context, container, six.text_type(e))
|
||||
return
|
||||
|
||||
@ -134,15 +144,14 @@ class Manager(object):
|
||||
rt = self._get_resource_tracker()
|
||||
with rt.container_claim(context, container, container.host,
|
||||
limits):
|
||||
container = self.driver.create(context, container,
|
||||
sandbox_id, image)
|
||||
container = self.driver.create(context, container, image)
|
||||
self._update_task_state(context, container, None)
|
||||
return container
|
||||
except exception.DockerError as e:
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.error("Error occurred while calling Docker create API: %s",
|
||||
six.text_type(e))
|
||||
self._do_sandbox_cleanup(context, container, sandbox_id)
|
||||
self._do_sandbox_cleanup(context, container)
|
||||
self._fail_container(context, container, six.text_type(e),
|
||||
unset_host=True)
|
||||
return
|
||||
@ -150,11 +159,24 @@ class Manager(object):
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.exception("Unexpected exception: %s",
|
||||
six.text_type(e))
|
||||
self._do_sandbox_cleanup(context, container, sandbox_id)
|
||||
self._do_sandbox_cleanup(context, container)
|
||||
self._fail_container(context, container, six.text_type(e),
|
||||
unset_host=True)
|
||||
return
|
||||
|
||||
def _use_sandbox(self):
|
||||
if CONF.use_sandbox and self.driver.capabilities["support_sandbox"]:
|
||||
return True
|
||||
elif (not CONF.use_sandbox and
|
||||
self.driver.capabilities["support_standalone"]):
|
||||
return False
|
||||
else:
|
||||
raise exception.ZunException(_(
|
||||
"The configuration of use_sandbox '%(use_sandbox)s' is not "
|
||||
"supported by driver '%(driver)s'.") %
|
||||
{'use_sandbox': CONF.use_sandbox,
|
||||
'driver': self.driver})
|
||||
|
||||
def _create_sandbox(self, context, container, requested_networks,
|
||||
reraise=False):
|
||||
self._update_task_state(context, container, consts.SANDBOX_CREATING)
|
||||
@ -202,7 +224,7 @@ class Manager(object):
|
||||
self._update_task_state(context, container, consts.CONTAINER_DELETING)
|
||||
reraise = not force
|
||||
try:
|
||||
self.driver.delete(container, force)
|
||||
self.driver.delete(context, container, force)
|
||||
except exception.DockerError as e:
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.error(("Error occurred while calling Docker "
|
||||
@ -213,7 +235,9 @@ class Manager(object):
|
||||
LOG.exception("Unexpected exception: %s", six.text_type(e))
|
||||
self._fail_container(context, container, six.text_type(e))
|
||||
|
||||
self._delete_sandbox(context, container, reraise)
|
||||
if self.use_sandbox:
|
||||
self._delete_sandbox(context, container, reraise)
|
||||
|
||||
self._update_task_state(context, container, None)
|
||||
container.destroy(context)
|
||||
self._get_resource_tracker()
|
||||
@ -224,12 +248,12 @@ class Manager(object):
|
||||
return container
|
||||
|
||||
def _delete_sandbox(self, context, container, reraise=False):
|
||||
sandbox_id = self.driver.get_sandbox_id(container)
|
||||
sandbox_id = container.get_sandbox_id()
|
||||
if sandbox_id:
|
||||
self._update_task_state(context, container,
|
||||
consts.SANDBOX_DELETING)
|
||||
try:
|
||||
self.driver.delete_sandbox(context, container, sandbox_id)
|
||||
self.driver.delete_sandbox(context, container)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||
LOG.exception("Unexpected exception: %s", six.text_type(e))
|
||||
@ -242,9 +266,7 @@ class Manager(object):
|
||||
def _add_security_group(self, context, container, security_group):
|
||||
LOG.debug('Adding security_group to container: %s', container.uuid)
|
||||
try:
|
||||
sandbox_id = self.driver.get_sandbox_id(container)
|
||||
self.driver.add_security_group(context, container, security_group,
|
||||
sandbox_id=sandbox_id)
|
||||
self.driver.add_security_group(context, container, security_group)
|
||||
container.security_groups += [security_group]
|
||||
container.save(context)
|
||||
except Exception as e:
|
||||
|
@ -37,6 +37,16 @@ Interdependencies to other options:
|
||||
cfg.StrOpt('floating_cpu_set',
|
||||
default="",
|
||||
help='Define the cpusets to be excluded from pinning'),
|
||||
cfg.BoolOpt('use_sandbox',
|
||||
default=False,
|
||||
help="""Whether to use infra container. If set to True,
|
||||
Zun will create an infra container that serves as a placeholder of a few
|
||||
Linux namespaces (i.e. network namespace). Then, one or multiple containers
|
||||
could join the namespaces of the infra container thus sharing resources inside
|
||||
the sandbox (i.e. the network interface). This is typically used to group
|
||||
a set of high-coupled containers into a unit. If set to False, infra container
|
||||
won't be created.
|
||||
""")
|
||||
]
|
||||
|
||||
|
||||
|
@ -76,6 +76,10 @@ def wrap_docker_error(function):
|
||||
|
||||
class DockerDriver(driver.ContainerDriver):
|
||||
"""Implementation of container drivers for Docker."""
|
||||
capabilities = {
|
||||
"support_sandbox": True,
|
||||
"support_standalone": True,
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super(DockerDriver, self).__init__()
|
||||
@ -102,12 +106,24 @@ class DockerDriver(driver.ContainerDriver):
|
||||
with docker_utils.docker_client() as docker:
|
||||
return docker.images(repo, quiet)
|
||||
|
||||
def create(self, context, container, sandbox_id, image):
|
||||
def create(self, context, container, image, requested_networks=None):
|
||||
sandbox_id = container.get_sandbox_id()
|
||||
network_standalone = False if sandbox_id else True
|
||||
|
||||
with docker_utils.docker_client() as docker:
|
||||
network_api = zun_network.api(context=context, docker_api=docker)
|
||||
name = container.name
|
||||
image = container.image
|
||||
LOG.debug('Creating container with image %(image)s name %(name)s',
|
||||
{'image': image, 'name': name})
|
||||
if requested_networks is None:
|
||||
if network_standalone:
|
||||
network = self._provision_network(context, container,
|
||||
network_api)
|
||||
requested_networks = [{'network': network['Name'],
|
||||
'port': '',
|
||||
'v4-fixed-ip': '',
|
||||
'v6-fixed-ip': ''}]
|
||||
|
||||
kwargs = {
|
||||
'name': self.get_container_name(container),
|
||||
@ -120,12 +136,13 @@ class DockerDriver(driver.ContainerDriver):
|
||||
}
|
||||
|
||||
host_config = {}
|
||||
host_config['network_mode'] = 'container:%s' % sandbox_id
|
||||
# TODO(hongbin): Uncomment this after docker-py add support for
|
||||
# container mode for pid namespace.
|
||||
# host_config['pid_mode'] = 'container:%s' % sandbox_id
|
||||
host_config['ipc_mode'] = 'container:%s' % sandbox_id
|
||||
host_config['volumes_from'] = sandbox_id
|
||||
if sandbox_id:
|
||||
host_config['network_mode'] = 'container:%s' % sandbox_id
|
||||
# TODO(hongbin): Uncomment this after docker-py add support for
|
||||
# container mode for pid namespace.
|
||||
# host_config['pid_mode'] = 'container:%s' % sandbox_id
|
||||
host_config['ipc_mode'] = 'container:%s' % sandbox_id
|
||||
host_config['volumes_from'] = sandbox_id
|
||||
if container.auto_remove:
|
||||
host_config['auto_remove'] = container.auto_remove
|
||||
if container.memory is not None:
|
||||
@ -142,6 +159,12 @@ class DockerDriver(driver.ContainerDriver):
|
||||
|
||||
response = docker.create_container(image, **kwargs)
|
||||
container.container_id = response['Id']
|
||||
|
||||
if network_standalone:
|
||||
addresses = self._setup_network_for_container(
|
||||
context, container, requested_networks, network_api)
|
||||
container.addresses = addresses
|
||||
|
||||
container.status = consts.CREATED
|
||||
container.status_reason = None
|
||||
container.save(context)
|
||||
@ -160,26 +183,32 @@ class DockerDriver(driver.ContainerDriver):
|
||||
|
||||
def _setup_network_for_container(self, context, container,
|
||||
requested_networks, network_api):
|
||||
sandbox_id = self.get_sandbox_id(container)
|
||||
security_group_ids = self._get_security_group_ids(
|
||||
context, container.security_groups)
|
||||
# Container connects to the bridge network by default so disconnect
|
||||
# the container from it before connecting it to neutron network.
|
||||
# This avoids potential conflict between these two networks.
|
||||
network_api.disconnect_container_from_network(container, 'bridge',
|
||||
sandbox_id)
|
||||
network_api.disconnect_container_from_network(container, 'bridge')
|
||||
addresses = {}
|
||||
for network in requested_networks:
|
||||
network_name = network['network']
|
||||
addrs = network_api.connect_container_to_network(
|
||||
container, network_name, sandbox_id=sandbox_id,
|
||||
security_groups=security_group_ids)
|
||||
container, network_name, security_groups=security_group_ids)
|
||||
addresses[network_name] = addrs
|
||||
|
||||
return addresses
|
||||
|
||||
def delete(self, container, force):
|
||||
def delete(self, context, container, force):
|
||||
teardown_network = True
|
||||
if container.get_sandbox_id():
|
||||
teardown_network = False
|
||||
|
||||
with docker_utils.docker_client() as docker:
|
||||
if teardown_network:
|
||||
network_api = zun_network.api(context=context,
|
||||
docker_api=docker)
|
||||
self._cleanup_network_for_container(container, network_api)
|
||||
|
||||
if container.container_id:
|
||||
try:
|
||||
docker.remove_container(container.container_id,
|
||||
@ -189,11 +218,9 @@ class DockerDriver(driver.ContainerDriver):
|
||||
return
|
||||
raise
|
||||
|
||||
def _cleanup_network_for_container(self, container, network_api,
|
||||
sandbox_id):
|
||||
def _cleanup_network_for_container(self, container, network_api):
|
||||
for name in container.addresses:
|
||||
network_api.disconnect_container_from_network(container, name,
|
||||
sandbox_id)
|
||||
network_api.disconnect_container_from_network(container, name)
|
||||
|
||||
def list(self, context):
|
||||
id_to_container_map = {}
|
||||
@ -619,9 +646,13 @@ class DockerDriver(driver.ContainerDriver):
|
||||
name = self.get_sandbox_name(container)
|
||||
sandbox = docker.create_container(image, name=name,
|
||||
hostname=name[:63])
|
||||
self.set_sandbox_id(container, sandbox['Id'])
|
||||
container.set_sandbox_id(sandbox['Id'])
|
||||
addresses = self._setup_network_for_container(
|
||||
context, container, requested_networks, network_api)
|
||||
if addresses is None:
|
||||
raise exception.ZunException(_(
|
||||
"Unexpected missing of addresses"))
|
||||
|
||||
container.addresses = addresses
|
||||
container.save(context)
|
||||
|
||||
@ -669,11 +700,11 @@ class DockerDriver(driver.ContainerDriver):
|
||||
|
||||
return docker_networks[0]
|
||||
|
||||
def delete_sandbox(self, context, container, sandbox_id):
|
||||
def delete_sandbox(self, context, container):
|
||||
sandbox_id = container.get_sandbox_id()
|
||||
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,
|
||||
sandbox_id)
|
||||
self._cleanup_network_for_container(container, network_api)
|
||||
try:
|
||||
docker.remove_container(sandbox_id, force=True)
|
||||
except errors.APIError as api_error:
|
||||
@ -685,19 +716,6 @@ class DockerDriver(driver.ContainerDriver):
|
||||
with docker_utils.docker_client() as docker:
|
||||
docker.stop(sandbox_id)
|
||||
|
||||
def get_sandbox_id(self, container):
|
||||
if container.meta:
|
||||
return container.meta.get('sandbox_id', None)
|
||||
else:
|
||||
LOG.warning("Unexpected missing of sandbox_id")
|
||||
return None
|
||||
|
||||
def set_sandbox_id(self, container, sandbox_id):
|
||||
if container.meta is None:
|
||||
container.meta = {'sandbox_id': sandbox_id}
|
||||
else:
|
||||
container.meta['sandbox_id'] = sandbox_id
|
||||
|
||||
def get_sandbox_name(self, container):
|
||||
return 'zun-sandbox-' + container.uuid
|
||||
|
||||
@ -754,13 +772,18 @@ class DockerDriver(driver.ContainerDriver):
|
||||
sandbox = docker.inspect_container(sandbox_id)
|
||||
for network in sandbox["NetworkSettings"]["Networks"]:
|
||||
network_api.add_security_groups_to_ports(
|
||||
container, security_group_ids, sandbox_id)
|
||||
container, security_group_ids)
|
||||
|
||||
def get_available_nodes(self):
|
||||
return [self._host.get_hostname()]
|
||||
|
||||
|
||||
class NovaDockerDriver(DockerDriver):
|
||||
capabilities = {
|
||||
"support_sandbox": True,
|
||||
"support_standalone": False,
|
||||
}
|
||||
|
||||
def add_security_group(self, context, container, security_group, **kwargs):
|
||||
msg = "NovaDockerDriver does not support security_groups"
|
||||
raise exception.ZunException(msg)
|
||||
@ -839,7 +862,7 @@ class NovaDockerDriver(DockerDriver):
|
||||
def get_addresses(self, context, container):
|
||||
elevated = context.elevated()
|
||||
novaclient = nova.NovaClient(elevated)
|
||||
sandbox_id = self.get_sandbox_id(container)
|
||||
sandbox_id = container.get_sandbox_id()
|
||||
if sandbox_id:
|
||||
server_name = self._find_server_by_container_id(sandbox_id)
|
||||
if server_name:
|
||||
|
@ -68,7 +68,7 @@ class ContainerDriver(object):
|
||||
"""Commit a container."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete(self, container, force):
|
||||
def delete(self, context, container, force):
|
||||
"""Delete a container."""
|
||||
raise NotImplementedError()
|
||||
|
||||
@ -163,14 +163,6 @@ class ContainerDriver(object):
|
||||
"""Stop a sandbox."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_sandbox_id(self, container):
|
||||
"""Retrieve sandbox ID."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_sandbox_id(self, container, sandbox_id):
|
||||
"""Set sandbox ID."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_sandbox_name(self, container):
|
||||
"""Retrieve sandbox name."""
|
||||
raise NotImplementedError()
|
||||
|
@ -116,15 +116,15 @@ class KuryrNetwork(network.Network):
|
||||
return self.docker.networks(**kwargs)
|
||||
|
||||
def connect_container_to_network(self, container, network_name,
|
||||
sandbox_id=None, security_groups=None):
|
||||
security_groups=None):
|
||||
"""Connect container to the network
|
||||
|
||||
This method will create a neutron port, retrieve the ip address(es)
|
||||
of the port, and pass them to docker.connect_container_to_network.
|
||||
"""
|
||||
container_id = container.container_id
|
||||
if sandbox_id:
|
||||
container_id = sandbox_id
|
||||
container_id = container.get_sandbox_id()
|
||||
if not container_id:
|
||||
container_id = container.container_id
|
||||
|
||||
network = self.inspect_network(network_name)
|
||||
neutron_net_id = network['Options']['neutron.net.uuid']
|
||||
@ -166,11 +166,10 @@ class KuryrNetwork(network.Network):
|
||||
container_id, network_name, **kwargs)
|
||||
return addresses
|
||||
|
||||
def disconnect_container_from_network(self, container, network_name,
|
||||
sandbox_id=None):
|
||||
container_id = container.container_id
|
||||
if sandbox_id:
|
||||
container_id = sandbox_id
|
||||
def disconnect_container_from_network(self, container, network_name):
|
||||
container_id = container.get_sandbox_id()
|
||||
if not container_id:
|
||||
container_id = container.container_id
|
||||
|
||||
neutron_ports = set()
|
||||
if container.addresses:
|
||||
@ -190,8 +189,11 @@ class KuryrNetwork(network.Network):
|
||||
'or neutron tag extension does not supported or'
|
||||
' not enabled.')
|
||||
|
||||
def add_security_groups_to_ports(self, container, security_group_ids,
|
||||
sandbox_id=None):
|
||||
def add_security_groups_to_ports(self, container, security_group_ids):
|
||||
container_id = container.get_sandbox_id()
|
||||
if not container_id:
|
||||
container_id = container.container_id
|
||||
|
||||
port_ids = set()
|
||||
for addrs_list in container.addresses.values():
|
||||
for addr in addrs_list:
|
||||
|
@ -58,6 +58,6 @@ class Network(object):
|
||||
**kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
def add_security_groups_to_ports(self, container, network_name,
|
||||
security_group_ids, **kwargs):
|
||||
def add_security_groups_to_ports(self, container, security_group_ids,
|
||||
**kwargs):
|
||||
raise NotImplementedError()
|
||||
|
@ -214,3 +214,15 @@ class Container(base.ZunPersistentObject, base.ZunObject):
|
||||
if self.obj_attr_is_set(field) and \
|
||||
getattr(self, field) != getattr(current, field):
|
||||
setattr(self, field, getattr(current, field))
|
||||
|
||||
def get_sandbox_id(self):
|
||||
if self.meta:
|
||||
return self.meta.get('sandbox_id', None)
|
||||
else:
|
||||
return None
|
||||
|
||||
def set_sandbox_id(self, sandbox_id):
|
||||
if self.meta is None:
|
||||
self.meta = {'sandbox_id': sandbox_id}
|
||||
else:
|
||||
self.meta['sandbox_id'] = sandbox_id
|
||||
|
@ -55,13 +55,10 @@ class TestManager(base.TestCase):
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(fake_driver, 'create')
|
||||
@mock.patch.object(fake_driver, 'create_sandbox')
|
||||
def test_container_create(self, mock_create_sandbox, mock_create,
|
||||
mock_pull, mock_save):
|
||||
def test_container_create(self, mock_create, mock_pull, mock_save):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
image = {'image': 'repo', 'path': 'out_path', 'driver': 'glance'}
|
||||
mock_pull.return_value = image, False
|
||||
mock_create_sandbox.return_value = 'fake_id'
|
||||
self.compute_manager._resource_tracker = FakeResourceTracker()
|
||||
networks = []
|
||||
self.compute_manager._do_container_create(self.context, container,
|
||||
@ -69,18 +66,15 @@ class TestManager(base.TestCase):
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_pull.assert_any_call(self.context, container.image, 'latest',
|
||||
'always', 'glance')
|
||||
mock_create.assert_called_once_with(self.context, container,
|
||||
'fake_id', image)
|
||||
mock_create.assert_called_once_with(self.context, container, image)
|
||||
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'create_sandbox')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_create_pull_image_failed_docker_error(
|
||||
self, mock_fail, mock_pull, mock_create_sandbox, mock_save):
|
||||
self, mock_fail, mock_pull, mock_save):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_pull.side_effect = exception.DockerError("Pull Failed")
|
||||
mock_create_sandbox.return_value = mock.MagicMock()
|
||||
networks = []
|
||||
self.compute_manager._do_container_create(self.context, container,
|
||||
networks)
|
||||
@ -88,14 +82,12 @@ class TestManager(base.TestCase):
|
||||
container, "Pull Failed")
|
||||
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'create_sandbox')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_create_pull_image_failed_image_not_found(
|
||||
self, mock_fail, mock_pull, mock_create_sandbox, mock_save):
|
||||
self, mock_fail, mock_pull, mock_save):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_pull.side_effect = exception.ImageNotFound("Image Not Found")
|
||||
mock_create_sandbox.return_value = mock.MagicMock()
|
||||
networks = []
|
||||
self.compute_manager._do_container_create(self.context, container,
|
||||
networks)
|
||||
@ -103,15 +95,13 @@ class TestManager(base.TestCase):
|
||||
container, "Image Not Found")
|
||||
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'create_sandbox')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_create_pull_image_failed_zun_exception(
|
||||
self, mock_fail, mock_pull, mock_create_sandbox, mock_save):
|
||||
self, mock_fail, mock_pull, mock_save):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_pull.side_effect = exception.ZunException(
|
||||
message="Image Not Found")
|
||||
mock_create_sandbox.return_value = mock.MagicMock()
|
||||
networks = []
|
||||
self.compute_manager._do_container_create(self.context, container,
|
||||
networks)
|
||||
@ -121,17 +111,14 @@ class TestManager(base.TestCase):
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(fake_driver, 'create')
|
||||
@mock.patch.object(fake_driver, 'create_sandbox')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_create_docker_create_failed(self, mock_fail,
|
||||
mock_create_sandbox,
|
||||
mock_create, mock_pull,
|
||||
mock_save):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
image = {'image': 'repo', 'path': 'out_path', 'driver': 'glance'}
|
||||
mock_pull.return_value = image, False
|
||||
mock_create.side_effect = exception.DockerError("Creation Failed")
|
||||
mock_create_sandbox.return_value = mock.MagicMock()
|
||||
self.compute_manager._resource_tracker = FakeResourceTracker()
|
||||
networks = []
|
||||
self.compute_manager._do_container_create(self.context, container,
|
||||
@ -157,8 +144,7 @@ class TestManager(base.TestCase):
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_pull.assert_any_call(self.context, container.image, 'latest',
|
||||
'always', 'glance')
|
||||
mock_create.assert_called_once_with(self.context, container,
|
||||
'fake_sandbox', image)
|
||||
mock_create.assert_called_once_with(self.context, container, image)
|
||||
mock_start.assert_called_once_with(self.context, container)
|
||||
|
||||
@mock.patch.object(Container, 'save')
|
||||
@ -166,7 +152,10 @@ class TestManager(base.TestCase):
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_run_image_not_found(self, mock_fail,
|
||||
mock_pull, mock_save):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
container_dict = utils.get_test_container(
|
||||
image='test:latest', image_driver='docker',
|
||||
image_pull_policy='ifnotpresent')
|
||||
container = Container(self.context, **container_dict)
|
||||
mock_pull.side_effect = exception.ImageNotFound(
|
||||
message="Image Not Found")
|
||||
networks = []
|
||||
@ -176,15 +165,18 @@ class TestManager(base.TestCase):
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_fail.assert_called_with(self.context,
|
||||
container, 'Image Not Found')
|
||||
mock_pull.assert_called_once_with(self.context, 'kubernetes/pause',
|
||||
'latest', 'ifnotpresent', 'docker')
|
||||
mock_pull.assert_called_once_with(self.context, 'test', 'latest',
|
||||
'ifnotpresent', 'docker')
|
||||
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_run_image_pull_exception_raised(self, mock_fail,
|
||||
mock_pull, mock_save):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
container_dict = utils.get_test_container(
|
||||
image='test:latest', image_driver='docker',
|
||||
image_pull_policy='ifnotpresent')
|
||||
container = Container(self.context, **container_dict)
|
||||
mock_pull.side_effect = exception.ZunException(
|
||||
message="Image Not Found")
|
||||
networks = []
|
||||
@ -194,15 +186,18 @@ class TestManager(base.TestCase):
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_fail.assert_called_with(self.context,
|
||||
container, 'Image Not Found')
|
||||
mock_pull.assert_called_once_with(self.context, 'kubernetes/pause',
|
||||
'latest', 'ifnotpresent', 'docker')
|
||||
mock_pull.assert_called_once_with(self.context, 'test', 'latest',
|
||||
'ifnotpresent', 'docker')
|
||||
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
def test_container_run_image_pull_docker_error(self, mock_fail,
|
||||
mock_pull, mock_save):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
container_dict = utils.get_test_container(
|
||||
image='test:latest', image_driver='docker',
|
||||
image_pull_policy='ifnotpresent')
|
||||
container = Container(self.context, **container_dict)
|
||||
mock_pull.side_effect = exception.DockerError(
|
||||
message="Docker Error occurred")
|
||||
networks = []
|
||||
@ -212,8 +207,8 @@ class TestManager(base.TestCase):
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_fail.assert_called_with(self.context,
|
||||
container, 'Docker Error occurred')
|
||||
mock_pull.assert_called_once_with(self.context, 'kubernetes/pause',
|
||||
'latest', 'ifnotpresent', 'docker')
|
||||
mock_pull.assert_called_once_with(self.context, 'test', 'latest',
|
||||
'ifnotpresent', 'docker')
|
||||
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch('zun.image.driver.pull_image')
|
||||
@ -237,8 +232,7 @@ class TestManager(base.TestCase):
|
||||
mock_pull.assert_any_call(self.context, container.image, 'latest',
|
||||
'always', 'glance')
|
||||
mock_create.assert_called_once_with(
|
||||
self.context, container, 'fake_sandbox',
|
||||
{'name': 'nginx', 'path': None})
|
||||
self.context, container, {'name': 'nginx', 'path': None})
|
||||
|
||||
@mock.patch.object(compute_node_tracker.ComputeNodeTracker,
|
||||
'remove_usage_from_container')
|
||||
@ -250,7 +244,7 @@ class TestManager(base.TestCase):
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
self.compute_manager.container_delete(self. context, container, False)
|
||||
mock_save.assert_called_with(self.context)
|
||||
mock_delete.assert_called_once_with(container, False)
|
||||
mock_delete.assert_called_once_with(self.context, container, False)
|
||||
mock_cnt_destroy.assert_called_once_with(self.context)
|
||||
mock_remove_usage.assert_called_once_with(self.context, container,
|
||||
True)
|
||||
@ -272,14 +266,14 @@ class TestManager(base.TestCase):
|
||||
|
||||
@mock.patch.object(manager.Manager, '_fail_container')
|
||||
@mock.patch.object(fake_driver, 'delete_sandbox')
|
||||
@mock.patch.object(fake_driver, 'get_sandbox_id')
|
||||
@mock.patch.object(Container, 'save')
|
||||
@mock.patch.object(fake_driver, 'delete')
|
||||
def test_container_delete_sandbox_failed(self, mock_delete, mock_save,
|
||||
mock_sandbox, mock_delete_sandbox,
|
||||
mock_delete_sandbox,
|
||||
mock_fail):
|
||||
self.compute_manager.use_sandbox = True
|
||||
container = Container(self.context, **utils.get_test_container())
|
||||
mock_sandbox.return_value = "sandbox_id"
|
||||
container.set_sandbox_id("sandbox_id")
|
||||
mock_delete_sandbox.side_effect = exception.ZunException(
|
||||
message="Unexpected exception")
|
||||
self.assertRaises(exception.ZunException,
|
||||
|
@ -79,20 +79,24 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self.driver.images(repo='test')
|
||||
self.mock_docker.images.assert_called_once_with('test', False)
|
||||
|
||||
@mock.patch('zun.network.kuryr_network.KuryrNetwork'
|
||||
'.connect_container_to_network')
|
||||
@mock.patch(
|
||||
'zun.container.docker.driver.DockerDriver._get_security_group_ids')
|
||||
@mock.patch('zun.objects.container.Container.save')
|
||||
def test_create_image_path_is_none(self, mock_save):
|
||||
def test_create_image_path_is_none(self, mock_save,
|
||||
mock_get_security_group_ids,
|
||||
mock_connect):
|
||||
self.mock_docker.create_host_config = mock.Mock(
|
||||
return_value={'Id1': 'val1', 'key2': 'val2'})
|
||||
self.mock_docker.create_container = mock.Mock(
|
||||
return_value={'Id': 'val1', 'key1': 'val2'})
|
||||
image = {'path': ''}
|
||||
mock_container = self.mock_default_container
|
||||
result_container = self.driver.create(self.context, mock_container,
|
||||
'test_sandbox', image)
|
||||
with mock.patch.object(self.driver, '_get_available_network'):
|
||||
result_container = self.driver.create(self.context, mock_container,
|
||||
image, None)
|
||||
host_config = {}
|
||||
host_config['network_mode'] = 'container:test_sandbox'
|
||||
host_config['ipc_mode'] = 'container:test_sandbox'
|
||||
host_config['volumes_from'] = 'test_sandbox'
|
||||
host_config['mem_limit'] = '512m'
|
||||
host_config['cpu_quota'] = 100000
|
||||
host_config['cpu_period'] = 100000
|
||||
@ -119,7 +123,7 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
def test_delete_success(self):
|
||||
self.mock_docker.remove_container = mock.Mock()
|
||||
mock_container = mock.MagicMock()
|
||||
self.driver.delete(mock_container, True)
|
||||
self.driver.delete(self.context, mock_container, True)
|
||||
self.mock_docker.remove_container.assert_called_once_with(
|
||||
mock_container.container_id, force=True)
|
||||
|
||||
@ -129,7 +133,7 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
self.mock_docker.remove_container = mock.Mock(
|
||||
side_effect=errors.APIError('Error', '', ''))
|
||||
mock_container = mock.MagicMock()
|
||||
self.driver.delete(mock_container, True)
|
||||
self.driver.delete(self.context, mock_container, True)
|
||||
self.mock_docker.remove_container.assert_called_once_with(
|
||||
mock_container.container_id, force=True)
|
||||
self.assertEqual(1, mock_init.call_count)
|
||||
@ -141,7 +145,7 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
side_effect=errors.APIError('Error', '', ''))
|
||||
mock_container = mock.MagicMock()
|
||||
self.assertRaises(errors.APIError, self.driver.delete,
|
||||
mock_container,
|
||||
self.context, mock_container,
|
||||
True)
|
||||
self.mock_docker.remove_container.assert_called_once_with(
|
||||
mock_container.container_id, force=True)
|
||||
@ -355,8 +359,8 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
def test_delete_sandbox(self):
|
||||
self.mock_docker.remove_container = mock.Mock()
|
||||
mock_container = mock.MagicMock()
|
||||
self.driver.delete_sandbox(self.context, mock_container,
|
||||
sandbox_id='test_sandbox_id')
|
||||
mock_container.get_sandbox_id.return_value = 'test_sandbox_id'
|
||||
self.driver.delete_sandbox(self.context, mock_container)
|
||||
self.mock_docker.remove_container.assert_called_once_with(
|
||||
'test_sandbox_id', force=True)
|
||||
|
||||
@ -366,24 +370,6 @@ class TestDockerDriver(base.DriverTestCase):
|
||||
sandbox_id='test_sandbox_id')
|
||||
self.mock_docker.stop.assert_called_once_with('test_sandbox_id')
|
||||
|
||||
def test_get_sandbox_none_id(self):
|
||||
mock_container = mock.MagicMock()
|
||||
mock_container.meta = None
|
||||
result_sandbox_id = self.driver.get_sandbox_id(mock_container)
|
||||
self.assertIsNone(result_sandbox_id)
|
||||
|
||||
def test_get_sandbox_not_none_id(self):
|
||||
mock_container = mock.MagicMock()
|
||||
result_sandbox_id = self.driver.get_sandbox_id(mock_container)
|
||||
self.assertEqual(result_sandbox_id,
|
||||
mock_container.meta.get('sandbox_id', None))
|
||||
|
||||
def test_set_sandbox_id(self):
|
||||
mock_container = mock.MagicMock(meta={'sandbox_id': 'test_sandbox_id'})
|
||||
self.driver.set_sandbox_id(mock_container, 'test_sandbox_id')
|
||||
self.assertEqual(mock_container.meta['sandbox_id'],
|
||||
'test_sandbox_id')
|
||||
|
||||
def test_get_sandbox_name(self):
|
||||
mock_container = mock.MagicMock(
|
||||
uuid='ea8e2a25-2901-438d-8157-de7ffd68d051')
|
||||
@ -548,19 +534,17 @@ class TestNovaDockerDriver(base.DriverTestCase):
|
||||
|
||||
@mock.patch('zun.container.docker.driver.'
|
||||
'NovaDockerDriver._find_server_by_container_id')
|
||||
@mock.patch('zun.container.docker.driver.NovaDockerDriver.get_sandbox_id')
|
||||
@mock.patch('zun.common.nova.NovaClient')
|
||||
def test_get_addresses(self, mock_nova_client, mock_get_sandbox_id,
|
||||
def test_get_addresses(self, mock_nova_client,
|
||||
mock_find_server_by_container_id):
|
||||
nova_client_instance = mock.MagicMock()
|
||||
nova_client_instance.get_addresses.return_value = 'test_address'
|
||||
mock_nova_client.return_value = nova_client_instance
|
||||
mock_get_sandbox_id.return_value = 'test_sanbox_id'
|
||||
mock_find_server_by_container_id.return_value = 'test_test_server_name'
|
||||
mock_container = mock.MagicMock()
|
||||
mock_container.get_sandbox_id.return_value = 'test_sanbox_id'
|
||||
result_address = self.driver.get_addresses(self.context,
|
||||
mock_container)
|
||||
mock_get_sandbox_id.assert_called_once_with(mock_container)
|
||||
mock_find_server_by_container_id.assert_called_once_with(
|
||||
'test_sanbox_id')
|
||||
nova_client_instance.get_addresses.assert_called_once_with(
|
||||
|
@ -18,6 +18,10 @@ from zun.container import driver
|
||||
|
||||
class FakeDriver(driver.ContainerDriver):
|
||||
"""Fake driver for testing."""
|
||||
capabilities = {
|
||||
"support_sandbox": True,
|
||||
"support_standalone": True,
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super(FakeDriver, self).__init__()
|
||||
@ -87,17 +91,11 @@ class FakeDriver(driver.ContainerDriver):
|
||||
pass
|
||||
|
||||
def create_sandbox(self, context, name, **kwargs):
|
||||
return "fake_sandbox"
|
||||
pass
|
||||
|
||||
def delete_sandbox(self, context, id):
|
||||
pass
|
||||
|
||||
def get_sandbox_id(self, container):
|
||||
pass
|
||||
|
||||
def set_sandbox_id(self, container, id):
|
||||
pass
|
||||
|
||||
def get_addresses(self, context, container):
|
||||
pass
|
||||
|
||||
|
@ -62,7 +62,7 @@ def get_test_container(**kwargs):
|
||||
{'Name': 'no', 'MaximumRetryCount': '0'}),
|
||||
'status_detail': kwargs.get('status_detail', 'up from 5 hours'),
|
||||
'interactive': kwargs.get('interactive', True),
|
||||
'image_driver': 'glance',
|
||||
'image_driver': kwargs.get('image_driver', 'glance'),
|
||||
'websocket_url': 'ws://127.0.0.1:6784/4c03164962fa/attach/'
|
||||
'ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1',
|
||||
'websocket_token': '7878038e-957c-4d52-ae19-1e9561784e7b',
|
||||
|
Loading…
x
Reference in New Issue
Block a user