예제 #1
0
 def delete(self, key):
     try:
         del self.struct['data'][key]
     except KeyError:
         raise HokusaiError("Cannot unset '%s' as it does not exist" % key)
예제 #2
0
파일: setup.py 프로젝트: rm3l/hokusai
def setup(project_name, template_remote, template_dir, template_vars,
          allow_missing_vars):
    mkpath(os.path.join(CWD, HOKUSAI_CONFIG_DIR))
    config.create(clean_string(project_name))

    ecr = ECR()
    if ecr.project_repo_exists():
        print_green("Project repo %s already exists.  Skipping create." %
                    ecr.project_repo)
    else:
        ecr.create_project_repo()
        print_green("Created project repo %s" % ecr.project_repo)

    scratch_dir = None
    if template_remote:
        scratch_dir = tempfile.mkdtemp()
        git_repo_and_branch = template_remote.split('#', 1)
        git_repo = git_repo_and_branch[0]
        if len(git_repo_and_branch) == 2:
            git_branch = git_repo_and_branch[1]
        else:
            git_branch = "master"
        shout("git clone -b %s --single-branch %s %s" %
              (git_branch, git_repo, scratch_dir))

    custom_template_dir = None
    if allow_missing_vars:
        loader_kwargs = {}
    else:
        loader_kwargs = {"undefined": StrictUndefined}

    if scratch_dir and template_dir:
        custom_template_dir = os.path.join(scratch_dir,
                                           os.path.basename(template_dir))
        env = Environment(loader=FileSystemLoader(
            os.path.join(scratch_dir, os.path.basename(template_dir))),
                          **loader_kwargs)
    elif scratch_dir:
        custom_template_dir = scratch_dir
        env = Environment(loader=FileSystemLoader(scratch_dir),
                          **loader_kwargs)
    elif template_dir:
        custom_template_dir = os.path.abspath(template_dir)
        env = Environment(loader=FileSystemLoader(
            os.path.abspath(template_dir)),
                          **loader_kwargs)
    else:
        try:
            base_path = sys._MEIPASS
            env = Environment(loader=FileSystemLoader(
                os.path.join(base_path, 'hokusai', 'templates')))
        except:
            env = Environment(loader=PackageLoader('hokusai', 'templates'))

    required_templates = [
        'Dockerfile.j2', '.dockerignore.j2', 'hokusai/build.yml.j2',
        'hokusai/development.yml.j2', 'hokusai/test.yml.j2',
        'hokusai/staging.yml.j2', 'hokusai/production.yml.j2'
    ]

    template_context = {
        "project_name": config.project_name,
        "project_repo": ecr.project_repo
    }

    for s in template_vars:
        if '=' not in s:
            raise HokusaiError(
                "Error: template variables must be of the form 'key=value'")
        split = s.split('=', 1)
        template_context[split[0]] = split[1]

    try:
        for template in required_templates:
            if custom_template_dir and not os.path.isfile(
                    os.path.join(custom_template_dir, template)):
                raise HokusaiError("Could not find required template file %s" %
                                   template)
            with open(os.path.join(CWD, template.rstrip('.j2')), 'w') as f:
                f.write(env.get_template(template).render(**template_context))
            print_green("Created %s" % template.rstrip('.j2'))

        if custom_template_dir:
            for root, _, files in os.walk(custom_template_dir):
                subpath = os.path.relpath(root, custom_template_dir)
                if subpath is not '.':
                    mkpath(os.path.join(CWD, subpath))
                for file in files:
                    if subpath is not '.':
                        file_path = os.path.join(subpath, file)
                    else:
                        file_path = file
                    if file_path in required_templates:
                        continue
                    if file_path.endswith('.j2'):
                        with open(os.path.join(CWD, file_path.rstrip('.j2')),
                                  'w') as f:
                            f.write(
                                env.get_template(file_path).render(
                                    **template_context))
                    else:
                        copyfile(os.path.join(custom_template_dir, file_path),
                                 os.path.join(CWD, file_path))
                    print_green("Created %s" % file_path.rstrip('.j2'))
    finally:
        if scratch_dir:
            rmtree(scratch_dir)
