Exemplo n.º 1
0
    def _ensureResource(self, action, resource_type):
        # Check input args
        assert action in Service.VALID_ACTIONS
        assert resource_type in Service.VALID_RESOURCE_TYPES
        assert resource_type in self.resourceTemplates

        resourceTemplates = self.resourceTemplates[resource_type]

        # If action is delete, then delete the resourceTemplates in
        # reverse order.
        if action == 'delete':
            resourceTemplates = reversed(resourceTemplates)

        for resourceTemplate in resourceTemplates:
            # Build the command based on if shell script or not. If
            # shell script, pipe to sh.  Else, pipe to kubectl
            cmd = "kolla-kubernetes resource-template {} {} {}".format(
                action, resource_type, resourceTemplate.getName())
            if resourceTemplate.getTemplatePath().endswith('.sh.j2'):
                cmd += " | sh"
            else:
                cmd += " | kubectl {} -f -".format(action)

            # Execute the command
            ExecUtils.exec_command(cmd)
Exemplo n.º 2
0
    def _ensureConfigMaps(self, action):
        assert action in Service.VALID_ACTIONS

        nsname = 'kolla_kubernetes_namespace'
        cmd = ("kubectl {} configmap {} --namespace={}".format(
            action, self.getName(),
            KollaKubernetesResources.GetJinjaDict()[nsname]))

        # For the create action, add some more arguments
        if action == 'create':
            for f in PathFinder.find_config_files(self.getName()):
                cmd += ' --from-file={}={}'.format(
                    os.path.basename(f).replace("_", "-"), f)

        # Execute the command
        ExecUtils.exec_command(cmd)
Exemplo n.º 3
0
    def doCheck(self):

        # Build the templating command
        cmd = "kolla-kubernetes resource-template {} {} {}".format(
            'create', self.resource_type, self.resource_template_obj.getName())

        # Execute the command to get the processed template output
        template_out, err = ExecUtils.exec_command(cmd)

        # Skip templates which which produce no-ops (100% whitespace)
        #   (e.g. pv templates for AWS should not use persistent
        #   volumes because AWS uses experimental
        #   auto-provisioning)
        if (err is not None):
            self.errors.append('error processing template file: {}'.format(
                str(err)))
            return
        elif re.match("^\s+$", template_out):
            msg = "template {} produced empty output (NO-OP)".format(
                self.resource_template_obj.getTemplatePath())
            self.oks.append(msg)
            return

        # If the template output produces a stream of yaml documents
        # which are then piped to kubectl, then we will receive a
        # stream of reports separated by "\n\n".  Split on "\n\n" and
        # process each result individually.  The overall result is the
        # merged output.
        definitions = re.split("^---", template_out, re.MULTILINE)
        for definition in definitions:
            kr = KubeResourceYamlStatus(definition)
            self.kube_resources.append(kr)
Exemplo n.º 4
0
    def test_validate_templates(self):
        srcdir = os.environ['HELMDIR']
        helmbin = os.environ['HELMBIN']
        repodir = os.environ['REPODIR']
        microdir = os.path.join(srcdir, "microservice")
        microservices = os.listdir(microdir)
        packages = [p for p in microservices if _isdir(microdir, p)]
        print("Working on:")
        for package in packages:
            print("    %s" % package)
            with open(os.path.join(microdir, package, 'Chart.yaml')) as stream:
                version = yaml.safe_load(stream)['version']

            cmd = "%s template %s/%s-%s.tgz" % (helmbin, repodir, package,
                                                version)
            out, err = ExecUtils.exec_command(cmd)
            if err:
                raise err

            l = yaml.safe_load_all(out)
            for y in l:
                js = '[]'
                try:
                    # If there is a beta init container, validate it is proper
                    # json
                    key = 'pod.beta.kubernetes.io/init-containers'
                    js = y['spec']['template']['metadata']['annotations'][key]
                except KeyError:
                    pass
                except TypeError as e:
                    m = ("'NoneType' object has no attribute '__getitem__'",
                         "'NoneType' object is not subscriptable")
                    if e.args[0] not in m:
                        raise
                json.loads(js)
                pod = None
                try:
                    pod = y['spec']['template']
                except Exception:
                    pass
                if pod:
                    self._validate_image_pull_policy(package, pod)
