示例#1
0
class Install(object):
    dryrun = False
    params = None
    answers_file = None
    docker_cli = "docker"
    answers_file_values = {}

    def __init__(
            self, answers, APP, nodeps=False, update=False, target_path=None,
            dryrun=False, answers_format=ANSWERS_FILE_SAMPLE_FORMAT, **kwargs):
        self.dryrun = dryrun
        self.kwargs = kwargs

        app = APP  # FIXME

        self.nulecule_base = Nulecule_Base(
            nodeps, update, target_path, dryrun, answers_format)

        if os.path.exists(app):
            logger.info("App path is %s, will be populated to %s", app, target_path)
            app = self._loadApp(app)
        else:
            logger.info("App name is %s, will be populated to %s", app, target_path)

        printStatus("Loading app %s ." % app)
        if not target_path:
            if self.nulecule_base.app_path:
                self.nulecule_base.target_path = self.nulecule_base.app_path
            else:
                self.nulecule_base.target_path = os.getcwd()

        self.utils = Utils(self.nulecule_base.target_path)

        self.nulecule_base.app = app

        self.answers_file = answers
        self.docker_cli = Utils.getDockerCli(self.dryrun)

    def _loadApp(self, app_path):
        self.nulecule_base.app_path = app_path

        if not os.path.basename(app_path) == MAIN_FILE:
            app_path = os.path.join(app_path, MAIN_FILE)

        mainfile_data = self.nulecule_base.loadMainfile(app_path)
        app = os.environ["IMAGE"] if "IMAGE" in os.environ else mainfile_data["id"]
        logger.debug("Setting path to %s", self.nulecule_base.app_path)

        return app

    def _copyFromContainer(self, image):
        image = self.nulecule_base.getImageURI(image)

        name = "%s-%s" % (self.utils.getComponentName(image),
                          ''.join(random.sample(string.letters, 6)))
        logger.debug("Creating a container with name %s", name)

        # Workaround docker bug BZ1252168 by using run instead of create
        create = [self.docker_cli, "run", "--name", name, "--entrypoint", "/bin/true", image]
        logger.debug(" ".join(create))
        subprocess.call(create)
        cp = [self.docker_cli, "cp", "%s:/%s" % (name, APP_ENT_PATH), self.utils.tmpdir]
        logger.debug(cp)
        if not subprocess.call(cp):
            logger.debug("Application entity data copied to %s", self.utils.tmpdir)

        printStatus("Copied app successfully.")
        rm = [self.docker_cli, "rm", name]
        subprocess.call(rm)

    def _populateApp(self, src=None, dst=None):
        logger.info("Copying app %s", self.utils.getComponentName(self.nulecule_base.app))
        if not src:
            src = os.path.join(self.utils.tmpdir, APP_ENT_PATH)

        if not dst:
            dst = self.nulecule_base.target_path
        distutils.dir_util.copy_tree(src, dst, update=(not self.nulecule_base.update))

    def _fromImage(self):
        return not self.nulecule_base.app_path or \
            self.nulecule_base.target_path == self.nulecule_base.app_path

    def install(self):
        answerContent = self.nulecule_base.loadAnswers(self.answers_file)
        printAnswerFile(json.dumps(answerContent))

        mainfile_dir = self.nulecule_base.app_path
        if not self.dryrun:
            if self._fromImage():
                self.nulecule_base.pullApp()
                self._copyFromContainer(self.nulecule_base.app)
                mainfile_dir = self.utils.getTmpAppDir()

            current_app_id = None
            if os.path.isfile(self.nulecule_base.getMainfilePath()):
                current_app_id = Utils.getAppId(self.nulecule_base.getMainfilePath())
                printStatus("Loading app_id %s ." % current_app_id)

            if current_app_id:
                tmp_mainfile_path = os.path.join(mainfile_dir, MAIN_FILE)
                self.nulecule_base.loadMainfile(tmp_mainfile_path)
                logger.debug("%s path for pulled image: %s", MAIN_FILE, tmp_mainfile_path)
                if current_app_id != self.nulecule_base.app_id:
                    msg = ("You are trying to overwrite existing app %s with "
                           "app %s - clear or change current directory."
                           % (current_app_id, self.nulecule_base.app_id))
                    raise Exception(msg)
        elif self._fromImage():
            logger.warning("Using DRY-RUN together with install from image "
                           "may result in unexpected behaviour")

        if self.nulecule_base.update or \
            (not self.dryrun
             and not os.path.exists(self.nulecule_base.getMainfilePath())):
            if self._fromImage():
                self._populateApp()
            else:
                logger.info("Copying content of directory %s to %s",
                            self.nulecule_base.app_path, self.nulecule_base.target_path)
                self._populateApp(src=self.nulecule_base.app_path)

        mainfile_path = os.path.join(self.nulecule_base.target_path, MAIN_FILE)
        if not self.nulecule_base.mainfile_data:
            self.nulecule_base.loadMainfile(mainfile_path)

        logger.debug("App ID: %s", self.nulecule_base.app_id)

        self.nulecule_base.checkSpecVersion()
        printStatus("Checking all artifacts")
        self.nulecule_base.checkAllArtifacts()

        printStatus("Loading Nulecule file.")
        if not self.nulecule_base.nodeps:
            logger.info("Installing dependencies for %s", self.nulecule_base.app_id)
            self.answers_file_values = self._installDependencies()
            printStatus("All dependencies installed successfully.")

        logger.debug(self.answers_file_values)
        answerContent = self.nulecule_base.loadAnswers(self.answers_file_values)
        logger.debug(self.nulecule_base.answers_data)
        if self.nulecule_base.write_sample_answers:
            self.nulecule_base.writeAnswersSample()

        printAnswerFile(json.dumps(answerContent))
        printStatus("Install Successful.")
        return None

    def _installDependencies(self):
        values = {}
        for graph_item in self.nulecule_base.mainfile_data["graph"]:
            component = graph_item.get("name")
            if not component:
                raise ValueError("Component name missing in graph")

            if not self.utils.isExternal(graph_item):
                values[component] = self.nulecule_base.getValues(
                    component, skip_asking=True)
                logger.debug("Component %s is part of the app", component)
                logger.debug("Values: %s", values)
                continue

            logger.info("Component %s is external dependency", component)

            image_name = self.utils.getSourceImage(graph_item)
            component_path = self.utils.getExternalAppDir(component)
            mainfile_component_path = os.path.join(component_path, MAIN_FILE)
            logger.debug("Component path: %s", component_path)
            if not os.path.isfile(mainfile_component_path) or self.nulecule_base.update:
                printStatus("Pulling %s ..." % image_name)
                component_app = Install(
                    self.nulecule_base.answers_data,
                    image_name, self.nulecule_base.nodeps,
                    self.nulecule_base.update, component_path, self.dryrun)
                component_app.install()
                values = Utils.update(values, component_app.answers_file_values)
                printStatus("Component %s installed successfully." % component)
                logger.debug("Component installed into %s", component_path)
            else:
                printStatus("Component %s already installed." % component)
                logger.info("Component %s already exists at %s - remove the directory "
                            "or use --update option" % (component, component_path))

        return values
