def testSingleTypeMultiResource(self): args = ("pod", "mypod", "myotherpod") _, rl = parse.parse_get_resources(args) r_type, r_name = next(rl) self.assertEqual(1, len(rl)) self.assertEqual("pod", r_type) self.assertEqual({"mypod", "myotherpod"}, r_name)
def testSingleSlash(self): args = ("pods/mypod", ) _, rl = parse.parse_get_resources(args) r_type, r_name = next(rl) self.assertEqual(1, len(rl)) self.assertEqual("pod", r_type) self.assertEqual({"mypod"}, r_name)
def testAllResource(self): args = ("pods", ) _, rl = parse.parse_get_resources(args) r_type, r_name = next(rl) self.assertEqual(1, len(rl)) self.assertEqual("pod", r_type) self.assertEqual({parse.ALL_RESOURCES}, r_name)
def generate_completions(objects, incomplete, namespace): # We're completing something like `oc get pod/<tab>`. if "/" in incomplete: restypein = incomplete.split("/")[0] resname = incomplete.split("/")[1] names = get_resource_names(restypein, "_all", namespace) return [ restypein + "/" + n for n in names if n.startswith(resname) and restypein + "/" + n not in objects ] if "," in incomplete or [o for o in objects if "," in o]: # This is a NOP like oc return [] get_method, resource_list = parse.parse_get_resources(objects) # First arg after get, autocomplete type # or autocompleting after existing slash-notation arg if not objects or get_method == parse.Method.SLASH: if get_method == parse.Method.SLASH: add_slash = "/" else: add_slash = "" sugg = _suggest_type(incomplete) return [s + add_slash for s in sugg] if get_method == parse.Method.PLAIN and len(resource_list) > 0: # Autocomplete resource names based on the type: oc get pod mypod1 mypod2 restypein, _ = next(resource_list) names = get_resource_names(restypein, "_all", namespace) return [n for n in names if n.startswith(incomplete) and n not in objects] # Catch all return []
def testMultipleResourcesOneName(self): expected_args = ["endpoint", "service"] args = ("svc,endpoints", "dns-default") _, rl = parse.parse_get_resources(args) for r_type, r_name in rl: expected = expected_args.pop() self.assertEqual(expected, r_type) self.assertEqual({"dns-default"}, r_name)
def testMultipleResources(self): expected_args = ["endpoint", "service", "pod"] args = ("pods,svc,endpoints", ) _, rl = parse.parse_get_resources(args) for r_type, r_name in rl: expected = expected_args.pop() self.assertEqual(expected, r_type) self.assertEqual({parse.ALL_RESOURCES}, r_name)
def testAllTypes(self): args = ("all", ) _, rl = parse.parse_get_resources(args) for expected_type in parse.ALL_TYPES: self.assertIn(expected_type, rl) for _, n in rl: self.assertEqual({parse.ALL_RESOURCES}, n)
def testMultiSlash(self): args = ("pods/mypod", "svc/default") _, rl = parse.parse_get_resources(args) self.assertEqual(2, len(rl)) r_type, r_name = next(rl) self.assertEqual("pod", r_type) self.assertEqual({"mypod"}, r_name) r_type, r_name = next(rl) self.assertEqual("service", r_type) self.assertEqual({"default"}, r_name)
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 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 testInvalidMultiTypeMultiResource(self): args = ("pods/mypod", "svc/myservice", "blarg/bad") with self.assertRaises(parse.ResourceParseError): parse.parse_get_resources(args)
def testInvalidMultiTypeComma(self): args = ("pods,svc,asdf", ) with self.assertRaises(parse.ResourceParseError): parse.parse_get_resources(args)
def testInvalidType(self): args = ("podzzzz", ) with self.assertRaises(parse.ResourceParseError): parse.parse_get_resources(args)
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)