Exemplo n.º 5
0
    def take_action(self, args, skip_and_return=False):
        # Validate input arguments
        self.validate_args(args)
        multi = len(args.resource_name) != 1
        multidoc = {'apiVersion': 'v1', 'kind': 'List', 'items': []}
        for resource_name in args.resource_name:
            service_name = KKR.getServiceNameByResourceTypeName(
                args.resource_type, resource_name)
            service = KKR.getServiceByName(service_name)
            rt = service.getResourceTemplateByTypeAndName(
                args.resource_type, resource_name)

            tmpargs = copy.deepcopy(vars(args))
            tmpargs['resource_name'] = resource_name
            variables = KKR.GetJinjaDict(service_name, tmpargs,
                                         args.print_jinja_keys_regex)

            # Merge the template vars with the jinja vars before processing
            variables['kolla_kubernetes'].update(
                {"template": {
                    "vars": rt.getVars()
                }})

            # handle the debug option --print-jinja-vars
            if args.print_jinja_vars is True:
                print(YamlUtils.yaml_dict_to_string(variables),
                      file=sys.stderr)

            if args.resource_type == 'configmap' and \
               rt.getTemplate() == 'auto':
                nsname = 'kolla_kubernetes_namespace'
                cmd = "kubectl create configmap {} -o yaml --dry-run"
                cmd = cmd.format(resource_name)

                for f in PathFinder.find_config_files(resource_name):
                    cmd += ' --from-file={}={}'.format(
                        os.path.basename(f).replace("_", "-"), f)

                # Execute the command
                out, err = ExecUtils.exec_command(cmd)
                y = yaml.load(out)
                y['metadata']['namespace'] = variables[nsname]

                res = y
            else:
                # process the template
                raw_doc = JinjaUtils.render_jinja(
                    variables,
                    FileUtils.read_string_from_file(rt.getTemplatePath()))
                res = yaml.load(raw_doc)

            if args.debug_container is not None:
                y = res
                kind = y['kind']
                if kind not in ('PetSet', 'Deployment', 'Job', 'DaemonSet',
                                'ReplicationController', 'Pod'):
                    raise Exception("Template doesn't have containers.")
                pod = y
                if kind != 'Pod':
                    pod = y['spec']['template']
                alpha_init_containers = None
                annotation = 'pod.alpha.kubernetes.io/init-containers'
                if 'metadata' in pod and 'annotations' in pod['metadata'] and \
                   annotation in pod['metadata']['annotations']:
                    j = json.loads(pod['metadata']['annotations'][annotation])
                    alpha_init_containers = {}
                    for c in j:
                        alpha_init_containers[c['name']] = c
                containers = {}
                for c in pod['spec']['containers']:
                    containers[c['name']] = c
                for c in args.debug_container:
                    found = False
                    warn_msg = "WARNING: container [{}] already has a" + \
                               " command override."
                    warn_msg = warn_msg.format(c)
                    if alpha_init_containers and c in alpha_init_containers:
                        if 'command' in alpha_init_containers[c]:
                            print(warn_msg, file=sys.stderr)
                        if 'args' in alpha_init_containers[c]:
                            del alpha_init_containers[c]['args']
                        alpha_init_containers[c]['command'] = \
                            ['/bin/bash', '-c',
                             'while true; do sleep 1000; done']
                        found = True
                    if c in containers:
                        if 'command' in containers[c]:
                            print(warn_msg, file=sys.stderr)
                        if 'args' in containers[c]:
                            del containers[c]['args']
                        containers[c]['command'] = \
                            ['/bin/bash', '-c',
                             'while true; do sleep 1000; done']
                        found = True

                    if not found:
                        raise Exception("Failed to find container: %s" % c)

                if alpha_init_containers:
                    annotation = 'pod.alpha.kubernetes.io/init-containers'
                    v = alpha_init_containers.values()
                    pod['metadata']['annotations'][annotation] = json.dumps(v)
            multidoc['items'].append(res)

        if skip_and_return:
            if multi:
                return yaml.safe_dump(multidoc)
            else:
                return yaml.safe_dump(res)

        if args.output == 'json':
            if multi:
                print(json.dumps(multidoc, indent=4), end="")
            else:
                print(json.dumps(res, indent=4), end="")
        elif multi:
            print(yaml.safe_dump(multidoc))
        else:
            if args.debug_container is not None:
                print(yaml.safe_dump(res), end="")
            else:
                print(raw_doc, end="")
