# 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 os
import sys

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 import lxc
from autotest_lib.site_utils.lxc import utils as lxc_utils
from autotest_lib.site_utils.lxc.container import Container


class BaseImage(object):
    """A class that manages a base container.

    Instantiating this class will cause it to search for a base container under
    the given path and name.  If one is found, the class adopts it.  If not, the
    setup() method needs to be called, to download and install a new base
    container.

    The actual base container can be obtained by calling the get() method.

    Calling cleanup() will delete the base container along with all of its
    associated snapshot clones.
    """

    def __init__(self,
                 container_path=constants.DEFAULT_CONTAINER_PATH,
                 base_name=constants.BASE):
        """Creates a new BaseImage.

        If a valid base container already exists on this machine, the BaseImage
        adopts it.  Otherwise, setup needs to be called to download a base and
        install a base container.

        @param container_path: The LXC path for the base container.
        @param base_name: The base container name.
        """
        self.container_path = container_path
        self.base_name = base_name
        try:
            base_container = Container.create_from_existing_dir(
                    container_path, base_name);
            base_container.refresh_status()
            self.base_container = base_container
        except error.ContainerError:
            self.base_container = None


    def setup(self, name=None, force_delete=False):
        """Download and setup the base container.

        @param name: Name of the base container, defaults to the name passed to
                     the constructor.  If a different name is provided, that
                     name overrides the name originally passed to the
                     constructor.
        @param force_delete: True to force to delete existing base container.
                             This action will destroy all running test
                             containers. Default is set to False.
        """
        if name is not None:
            self.base_name = name

        if not self.container_path:
            raise error.ContainerError(
                    'You must set a valid directory to store containers in '
                    'global config "AUTOSERV/ container_path".')

        if not os.path.exists(self.container_path):
            os.makedirs(self.container_path)

        if self.base_container and not force_delete:
            logging.error(
                    'Base container already exists. Set force_delete to True '
                    'to force to re-stage base container. Note that this '
                    'action will destroy all running test containers')
            # Set proper file permission. base container in moblab may have
            # owner of not being root. Force to update the folder's owner.
            self._set_root_owner()
            return

        # Destroy existing base container if exists.
        if self.base_container:
            self.cleanup()

        try:
            self._download_and_install_base_container()
            self._set_root_owner()
        except:
            # Clean up if something went wrong.
            base_path = os.path.join(self.container_path, self.base_name)
            if lxc_utils.path_exists(base_path):
                exc_info = sys.exc_info()
                container = Container.create_from_existing_dir(
                        self.container_path, self.base_name)
                # Attempt destroy.  Log but otherwise ignore errors.
                try:
                    container.destroy()
                except error.CmdError as e:
                    logging.error(e)
            # Raise the cached exception with original backtrace.
            raise exc_info[0], exc_info[1], exc_info[2]
        else:
            self.base_container = Container.create_from_existing_dir(
                    self.container_path, self.base_name)


    def cleanup(self):
        """Destroys the base container.

        This operation will also destroy all snapshot clones of the base
        container.
        """
        # Find and delete clones first.
        for clone in self._find_clones():
            clone.destroy()
        base = Container.create_from_existing_dir(self.container_path,
                                                  self.base_name)
        base.destroy()


    def get(self):
        """Returns the base container.

        @raise ContainerError: If the base image is invalid or missing.
        """
        if self.base_container is None:
            raise error.ContainerError('Invalid base container.')
        else:
            return self.base_container


    def _download_and_install_base_container(self):
        """Downloads the base image, untars and configures it."""
        base_path = os.path.join(self.container_path, self.base_name)
        tar_path = os.path.join(self.container_path,
                                '%s.tar.xz' % self.base_name)

        # Force cleanup of any previously downloaded/installed base containers.
        # This ensures a clean setup of the new base container.
        #
        # TODO(kenobi): Add a check to ensure that the base container doesn't
        # get deleted while snapshot clones exist (otherwise running tests might
        # get disrupted).
        path_to_cleanup = [tar_path, base_path]
        for path in path_to_cleanup:
            if os.path.exists(path):
                utils.run('sudo rm -rf "%s"' % path)
        container_url = constants.CONTAINER_BASE_URL_FMT % self.base_name
        lxc.download_extract(container_url, tar_path, self.container_path)
        # Remove the downloaded container tar file.
        utils.run('sudo rm "%s"' % tar_path)

        # Update container config with container_path from global config.
        config_path = os.path.join(base_path, 'config')
        rootfs_path = os.path.join(base_path, 'rootfs')
        utils.run(('sudo sed '
                   '-i "s|\(lxc\.rootfs[[:space:]]*=\).*$|\\1 {rootfs}|" '
                   '"{config}"').format(rootfs=rootfs_path,
                                        config=config_path))

    def _set_root_owner(self):
        """Changes the container group and owner to root.

        This is necessary because we currently run privileged containers.
        """
        # TODO(dshi): Change root to current user when test container can be
        # unprivileged container.
        base_path = os.path.join(self.container_path, self.base_name)
        utils.run('sudo chown -R root "%s"' % base_path)
        utils.run('sudo chgrp -R root "%s"' % base_path)


    def _find_clones(self):
        """Finds snapshot clones of the current base container."""
        snapshot_file = os.path.join(self.container_path,
                                     self.base_name,
                                     'lxc_snapshots')
        if not lxc_utils.path_exists(snapshot_file):
            return
        cmd = 'sudo cat %s' % snapshot_file
        clone_info = [line.strip()
                      for line in utils.run(cmd).stdout.splitlines()]
        # lxc_snapshots contains pairs of lines (lxc_path, container_name).
        for i in range(0, len(clone_info), 2):
            lxc_path = clone_info[i]
            name = clone_info[i+1]
            yield Container.create_from_existing_dir(lxc_path, name)
