def do_apply(self, action, resource_types, dry_run=False):
        """Apply action to resource_types

        Example: service.apply("create", "disk")
        Example: service.apply("create", ["disk", "pv", "pvc"])
        Example: service.apply("delete", "all")
        Example: service.apply("status", "all")

        ACTION: string value of (create|delete|status)
        RESOURCE_TYPES: string value of one resource type, or list of
          string values of many resource types
          (configmap|disk|pv|pvc|svc|bootstrap|pod).
          In addition 'all' is a valid resource type.
        """

        # Check action input arg for code errors
        assert type(action) is str
        assert action in Service.VALID_ACTIONS

        # Handle resource_types as string or list, and the special case 'all'
        if type(resource_types) is str:
            if resource_types == 'all':
                resource_types = Service.VALID_RESOURCE_TYPES
            else:
                resource_types = [resource_types]

        # Check resource_type input arg for code errors
        assert type(resource_types) is list
        for t in resource_types:
            assert t in Service.VALID_RESOURCE_TYPES

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

        # Execute the action for each resource_type
        for rt in resource_types:
            # Handle status action
            if action == "status":
                if rt == "disk":
                    raise Exception('resource type for disk not supported yet')
                krs = KubeResourceTypeStatus(self, rt)
                print(YamlUtils.yaml_dict_to_string(krs.asDict()))
                continue

            # Handle create and delete action
            if rt == "configmap":
                # Take care of configmap as a special case
                for pod in self.getPods().values():
                    for container in pod.getContainers().values():
                        if action == 'create':
                            container.createConfigMaps()
                        elif action == 'delete':
                            container.deleteConfigMaps()
                        else:
                            raise Exception('Code Error')
            else:
                # Handle all other resource_types as the same
                self._ensureResource(action, rt)