예제 #3
0
    def run(self, image_tag, cmd, tty=False, env=(), constraint=()):
        if not self.ecr.project_repo_exists():
            raise HokusaiError("Project repo does not exist.  Aborting.")

        if os.environ.get('USER') is not None:
            uuid = "%s-%s" % (os.environ.get('USER'), k8s_uuid())
        else:
            uuid = k8s_uuid()

        name = "%s-hokusai-run-%s" % (config.project_name, uuid)
        image_name = "%s:%s" % (self.ecr.project_repo, image_tag)
        container = {
            "args":
            cmd.split(' '),
            "name":
            name,
            "image":
            image_name,
            "imagePullPolicy":
            "Always",
            'envFrom': [{
                'configMapRef': {
                    'name': "%s-environment" % config.project_name
                }
            }]
        }

        if tty:
            container.update({"stdin": True, "stdinOnce": True, "tty": True})

        if env:
            container['env'] = []
            for s in env:
                if '=' not in s:
                    raise HokusaiError(
                        "Error: environment variables must be of the form 'KEY=VALUE'"
                    )
                split = s.split('=', 1)
                container['env'].append({'name': split[0], 'value': split[1]})

        spec = {"containers": [container]}
        if constraint:
            spec['nodeSelector'] = {}
            for label in constraint:
                if '=' not in label:
                    raise HokusaiError(
                        "Error: Node selectors must of the form 'key=value'")
                split = label.split('=', 1)
                spec['nodeSelector'][split[0]] = split[1]

        overrides = {"apiVersion": "v1", "spec": spec}

        if tty:
            shout(self.kctl.command(
                "run %s -t -i --image=%s --restart=Never --overrides='%s' --rm"
                % (name, image_name, json.dumps(overrides))),
                  print_output=True)
        else:
            return returncode(
                self.kctl.command(
                    "run %s --attach --image=%s --overrides='%s' --restart=Never --rm"
                    % (name, image_name, json.dumps(overrides))))
예제 #4
0
 def project_name(self):
     project = self.get('project-name')
     if project is None:
         raise HokusaiError(
             "Unconfigured 'project-name'! Plz check ./hokusai/config.yml")
     return project
예제 #5
0
    def update(self, tag, constraint, git_remote, resolve_tag_sha1=True):
        if not self.ecr.project_repo_exists():
            raise HokusaiError("Project repo does not exist.  Aborting.")

        if resolve_tag_sha1:
            tag = self.ecr.find_git_sha1_image_tag(tag)
            if tag is None:
                raise HokusaiError(
                    "Could not find a git SHA1 for tag %s.  Aborting." % tag)

        if self.namespace is None:
            print_green("Deploying %s to %s..." % (tag, self.context))
        else:
            print_green("Deploying %s to %s/%s..." %
                        (tag, self.context, self.namespace))

        if self.namespace is None:
            self.ecr.retag(tag, self.context)
            print_green("Updated tag %s -> %s" % (tag, self.context))

            deployment_tag = "%s--%s" % (
                self.context,
                datetime.datetime.utcnow().strftime("%Y-%m-%d--%H-%M-%S"))
            self.ecr.retag(tag, deployment_tag)
            print_green("Updated tag %s -> %s" % (tag, deployment_tag))

            remote = git_remote or config.git_remote
            if remote is not None:
                print_green("Pushing deployment tags to %s..." % remote)
                shout("git tag -f %s" % self.context, print_output=True)
                shout("git tag %s" % deployment_tag, print_output=True)
                shout("git push --force %s --tags" % remote, print_output=True)

        if config.pre_deploy is not None:
            print_green("Running pre-deploy hook '%s'..." % config.pre_deploy)
            return_code = CommandRunner(self.context,
                                        namespace=self.namespace).run(
                                            tag,
                                            config.pre_deploy,
                                            constraint=constraint)
            if return_code:
                raise HokusaiError(
                    "Pre-deploy hook failed with return code %s" % return_code,
                    return_code=return_code)

        deployment_timestamp = datetime.datetime.utcnow().strftime("%s%f")
        for deployment in self.cache:
            containers = deployment['spec']['template']['spec']['containers']
            container_names = [container['name'] for container in containers]
            deployment_targets = [{
                "name":
                name,
                "image":
                "%s:%s" % (self.ecr.project_repo, tag)
            } for name in container_names]
            patch = {
                "spec": {
                    "template": {
                        "metadata": {
                            "labels": {
                                "deploymentTimestamp": deployment_timestamp
                            }
                        },
                        "spec": {
                            "containers": deployment_targets
                        }
                    }
                }
            }
            print_green("Patching deployment %s..." %
                        deployment['metadata']['name'])
            shout(
                self.kctl.command(
                    "patch deployment %s -p '%s'" %
                    (deployment['metadata']['name'], json.dumps(patch))))

        print_green("Waiting for rollout to complete...")

        rollout_commands = [
            self.kctl.command("rollout status deployment/%s" %
                              deployment['metadata']['name'])
            for deployment in self.cache
        ]
        return_code = shout_concurrent(rollout_commands)
        if return_code:
            raise HokusaiError("Deployment failed!", return_code=return_code)

        if config.post_deploy is not None:
            print_green("Running post-deploy hook '%s'..." %
                        config.post_deploy)
            return_code = CommandRunner(self.context,
                                        namespace=self.namespace).run(
                                            tag,
                                            config.post_deploy,
                                            constraint=constraint)
            if return_code:
                raise HokusaiError(
                    "Post-deploy hook failed with return code %s" %
                    return_code,
                    return_code=return_code)