示例#2
0
class Install(object):
    dryrun = False
    params = None
    answers_file = None
    docker_cli = "docker"

    def __init__(self,
                 answers,
                 APP,
                 nodeps=False,
                 update=False,
                 target_path=None,
                 dryrun=False,
                 **kwargs):
        self.dryrun = dryrun
        self.kwargs = kwargs

        app = APP  #FIXME

        self.nulecule_base = Nulecule_Base(nodeps, update, target_path, dryrun)

        if os.path.exists(app):
            logger.info("App path is %s, will be populated to %s", app,
                        target_path)
            app = self._loadApp(app)
        else:
            logger.info("App name is %s, will be populated to %s", app,
                        target_path)

        if not target_path:
            if self.nulecule_base.app_path:
                self.nulecule_base.target_path = self.nulecule_base.app_path
            else:
                self.nulecule_base.target_path = os.getcwd()

        self.utils = Utils(self.nulecule_base.target_path)

        self.nulecule_base.app = app

        self.answers_file = answers
        self.docker_cli = Utils.getDockerCli(self.dryrun)

    def _loadApp(self, app_path):
        self.nulecule_base.app_path = app_path

        if not os.path.basename(app_path) == MAIN_FILE:
            app_path = os.path.join(app_path, MAIN_FILE)

        mainfile_data = self.nulecule_base.loadMainfile(app_path)
        app = os.environ["IMAGE"] if "IMAGE" in os.environ else mainfile_data[
            "id"]
        logger.debug("Setting path to %s", self.nulecule_base.app_path)

        return app

    def _copyFromContainer(self, image):
        image = self.nulecule_base.getImageURI(image)

        name = "%s-%s" % (self.utils.getComponentName(image), ''.join(
            random.sample(string.letters, 6)))
        logger.debug("Creating a container with name %s", name)

        create = [self.docker_cli, "create", "--name", name, image, "nop"]
        subprocess.call(create)
        cp = [
            self.docker_cli, "cp",
            "%s:/%s" % (name, APP_ENT_PATH), self.utils.tmpdir
        ]
        logger.debug(cp)
        if not subprocess.call(cp):
            logger.debug("Application entity data copied to %s",
                         self.utils.tmpdir)

        rm = [self.docker_cli, "rm", name]
        subprocess.call(rm)

    def _populateApp(self, src=None, dst=None):
        logger.info("Copying app %s",
                    self.utils.getComponentName(self.nulecule_base.app))
        if not src:
            src = os.path.join(self.utils.tmpdir, APP_ENT_PATH)

        if not dst:
            dst = self.nulecule_base.target_path
        distutils.dir_util.copy_tree(src,
                                     dst,
                                     update=(not self.nulecule_base.update))

    def _fromImage(self):
        return not self.nulecule_base.app_path or self.nulecule_base.target_path == self.nulecule_base.app_path

    def install(self):
        self.nulecule_base.loadAnswers(self.answers_file)

        mainfile_dir = self.nulecule_base.app_path
        if not self.dryrun:
            if self._fromImage():
                self.nulecule_base.pullApp()
                self._copyFromContainer(self.nulecule_base.app)
                mainfile_dir = self.utils.getTmpAppDir()

            current_app_id = None
            if os.path.isfile(self.nulecule_base.getMainfilePath()):
                current_app_id = Utils.getAppId(
                    self.nulecule_base.getMainfilePath())

            if current_app_id:
                tmp_mainfile_path = os.path.join(mainfile_dir, MAIN_FILE)
                self.nulecule_base.loadMainfile(tmp_mainfile_path)
                logger.debug("%s path for pulled image: %s", MAIN_FILE,
                             tmp_mainfile_path)
                if current_app_id != self.nulecule_base.app_id:
                    raise Exception(
                        "You are trying to overwrite existing app %s with app %s - clear or change current directory."
                        % (current_app_id, self.nulecule_base.app_id))
        elif self._fromImage():
            logger.warning(
                "Using DRY-RUN together with install from image may result in unexpected behaviour"
            )

        if self.nulecule_base.update or (
                not self.dryrun
                and not os.path.exists(self.nulecule_base.getMainfilePath())):
            if self._fromImage():
                self._populateApp()
            else:
                logger.info("Copying content of directory %s to %s",
                            self.nulecule_base.app_path,
                            self.nulecule_base.target_path)
                self._populateApp(src=self.nulecule_base.app_path)

        mainfile_path = os.path.join(self.nulecule_base.target_path, MAIN_FILE)
        if not self.nulecule_base.mainfile_data:
            self.nulecule_base.loadMainfile(mainfile_path)

        logger.debug("App ID: %s", self.nulecule_base.app_id)

        self.nulecule_base.checkSpecVersion()
        self.nulecule_base.checkAllArtifacts()

        values = {}
        if not self.nulecule_base.nodeps:
            logger.info("Installing dependencies for %s",
                        self.nulecule_base.app_id)
            values = self._installDependencies()

        logger.debug(values)
        self.nulecule_base.loadAnswers(values)
        logger.debug(self.nulecule_base.answers_data)
        if self.nulecule_base.write_sample_answers:
            self.nulecule_base.writeAnswersSample()

        return values

    def _installDependencies(self):
        values = {}
        for graph_item in self.nulecule_base.mainfile_data["graph"]:
            component = graph_item.get("name")
            if not component:
                raise ValueError("Component name missing in graph")

            if not self.utils.isExternal(graph_item):
                values[component] = self.nulecule_base.getValues(
                    component, skip_asking=True)
                logger.debug("Component %s is part of the app", component)
                logger.debug("Values: %s", values)
                continue

            logger.info("Component %s is external dependency", component)

            image_name = self.utils.getSourceImage(graph_item)
            component_path = self.utils.getExternalAppDir(component)
            mainfile_component_path = os.path.join(component_path, MAIN_FILE)
            logger.debug("Component path: %s", component_path)
            if not os.path.isfile(
                    mainfile_component_path) or self.nulecule_base.update:
                logger.info("Pulling %s", image_name)
                component_app = Install(self.nulecule_base.answers_data,
                                        image_name, self.nulecule_base.nodeps,
                                        self.nulecule_base.update,
                                        component_path, self.dryrun)
                values = Utils.update(values, component_app.install())
                logger.info("Component installed into %s", component_path)
            else:
                logger.info(
                    "Component %s already exists at %s - remove the directory or use --update option",
                    component, component_path)

        return values