Merge "Consolidate Container and Capsule in compute"
This commit is contained in:
commit
1e11ff8708
@ -25,7 +25,7 @@
|
||||
test-config:
|
||||
$TEMPEST_CONFIG:
|
||||
container_service:
|
||||
min_microversion: 1.27
|
||||
min_microversion: 1.32
|
||||
devstack_services:
|
||||
tempest: true
|
||||
devstack_plugins:
|
||||
|
@ -13,7 +13,6 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
import pecan
|
||||
import six
|
||||
|
||||
@ -252,8 +251,13 @@ class CapsuleController(base.Controller):
|
||||
new_capsule.cpu = capsule_need_cpu
|
||||
new_capsule.memory = str(capsule_need_memory)
|
||||
new_capsule.save(context)
|
||||
compute_api.capsule_create(context, new_capsule, requested_networks,
|
||||
requested_volumes, extra_spec)
|
||||
|
||||
kwargs = {}
|
||||
kwargs['extra_spec'] = extra_spec
|
||||
kwargs['requested_networks'] = requested_networks
|
||||
kwargs['requested_volumes'] = requested_volumes
|
||||
kwargs['run'] = True
|
||||
compute_api.container_create(context, new_capsule, **kwargs)
|
||||
# Set the HTTP Location Header
|
||||
pecan.response.location = link.build_url('capsules',
|
||||
new_capsule.uuid)
|
||||
@ -291,7 +295,8 @@ class CapsuleController(base.Controller):
|
||||
compute_api = pecan.request.compute_api
|
||||
capsule.task_state = consts.CONTAINER_DELETING
|
||||
capsule.save(context)
|
||||
compute_api.capsule_delete(context, capsule)
|
||||
compute_api.container_stop(context, capsule, 10)
|
||||
compute_api.container_delete(context, capsule)
|
||||
pecan.response.status = 204
|
||||
|
||||
def _generate_name_for_capsule_container(self, new_capsule):
|
||||
|
@ -64,10 +64,11 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
* 1.29 - Add enable_cpu_pinning to compute_node
|
||||
* 1.30 - Introduce API resource for representing private registry
|
||||
* 1.31 - Add 'registry_id' to containers
|
||||
* 1.32 - Make capsule deletion asynchronized
|
||||
"""
|
||||
|
||||
BASE_VER = '1.1'
|
||||
CURRENT_MAX_VER = '1.31'
|
||||
CURRENT_MAX_VER = '1.32'
|
||||
|
||||
|
||||
class Version(object):
|
||||
|
@ -241,3 +241,10 @@ user documentation.
|
||||
|
||||
Add 'registry_id' to container resource.
|
||||
This attribute indicate the registry from which the container pulls images.
|
||||
|
||||
1.32
|
||||
----
|
||||
|
||||
Make capsule deletion asynchronized.
|
||||
API request to delete a capsule will return without waiting for the
|
||||
capsule to be deleted.
|
||||
|
@ -208,32 +208,6 @@ class API(object):
|
||||
return self.rpcapi.image_search(context, image, image_driver,
|
||||
exact_match, *args)
|
||||
|
||||
def capsule_create(self, context, new_capsule, requested_networks,
|
||||
requested_volumes, extra_spec):
|
||||
try:
|
||||
host_state = self._schedule_container(context, new_capsule,
|
||||
extra_spec)
|
||||
except exception.NoValidHost:
|
||||
new_capsule.status = consts.ERROR
|
||||
new_capsule.status_reason = _(
|
||||
"There are not enough hosts available.")
|
||||
new_capsule.save(context)
|
||||
return
|
||||
except Exception:
|
||||
new_capsule.status = consts.ERROR
|
||||
new_capsule.status_reason = _("Unexpected exception occurred.")
|
||||
new_capsule.save(context)
|
||||
raise
|
||||
for container in new_capsule.containers:
|
||||
self._record_action_start(context, container,
|
||||
container_actions.CREATE)
|
||||
self.rpcapi.capsule_create(context, host_state['host'], new_capsule,
|
||||
requested_networks, requested_volumes,
|
||||
host_state['limits'])
|
||||
|
||||
def capsule_delete(self, context, capsule):
|
||||
return self.rpcapi.capsule_delete(context, capsule)
|
||||
|
||||
def network_detach(self, context, container, *args):
|
||||
self._record_action_start(context, container,
|
||||
container_actions.NETWORK_DETACH)
|
||||
|
@ -319,6 +319,12 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
self.driver.read_tar_image(image)
|
||||
if image['tag'] != tag:
|
||||
LOG.warning("The input tag is different from the tag in tar")
|
||||
if isinstance(container, objects.Capsule):
|
||||
container = self.driver.create_capsule(context, container,
|
||||
image,
|
||||
requested_networks,
|
||||
requested_volumes)
|
||||
elif isinstance(container, objects.Container):
|
||||
container = self.driver.create(context, container, image,
|
||||
requested_networks,
|
||||
requested_volumes)
|
||||
@ -502,7 +508,11 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
self._update_task_state(context, container, consts.CONTAINER_DELETING)
|
||||
reraise = not force
|
||||
try:
|
||||
if isinstance(container, objects.Capsule):
|
||||
self.driver.delete_capsule(context, container, force)
|
||||
elif isinstance(container, objects.Container):
|
||||
self.driver.delete(context, container, force)
|
||||
|
||||
if self.use_sandbox:
|
||||
self._delete_sandbox(context, container, reraise)
|
||||
except exception.DockerError as e:
|
||||
@ -650,6 +660,9 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
try:
|
||||
self._update_task_state(context, container,
|
||||
consts.CONTAINER_DELETING)
|
||||
if isinstance(container, objects.Capsule):
|
||||
self.driver.delete_capsule(context, container)
|
||||
elif isinstance(container, objects.Container):
|
||||
self.driver.delete(context, container, True)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
@ -1162,83 +1175,6 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
self.driver.update_containers_states(ctx, containers, self)
|
||||
capsules = objects.Capsule.list(ctx)
|
||||
self.driver.update_containers_states(ctx, capsules, self)
|
||||
LOG.debug('Complete syncing container states.')
|
||||
|
||||
def capsule_create(self, context, capsule, requested_networks,
|
||||
requested_volumes, limits):
|
||||
@utils.synchronized("capsule-" + capsule.uuid)
|
||||
def do_capsule_create():
|
||||
self._do_capsule_create(context, capsule, requested_networks,
|
||||
requested_volumes, limits)
|
||||
|
||||
utils.spawn_n(do_capsule_create)
|
||||
|
||||
def _do_capsule_create(self, context, capsule,
|
||||
requested_networks=None,
|
||||
requested_volumes=None,
|
||||
limits=None):
|
||||
"""Create capsule in the compute node
|
||||
|
||||
:param context: security context
|
||||
:param capsule: the special capsule object
|
||||
:param requested_networks: the network ports that capsule will
|
||||
connect
|
||||
:param requested_volumes: the volume that capsule need
|
||||
:param limits: no use field now.
|
||||
"""
|
||||
# NOTE(kevinz): Here create the sandbox container for the
|
||||
# first function container --> capsule.containers[1].
|
||||
# capsule.containers[0] will only be used as recording the
|
||||
# the sandbox_container info, and the sandbox_id of this contianer
|
||||
# is itself.
|
||||
sandbox_id = self._create_sandbox(context,
|
||||
capsule,
|
||||
requested_networks)
|
||||
# Create init containers first
|
||||
if capsule.init_containers:
|
||||
for container in capsule.init_containers:
|
||||
self._do_capsule_create_each_container(context,
|
||||
capsule,
|
||||
container,
|
||||
sandbox_id,
|
||||
limits,
|
||||
requested_volumes,
|
||||
requested_networks)
|
||||
for container in capsule.init_containers:
|
||||
self._wait_for_containers_completed(context, container)
|
||||
|
||||
# Create common containers
|
||||
for container in capsule.containers:
|
||||
self._do_capsule_create_each_container(context,
|
||||
capsule,
|
||||
container,
|
||||
sandbox_id,
|
||||
limits,
|
||||
requested_volumes,
|
||||
requested_networks)
|
||||
|
||||
capsule.host = self.host
|
||||
capsule.status = consts.RUNNING
|
||||
capsule.save(context)
|
||||
|
||||
def capsule_delete(self, context, capsule):
|
||||
# NOTE(kevinz): Delete functional containers first and then delete
|
||||
# sandbox container
|
||||
for container in (capsule.containers + capsule.init_containers):
|
||||
try:
|
||||
self._do_container_delete(context, container, force=True)
|
||||
except Exception as e:
|
||||
uuid = container.uuid
|
||||
LOG.exception("Failed to delete container %(uuid0)s because "
|
||||
"it doesn't exist in the capsule. Stale data "
|
||||
"identified by %(uuid1)s is deleted from "
|
||||
"database: %(error)s",
|
||||
{'uuid0': uuid, 'uuid1': uuid, 'error': e})
|
||||
try:
|
||||
self._delete_sandbox(context, capsule, reraise=False)
|
||||
self._do_container_delete(context, capsule, force=True)
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
|
||||
def network_detach(self, context, container, network):
|
||||
@utils.synchronized(container.uuid)
|
||||
@ -1292,47 +1228,3 @@ class Manager(periodic_task.PeriodicTasks):
|
||||
self.container_update(context, container, patch)
|
||||
|
||||
utils.spawn_n(do_container_resize)
|
||||
|
||||
def _do_capsule_create_each_container(self, context, capsule,
|
||||
container, sandbox_id,
|
||||
limits=None,
|
||||
requested_volumes=None,
|
||||
requested_networks=None):
|
||||
container_requested_volumes = []
|
||||
container.set_sandbox_id(sandbox_id)
|
||||
container.addresses = capsule.addresses
|
||||
container_name = container.name
|
||||
for volume in requested_volumes:
|
||||
if volume.get(container_name, None):
|
||||
container_requested_volumes.append(
|
||||
volume.get(container_name))
|
||||
self._attach_volumes(context, container,
|
||||
container_requested_volumes)
|
||||
# Make sure the sandbox_id is set into meta. If not,
|
||||
# when container delete, it will delete container network
|
||||
# without considering sandbox.
|
||||
container.save(context)
|
||||
# Add volume assignment
|
||||
created_container = \
|
||||
self._do_container_create_base(context,
|
||||
container,
|
||||
requested_networks,
|
||||
container_requested_volumes,
|
||||
sandbox=capsule,
|
||||
limits=limits)
|
||||
self._do_container_start(context, created_container)
|
||||
|
||||
def _wait_for_containers_completed(self, context, container,
|
||||
timeout=60, poll_interval=1):
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < timeout:
|
||||
container = self.driver.show(context, container)
|
||||
if container.status == consts.STOPPED:
|
||||
return
|
||||
time.sleep(poll_interval)
|
||||
|
||||
msg = _('Init container %(container_name)s failed: ') % {
|
||||
'container_name': container.name
|
||||
}
|
||||
self._fail_container(context, container, msg, unset_host=True)
|
||||
raise exception.Invalid(msg)
|
||||
|
@ -66,7 +66,7 @@ class API(rpc_service.API):
|
||||
pci_requests=pci_requests)
|
||||
|
||||
@check_container_host
|
||||
def container_delete(self, context, container, force):
|
||||
def container_delete(self, context, container, force=False):
|
||||
return self._cast(container.host, 'container_delete',
|
||||
container=container, force=force)
|
||||
|
||||
|
@ -1260,3 +1260,120 @@ class DockerDriver(driver.ContainerDriver):
|
||||
network_api = zun_network.api(context,
|
||||
docker_api=docker)
|
||||
network_api.remove_network(network)
|
||||
|
||||
def create_capsule(self, context, capsule, image, requested_networks,
|
||||
requested_volumes):
|
||||
capsule = self.create(context, capsule, image, requested_networks,
|
||||
requested_volumes)
|
||||
self.start(context, capsule)
|
||||
for container in capsule.containers:
|
||||
self._create_container_in_capsule(context, capsule, container,
|
||||
requested_networks,
|
||||
requested_volumes)
|
||||
return capsule
|
||||
|
||||
def _create_container_in_capsule(self, context, capsule, container,
|
||||
requested_volumes, requested_networks):
|
||||
# pull image
|
||||
image_driver_name = container.image_driver
|
||||
repo, tag = utils.parse_image_name(container.image, image_driver_name)
|
||||
image_pull_policy = utils.get_image_pull_policy(
|
||||
container.image_pull_policy, tag)
|
||||
image, image_loaded = self.pull_image(
|
||||
context, repo, tag, image_pull_policy, image_driver_name)
|
||||
image['repo'], image['tag'] = repo, tag
|
||||
if not image_loaded:
|
||||
self.load_image(image['path'])
|
||||
if image_driver_name == 'glance':
|
||||
self.read_tar_image(image)
|
||||
if image['tag'] != tag:
|
||||
LOG.warning("The input tag is different from the tag in tar")
|
||||
|
||||
# create container
|
||||
with docker_utils.docker_client() as docker:
|
||||
name = container.name
|
||||
LOG.debug('Creating container with image %(image)s name %(name)s',
|
||||
{'image': image['image'], 'name': name})
|
||||
binds = self._get_binds(context, requested_volumes)
|
||||
kwargs = {
|
||||
'name': self.get_container_name(container),
|
||||
'command': container.command,
|
||||
'environment': container.environment,
|
||||
'working_dir': container.workdir,
|
||||
'labels': container.labels,
|
||||
'tty': container.interactive,
|
||||
'stdin_open': container.interactive,
|
||||
}
|
||||
|
||||
host_config = {}
|
||||
host_config['privileged'] = container.privileged
|
||||
host_config['binds'] = binds
|
||||
kwargs['volumes'] = [b['bind'] for b in binds.values()]
|
||||
host_config['network_mode'] = 'container:%s' % capsule.container_id
|
||||
# TODO(hongbin): Uncomment this after docker-py add support for
|
||||
# container mode for pid namespace.
|
||||
# host_config['pid_mode'] = 'container:%s' % capsule.container_id
|
||||
host_config['ipc_mode'] = 'container:%s' % capsule.container_id
|
||||
if container.auto_remove:
|
||||
host_config['auto_remove'] = container.auto_remove
|
||||
if container.memory is not None:
|
||||
host_config['mem_limit'] = str(container.memory) + 'M'
|
||||
if container.cpu is not None:
|
||||
host_config['cpu_quota'] = int(100000 * container.cpu)
|
||||
host_config['cpu_period'] = 100000
|
||||
if container.restart_policy:
|
||||
count = int(container.restart_policy['MaximumRetryCount'])
|
||||
name = container.restart_policy['Name']
|
||||
host_config['restart_policy'] = {'Name': name,
|
||||
'MaximumRetryCount': count}
|
||||
|
||||
if container.disk:
|
||||
disk_size = str(container.disk) + 'G'
|
||||
host_config['storage_opt'] = {'size': disk_size}
|
||||
# The time unit in docker of heath checking is us, and the unit
|
||||
# of interval and timeout is seconds.
|
||||
if container.healthcheck:
|
||||
healthcheck = {}
|
||||
healthcheck['test'] = container.healthcheck.get('test', '')
|
||||
interval = container.healthcheck.get('interval', 0)
|
||||
healthcheck['interval'] = interval * 10 ** 9
|
||||
healthcheck['retries'] = int(container.healthcheck.
|
||||
get('retries', 0))
|
||||
timeout = container.healthcheck.get('timeout', 0)
|
||||
healthcheck['timeout'] = timeout * 10 ** 9
|
||||
kwargs['healthcheck'] = healthcheck
|
||||
|
||||
kwargs['host_config'] = docker.create_host_config(**host_config)
|
||||
if image['tag']:
|
||||
image_repo = image['repo'] + ":" + image['tag']
|
||||
else:
|
||||
image_repo = image['repo']
|
||||
response = docker.create_container(image_repo, **kwargs)
|
||||
container.container_id = response['Id']
|
||||
docker.start(container.container_id)
|
||||
|
||||
response = docker.inspect_container(container.container_id)
|
||||
self._populate_container(container, response)
|
||||
container.save(context)
|
||||
|
||||
def delete_capsule(self, context, capsule, force):
|
||||
for container in capsule.containers:
|
||||
self._delete_container_in_capsule(context, capsule, container,
|
||||
force)
|
||||
self.delete(context, capsule, force)
|
||||
|
||||
def _delete_container_in_capsule(self, context, capsule, container, force):
|
||||
if not container.container_id:
|
||||
return
|
||||
|
||||
with docker_utils.docker_client() as docker:
|
||||
try:
|
||||
docker.stop(container.container_id)
|
||||
docker.remove_container(container.container_id,
|
||||
force=force)
|
||||
except errors.APIError as api_error:
|
||||
if is_not_found(api_error):
|
||||
return
|
||||
if is_not_connected(api_error):
|
||||
return
|
||||
raise
|
||||
|
@ -297,3 +297,9 @@ class ContainerDriver(object):
|
||||
|
||||
def delete_image(self, context, img_id, image_driver):
|
||||
raise NotImplementedError()
|
||||
|
||||
def create_capsule(self, context, capsule, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete_capsule(self, context, capsule, **kwargs):
|
||||
raise NotImplementedError()
|
||||
|
@ -26,7 +26,7 @@ from zun.tests.unit.db import base
|
||||
|
||||
|
||||
PATH_PREFIX = '/v1'
|
||||
CURRENT_VERSION = "container 1.31"
|
||||
CURRENT_VERSION = "container 1.32"
|
||||
|
||||
|
||||
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.31',
|
||||
'max_version': '1.32',
|
||||
'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.31',
|
||||
'max_version': '1.32',
|
||||
'min_version': '1.1',
|
||||
'status': 'CURRENT'}]}
|
||||
|
||||
|
@ -21,7 +21,7 @@ from zun.tests.unit.db import utils
|
||||
|
||||
|
||||
class TestCapsuleController(api_base.FunctionalTest):
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.network.neutron.NeutronAPI.get_available_network')
|
||||
def test_create_capsule(self, mock_capsule_create,
|
||||
mock_neutron_get_network):
|
||||
@ -56,7 +56,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
self.assertTrue(mock_capsule_create.called)
|
||||
self.assertTrue(mock_neutron_get_network.called)
|
||||
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.network.neutron.NeutronAPI.get_available_network')
|
||||
def test_create_capsule_two_containers(self, mock_capsule_create,
|
||||
mock_neutron_get_network):
|
||||
@ -92,7 +92,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
self.assertTrue(mock_capsule_create.called)
|
||||
self.assertTrue(mock_neutron_get_network.called)
|
||||
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.common.utils.check_capsule_template')
|
||||
def test_create_capsule_wrong_kind_set(self, mock_check_template,
|
||||
mock_capsule_create):
|
||||
@ -109,7 +109,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
self.assertEqual(400, response.status_int)
|
||||
self.assertFalse(mock_capsule_create.called)
|
||||
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.common.utils.check_capsule_template')
|
||||
def test_create_capsule_less_than_one_container(self, mock_check_template,
|
||||
mock_capsule_create):
|
||||
@ -123,7 +123,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
self.assertEqual(400, response.status_int)
|
||||
self.assertFalse(mock_capsule_create.called)
|
||||
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.common.utils.check_capsule_template')
|
||||
def test_create_capsule_no_container_field(self, mock_check_template,
|
||||
mock_capsule_create):
|
||||
@ -137,7 +137,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
params=params, content_type='application/json')
|
||||
self.assertFalse(mock_capsule_create.called)
|
||||
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.common.utils.check_capsule_template')
|
||||
def test_create_capsule_no_container_image(self, mock_check_template,
|
||||
mock_capsule_create):
|
||||
@ -152,7 +152,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
params=params, content_type='application/json')
|
||||
self.assertFalse(mock_capsule_create.called)
|
||||
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.network.neutron.NeutronAPI.get_available_network')
|
||||
def test_create_capsule_with_init_containers(self, mock_capsule_create,
|
||||
mock_neutron_get_network):
|
||||
@ -192,7 +192,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
self.assertTrue(mock_capsule_create.called)
|
||||
self.assertTrue(mock_neutron_get_network.called)
|
||||
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.network.neutron.NeutronAPI.get_available_network')
|
||||
def test_create_capsule_with_two_init_containers(self, mock_capsule_create,
|
||||
mock_neutron_get_network):
|
||||
@ -233,7 +233,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
|
||||
@patch('zun.volume.cinder_api.CinderAPI.ensure_volume_usable')
|
||||
@patch('zun.volume.cinder_api.CinderAPI.create_volume')
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.network.neutron.NeutronAPI.get_available_network')
|
||||
def test_create_capsule_with_create_new_volume(self, mock_capsule_create,
|
||||
mock_neutron_get_network,
|
||||
@ -283,7 +283,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
|
||||
@patch('zun.volume.cinder_api.CinderAPI.ensure_volume_usable')
|
||||
@patch('zun.volume.cinder_api.CinderAPI.search_volume')
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.network.neutron.NeutronAPI.get_available_network')
|
||||
def test_create_capsule_with_existed_volume(self, mock_capsule_create,
|
||||
mock_neutron_get_network,
|
||||
@ -336,7 +336,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
@patch('zun.volume.cinder_api.CinderAPI.create_volume')
|
||||
@patch('zun.volume.cinder_api.CinderAPI.ensure_volume_usable')
|
||||
@patch('zun.volume.cinder_api.CinderAPI.search_volume')
|
||||
@patch('zun.compute.api.API.capsule_create')
|
||||
@patch('zun.compute.api.API.container_create')
|
||||
@patch('zun.network.neutron.NeutronAPI.get_available_network')
|
||||
def test_create_capsule_with_two_volumes(self, mock_capsule_create,
|
||||
mock_neutron_get_network,
|
||||
@ -441,18 +441,14 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
self.assertEqual(test_capsule['uuid'],
|
||||
response.json['uuid'])
|
||||
|
||||
@patch('zun.compute.api.API.capsule_delete')
|
||||
@patch('zun.compute.api.API.container_delete')
|
||||
@patch('zun.compute.api.API.container_stop')
|
||||
@patch('zun.objects.Capsule.get_by_uuid')
|
||||
@patch('zun.objects.Container.get_by_uuid')
|
||||
@patch('zun.objects.Capsule.save')
|
||||
def test_delete_capsule_by_uuid(self, mock_capsule_save,
|
||||
mock_container_get_by_uuid,
|
||||
mock_capsule_get_by_uuid,
|
||||
mock_capsule_stop,
|
||||
mock_capsule_delete):
|
||||
test_container = utils.get_test_container()
|
||||
test_container_obj = objects.Container(self.context, **test_container)
|
||||
mock_container_get_by_uuid.return_value = test_container_obj
|
||||
|
||||
test_capsule = utils.create_test_container(context=self.context)
|
||||
test_capsule_obj = objects.Capsule(self.context,
|
||||
**test_capsule)
|
||||
@ -464,26 +460,23 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
response = self.app.delete('/v1/capsules/%s' % capsule_uuid)
|
||||
|
||||
self.assertTrue(mock_capsule_delete.called)
|
||||
self.assertTrue(mock_capsule_stop.called)
|
||||
self.assertEqual(204, response.status_int)
|
||||
context = mock_capsule_save.call_args[0][0]
|
||||
self.assertIs(False, context.all_projects)
|
||||
|
||||
@patch('zun.common.policy.enforce')
|
||||
@patch('zun.compute.api.API.capsule_delete')
|
||||
@patch('zun.compute.api.API.container_delete')
|
||||
@patch('zun.compute.api.API.container_stop')
|
||||
@patch('zun.objects.Capsule.get_by_uuid')
|
||||
@patch('zun.objects.Container.get_by_uuid')
|
||||
@patch('zun.objects.Capsule.save')
|
||||
def test_delete_capsule_by_uuid_all_projects(self,
|
||||
mock_capsule_save,
|
||||
mock_container_get_by_uuid,
|
||||
mock_capsule_get_by_uuid,
|
||||
mock_capsule_stop,
|
||||
mock_capsule_delete,
|
||||
mock_policy):
|
||||
mock_policy.return_value = True
|
||||
test_container = utils.get_test_container()
|
||||
test_container_obj = objects.Container(self.context, **test_container)
|
||||
mock_container_get_by_uuid.return_value = test_container_obj
|
||||
|
||||
test_capsule = utils.create_test_container(context=self.context)
|
||||
test_capsule_obj = objects.Capsule(self.context,
|
||||
**test_capsule)
|
||||
@ -496,6 +489,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
'/v1/capsules/%s/?all_projects=1' % capsule_uuid)
|
||||
|
||||
self.assertTrue(mock_capsule_delete.called)
|
||||
self.assertTrue(mock_capsule_stop.called)
|
||||
self.assertEqual(204, response.status_int)
|
||||
context = mock_capsule_save.call_args[0][0]
|
||||
self.assertIs(True, context.all_projects)
|
||||
@ -505,18 +499,14 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
self.assertRaises(AppError, self.app.delete,
|
||||
'/capsules/%s' % uuid)
|
||||
|
||||
@patch('zun.compute.api.API.capsule_delete')
|
||||
@patch('zun.compute.api.API.container_delete')
|
||||
@patch('zun.compute.api.API.container_stop')
|
||||
@patch('zun.objects.Capsule.get_by_name')
|
||||
@patch('zun.objects.Container.get_by_uuid')
|
||||
@patch('zun.objects.Capsule.save')
|
||||
def test_delete_capsule_by_name(self, mock_capsule_save,
|
||||
mock_container_get_by_name,
|
||||
mock_capsule_get_by_uuid,
|
||||
mock_capsule_stop,
|
||||
mock_capsule_delete):
|
||||
test_container = utils.get_test_container()
|
||||
test_container_obj = objects.Container(self.context, **test_container)
|
||||
mock_container_get_by_name.return_value = test_container_obj
|
||||
|
||||
test_capsule = utils.create_test_container(context=self.context)
|
||||
test_capsule_obj = objects.Capsule(self.context,
|
||||
**test_capsule)
|
||||
@ -529,6 +519,7 @@ class TestCapsuleController(api_base.FunctionalTest):
|
||||
capsule_name)
|
||||
|
||||
self.assertTrue(mock_capsule_delete.called)
|
||||
self.assertTrue(mock_capsule_stop.called)
|
||||
self.assertEqual(204, response.status_int)
|
||||
context = mock_capsule_save.call_args[0][0]
|
||||
self.assertIs(False, context.all_projects)
|
||||
|
@ -116,14 +116,6 @@ class TestAPI(base.TestCase):
|
||||
self.assertTrue(mock_save.called)
|
||||
self.assertEqual(consts.ERROR, container.status)
|
||||
|
||||
@mock.patch('zun.compute.rpcapi.API._call')
|
||||
def test_capsule_delete(self, mock_call):
|
||||
capsule = self.container
|
||||
self.compute_api.capsule_delete(
|
||||
self.context, capsule)
|
||||
mock_call.assert_called_once_with(
|
||||
capsule.host, "capsule_delete", capsule=capsule)
|
||||
|
||||
@mock.patch('zun.compute.rpcapi.API._cast')
|
||||
@mock.patch('zun.api.servicegroup.ServiceGroup.service_is_up')
|
||||
@mock.patch('zun.objects.ZunService.list_by_binary')
|
||||
|
Loading…
Reference in New Issue
Block a user