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)
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)