Split capsule code out of container driver
Introduce a capsule driver in parallel with container driver. Capsule logic goes to capsule driver and container logic goes to container driver. Change-Id: I0c3efdb0068cfa89b8cfc6cad68425838cd2e50f
This commit is contained in:
parent
83dbf2d5c4
commit
624eebbc8a
@ -72,6 +72,10 @@ zun.container.driver =
|
|||||||
docker = zun.container.docker.driver:DockerDriver
|
docker = zun.container.docker.driver:DockerDriver
|
||||||
fake = zun.tests.unit.container.fake_driver:FakeDriver
|
fake = zun.tests.unit.container.fake_driver:FakeDriver
|
||||||
|
|
||||||
|
zun.capsule.driver =
|
||||||
|
docker = zun.container.docker.driver:DockerDriver
|
||||||
|
fake = zun.tests.unit.container.fake_driver:FakeDriver
|
||||||
|
|
||||||
zun.image.driver =
|
zun.image.driver =
|
||||||
glance = zun.image.glance.driver:GlanceDriver
|
glance = zun.image.glance.driver:GlanceDriver
|
||||||
docker = zun.image.docker.driver:DockerDriver
|
docker = zun.image.docker.driver:DockerDriver
|
||||||
|
@ -350,7 +350,7 @@ class CapsuleController(base.Controller):
|
|||||||
kwargs['extra_spec'] = extra_spec
|
kwargs['extra_spec'] = extra_spec
|
||||||
kwargs['requested_networks'] = requested_networks
|
kwargs['requested_networks'] = requested_networks
|
||||||
kwargs['requested_volumes'] = requested_volumes
|
kwargs['requested_volumes'] = requested_volumes
|
||||||
kwargs['run'] = True
|
kwargs['run'] = False
|
||||||
compute_api.container_create(context, new_capsule, **kwargs)
|
compute_api.container_create(context, new_capsule, **kwargs)
|
||||||
# Set the HTTP Location Header
|
# Set the HTTP Location Header
|
||||||
pecan.response.location = link.build_url('capsules',
|
pecan.response.location = link.build_url('capsules',
|
||||||
@ -406,7 +406,6 @@ class CapsuleController(base.Controller):
|
|||||||
capsule.task_state = consts.CONTAINER_DELETING
|
capsule.task_state = consts.CONTAINER_DELETING
|
||||||
capsule.save(context)
|
capsule.save(context)
|
||||||
if capsule.host:
|
if capsule.host:
|
||||||
compute_api.container_stop(context, capsule, 10)
|
|
||||||
compute_api.container_delete(context, capsule)
|
compute_api.container_delete(context, capsule)
|
||||||
else:
|
else:
|
||||||
merged_containers = capsule.containers + capsule.init_containers
|
merged_containers = capsule.containers + capsule.init_containers
|
||||||
|
@ -36,9 +36,10 @@ COMPUTE_RESOURCE_SEMAPHORE = "compute_resources"
|
|||||||
|
|
||||||
|
|
||||||
class ComputeNodeTracker(object):
|
class ComputeNodeTracker(object):
|
||||||
def __init__(self, host, container_driver, reportclient):
|
def __init__(self, host, container_driver, capsule_driver, reportclient):
|
||||||
self.host = host
|
self.host = host
|
||||||
self.container_driver = container_driver
|
self.container_driver = container_driver
|
||||||
|
self.capsule_driver = capsule_driver
|
||||||
self.compute_node = None
|
self.compute_node = None
|
||||||
self.tracked_containers = {}
|
self.tracked_containers = {}
|
||||||
self.old_resources = collections.defaultdict(objects.ComputeNode)
|
self.old_resources = collections.defaultdict(objects.ComputeNode)
|
||||||
@ -58,6 +59,8 @@ class ComputeNodeTracker(object):
|
|||||||
compute_node.pci_device_pools = dev_pools_obj
|
compute_node.pci_device_pools = dev_pools_obj
|
||||||
|
|
||||||
def update_available_resources(self, context):
|
def update_available_resources(self, context):
|
||||||
|
# TODO(hongbin): get available resources from capsule_driver
|
||||||
|
# and aggregates resources
|
||||||
resources = self.container_driver.get_available_resources()
|
resources = self.container_driver.get_available_resources()
|
||||||
# We allow 'cpu_used' to be missing from the container driver,
|
# We allow 'cpu_used' to be missing from the container driver,
|
||||||
# but the DB requires it to be non-null so just initialize it to 0.
|
# but the DB requires it to be non-null so just initialize it to 0.
|
||||||
@ -391,6 +394,7 @@ class ComputeNodeTracker(object):
|
|||||||
# Now get the driver's capabilities and add any supported
|
# Now get the driver's capabilities and add any supported
|
||||||
# traits that are missing, and remove any existing set traits
|
# traits that are missing, and remove any existing set traits
|
||||||
# that are not currently supported.
|
# that are not currently supported.
|
||||||
|
# TODO(hongbin): get traits from capsule_driver as well
|
||||||
capabilities_traits = self.container_driver.capabilities_as_traits()
|
capabilities_traits = self.container_driver.capabilities_as_traits()
|
||||||
for trait, supported in capabilities_traits.items():
|
for trait, supported in capabilities_traits.items():
|
||||||
if supported:
|
if supported:
|
||||||
|
@ -35,7 +35,7 @@ from zun.common.utils import wrap_exception
|
|||||||
from zun.compute import compute_node_tracker
|
from zun.compute import compute_node_tracker
|
||||||
from zun.compute import container_actions
|
from zun.compute import container_actions
|
||||||
import zun.conf
|
import zun.conf
|
||||||
from zun.container import driver
|
from zun.container import driver as driver_module
|
||||||
from zun.image.glance import driver as glance
|
from zun.image.glance import driver as glance
|
||||||
from zun.network import neutron
|
from zun.network import neutron
|
||||||
from zun import objects
|
from zun import objects
|
||||||
@ -50,11 +50,23 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
|
|
||||||
def __init__(self, container_driver=None):
|
def __init__(self, container_driver=None):
|
||||||
super(Manager, self).__init__(CONF)
|
super(Manager, self).__init__(CONF)
|
||||||
self.driver = driver.load_container_driver(container_driver)
|
self.driver = driver_module.load_container_driver(container_driver)
|
||||||
|
self.capsule_driver = driver_module.load_capsule_driver()
|
||||||
self.host = CONF.host
|
self.host = CONF.host
|
||||||
self._resource_tracker = None
|
self._resource_tracker = None
|
||||||
self.reportclient = report.SchedulerReportClient()
|
self.reportclient = report.SchedulerReportClient()
|
||||||
|
|
||||||
|
def _get_driver(self, container):
|
||||||
|
if (isinstance(container, objects.Capsule) or
|
||||||
|
isinstance(container, objects.CapsuleContainer) or
|
||||||
|
isinstance(container, objects.CapsuleInitContainer)):
|
||||||
|
return self.capsule_driver
|
||||||
|
elif isinstance(container, objects.Container):
|
||||||
|
return self.driver
|
||||||
|
else:
|
||||||
|
raise exception.ZunException('Unexpected container type: %(type)s.'
|
||||||
|
% {'type': type(container)})
|
||||||
|
|
||||||
def restore_running_container(self, context, container, current_status):
|
def restore_running_container(self, context, container, current_status):
|
||||||
if (container.status == consts.RUNNING and
|
if (container.status == consts.RUNNING and
|
||||||
current_status == consts.STOPPED):
|
current_status == consts.STOPPED):
|
||||||
@ -68,6 +80,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
|
|
||||||
def init_containers(self, context):
|
def init_containers(self, context):
|
||||||
containers = objects.Container.list_by_host(context, self.host)
|
containers = objects.Container.list_by_host(context, self.host)
|
||||||
|
# TODO(hongbin): init capsules as well
|
||||||
local_containers, _ = self.driver.list(context)
|
local_containers, _ = self.driver.list(context)
|
||||||
uuid_to_status_map = {container.uuid: container.status
|
uuid_to_status_map = {container.uuid: container.status
|
||||||
for container in local_containers}
|
for container in local_containers}
|
||||||
@ -162,12 +175,13 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
|
|
||||||
def _wait_for_volumes_available(self, context, requested_volumes,
|
def _wait_for_volumes_available(self, context, requested_volumes,
|
||||||
container, timeout=60, poll_interval=1):
|
container, timeout=60, poll_interval=1):
|
||||||
|
driver = self._get_driver(container)
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
try:
|
try:
|
||||||
volmaps = itertools.chain.from_iterable(requested_volumes.values())
|
volmaps = itertools.chain.from_iterable(requested_volumes.values())
|
||||||
volmap = next(volmaps)
|
volmap = next(volmaps)
|
||||||
while time.time() - start_time < timeout:
|
while time.time() - start_time < timeout:
|
||||||
is_available, is_error = self.driver.is_volume_available(
|
is_available, is_error = driver.is_volume_available(
|
||||||
context, volmap)
|
context, volmap)
|
||||||
if is_available:
|
if is_available:
|
||||||
volmap = next(volmaps)
|
volmap = next(volmaps)
|
||||||
@ -180,7 +194,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
for volmap in volmaps:
|
for volmap in volmaps:
|
||||||
if volmap.auto_remove:
|
if volmap.auto_remove:
|
||||||
try:
|
try:
|
||||||
self.driver.delete_volume(context, volmap)
|
driver.delete_volume(context, volmap)
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception("Failed to delete volume")
|
LOG.exception("Failed to delete volume")
|
||||||
msg = _("Volumes did not reach available status after "
|
msg = _("Volumes did not reach available status after "
|
||||||
@ -197,7 +211,8 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
while time.time() - start_time < timeout:
|
while time.time() - start_time < timeout:
|
||||||
if not volmap.auto_remove:
|
if not volmap.auto_remove:
|
||||||
volmap = next(volmaps)
|
volmap = next(volmaps)
|
||||||
is_deleted, is_error = self.driver.is_volume_deleted(
|
driver = self._get_driver(container)
|
||||||
|
is_deleted, is_error = driver.is_volume_deleted(
|
||||||
context, volmap)
|
context, volmap)
|
||||||
if is_deleted:
|
if is_deleted:
|
||||||
volmap = next(volmaps)
|
volmap = next(volmaps)
|
||||||
@ -212,7 +227,8 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
raise exception.Conflict(msg)
|
raise exception.Conflict(msg)
|
||||||
|
|
||||||
def _check_support_disk_quota(self, context, container):
|
def _check_support_disk_quota(self, context, container):
|
||||||
base_device_size = self.driver.get_host_default_base_size()
|
driver = self._get_driver(container)
|
||||||
|
base_device_size = driver.get_host_default_base_size()
|
||||||
if base_device_size:
|
if base_device_size:
|
||||||
# NOTE(kiennt): If default_base_size is not None, it means
|
# NOTE(kiennt): If default_base_size is not None, it means
|
||||||
# host storage_driver is in list ['devicemapper',
|
# host storage_driver is in list ['devicemapper',
|
||||||
@ -237,14 +253,14 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
raise exception.Invalid(msg)
|
raise exception.Invalid(msg)
|
||||||
# NOTE(kiennt): Only raise Exception when user passes disk size and
|
# NOTE(kiennt): Only raise Exception when user passes disk size and
|
||||||
# the disk quota feature isn't supported in host.
|
# the disk quota feature isn't supported in host.
|
||||||
if not self.driver.node_support_disk_quota():
|
if not driver.node_support_disk_quota():
|
||||||
if container.disk:
|
if container.disk:
|
||||||
msg = _('Your host does not support disk quota feature.')
|
msg = _('Your host does not support disk quota feature.')
|
||||||
self._fail_container(context, container, msg, unset_host=True)
|
self._fail_container(context, container, msg, unset_host=True)
|
||||||
raise exception.Invalid(msg)
|
raise exception.Invalid(msg)
|
||||||
LOG.warning("Ignore the configured default disk size because "
|
LOG.warning("Ignore the configured default disk size because "
|
||||||
"the driver does not support disk quota.")
|
"the driver does not support disk quota.")
|
||||||
if self.driver.node_support_disk_quota() and not container.disk:
|
if driver.node_support_disk_quota() and not container.disk:
|
||||||
container.disk = CONF.default_disk
|
container.disk = CONF.default_disk
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -297,6 +313,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
image_pull_policy = utils.get_image_pull_policy(
|
image_pull_policy = utils.get_image_pull_policy(
|
||||||
container.image_pull_policy, tag)
|
container.image_pull_policy, tag)
|
||||||
try:
|
try:
|
||||||
|
# TODO(hongbin): move image pulling logic to docker driver
|
||||||
image, image_loaded = self.driver.pull_image(
|
image, image_loaded = self.driver.pull_image(
|
||||||
context, repo, tag, image_pull_policy, image_driver_name,
|
context, repo, tag, image_pull_policy, image_driver_name,
|
||||||
registry=container.registry)
|
registry=container.registry)
|
||||||
@ -327,10 +344,9 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
LOG.warning("The input tag is different from the tag in "
|
LOG.warning("The input tag is different from the tag in "
|
||||||
"tar")
|
"tar")
|
||||||
if isinstance(container, objects.Capsule):
|
if isinstance(container, objects.Capsule):
|
||||||
container = self.driver.create_capsule(context, container,
|
container = self.capsule_driver.create_capsule(
|
||||||
image,
|
context, container, image, requested_networks,
|
||||||
requested_networks,
|
requested_volumes)
|
||||||
requested_volumes)
|
|
||||||
elif isinstance(container, objects.Container):
|
elif isinstance(container, objects.Container):
|
||||||
container = self.driver.create(context, container, image,
|
container = self.driver.create(context, container, image,
|
||||||
requested_networks,
|
requested_networks,
|
||||||
@ -397,20 +413,21 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
# This will happen only if there are multiple containers
|
# This will happen only if there are multiple containers
|
||||||
# inside a capsule sharing the same volume.
|
# inside a capsule sharing the same volume.
|
||||||
continue
|
continue
|
||||||
self._attach_volume(context, volmap)
|
self._attach_volume(context, container, volmap)
|
||||||
self._refresh_attached_volumes(requested_volumes, volmap)
|
self._refresh_attached_volumes(requested_volumes, volmap)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self._fail_container(context, container, six.text_type(e),
|
self._fail_container(context, container, six.text_type(e),
|
||||||
unset_host=True)
|
unset_host=True)
|
||||||
|
|
||||||
def _attach_volume(self, context, volmap):
|
def _attach_volume(self, context, container, volmap):
|
||||||
|
driver = self._get_driver(container)
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
LOG.info('Attaching volume %(volume_id)s to %(host)s',
|
LOG.info('Attaching volume %(volume_id)s to %(host)s',
|
||||||
{'volume_id': volmap.cinder_volume_id,
|
{'volume_id': volmap.cinder_volume_id,
|
||||||
'host': CONF.host})
|
'host': CONF.host})
|
||||||
try:
|
try:
|
||||||
self.driver.attach_volume(context, volmap)
|
driver.attach_volume(context, volmap)
|
||||||
except Exception:
|
except Exception:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.error("Failed to attach volume %(volume_id)s to "
|
LOG.error("Failed to attach volume %(volume_id)s to "
|
||||||
@ -419,7 +436,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
'container_id': volmap.container_uuid})
|
'container_id': volmap.container_uuid})
|
||||||
if volmap.auto_remove:
|
if volmap.auto_remove:
|
||||||
try:
|
try:
|
||||||
self.driver.delete_volume(context, volmap)
|
driver.delete_volume(context, volmap)
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception("Failed to delete volume %s.",
|
LOG.exception("Failed to delete volume %s.",
|
||||||
volmap.cinder_volume_id)
|
volmap.cinder_volume_id)
|
||||||
@ -452,18 +469,18 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
for volmap in volmaps:
|
for volmap in volmaps:
|
||||||
db_volmaps = objects.VolumeMapping.list_by_cinder_volume(
|
db_volmaps = objects.VolumeMapping.list_by_cinder_volume(
|
||||||
context, volmap.cinder_volume_id)
|
context, volmap.cinder_volume_id)
|
||||||
self._detach_volume(context, volmap, reraise=reraise)
|
self._detach_volume(context, container, volmap, reraise=reraise)
|
||||||
if volmap.auto_remove and len(db_volmaps) == 1:
|
if volmap.auto_remove and len(db_volmaps) == 1:
|
||||||
self.driver.delete_volume(context, volmap)
|
self._get_driver(container).delete_volume(context, volmap)
|
||||||
auto_remove_volmaps.append(volmap)
|
auto_remove_volmaps.append(volmap)
|
||||||
self._wait_for_volumes_deleted(context, auto_remove_volmaps, container)
|
self._wait_for_volumes_deleted(context, auto_remove_volmaps, container)
|
||||||
|
|
||||||
def _detach_volume(self, context, volmap, reraise=True):
|
def _detach_volume(self, context, container, volmap, reraise=True):
|
||||||
if objects.VolumeMapping.count(
|
if objects.VolumeMapping.count(
|
||||||
context, volume_id=volmap.volume_id) == 1:
|
context, volume_id=volmap.volume_id) == 1:
|
||||||
context = context.elevated()
|
context = context.elevated()
|
||||||
try:
|
try:
|
||||||
self.driver.detach_volume(context, volmap)
|
self._get_driver(container).detach_volume(context, volmap)
|
||||||
except Exception:
|
except Exception:
|
||||||
with excutils.save_and_reraise_exception(reraise=reraise):
|
with excutils.save_and_reraise_exception(reraise=reraise):
|
||||||
LOG.error("Failed to detach volume %(volume_id)s from "
|
LOG.error("Failed to detach volume %(volume_id)s from "
|
||||||
@ -478,6 +495,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
with self._update_task_state(context, container,
|
with self._update_task_state(context, container,
|
||||||
consts.CONTAINER_STARTING):
|
consts.CONTAINER_STARTING):
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.start(context, container)
|
container = self.driver.start(context, container)
|
||||||
container.started_at = timeutils.utcnow()
|
container.started_at = timeutils.utcnow()
|
||||||
container.save(context)
|
container.save(context)
|
||||||
@ -508,7 +526,8 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
reraise = not force
|
reraise = not force
|
||||||
try:
|
try:
|
||||||
if isinstance(container, objects.Capsule):
|
if isinstance(container, objects.Capsule):
|
||||||
self.driver.delete_capsule(context, container, force)
|
self.capsule_driver.delete_capsule(context, container,
|
||||||
|
force)
|
||||||
elif isinstance(container, objects.Container):
|
elif isinstance(container, objects.Container):
|
||||||
self.driver.delete(context, container, force)
|
self.driver.delete(context, container, force)
|
||||||
except exception.DockerError as e:
|
except exception.DockerError as e:
|
||||||
@ -546,6 +565,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def _add_security_group(self, context, container, security_group):
|
def _add_security_group(self, context, container, security_group):
|
||||||
LOG.debug('Adding security_group to container: %s', container.uuid)
|
LOG.debug('Adding security_group to container: %s', container.uuid)
|
||||||
with self._update_task_state(context, container, consts.SG_ADDING):
|
with self._update_task_state(context, container, consts.SG_ADDING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.add_security_group(context, container, security_group)
|
self.driver.add_security_group(context, container, security_group)
|
||||||
container.security_groups += [security_group]
|
container.security_groups += [security_group]
|
||||||
container.save(context)
|
container.save(context)
|
||||||
@ -564,6 +584,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def _remove_security_group(self, context, container, security_group):
|
def _remove_security_group(self, context, container, security_group):
|
||||||
LOG.debug('Removing security_group from container: %s', container.uuid)
|
LOG.debug('Removing security_group from container: %s', container.uuid)
|
||||||
with self._update_task_state(context, container, consts.SG_REMOVING):
|
with self._update_task_state(context, container, consts.SG_REMOVING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.remove_security_group(context, container,
|
self.driver.remove_security_group(context, container,
|
||||||
security_group)
|
security_group)
|
||||||
container.security_groups = list(set(container.security_groups)
|
container.security_groups = list(set(container.security_groups)
|
||||||
@ -574,6 +595,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def container_show(self, context, container):
|
def container_show(self, context, container):
|
||||||
LOG.debug('Showing container: %s', container.uuid)
|
LOG.debug('Showing container: %s', container.uuid)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.show(context, container)
|
container = self.driver.show(context, container)
|
||||||
if container.obj_what_changed():
|
if container.obj_what_changed():
|
||||||
container.save(context)
|
container.save(context)
|
||||||
@ -593,6 +615,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
LOG.debug('Rebooting container: %s', container.uuid)
|
LOG.debug('Rebooting container: %s', container.uuid)
|
||||||
with self._update_task_state(context, container,
|
with self._update_task_state(context, container,
|
||||||
consts.CONTAINER_REBOOTING):
|
consts.CONTAINER_REBOOTING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.reboot(context, container, timeout)
|
container = self.driver.reboot(context, container, timeout)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
@ -610,6 +633,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
LOG.debug('Stopping container: %s', container.uuid)
|
LOG.debug('Stopping container: %s', container.uuid)
|
||||||
with self._update_task_state(context, container,
|
with self._update_task_state(context, container,
|
||||||
consts.CONTAINER_STOPPING):
|
consts.CONTAINER_STOPPING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.stop(context, container, timeout)
|
container = self.driver.stop(context, container, timeout)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
@ -644,16 +668,15 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
self._fail_container(context, container, six.text_type(e))
|
self._fail_container(context, container, six.text_type(e))
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
if self.driver.check_container_exist(container):
|
if self.driver.check_container_exist(container):
|
||||||
for addr in container.addresses.values():
|
for addr in container.addresses.values():
|
||||||
for port in addr:
|
for port in addr:
|
||||||
port['preserve_on_delete'] = True
|
port['preserve_on_delete'] = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if isinstance(container, objects.Capsule):
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.delete_capsule(context, container)
|
self.driver.delete(context, container, True)
|
||||||
elif isinstance(container, objects.Container):
|
|
||||||
self.driver.delete(context, container, True)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.error("Rebuild container: %s failed, "
|
LOG.error("Rebuild container: %s failed, "
|
||||||
@ -729,6 +752,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
LOG.debug('Pausing container: %s', container.uuid)
|
LOG.debug('Pausing container: %s', container.uuid)
|
||||||
with self._update_task_state(context, container,
|
with self._update_task_state(context, container,
|
||||||
consts.CONTAINER_PAUSING):
|
consts.CONTAINER_PAUSING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.pause(context, container)
|
container = self.driver.pause(context, container)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
@ -746,6 +770,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
LOG.debug('Unpausing container: %s', container.uuid)
|
LOG.debug('Unpausing container: %s', container.uuid)
|
||||||
with self._update_task_state(context, container,
|
with self._update_task_state(context, container,
|
||||||
consts.CONTAINER_UNPAUSING):
|
consts.CONTAINER_UNPAUSING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.unpause(context, container)
|
container = self.driver.unpause(context, container)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
@ -761,6 +786,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
timestamps, tail, since):
|
timestamps, tail, since):
|
||||||
LOG.debug('Showing container logs: %s', container.uuid)
|
LOG.debug('Showing container logs: %s', container.uuid)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
return self.driver.show_logs(context, container,
|
return self.driver.show_logs(context, container,
|
||||||
stdout=stdout, stderr=stderr,
|
stdout=stdout, stderr=stderr,
|
||||||
timestamps=timestamps, tail=tail,
|
timestamps=timestamps, tail=tail,
|
||||||
@ -777,9 +803,11 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def container_exec(self, context, container, command, run, interactive):
|
def container_exec(self, context, container, command, run, interactive):
|
||||||
LOG.debug('Executing command in container: %s', container.uuid)
|
LOG.debug('Executing command in container: %s', container.uuid)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
exec_id = self.driver.execute_create(context, container, command,
|
exec_id = self.driver.execute_create(context, container, command,
|
||||||
interactive)
|
interactive)
|
||||||
if run:
|
if run:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
output, exit_code = self.driver.execute_run(exec_id, command)
|
output, exit_code = self.driver.execute_run(exec_id, command)
|
||||||
return {"output": output,
|
return {"output": output,
|
||||||
"exit_code": exit_code,
|
"exit_code": exit_code,
|
||||||
@ -808,6 +836,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def container_exec_resize(self, context, exec_id, height, width):
|
def container_exec_resize(self, context, exec_id, height, width):
|
||||||
LOG.debug('Resizing the tty session used by the exec: %s', exec_id)
|
LOG.debug('Resizing the tty session used by the exec: %s', exec_id)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
return self.driver.execute_resize(exec_id, height, width)
|
return self.driver.execute_resize(exec_id, height, width)
|
||||||
except exception.DockerError as e:
|
except exception.DockerError as e:
|
||||||
LOG.error("Error occurred while calling Docker exec API: %s",
|
LOG.error("Error occurred while calling Docker exec API: %s",
|
||||||
@ -824,6 +853,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
LOG.debug('Killing a container: %s', container.uuid)
|
LOG.debug('Killing a container: %s', container.uuid)
|
||||||
with self._update_task_state(context, container,
|
with self._update_task_state(context, container,
|
||||||
consts.CONTAINER_KILLING):
|
consts.CONTAINER_KILLING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.kill(context, container, signal)
|
container = self.driver.kill(context, container, signal)
|
||||||
return container
|
return container
|
||||||
|
|
||||||
@ -854,6 +884,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
container)
|
container)
|
||||||
with rt.container_update_claim(context, container, old_container,
|
with rt.container_update_claim(context, container, old_container,
|
||||||
limits):
|
limits):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.update(context, container)
|
self.driver.update(context, container)
|
||||||
container.save(context)
|
container.save(context)
|
||||||
return container
|
return container
|
||||||
@ -870,6 +901,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def container_attach(self, context, container):
|
def container_attach(self, context, container):
|
||||||
LOG.debug('Get websocket url from the container: %s', container.uuid)
|
LOG.debug('Get websocket url from the container: %s', container.uuid)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
url = self.driver.get_websocket_url(context, container)
|
url = self.driver.get_websocket_url(context, container)
|
||||||
token = uuidutils.generate_uuid()
|
token = uuidutils.generate_uuid()
|
||||||
container.websocket_url = url
|
container.websocket_url = url
|
||||||
@ -886,6 +918,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def container_resize(self, context, container, height, width):
|
def container_resize(self, context, container, height, width):
|
||||||
LOG.debug('Resize tty to the container: %s', container.uuid)
|
LOG.debug('Resize tty to the container: %s', container.uuid)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.resize(context, container, height, width)
|
container = self.driver.resize(context, container, height, width)
|
||||||
return container
|
return container
|
||||||
except exception.DockerError as e:
|
except exception.DockerError as e:
|
||||||
@ -899,6 +932,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
LOG.debug('Displaying the running processes inside the container: %s',
|
LOG.debug('Displaying the running processes inside the container: %s',
|
||||||
container.uuid)
|
container.uuid)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
return self.driver.top(context, container, ps_args)
|
return self.driver.top(context, container, ps_args)
|
||||||
except exception.DockerError as e:
|
except exception.DockerError as e:
|
||||||
LOG.error("Error occurred while calling Docker top API: %s",
|
LOG.error("Error occurred while calling Docker top API: %s",
|
||||||
@ -912,6 +946,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def container_get_archive(self, context, container, path, encode_data):
|
def container_get_archive(self, context, container, path, encode_data):
|
||||||
LOG.debug('Copying resource from the container: %s', container.uuid)
|
LOG.debug('Copying resource from the container: %s', container.uuid)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
filedata, stat = self.driver.get_archive(context, container, path)
|
filedata, stat = self.driver.get_archive(context, container, path)
|
||||||
if encode_data:
|
if encode_data:
|
||||||
filedata = utils.encode_file_data(filedata)
|
filedata = utils.encode_file_data(filedata)
|
||||||
@ -932,6 +967,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
if decode_data:
|
if decode_data:
|
||||||
data = utils.decode_file_data(data)
|
data = utils.decode_file_data(data)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
return self.driver.put_archive(context, container, path, data)
|
return self.driver.put_archive(context, container, path, data)
|
||||||
except exception.DockerError as e:
|
except exception.DockerError as e:
|
||||||
LOG.error(
|
LOG.error(
|
||||||
@ -946,6 +982,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def container_stats(self, context, container):
|
def container_stats(self, context, container):
|
||||||
LOG.debug('Displaying stats of the container: %s', container.uuid)
|
LOG.debug('Displaying stats of the container: %s', container.uuid)
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
return self.driver.stats(context, container)
|
return self.driver.stats(context, container)
|
||||||
except exception.DockerError as e:
|
except exception.DockerError as e:
|
||||||
LOG.error("Error occurred while calling Docker stats API: %s",
|
LOG.error("Error occurred while calling Docker stats API: %s",
|
||||||
@ -963,6 +1000,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
# NOTE(miaohb): Glance is the only driver that support image
|
# NOTE(miaohb): Glance is the only driver that support image
|
||||||
# uploading in the current version, so we have hard-coded here.
|
# uploading in the current version, so we have hard-coded here.
|
||||||
# https://bugs.launchpad.net/zun/+bug/1697342
|
# https://bugs.launchpad.net/zun/+bug/1697342
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
snapshot_image = self.driver.create_image(context, repository,
|
snapshot_image = self.driver.create_image(context, repository,
|
||||||
glance.GlanceDriver())
|
glance.GlanceDriver())
|
||||||
except exception.DockerError as e:
|
except exception.DockerError as e:
|
||||||
@ -981,11 +1019,13 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def _do_container_image_upload(self, context, snapshot_image,
|
def _do_container_image_upload(self, context, snapshot_image,
|
||||||
container_image_id, data, tag):
|
container_image_id, data, tag):
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.upload_image_data(context, snapshot_image,
|
self.driver.upload_image_data(context, snapshot_image,
|
||||||
tag, data, glance.GlanceDriver())
|
tag, data, glance.GlanceDriver())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception("Unexpected exception while uploading image: %s",
|
LOG.exception("Unexpected exception while uploading image: %s",
|
||||||
six.text_type(e))
|
six.text_type(e))
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.delete_committed_image(context, snapshot_image.id,
|
self.driver.delete_committed_image(context, snapshot_image.id,
|
||||||
glance.GlanceDriver())
|
glance.GlanceDriver())
|
||||||
self.driver.delete_image(context, container_image_id,
|
self.driver.delete_image(context, container_image_id,
|
||||||
@ -1004,23 +1044,27 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
# ensure the container is paused before doing commit
|
# ensure the container is paused before doing commit
|
||||||
unpause = False
|
unpause = False
|
||||||
if container.status == consts.RUNNING:
|
if container.status == consts.RUNNING:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.pause(context, container)
|
container = self.driver.pause(context, container)
|
||||||
container.save(context)
|
container.save(context)
|
||||||
unpause = True
|
unpause = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container_image_id = self.driver.commit(context, container,
|
container_image_id = self.driver.commit(context, container,
|
||||||
repository, tag)
|
repository, tag)
|
||||||
container_image = self.driver.get_image(repository + ':' + tag)
|
container_image = self.driver.get_image(repository + ':' + tag)
|
||||||
except exception.DockerError as e:
|
except exception.DockerError as e:
|
||||||
LOG.error("Error occurred while calling docker commit API: %s",
|
LOG.error("Error occurred while calling docker commit API: %s",
|
||||||
six.text_type(e))
|
six.text_type(e))
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.delete_committed_image(context, snapshot_image.id,
|
self.driver.delete_committed_image(context, snapshot_image.id,
|
||||||
glance.GlanceDriver())
|
glance.GlanceDriver())
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
if unpause:
|
if unpause:
|
||||||
try:
|
try:
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
container = self.driver.unpause(context, container)
|
container = self.driver.unpause(context, container)
|
||||||
container.save(context)
|
container.save(context)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -1125,7 +1169,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
def _get_resource_tracker(self):
|
def _get_resource_tracker(self):
|
||||||
if not self._resource_tracker:
|
if not self._resource_tracker:
|
||||||
rt = compute_node_tracker.ComputeNodeTracker(
|
rt = compute_node_tracker.ComputeNodeTracker(
|
||||||
self.host, self.driver, self.reportclient)
|
self.host, self.driver, self.capsule_driver, self.reportclient)
|
||||||
self._resource_tracker = rt
|
self._resource_tracker = rt
|
||||||
return self._resource_tracker
|
return self._resource_tracker
|
||||||
|
|
||||||
@ -1168,6 +1212,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
containers = objects.Container.list(ctx)
|
containers = objects.Container.list(ctx)
|
||||||
self.driver.update_containers_states(ctx, containers, self)
|
self.driver.update_containers_states(ctx, containers, self)
|
||||||
capsules = objects.Capsule.list(ctx)
|
capsules = objects.Capsule.list(ctx)
|
||||||
|
# TODO(hongbin): use capsule driver to update capsules status
|
||||||
self.driver.update_containers_states(ctx, capsules, self)
|
self.driver.update_containers_states(ctx, capsules, self)
|
||||||
|
|
||||||
def network_detach(self, context, container, network):
|
def network_detach(self, context, container, network):
|
||||||
@ -1185,6 +1230,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
{'container': container, 'network': network})
|
{'container': container, 'network': network})
|
||||||
with self._update_task_state(context, container,
|
with self._update_task_state(context, container,
|
||||||
consts.NETWORK_DETACHING):
|
consts.NETWORK_DETACHING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.network_detach(context, container, network)
|
self.driver.network_detach(context, container, network)
|
||||||
|
|
||||||
def network_attach(self, context, container, requested_network):
|
def network_attach(self, context, container, requested_network):
|
||||||
@ -1202,6 +1248,7 @@ class Manager(periodic_task.PeriodicTasks):
|
|||||||
{'container': container, 'network': requested_network})
|
{'container': container, 'network': requested_network})
|
||||||
with self._update_task_state(context, container,
|
with self._update_task_state(context, container,
|
||||||
consts.NETWORK_ATTACHING):
|
consts.NETWORK_ATTACHING):
|
||||||
|
# NOTE(hongbin): capsule shouldn't reach here
|
||||||
self.driver.network_attach(context, container, requested_network)
|
self.driver.network_attach(context, container, requested_network)
|
||||||
|
|
||||||
def network_create(self, context, neutron_net_id):
|
def network_create(self, context, neutron_net_id):
|
||||||
|
@ -27,6 +27,21 @@ Services which consume this:
|
|||||||
|
|
||||||
Interdependencies to other options:
|
Interdependencies to other options:
|
||||||
|
|
||||||
|
* None
|
||||||
|
"""),
|
||||||
|
cfg.StrOpt('capsule_driver',
|
||||||
|
default='docker',
|
||||||
|
help="""Defines which driver to use for controlling capsule.
|
||||||
|
Possible values:
|
||||||
|
|
||||||
|
* ``docker``
|
||||||
|
|
||||||
|
Services which consume this:
|
||||||
|
|
||||||
|
* ``zun-compute``
|
||||||
|
|
||||||
|
Interdependencies to other options:
|
||||||
|
|
||||||
* None
|
* None
|
||||||
"""),
|
"""),
|
||||||
cfg.IntOpt('default_sleep_time', default=1,
|
cfg.IntOpt('default_sleep_time', default=1,
|
||||||
|
@ -104,7 +104,8 @@ def wrap_docker_error(function):
|
|||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
||||||
|
|
||||||
class DockerDriver(driver.BaseDriver, driver.ContainerDriver):
|
class DockerDriver(driver.BaseDriver, driver.ContainerDriver,
|
||||||
|
driver.CapsuleDriver):
|
||||||
"""Implementation of container drivers for Docker."""
|
"""Implementation of container drivers for Docker."""
|
||||||
|
|
||||||
# TODO(hongbin): define a list of capabilities of this driver.
|
# TODO(hongbin): define a list of capabilities of this driver.
|
||||||
@ -1323,6 +1324,7 @@ class DockerDriver(driver.BaseDriver, driver.ContainerDriver):
|
|||||||
for container in capsule.containers:
|
for container in capsule.containers:
|
||||||
self._delete_container_in_capsule(context, capsule, container,
|
self._delete_container_in_capsule(context, capsule, container,
|
||||||
force)
|
force)
|
||||||
|
self.stop(context, capsule, None)
|
||||||
self.delete(context, capsule, force)
|
self.delete(context, capsule, force)
|
||||||
|
|
||||||
def _delete_container_in_capsule(self, context, capsule, container, force):
|
def _delete_container_in_capsule(self, context, capsule, container, force):
|
||||||
|
@ -83,6 +83,19 @@ def load_container_driver(container_driver=None):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def load_capsule_driver():
|
||||||
|
driver = stevedore_driver.DriverManager(
|
||||||
|
"zun.capsule.driver",
|
||||||
|
CONF.capsule_driver,
|
||||||
|
invoke_on_load=True).driver
|
||||||
|
|
||||||
|
if not isinstance(driver, CapsuleDriver):
|
||||||
|
raise Exception(_('Expected driver of type: %s') %
|
||||||
|
str(ContainerDriver))
|
||||||
|
|
||||||
|
return driver
|
||||||
|
|
||||||
|
|
||||||
class BaseDriver(object):
|
class BaseDriver(object):
|
||||||
"""Base class for driver."""
|
"""Base class for driver."""
|
||||||
|
|
||||||
@ -146,6 +159,9 @@ class BaseDriver(object):
|
|||||||
def node_support_disk_quota(self):
|
def node_support_disk_quota(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_host_default_base_size(self):
|
||||||
|
return None
|
||||||
|
|
||||||
def get_available_resources(self):
|
def get_available_resources(self):
|
||||||
"""Retrieve resource information.
|
"""Retrieve resource information.
|
||||||
|
|
||||||
@ -434,9 +450,6 @@ class ContainerDriver(object):
|
|||||||
def inspect_network(self, network):
|
def inspect_network(self, network):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def get_host_default_base_size(self):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def pull_image(self, context, repo, tag, **kwargs):
|
def pull_image(self, context, repo, tag, **kwargs):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@ -456,6 +469,10 @@ class ContainerDriver(object):
|
|||||||
def delete_image(self, context, img_id, image_driver):
|
def delete_image(self, context, img_id, image_driver):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class CapsuleDriver(object):
|
||||||
|
"""Interface for container driver."""
|
||||||
|
|
||||||
def create_capsule(self, context, capsule, **kwargs):
|
def create_capsule(self, context, capsule, **kwargs):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@ -498,12 +498,10 @@ class TestCapsuleController(api_base.FunctionalTest):
|
|||||||
response.json['uuid'])
|
response.json['uuid'])
|
||||||
|
|
||||||
@patch('zun.compute.api.API.container_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.Capsule.get_by_uuid')
|
||||||
@patch('zun.objects.Capsule.save')
|
@patch('zun.objects.Capsule.save')
|
||||||
def test_delete_capsule_by_uuid(self, mock_capsule_save,
|
def test_delete_capsule_by_uuid(self, mock_capsule_save,
|
||||||
mock_capsule_get_by_uuid,
|
mock_capsule_get_by_uuid,
|
||||||
mock_capsule_stop,
|
|
||||||
mock_capsule_delete):
|
mock_capsule_delete):
|
||||||
test_capsule = utils.create_test_container(context=self.context)
|
test_capsule = utils.create_test_container(context=self.context)
|
||||||
test_capsule_obj = objects.Capsule(self.context,
|
test_capsule_obj = objects.Capsule(self.context,
|
||||||
@ -516,20 +514,17 @@ class TestCapsuleController(api_base.FunctionalTest):
|
|||||||
response = self.app.delete('/v1/capsules/%s' % capsule_uuid)
|
response = self.app.delete('/v1/capsules/%s' % capsule_uuid)
|
||||||
|
|
||||||
self.assertTrue(mock_capsule_delete.called)
|
self.assertTrue(mock_capsule_delete.called)
|
||||||
self.assertTrue(mock_capsule_stop.called)
|
|
||||||
self.assertEqual(204, response.status_int)
|
self.assertEqual(204, response.status_int)
|
||||||
context = mock_capsule_save.call_args[0][0]
|
context = mock_capsule_save.call_args[0][0]
|
||||||
self.assertIs(False, context.all_projects)
|
self.assertIs(False, context.all_projects)
|
||||||
|
|
||||||
@patch('zun.common.policy.enforce')
|
@patch('zun.common.policy.enforce')
|
||||||
@patch('zun.compute.api.API.container_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.Capsule.get_by_uuid')
|
||||||
@patch('zun.objects.Capsule.save')
|
@patch('zun.objects.Capsule.save')
|
||||||
def test_delete_capsule_by_uuid_all_projects(self,
|
def test_delete_capsule_by_uuid_all_projects(self,
|
||||||
mock_capsule_save,
|
mock_capsule_save,
|
||||||
mock_capsule_get_by_uuid,
|
mock_capsule_get_by_uuid,
|
||||||
mock_capsule_stop,
|
|
||||||
mock_capsule_delete,
|
mock_capsule_delete,
|
||||||
mock_policy):
|
mock_policy):
|
||||||
mock_policy.return_value = True
|
mock_policy.return_value = True
|
||||||
@ -545,7 +540,6 @@ class TestCapsuleController(api_base.FunctionalTest):
|
|||||||
'/v1/capsules/%s/?all_projects=1' % capsule_uuid)
|
'/v1/capsules/%s/?all_projects=1' % capsule_uuid)
|
||||||
|
|
||||||
self.assertTrue(mock_capsule_delete.called)
|
self.assertTrue(mock_capsule_delete.called)
|
||||||
self.assertTrue(mock_capsule_stop.called)
|
|
||||||
self.assertEqual(204, response.status_int)
|
self.assertEqual(204, response.status_int)
|
||||||
context = mock_capsule_save.call_args[0][0]
|
context = mock_capsule_save.call_args[0][0]
|
||||||
self.assertIs(True, context.all_projects)
|
self.assertIs(True, context.all_projects)
|
||||||
@ -556,12 +550,10 @@ class TestCapsuleController(api_base.FunctionalTest):
|
|||||||
'/capsules/%s' % uuid)
|
'/capsules/%s' % uuid)
|
||||||
|
|
||||||
@patch('zun.compute.api.API.container_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.Capsule.get_by_name')
|
||||||
@patch('zun.objects.Capsule.save')
|
@patch('zun.objects.Capsule.save')
|
||||||
def test_delete_capsule_by_name(self, mock_capsule_save,
|
def test_delete_capsule_by_name(self, mock_capsule_save,
|
||||||
mock_capsule_get_by_uuid,
|
mock_capsule_get_by_uuid,
|
||||||
mock_capsule_stop,
|
|
||||||
mock_capsule_delete):
|
mock_capsule_delete):
|
||||||
test_capsule = utils.create_test_container(context=self.context)
|
test_capsule = utils.create_test_container(context=self.context)
|
||||||
test_capsule_obj = objects.Capsule(self.context,
|
test_capsule_obj = objects.Capsule(self.context,
|
||||||
@ -575,7 +567,6 @@ class TestCapsuleController(api_base.FunctionalTest):
|
|||||||
capsule_name)
|
capsule_name)
|
||||||
|
|
||||||
self.assertTrue(mock_capsule_delete.called)
|
self.assertTrue(mock_capsule_delete.called)
|
||||||
self.assertTrue(mock_capsule_stop.called)
|
|
||||||
self.assertEqual(204, response.status_int)
|
self.assertEqual(204, response.status_int)
|
||||||
context = mock_capsule_save.call_args[0][0]
|
context = mock_capsule_save.call_args[0][0]
|
||||||
self.assertIs(False, context.all_projects)
|
self.assertIs(False, context.all_projects)
|
||||||
|
@ -100,6 +100,7 @@ class TestManager(base.TestCase):
|
|||||||
self.addCleanup(p.stop)
|
self.addCleanup(p.stop)
|
||||||
|
|
||||||
zun.conf.CONF.set_override('container_driver', 'fake')
|
zun.conf.CONF.set_override('container_driver', 'fake')
|
||||||
|
zun.conf.CONF.set_override('capsule_driver', 'fake')
|
||||||
self.compute_manager = manager.Manager()
|
self.compute_manager = manager.Manager()
|
||||||
self.compute_manager._resource_tracker = FakeResourceTracker()
|
self.compute_manager._resource_tracker = FakeResourceTracker()
|
||||||
|
|
||||||
|
@ -27,9 +27,11 @@ class TestNodeStracker(base.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestNodeStracker, self).setUp()
|
super(TestNodeStracker, self).setUp()
|
||||||
self.container_driver = fake_driver.FakeDriver()
|
self.container_driver = fake_driver.FakeDriver()
|
||||||
|
self.capsule_driver = fake_driver.FakeDriver()
|
||||||
self.report_client_mock = mock.MagicMock()
|
self.report_client_mock = mock.MagicMock()
|
||||||
self._resource_tracker = compute_node_tracker.ComputeNodeTracker(
|
self._resource_tracker = compute_node_tracker.ComputeNodeTracker(
|
||||||
'testhost', self.container_driver, self.report_client_mock)
|
'testhost', self.container_driver, self.capsule_driver,
|
||||||
|
self.report_client_mock)
|
||||||
|
|
||||||
@mock.patch.object(compute_node_tracker.ComputeNodeTracker, '_update')
|
@mock.patch.object(compute_node_tracker.ComputeNodeTracker, '_update')
|
||||||
@mock.patch.object(compute_node_tracker.ComputeNodeTracker,
|
@mock.patch.object(compute_node_tracker.ComputeNodeTracker,
|
||||||
|
@ -16,7 +16,8 @@ from zun.common.utils import check_container_id
|
|||||||
from zun.container import driver
|
from zun.container import driver
|
||||||
|
|
||||||
|
|
||||||
class FakeDriver(driver.BaseDriver, driver.ContainerDriver):
|
class FakeDriver(driver.BaseDriver, driver.ContainerDriver,
|
||||||
|
driver.CapsuleDriver):
|
||||||
"""Fake driver for testing."""
|
"""Fake driver for testing."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user