Exemplo n.º 6
0
    def doDescribeAndCheck(self):

        # This yaml segment may be empty (comments-only)
        if self.y is None:
            self.oks.append('Yaml segment is empty of content and perhaps '
                            'only contains comments')
            return  # Allow to succeed

        # Create the command to send this single resource yaml blob to
        # kubectl to query its existence.
        cmd = ('echo \'{}\' | kubectl describe -f -'.format(
            self.definition.replace("'", "'\\''")))  # escape for bash

        out, err = ExecUtils.exec_command(cmd)

        # Check if kubectl returns non-zero exit status
        if err is not None:
            self.errors.append('Either resource does not exist, '
                               'or invalid resource yaml')
            return

        # For all resource types, check the Name to verify existence
        name = KubeResourceYamlStatus._matchSingleLineField('Name', out)
        if name is None or name != self.getName():
            self.errors.append('No resource with name {} exists'.format(
                self.getName()))
        else:
            self.oks.append('Verified resource with name {} exists'.format(
                self.getName()))

        # For PersistentVolumes and PersistentVolumeClaims
        if self.getKind() == 'PersistentVolume' or (
                self.getKind() == 'PersistentVolumeClaim'):

            # Verify that the PV/PVC is bound
            status = KubeResourceYamlStatus._matchSingleLineField(
                'Status', out)
            if status is None or status != "Bound":
                self.errors.append("{} not Bound".format(self.getKind()))
            else:
                self.oks.append("{} Bound".format(self.getKind()))

        # For Services
        if self.getKind() == 'Service':
            # Verify the service has an IP
            ip = KubeResourceYamlStatus._matchSingleLineField('IP', out)
            if ip is None or len(ip) == 0:
                self.errors.append("{} has no IP".format(self.getKind()))
            else:
                self.oks.append("{} has IP".format(self.getKind()))

        # For ReplicationControllers
        # Replicas:       1 current / 1 desired
        # Pods Status:    1 Running / 0 Waiting / 0 Succeeded / 0 Failed
        if self.getKind() == 'ReplicationController':

            # Verify the rc has the right number of replicas
            replicas = KubeResourceYamlStatus._matchSingleLineField(
                'Replicas', out)
            if replicas is None:
                self.errors.append("{} replicas not found".format(
                    self.getKind()))
            else:
                self.oks.append("{} replicas found".format(self.getKind()))
                replicas_detail = KubeResourceYamlStatus._matchReturnGroups(
                    '^(\d+) current / (\d+) desired', replicas)
                if replicas_detail is not None:
                    current, desired = replicas_detail
                    if current != desired:
                        self.errors.append(
                            "current != desired: {}".format(replicas))
                    else:
                        self.oks.append(
                            "current == desired: {}".format(replicas))

            # Verify the rc has the right number of pod_status
            pod_status = KubeResourceYamlStatus._matchSingleLineField(
                'Pods Status', out)
            if pod_status is None:
                self.errors.append("{} pod_status not found".format(
                    self.getKind()))
            else:
                self.oks.append("{} pod_status found".format(self.getKind()))

                pod_status_detail = KubeResourceYamlStatus._matchReturnGroups(
                    '^(\d+) Running / (\d+) Waiting /'
                    ' (\d+) Succeeded / (\d+) Failed', pod_status)
                if pod_status_detail is not None:
                    running, waiting, succeeded, failed = pod_status_detail
                    if (int(running) == 0 or int(waiting) > 0
                            or (int(failed) > 0)):
                        self.errors.append(
                            "pod_status has errors {}".format(pod_status))
                    else:
                        self.oks.append(
                            "pod_status has no errors: {}".format(pod_status))