Example #1
0
class Run(object):
    debug = False
    dryrun = False
    params = None
    answers_data = {GLOBAL_CONF: {}}
    tmpdir = None
    answers_file = None
    provider = DEFAULT_PROVIDER
    installed = False
    plugins = []
    update = False
    app_path = None
    target_path = None
    app_id = None
    app = None
    answers_output = None
    kwargs = None

    def __init__(self, answers, APP, dryrun = False, debug = False, stop = False, **kwargs):

        self.debug = debug
        self.dryrun = dryrun
        self.stop = stop
        self.kwargs = kwargs
        if "answers_output" in kwargs:
            self.answers_output = kwargs["answers_output"]

        if os.environ and "IMAGE" in os.environ:
            self.app_path = APP
            APP = os.environ["IMAGE"]
            del os.environ["IMAGE"]

        if APP and os.path.exists(APP):
            self.app_path = APP
        else:
            self.app_path = os.getcwd()
            install = Install(answers, APP, dryrun = dryrun, target_path = self.app_path)
            install.install()

        self.params = Params(target_path=self.app_path)
        if "ask" in kwargs:
            self.params.ask = kwargs["ask"]

        workdir = None
        if "workdir" in kwargs:
            workdir = kwargs["workdir"]

        self.utils = Utils(self.params, workdir)
        if not "workdir" in kwargs:
            kwargs["workdir"] = self.utils.workdir


        self.answers_file = answers
        self.plugin = Plugin()
        self.plugin.load_plugins()

    def _dispatchGraph(self):
        if not "graph" in self.params.mainfile_data:
            raise Exception("Graph not specified in %s" % MAIN_FILE)

        for component, graph_item in self.params.mainfile_data["graph"].iteritems():
            if self.utils.isExternal(graph_item):
                component_run = Run(self.answers_file, self.utils.getExternalAppDir(component), self.dryrun, self.debug, **self.kwargs)
                ret = component_run.run()
                if self.answers_output:
                    self.params.loadAnswers(ret)
            else:
                self._processComponent(component, graph_item)

    def _applyTemplate(self, data, component):
        template = Template(data)
        config = self.params.getValues(component)
        logger.debug("Config: %s ", config)

        output = None
        while not output:
            try:
                logger.debug(config)
                output = template.substitute(config)
            except KeyError as ex:
                name = ex.args[0]
                logger.debug("Artifact contains unknown parameter %s, asking for it", name)
                config[name] = self.params.askFor(name, {"description": "Missing parameter '%s', provide the value or fix your %s" % (name, MAIN_FILE)})
                if not len(config[name]):
                    raise Exception("Artifact contains unknown parameter %s" % name)
                self.params.loadAnswers({component: {name: config[name]}})

        return output

    def _processArtifacts(self, component, provider):
        artifacts = self.utils.getArtifacts(component)
        artifact_provider_list = []
        if not provider in artifacts:
            raise Exception("Data for provider \"%s\" are not part of this app" % self.params.provider)

        dst_dir = os.path.join(self.utils.workdir, component)
        data = None

        for artifact in artifacts[provider]:
            if "inherit" in artifact:
                logger.debug("Inheriting from %s", artifact["inherit"])
                for item in artifact["inherit"]:
                    inherited_artifacts, _ = self._processArtifacts(component, item)
                    artifact_provider_list += inherited_artifacts
                continue
            artifact_path = self.utils.sanitizePath(artifact)
            with open(os.path.join(self.app_path, artifact_path), "r") as fp:
                data = fp.read()

            logger.debug("Templating artifact %s/%s", self.app_path, artifact_path)
            data = self._applyTemplate(data, component)

            artifact_dst = os.path.join(dst_dir, artifact_path)

            if not os.path.isdir(os.path.dirname(artifact_dst)):
                os.makedirs(os.path.dirname(artifact_dst))
            with open(artifact_dst, "w") as fp:
                logger.debug("Writing artifact to %s", artifact_dst)
                fp.write(data)

            artifact_provider_list.append(artifact_path)

        return artifact_provider_list, dst_dir

    def _processComponent(self, component, graph_item):
        logger.debug("Processing component %s", component)

        artifact_list, dst_dir = self._processArtifacts(component, self.params.provider)
        provider_class = self.plugin.getProvider(self.params.provider)
        provider = provider_class(self.params.getValues(component), artifact_list, dst_dir, self.dryrun)
        if provider:
            logger.info("Using provider %s for component %s", self.params.provider, component)
        else:
            raise Exception("Something is broken - couldn't get the provider")

        try:
            provider.init()
            provider.deploy()
        except ProviderFailedException as ex:
            logger.error(ex)
            sys.exit(1)

    def run(self):
        self.params.loadMainfile(os.path.join(self.params.target_path, MAIN_FILE))
        self.params.loadAnswers(self.answers_file)

        self.utils.checkAllArtifacts()
        config = self.params.get()
        if "provider" in config:
            self.provider = config["provider"]

        self._dispatchGraph()