Exemple #2
0
    def __init__(self, kube_resource_definition_yaml):
        # Check input args
        assert len(kube_resource_definition_yaml) > 0

        # Initialize internal vars
        self.y = YamlUtils.yaml_dict_from_string(kube_resource_definition_yaml)
        self.definition = kube_resource_definition_yaml

        self.errors = []
        self.oks = []

        self.doDescribeAndCheck()
 def test_write_and_read_file(self):
     filename = os.path.join(
         UtilsTestCase.get_test_dir(),
         self.__class__.__name__ + "_test_write_and_read_file.txt")
     dict1 = YamlUtils.yaml_dict_from_string(test_yaml)
     YamlUtils.yaml_dict_to_file(dict1, filename)
     dict2 = YamlUtils.yaml_dict_from_file(filename)
     str1 = YamlUtils.yaml_dict_to_string(dict1)
     str2 = YamlUtils.yaml_dict_to_string(dict2)
     self.assertEqual(str1, str2)
    def __init__(self, filename):
        if not os.path.isfile(filename):
            print("configuration file={} not found".format(filename))
            sys.exit(1)

        self.filename = filename
        self.y = YamlUtils.yaml_dict_from_file(filename)
        self.services = collections.OrderedDict()
        self.rtn2sn = {}
        for service in self.y['kolla-kubernetes']['services']:
            self.services[service['name']] = Service(service)
            # This code creates a record:
            # rtn2sn[resource_type][resource_name] = service_name
            # for all resources
            for (resource_type, value) in service['resources'].items():
                resource_table = self.rtn2sn.get(resource_type)
                if resource_table is None:
                    self.rtn2sn[resource_type] = resource_table = {}
                for resource in value:
                    resource_table[resource['name']] = service['name']
    def test_merge_configs_and_self_render(self):
        file1 = os.path.join(
            UtilsTestCase.get_test_dir(), self.__class__.__name__ +
            "_file1_merge_configs_and_self_render.txt")
        file2 = os.path.join(
            UtilsTestCase.get_test_dir(), self.__class__.__name__ +
            "_file2_merge_configs_and_self_render.txt")
        FileUtils.write_string_to_file(test_conf1, file1)
        FileUtils.write_string_to_file(test_conf2, file2)

        d = JinjaUtils.merge_configs_to_dict([file1, file2])
        d2 = YamlUtils.yaml_dict_from_string(test_conf12_merged)
        self.assertEqual(YamlUtils.yaml_dict_to_string(d),
                         YamlUtils.yaml_dict_to_string(d2))

        d3 = JinjaUtils.dict_self_render(d2)
        d4 = YamlUtils.yaml_dict_from_string(test_conf12_merged_rendered)
        self.assertEqual(YamlUtils.yaml_dict_to_string(d3),
                         YamlUtils.yaml_dict_to_string(d4))
    def GetJinjaDict(service_name=None, cli_args={}, debug_regex=None):
        # check the cache first
        cache_key = ((service_name if service_name is not None else "None") +
                     str(cli_args) +
                     (debug_regex if debug_regex is not None else "None"))
        if cache_key in KollaKubernetesResources._jinja_dict_cache:
            return KollaKubernetesResources._jinja_dict_cache[cache_key]

        # Apply basic variables that aren't defined in any config file
        jvars = {'node_config_directory': '', 'timestamp': str(time.time())}

        # Add the cli args to the template vars, to be fed into templates
        jvars["kolla_kubernetes"] = {
            "cli": {
                "args": YamlUtils.yaml_dict_normalize(cli_args)
            }
        }

        # Create the prioritized list of config files that need to be
        # merged.  Search method for config files: locks onto the first
        # path where the file exists.  Search method for template files:
        # locks onto the first path that exists, and then expects the file
        # to be there.
        kolla_dir = PathFinder.find_kolla_dir()
        files = [
            PathFinder.find_config_file('kolla-kubernetes.yml'),
            PathFinder.find_config_file('globals.yml'),
            PathFinder.find_config_file('passwords.yml'),
            os.path.join(kolla_dir, 'ansible/group_vars/all.yml')
        ]
        if service_name is not None:
            service_ansible_file = os.path.join(kolla_dir, 'ansible/roles',
                                                service_name,
                                                'defaults/main.yml')
            if os.path.exists(service_ansible_file):
                files.append(service_ansible_file)
        files.append(
            os.path.join(kolla_dir, 'ansible/roles/common/defaults/main.yml'))
        # FIXME probably should move this stuff into
        # ansible/roles/common/defaults/main.yml instead.
        files.append(
            os.path.join(kolla_dir, 'ansible/roles/haproxy/defaults/main.yml'))

        # FIXME I think we need a way to add aditional roles to services
        # in the service_resources.yaml.
        files.append(
            os.path.join(kolla_dir, 'ansible/roles/neutron/defaults/main.yml'))

        # Create the config dict
        x = JinjaUtils.merge_configs_to_dict(reversed(files), jvars,
                                             debug_regex)

        # Render values containing nested jinja variables
        r = JinjaUtils.dict_self_render(x)

        # Add a self referential link so templates can look up things by name.
        r['global'] = r

        # Fix up hostlabels so that they are always strings. Kubernetes
        # expects this.
        for (key, value) in r.items():
            if key.startswith('kolla_kubernetes_hostlabel_'):
                value['value'] = "'%s'" % value['value'].replace("'", "''")

        if os.environ.get('KOLLA_KUBERNETES_TOX', None):
            r['kolla_kubernetes_namespace'] = 'not_real_namespace'

        # Update the cache
        KollaKubernetesResources._jinja_dict_cache[cache_key] = r
        return r
    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="")
 def test_write_and_read_string(self):
     dict1 = YamlUtils.yaml_dict_from_string(test_yaml)
     str1 = YamlUtils.yaml_dict_to_string(dict1)
     dict2 = YamlUtils.yaml_dict_from_string(str1)
     str2 = YamlUtils.yaml_dict_to_string(dict2)
     self.assertEqual(str1, str2)