def k8s_update(context, namespace=None, filename=None, check_branch="master", check_remote=None, skip_checks=False, dry_run=False): if filename is None: yaml_template = TemplateSelector().get(os.path.join(CWD, HOKUSAI_CONFIG_DIR, context)) else: yaml_template = TemplateSelector().get(filename) if not skip_checks: current_branch = None for branchname in shout('git branch').splitlines(): if '* ' in branchname: current_branch = branchname.replace('* ', '') break if 'detached' in current_branch: raise HokusaiError("Not on any branch! Aborting.") if current_branch != check_branch: raise HokusaiError("Not on %s branch! Aborting." % check_branch) remotes = [check_remote] if check_remote else shout('git remote').splitlines() for remote in remotes: shout("git fetch %s" % remote) if returncode("git diff --quiet %s/%s" % (remote, current_branch)): raise HokusaiError("Local branch %s is divergent from %s/%s. Aborting." % (current_branch, remote, current_branch)) kctl = Kubectl(context, namespace=namespace) yaml_spec = YamlSpec(yaml_template).to_file() if dry_run: shout(kctl.command("apply -f %s --dry-run" % yaml_spec), print_output=True) print_green("Updated Kubernetes environment %s (dry run)" % yaml_template) else: shout(kctl.command("apply -f %s" % yaml_spec), print_output=True) print_green("Updated Kubernetes environment %s" % yaml_template)
def run(self, image_tag, cmd, tty=False, env=(), constraint=()): 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" % (config.aws_ecr_registry, 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))))
def run(self, tag_or_digest, cmd, tty=None, env=(), constraint=()): if os.environ.get('USER') is not None: # The regex used for the validation of name is '[a-z0-9]([-a-z0-9]*[a-z0-9])?' user = re.sub("[^0-9a-z]+", "-", os.environ.get('USER').lower()) uuid = "%s-%s" % (user, k8s_uuid()) else: uuid = k8s_uuid() name = "%s-hokusai-run-%s" % (config.project_name, uuid) separator = "@" if ":" in tag_or_digest else ":" image_name = "%s%s%s" % (self.ecr.project_repo, separator, tag_or_digest) container = { "args": cmd.split(' '), "name": name, "image": image_name, "imagePullPolicy": "Always", 'envFrom': [{ 'configMapRef': { 'name': "%s-environment" % config.project_name } }] } run_tty = tty if tty is not None else config.run_tty if run_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]} constraints = constraint or config.run_constraints if constraints: spec['nodeSelector'] = {} for label in constraints: 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 run_tty: shout(self.kctl.command( "run %s -t -i --image=%s --restart=Never --overrides=%s --rm" % (name, image_name, pipes.quote(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, pipes.quote(json.dumps(overrides)))))
def test_returncode(self, mocked_call): with captured_output() as (out, err): self.assertEqual(returncode('whoami'), 0) mocked_call.assert_called_once_with('whoami', shell=True, stderr=-2)