#Think about this a bit more probably - it's (re)written for all components...
        if self.answers_output:
            self.params.writeAnswers(self.answers_output)
            return self.params.answers_data

        return None
Example #2
0
class Create(object):
    name = None
    app_id = None
    dryrun = False
    schema = None
    def __init__(self, name, schema = None, dryrun = False):
        self.name = name
        self.app_id = self._nameToId(name)
        self.dryrun = dryrun
        self.schema_path = schema

        if not self.schema_path:
            self.schema_path = SCHEMA_URL

        self.params = Params()
        self.params.app = self.app_id

    def _loadSchema(self):
        if not os.path.isfile(self.schema_path):
            response = urllib2.urlopen(self.schema_path)
            with open(os.path.basename(self.schema_path), "w") as fp:
                fp.write(response.read())
                self.schema_path = os.path.basename(self.schema_path)

        with open(self.schema_path, "r") as fp:
            self.schema = json.load(fp)

    def create(self):
        self._loadSchema()
        if self.schema and "elements" in self.schema:
            self._writeFromSchema(self.schema["elements"])
        else:
            print("Corrupted schema, couldn't create app")

    def build(self, tag):
        if not tag:
            tag = self.app_id

        cmd = ["docker", "build", "-t", tag, "."]
        if self.dryrun:
            print("Build: %s" % " ".join(cmd))
        else:
            subprocess.call(cmd)


    def _writeFromSchema(self, elements):
        for element in elements:
            value = element["value"]
            if not element["contents"] and not value:
                continue
            if element["name"] == "application":
                value = self.app_id
            print("Writing %s" % element["name"])
            if element["type"] == "directory":
                if value:
                    os.mkdir(value)
                    os.chdir(value)
                    self._writeFromSchema(element["contents"])
                    os.chdir("..")
                else:
                    logger.debug("No value for directory %s", element["name"])
            elif element["type"] == "file":
                with open(value, "w") as fp:
                    logger.debug(element)
                    if element["contents"]:
                        if isinstance(element["contents"], str) or isinstance(element["contents"], unicode):
                            fp.write(element["contents"])
                        elif isinstance(element["contents"], collections.Mapping):
                            fp.write(anymarkup.serialize(self._generateContents(element["contents"]), format='yaml'))
#                        elif element["contentType"] == "application/json":
#                            if element["name"] == "Atomicfile":
#                                element["contents"] = self._updateAtomicfile(element["contents"])

#                            fp.write(json.dumps(element["contents"]))

    def _pickOne(self, what, info, options):
        options_text = ""
        for i, option in enumerate(options):
            options_text += "%s. %s\n" % (i+1, option)

        required = False

        if "required" in info:
            required = info["required"]

        value = raw_input("%s (%s)\n Options:\n%s\nYour choice (default: 1): " % (what, info["description"], options_text))
        if len(value) == 0:
            value = 1
        elif int(value) == 0 and not required:
            return None

        return options[int(value)-1]

    def _getName(self, element, content, path = None):
        name = None
        if not "name" in content:
            name = element
        elif not content["name"]:
            name = self._generateValue(path)
            if not name:
                name = self.params.askFor(element, content)
        elif type(content["name"]) is list:
            name = self._pickOne(element, content, content["name"])
        else:
            name = content["name"]

        logger.debug(name)

        return name

    def _generateContents(self, contents, path="root"):
        result = {}
        for element, content in contents.iteritems():

            local_path = "%s.%s" % (path, element)
            name = self._getName(element, content, local_path)

            print("Filling %s" % name)
            if not content["required"]:
                skip = self.params.askFor("Element %s not required, do you want to skip it?" % name, {"description": "Type y or n", "default": "Y"})
                if isTrue(skip):
                    continue
            #logger.debug("Key: %s, value %s", element, content["value"])

            if content["type"] == "object":
                result[name] = self._generateContents(content["value"], local_path)
            elif content["type"] == "list":

                tmp_results = []
                while True:
                    value = self.params.askFor(content["value"].keys()[0], content["value"][content["value"].keys()[0]])
                    if len(value) == 0:
                        break
                    tmp_results.append(value)

                result[name] = tmp_results
            else:
                if not content["value"]:
                    logger.debug(local_path)
                    value = self._generateValue(local_path)
                    if not value:
                        value = self.params.askFor(element, content)
                    logger.debug(value)
                else:
                    value = content["value"]
                result[name] = value

        return result

    def _generateValue(self, element):
        if element == "root.id":
            return self.app_id
        elif element == "root.metadata.name":
            return self.name
        elif element == "root.graph.component":
            return self.app_id

        return None

    def _nameToId(self, name):
        return name.strip().lower().replace(" ", "-")

    def _updateAtomicfile(self, contents):
        print(contents)
        if "name" in contents:
            contents["name"] = self.name
        if "id" in contents:
            contents["id"] = self.app_id
        if "graph" in contents:
            component = {"repository": "", "name": self.app_id}
            contents["graph"].append(component)

        return contents