Example #1
0
    def test_apply(self, mock_json, mock_subprocess):
        mock_pipe = mock.MagicMock()
        mock_subprocess.PIPE = mock_pipe
        kubectl = Kubectl()
        file_name = 'deployment.yml'
        expected = ['kubectl', 'apply', '-f', file_name]

        kubectl.apply(file_name)

        mock_subprocess.run.assert_called_once_with(
            expected,
            stdout=mock_pipe,
            stderr=mock_pipe)
Example #2
0
def apply(from_file: str):
    # Load the deployments from file and get the current count of replicas in
    # the target cluster for each of the deployments. Then update the replicas
    # to match the target cluster. Save the file and pass on to kubectl apply.
    with open(from_file) as fd:
        content = fd.read()
    kube_list = yaml.load(content)

    kubectl = Kubectl()
    kubectl.update_replicas(kube_list)

    with open(from_file, mode='w') as fd:
        fd.write(yaml.dump(kube_list, default_flow_style=False))

    try:
        lines = kubectl.apply(from_file)
        for line in lines.split('\n'):
            prompt(line)
    except KubectlCallFailed as e:
        error_prompt(str(e))
Example #3
0
class Kube:
    def __init__(self,
                 namespace: str,
                 deployment_name: str,
                 printer: Callable[[str], int],
                 error_printer: Callable[[str], int],
                 deployment_template: str=None,
                 variants: List[str]=None):
        self.printer = printer
        self.error_printer = error_printer
        self.deployment_name = deployment_name
        self.deployment_template = deployment_template or 'deployment.yml'
        self.kubectl = Kubectl()
        self.kubectl.namespace = namespace
        self.variants = variants or []


    def get_remote_deployment(self):
        return self.kubectl.get_deployment(self.deployment_name)


    def apply(self, tag: str):
        # Load the deployment definition
        file_name = self.render_template(tag)
        output = self.kubectl.apply(file_name)
        for line in output.split('\n'):
            if line is not '':
                self.printer(line)


    def info(self):
        try:
            deployment = self.get_remote_deployment()
            self.print_deployment_info(
                'Current {}'.format(self.deployment_name),
                deployment)
        except KubectlCallFailed as e:
            self.error_printer(self.exception(e))


    def exception(self, e):
        return e.args[0].decode('utf8').strip()


    def print_deployment_info(
            self,
            title: str,
            deployment):

        info_template = Template('''
{{ meta.title }}:
{% for c in deployment.spec.template.spec.containers %}
  name: {{ c.name }}
  image: {{ c.image }}
{% endfor %}
  replicas: {{ deployment.status.readyReplicas }}/{{ deployment.status.replicas -}}
        ''')

        rendered = info_template.render(meta={'name': self.deployment_name,
                                              'title': title},
                                        deployment=deployment)

        for line in rendered.split('\n'):
            if line:
                self.printer(line)

        return


    def render_template(self, tag: str):
        jinja = Environment(loader=FileSystemLoader('./'))
        template = jinja.get_template(self.deployment_template)

        replicas = None
        try:
            deployment = self.get_remote_deployment()
            replicas = deployment['spec']['replicas']

            # make sure to use the same number of replicas as remote to honor
            # scaling
            if deployment.get('status'):
                replicas = deployment['status']['replicas']
        except KubectlCallFailed as e:
            self.error_printer(self.exception(e))

        data = {
            'image': tag,
            'name': self.deployment_name,
            'namespace': self.kubectl.namespace,
            'replicas': replicas,
            'variants': self.variants
        }

        rendered = template.render(data=data)
        tmp_file = tempfile.NamedTemporaryFile(delete=False)

        tmp_file.write(rendered.encode('utf8'))

        return tmp_file.name