blob: 6e3c4d44623cf178a02183332df3e1a5c72eb23e [file] [log] [blame]
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import common
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.site_utils.lxc import constants
from autotest_lib.site_utils.lxc.container import Container
try:
from chromite.lib import metrics
except ImportError:
metrics = utils.metrics_mock
class ContainerFactory(object):
"""A factory class for creating LXC container objects.
"""
def __init__(self, base_container, container_class=Container, snapshot=True,
force_cleanup=False):
"""Initializes a ContainerFactory.
@param base_container: The base container from which other containers
are cloned.
@param container_class: (optional) The Container class to instantiate.
By default, lxc.Container is instantiated.
@param snapshot: (optional) If True, creates LXC snapshot clones instead
of full clones. By default, snapshot clones are used.
@param force_cleanup: (optional) If True, if a container is created with
a name and LXC directory matching an existing
container, the existing container is destroyed,
and the new container created in its place. By
default, existing containers are not destroyed and
a ContainerError is raised.
"""
self._container_class = container_class
self._base_container = base_container
self._snapshot = snapshot
self._force_cleanup = force_cleanup
def create_container(self, cid, path):
"""Creates a new container.
@param cid: A ContainerId for the new container.
@param path: The LXC path for the new container.
"""
# Legacy: use the string representation of the ContainerId as its name.
name = str(cid)
container = self._create_from_base(name, path)
container.id = cid
return container
# create_from_base_duration is the original name of the metric. Keep this
# so we have history.
@metrics.SecondsTimerDecorator(
'%s/create_from_base_duration' % constants.STATS_KEY)
def _create_from_base(self, name, container_path):
"""Creates a container from the base container.
@param name: Name of the container.
@param container_path: The LXC path of the new container.
@return: A Container object for the created container.
@raise ContainerError: If the container already exist.
@raise error.CmdError: If lxc-clone call failed for any reason.
"""
use_snapshot = constants.SUPPORT_SNAPSHOT_CLONE and self._snapshot
try:
return self._container_class.clone(src=self._base_container,
new_name=name,
new_path=container_path,
snapshot=use_snapshot,
cleanup=self._force_cleanup)
except error.CmdError:
logging.debug('Creating snapshot clone failed. Attempting without '
'snapshot...')
if not use_snapshot:
raise
else:
# Snapshot clone failed, retry clone without snapshot.
container = self._container_class.clone(
src=self._base_container,
new_name=name,
new_path=container_path,
snapshot=False,
cleanup=self._force_cleanup)
return container