Exemple #1
0
    def _push(self):
        last_push_duration = files.fetch_action_arg('push',
                                                    'last_push_duration')
        self.container_name = files.fetch_action_arg('build', 'last_container')

        self.started_push_time = time.time()
        # TODO: unify these commands by factoring out docker command
        # based on config
        if 'gceProject' in self.config:
            self._push_gke()
        else:
            self._push_docker()

        progress_bar.duration_progress(
            'Pushing ', last_push_duration,
            lambda: self.push_process.poll() is not None)
        if self.push_process.poll() != 0:
            push_error = self.push_process.communicate()
            print(colored(push_error[0], 'red'))
            print(colored(push_error[1], 'red'))
            sys.exit(1)

        with open('.push.json', 'w') as f:
            f.write(
                json.dumps({
                    "last_remote_container":
                    self.remote_container_name,
                    "last_push_duration":
                    time.time() - self.started_push_time
                }))

        print("Pushed to {}".format(self.remote_container_name))
Exemple #2
0
    def _build(self):
        last_build_duration = files.fetch_action_arg('build',
                                                     'last_build_duration')

        started_build_time = time.time()

        container_name = "{}:{}".format(self.config['name'], uuid.uuid4())
        print("Starting build {}".format(container_name))

        # Add bar
        build_process = process_helpers.run_popen(
            "CONTAINER_NAME={} make build".format(container_name), shell=True)

        progress_bar.duration_progress(
            'Building', last_build_duration,
            lambda: build_process.poll() is not None)
        if build_process.poll() != 0:
            print(
                colored(build_process.communicate()[0].decode("utf-8"), 'red'))
            sys.exit(1)

        built_time = time.time()

        # Write last container to file
        with open('.build.json', 'w') as f:
            f.write(
                json.dumps({
                    "last_container":
                    container_name,
                    "last_build_duration":
                    built_time - started_build_time
                }))

        print("Built {}".format(container_name))
Exemple #3
0
    def _deploy_new_container(self):
        """Substitutes image, app, run data into k8s-template selected.
           Can also launch user into interactive shell with --interactive flag
        """
        app_name = self.config['name']
        self.namespace = self.config['namespace']
        remote_container_name = files.fetch_action_arg(
            'push', 'last_remote_container')
        if remote_container_name is None:
            raise ValueError("No image found to deploy with. Run a plain "
                             "`mlt deploy` to fix this. Most common reason "
                             "for this is a --no-push was used before "
                             "any image was available to use.")

        print("Deploying {}".format(remote_container_name))
        kubernetes_helpers.ensure_namespace_exists(self.namespace)

        app_run_id = str(uuid.uuid4())

        """
        we'll keep track of the number of containers that would be deployed
        so we know if we should exec into 1 or not (only auto-exec if 1 made)
        if we have replicas (with value > 1) then we automatically won't
        go into most recent pod, because there will be > 1 container made
        if we find > 1 container regardless of replica, same logic applies
        """
        self._replicas_found = False
        self._total_containers = 0

        # deploy our normal template sub logic, then if `deploy` in Makefile
        # add whatever custom stuff is desired
        self._default_deploy(app_name=app_name,
                             app_run_id=app_run_id,
                             remote_container_name=remote_container_name)
        if files.is_custom("deploy:"):
            # execute the custom deploy code
            self._custom_deploy(app_name=app_name,
                                app_run_id=app_run_id,
                                remote_container_name=remote_container_name)

        self._update_app_run_id(app_run_id)
        print("\nInspect created objects by running:\n"
              "$ kubectl get --namespace={} all\n"
              "or \n$ mlt status\n".format(self.namespace))

        if self.args["--interactive"] and not self._replicas_found \
                and self._total_containers == 1:
            self._exec_into_pod(self._get_most_recent_podname())
        elif self.args["--interactive"]:
            print("More than one container created."
                  ".\nCall `kubectl exec -it {{pod_name_here}} "
                  "--namespace={} /bin/bash` on a `Running` pod NAME "
                  "below.\nIf no pods are running yet, run `mlt status` "
                  "occasionally, or `watch -n1 mlt status` to watch until "
                  "pods are `Running`.\n".format(self.namespace))

            for line in self._get_pods_by_start_time():
                print(line)
Exemple #4
0
def test_fetch_action_arg_file_present(json_load_mock, isfile_mock, open_mock):
    isfile_mock.return_value = True
    action_data = {'somekey': 'someval'}
    json_load_mock.return_value.get.return_value = action_data

    result = fetch_action_arg('push', 'last_push_container')
    open_mock.assert_called_once()
    json_load_mock.assert_called_once()
    assert result == action_data
