def __contains__(self, item): """ Check if given resource type exists. """ res = map_res(item) if res is not None: return self.has_type(res['type'])
def get_resources(r_type, r_name='_all', ns=None, print_warnings=True): rt_info = map_res(r_type) get_func = rt_info['get_func'] yaml_loc = rt_info['yaml_loc'] need_ns = rt_info['need_ns'] return get_func(ns, r_name, yaml_loc, need_ns, print_warnings)
def get_resources(r_type, r_name="_all", ns=None, print_warnings=True): rt_info = map_res(r_type) get_func = rt_info["get_func"] yaml_loc = rt_info["yaml_loc"] need_ns = rt_info["need_ns"] return get_func(ns, r_name, yaml_loc, need_ns, print_warnings)
def _suggest_type(incomplete_type): """ Smart matching for type/alias based on incomplete string Suggest one type if matched types and aliases belongs to the the same type e.g,: if incomplete = 'po' return ['po'] instead of ['po', 'pod', 'pods'] if incomplete = 'ser' return ['service'] instead of ['service','services'] but if incomplete = 'buil' return ['build','buildconfigs','builds','buildconfig'] """ fullset = set( [t["type"] for t in map] + [a for aliases in [t["aliases"] for t in map] for a in aliases] ) match = [f for f in fullset if f.startswith(incomplete_type)] if len(match) > 1 and len(match) <= 3: unique_types = set([map_res(m)["type"] for m in match]) if len(unique_types) == 1: return list(unique_types) else: return match else: return match
def generate_completions(config, objects, incomplete): """ Given a config, tuple of args, and incomplete input from user, generate a list of completions. This function should not print stack traces or do any error logging (without turning it on explicitly) since shell completion should be transparent to user. """ try: get_method, resource_list = parse.parse_get_resources(objects) except Exception as e: # Swallow any error since we don't want to spam terminal during autcompletion. print(e) return [] # We're completing something like `oc get pod/name`. if "/" in incomplete: restypein = incomplete.split("/")[0] resname = incomplete.split("/")[1] restype = map_res(restypein) resources = restype['get_func']('items', config.project, '_all', restype['yaml_loc'], restype['need_ns']) return [ restypein + "/" + r['res']['metadata']['name'] for r in resources if r['res']['metadata']['name'].startswith(resname) ] if len(resource_list) == 0 and "," in incomplete: # This is a NOP like oc return [] elif get_method == parse.Method.SINGLE_TYPE or \ get_method == parse.Method.ALL: # Autocomplete resource names based on the type: oc get pod mypod1 mypod2 restypein, _ = next(resource_list) restype = map_res(restypein) resources = restype['get_func']('items', config.project, '_all', restype['yaml_loc'], restype['need_ns']) return [ r['res']['metadata']['name'] for r in resources if r['res']['metadata']['name'].startswith(incomplete) ] else: # Return completions for resource types # TODO: Include aliases fullset = set(parse.ALL_TYPES + [t['type'] for t in map]) return [t for t in fullset if t.startswith(incomplete)]
def _parse_slash(arg): """ Parses out a single word containing a slash, validates the type is known and returns: type name, resource name """ try: o_split = arg.split('/') r_type = o_split[0] r_name = o_split[1] checked_type = map_res(r_type) if r_type is None: raise ResourceParseError("[ERROR] Invalid object type: " + r_type) return checked_type['type'], r_name except Exception: raise ResourceParseError("[ERROR] Invalid object type: " + arg)
def parse_get_resources(objects: tuple) -> (Method, ResourceMap): """ Takes a tuple (examples below) of arguments passed to `omg get ...` and parses it into manageable class. Returns a tuple containing the Method enum and resource mapping. Raises ResourceParseError if it runs into any issues. Example object contents: ('pod', 'httpd') ('pods', 'httpd1', 'httpd2') ('dc/httpd', 'pod/httpd1') ('routes') ('pod,svc') """ method = Method.UNKNOWN resources = ResourceMap() if len(objects) == 0: # We've nothing to parse right now. return method, resources last_object = [] # Check first arg to see if we're doing multiple or single resources first = objects[0] if '/' in first: method = Method.MULTI_TYPE_MULTI_RESOURCE elif ',' in first: method = Method.MULTI_TYPE_SINGLE_RESOURCE else: method = Method.SINGLE_TYPE for o in objects: if '/' in o: r_type, r_name = _parse_slash(o) resources.add_resource(r_type, r_name) elif ',' in o: pass else: pass for o in objects: # Case where we have a '/' # e.g omg get pod/httpd if '/' in o: method = Method.MULTI_TYPE_MULTI_RESOURCE if not last_object: pre = o.split('/')[0] r_type = map_res(pre)['type'] r_name = o.split('/')[1] # If its a valid resource type, append it to objects if r_type is not None: resources.add_resource(r_type, r_name) else: raise ResourceParseError("[ERROR] Invalid object type: " + pre) # Convert 'all' to list of resource types in a specific order elif o == 'all': for rt in ALL_TYPES: # TODO Simplify to just: last_object.append(rt)? check_rt = map_res(rt) if check_rt is None: raise ResourceParseError("[ERROR] Invalid object type: " + rt) else: last_object.append(check_rt['type']) # Case where we have a ',' e.g `get dc,svc,pod httpd` # These all will be resource_types, not names, # resource_name will come it next iteration (if any) elif ',' in o: method = Method.MULTI_TYPE_SINGLE_RESOURCE if not last_object: r_types = o.split(',') # if all is present, we will replace it with all_types if 'all' in r_types: ai = r_types.index('all') r_types.remove('all') r_types[ai:ai] = ALL_TYPES for rt in r_types: check_rt = map_res(rt) if check_rt is None: raise ResourceParseError( "[ERROR] Invalid object type: " + rt) else: last_object.append(check_rt['type']) else: # last_object was set, meaning this should be object name raise ResourceParseError("[ERROR] Invalid resources to get: " + objects) # Simple word (without , or /) # If last_object was not set, means this is a resource_type elif not last_object: method = Method.SINGLE_TYPE check_rt = map_res(o) if check_rt is not None: last_object = [check_rt['type']] else: raise ResourceParseError( "[ERROR] Invalid resource type to get: " + o) # Simple word (without , or /) # If the last_object was set, means we got resource_type last time, # and this should be a resource_name. elif last_object: method = Method.SINGLE_TYPE for rt in last_object: resources.add_resource(rt, o) else: # Should never happen raise ResourceParseError("[ERROR] Invalid resources to get: " + o) if last_object: for rt in last_object: check_rt = map_res(rt) if check_rt is None: continue r_type = check_rt['type'] if not resources.has_type(r_type) or len( resources.get_resources(r_type)) == 0: method = Method.ALL resources.add_resource(r_type, ALL_RESOURCES) return method, resources
def get_main(a): # a = args passed from cli # Check if -A/--all-namespaces is set # else, Set the namespace # -n/--namespace takes precedence over current project if a.all_namespaces is True: ns = '_all' else: if a.namespace is not None: ns = a.namespace elif Config().project is not None: ns = Config().project else: ns = None # We collect the resources types/names in this dict # e.g for `get pod httpd1 httpd2` this will look like: # objects = { 'pod': ['httpd1', 'httpd2'] } # e.g, for `get pod,svc` this will look like: # objects = { 'pod': ['_all'], 'service': ['_all'] } objects = {} last_object = [] for o in a.objects: # Case where we have a '/' # e.g omg get pod/httpd if '/' in o: if not last_object: pre = o.split('/')[0] r_type = map_res(pre)['type'] r_name = o.split('/')[1] # If its a valid resource type, apppend it to objects if r_type is not None: if r_type in objects: objects[r_type].append(r_name) else: objects[r_type] = [r_name] else: print("[ERROR] Invalid object type: ", pre) sys.exit(1) else: # last_object was set, meaning this should be object name print( "[ERROR] There is no need to specify a resource type as a separate argument when passing arguments in resource/name form" ) sys.exit(1) # Case where we have a ',' e.g `get dc,svc,pod httpd` # These all will be resource_types, not names, # resource_name will come it next iteration (if any) elif ',' in o: if not last_object: r_types = o.split(',') for rt in r_types: check_rt = map_res(rt) if check_rt is None: print("[ERROR] Invalid object type: ", rt) sys.exit(1) else: last_object.append(check_rt['type']) else: # last_object was set, meaning this should be object name print("[ERROR] Invalid resources to get: ", a.objects) sys.exit(1) # Simple word (without , or /) # If last_object was not set, means this is a resource_type elif not last_object: check_rt = map_res(o) if check_rt is not None: last_object = [check_rt['type']] else: print("[ERROR] Invalid resource type to get: ", o) # Simple word (without , or /) # If the last_object was set, means we got resource_type last time, # and this should be a resource_name. elif last_object: for rt in last_object: if rt in objects: objects[rt].append(o) else: objects[rt] = [o] last_object = [] else: # Should never happen print("[ERROR] Invalid resources to get: ", o) sys.exit(1) # If after going through all the args, we have last_object set # means we didn't get a resource_name for these resource_type. # i.e, we need to get all names if last_object: for rt in last_object: check_rt = map_res(rt) objects[check_rt['type']] = ['_all'] # Debug # print(objects) # Object based routing # i.e, call the get function for all the requested types # then call the output function or simply print if its yaml/json for rt in objects.keys(): rt_info = map_res(rt) get_func = rt_info['get_func'] getout_func = rt_info['getout_func'] yaml_loc = rt_info['yaml_loc'] need_ns = rt_info['need_ns'] # Call the get function to get the resoruces res = get_func(rt, ns, objects[rt], yaml_loc, need_ns) # Error out if no objects/resources were collected if len(res) == 0: print('No resources found for type "%s" found in namespace "%s" ' % (rt, ns)) # Yaml dump if -o yaml elif a.output == 'yaml': if len(res) == 1: print(yaml.dump(res[0]['res'])) elif len(res) > 1: print( yaml.dump({ 'apiVersion': 'v1', 'items': [cp['res'] for cp in res] })) # Json dump if -o json elif a.output == 'json': if len(res) == 1: print(json.dumps(res[0]['res'], indent=4)) elif len(res) > 1: print( json.dumps( { 'apiVersion': 'v1', 'items': [cp['res'] for cp in res] }, indent=4)) # Call the respective output fucntion if -o is not set or -o wide elif a.output in [None, 'wide']: # If we displaying more than one resource_type, # we need to display resource_type with the name (type/name) if len(objects) > 1: show_type = True else: show_type = False getout_func(rt, ns, res, a.output, show_type)
def get_main(objects, output, namespace, all_namespaces, show_labels): # Check if -A/--all-namespaces is set # else, Set the namespace # -n/--namespace takes precedence over current project if all_namespaces is True: ns = "_all" else: if namespace is not None: ns = namespace elif Config().project is not None: ns = Config().project else: ns = None # Parse get args and get normalized resources to get try: _, resource_list = parse.parse_get_resources(objects) except parse.ResourceParseError as e: print(e) return # Call the get function for all the requested types # then call the output function or simply print if its yaml/json # Flag to mark if we have already printed something printed_something = False for r_type, r_name in resource_list: res = get_resources(r_type, r_name, ns) if len(res) > 0: # If printing multiple objects, add a blank line between each if printed_something: print("") # Yaml dump if -o yaml if output == "yaml": if len(res) == 1: print(yaml.dump(res[0]["res"])) elif len(res) > 1: print( yaml.dump({ "apiVersion": "v1", "items": [cp["res"] for cp in res] })) # Json dump if -o json elif output == "json": if len(res) == 1: print(json.dumps(res[0]["res"], indent=4)) elif len(res) > 1: print( json.dumps( { "apiVersion": "v1", "items": [cp["res"] for cp in res] }, indent=4, )) # Call the respective output function if -o is not set or -o wide elif output in [None, "wide"]: # If we displaying more than one resource_type, # we need to display resource_type with the name (type/name) if len(resource_list) > 1: show_type = True else: show_type = False getout_func = map_res(r_type)["getout_func"] getout_func(r_type, ns, res, output, show_type, show_labels) # We printed something printed_something = True # Error out if nothing was printed if not printed_something: print("No resources found in %s namespace" % ns)
def get_mc(m): mc_map = map_res('machineconfig') mcs = from_yaml( rt = mc_map['type'], ns = None, names = m, yaml_loc = mc_map['yaml_loc'], need_ns = False) return([mc['res'] for mc in mcs])
def get_main(objects, output, namespace, all_namespaces): # a = args passed from cli # Check if -A/--all-namespaces is set # else, Set the namespace # -n/--namespace takes precedence over current project if all_namespaces is True: ns = '_all' else: if namespace is not None: ns = namespace elif Config().project is not None: ns = Config().project else: ns = None try: get_method, resource_list = parse.parse_get_resources(objects) except parse.ResourceParseError as e: print(e) return # Object based routing # i.e, call the get function for all the requested types # then call the output function or simply print if its yaml/json # If printing multiple objects, add a blank line between each mult_objs_blank_line = False for r_type, res_set in resource_list: rt_info = map_res(r_type) get_func = rt_info['get_func'] getout_func = rt_info['getout_func'] yaml_loc = rt_info['yaml_loc'] need_ns = rt_info['need_ns'] # Call the get function to get the resoruces res = get_func(r_type, ns, res_set, yaml_loc, need_ns) # Error out if no objects/resources were collected if len(res) == 0 and get_method is not parse.Method.ALL: print('No resources found for type "%s" in %s namespace' % (r_type, ns)) elif len(res) > 0: # If printing multiple objects, add a blank line between each if mult_objs_blank_line: print('') # Yaml dump if -o yaml if output == 'yaml': if len(res) == 1: print(yaml.dump(res[0]['res'])) elif len(res) > 1: print( yaml.dump({ 'apiVersion': 'v1', 'items': [cp['res'] for cp in res] })) # Json dump if -o json elif output == 'json': if len(res) == 1: print(json.dumps(res[0]['res'], indent=4)) elif len(res) > 1: print( json.dumps( { 'apiVersion': 'v1', 'items': [cp['res'] for cp in res] }, indent=4)) # Call the respective output function if -o is not set or -o wide elif output in [None, 'wide']: # If we displaying more than one resource_type, # we need to display resource_type with the name (type/name) if len(resource_list) > 1: show_type = True else: show_type = False getout_func(r_type, ns, res, output, show_type) # Flag to print multiple objects if not mult_objs_blank_line: mult_objs_blank_line = True # Error out once if multiple objects/resources requested and none collected if not mult_objs_blank_line and get_method == parse.Method.ALL: print('No resources found in %s namespace' % ns)
def _validate_type(t): checked_type = map_res(t) if checked_type is None: raise ResourceParseError("[ERROR] Invalid object type: " + t) else: return checked_type['type']