Exemple #5
0
    def _build(self):
        last_build_duration = files.fetch_action_arg(
            'build', 'last_build_duration')

        schema.validate()

        started_build_time = time.time()

        container_name = "{}:{}".format(self.config['name'], uuid.uuid4())
        print("Starting build {}".format(container_name))

        template_parameters = config_helpers.\
            get_template_parameters(self.config)

        params = ""
        for key, val in template_parameters.items():
            params += "{}={} ".format(key.upper(), val)

        build_cmd = "CONTAINER_NAME={} {}make build".format(
            container_name, params)

        if self.args['--verbose']:
            build_process = process_helpers.run_popen(build_cmd,
                                                      shell=True,
                                                      stdout=True,
                                                      stderr=True)
        else:
            build_process = process_helpers.run_popen(build_cmd,
                                                      shell=True)
            with process_helpers.prevent_deadlock(build_process):
                progress_bar.duration_progress(
                    'Building {}'.format(
                        self.config["name"]), last_build_duration,
                    lambda: build_process.poll() is not None)
        if build_process.poll() != 0:
            # When we have an error, get the stdout and error output
            # and display them both with the error output in red.
            output, error_msg = build_process.communicate()
            if output:
                print(output.decode("utf-8"))
            if error_msg:
                error_handling.throw_error(error_msg.decode("utf-8"), 'red')

        built_time = time.time()

        # Write last container to file
        with open('.build.json', 'w') as f:
            f.write(json.dumps({
                "last_container": container_name,
                "last_build_duration": built_time - started_build_time
            }))

        print("Built {}".format(container_name))
Exemple #6
0
    def _deploy_new_container(self):
        """Substitutes image, app, run data into k8s-template selected.
           Can also launch user into interactive shell with --interactive flag
        """
        app_name = self.config['name']
        self.namespace = self.config['namespace']
        remote_container_name = files.fetch_action_arg(
            'push', 'last_remote_container')
        if remote_container_name is None:
            raise ValueError("No image found to deploy with. Run a plain "
                             "`mlt deploy` to fix this. Most common reason "
                             "for this is a --no-push was used before "
                             "any image was available to use.")

        print("Deploying {}".format(remote_container_name))
        kubernetes_helpers.ensure_namespace_exists(self.namespace)

        # do template substitution across everything in `k8s-templates` dir
        # replaces things with $ with the vars from template.substitute
        # also patches deployment if interactive mode is set
        self.interactive_deployment_found = False
        app_run_id = str(uuid.uuid4())
        for path, dirs, filenames in os.walk("k8s-templates"):
            self.file_count = len(filenames)
            for filename in filenames:
                with open(os.path.join(path, filename)) as f:
                    template = Template(f.read())
                out = template.substitute(
                    image=remote_container_name,
                    app=app_name,
                    run=app_run_id,
                    **config_helpers.get_template_parameters(self.config))

                interactive, out = self._check_for_interactive_deployment(
                    out, filename)
                self._apply_template(out, filename)
                if interactive:
                    interactive_podname = self._get_most_recent_podname()

            print("\nInspect created objects by running:\n"
                  "$ kubectl get --namespace={} all\n".format(self.namespace))

        self._update_app_run_id(app_run_id)
        # After everything is deployed we'll make a kubectl exec
        # call into our debug container if interactive mode
        if self.args["--interactive"] and self.interactive_deployment_found:
            self._exec_into_pod(interactive_podname)
        elif not self.interactive_deployment_found and \
                self.args['--interactive']:
            raise ValueError("Unable to find deployment to run interactively. "
                             "Multiple deployment files found and bad "
                             "<kube_spec> argument passed.")
Exemple #7
0
    def _poll_docker_proc(self):
        """used only in the case of non-verbose deploy mode to dump loading
           bar and any error that happened
        """
        last_push_duration = files.fetch_action_arg(
            'push', 'last_push_duration')
        with process_helpers.prevent_deadlock(self.push_process):
            progress_bar.duration_progress(
                'Pushing {}'.format(self.config["name"]), last_push_duration,
                lambda: self.push_process.poll() is not None)

        # If the push fails, get stdout/stderr messages and display them
        # to the user, with the error message in red.
        if self.push_process.poll() != 0:
            push_stdout, push_error = self.push_process.communicate()
            print(push_stdout.decode("utf-8"))
            error_handling.throw_error(push_error.decode("utf-8"), 'red')
Exemple #8
0
    def _push(self):
        self.container_name = files.fetch_action_arg(
            'build', 'last_container')

        self.started_push_time = time.time()
        self._push_docker()

        if not self.args['--verbose']:
            self._poll_docker_proc()

        with open('.push.json', 'w') as f:
            f.write(json.dumps({
                "last_remote_container": self.remote_container_name,
                "last_push_duration": time.time() - self.started_push_time
            }))

        print("Pushed {} to {}".format(
            self.config["name"], self.remote_container_name))
Exemple #9
0
def test_fetch_action_arg_file_nonexistent(open_mock):
    fetch_action_arg('build', 'last_build_container')
    open_mock.assert_not_called()