Ejemplo n.º 1
0
def complete_get(ctx, args, incomplete):
    """
    Pull out objects args from Click context and return completions.
    """
    lg.remove()
    try:
        cfg = config.get()
        project = dget(cfg, ["project"])
        namespace = ctx.params.get("namespace") or project

        objects = ctx.params.get("objects")

        if "/" in incomplete:
            # We're completing something like `oc get pod/<tab>`.
            in_rtype = incomplete.split("/")[0]
            in_rname = incomplete.split("/")[1]
            names = get_all_resource_names({in_rtype: []}, namespace)
            return [
                in_rtype + "/" + n for n in names
                if n.startswith(in_rname) and in_rtype + "/" + n not in objects
            ]

        if "," in incomplete or [o for o in objects if "," in o]:
            # This is a NOP like oc
            return []

        slash_mode = False
        comma_mode = False
        if objects:
            try:
                parsed_objects = parse_get_args(objects)
            except ParseError:
                return []
            else:
                slash_mode = all("/" in o for o in objects)
                comma_mode = all("," in o for o in objects)

        # First arg after get, autocomplete type
        # or autocompleting after existing slash-notation arg
        if not objects or slash_mode:
            if slash_mode:
                add_slash = "/"
            else:
                add_slash = ""
            sugg = _suggest_type(incomplete)
            return [s + add_slash for s in sugg]

        if not slash_mode and not comma_mode and len(parsed_objects) > 0:
            # Autocomplete resource names based on the type: oc get pod mypod1 mypod2
            names = get_all_resource_names(parsed_objects, namespace)
            return [
                n for n in names
                if n.startswith(incomplete) and n not in objects
            ]
        # Catch all
        return []

    except Exception:
        # Swallow any exception
        return []
Ejemplo n.º 2
0
def complete_containers(ctx, args, incomplete):
    """
    Callback for container name (within a pod and ns) autocompletion
    :return: List of matching container names or empty list
    """
    lg.remove()
    cfg = config.get()
    c_paths = dget(cfg, ["paths"])
    c_project = dget(cfg, ["project"])

    if (
        len(ctx.args) != 1
    ):
        # If there's no pod specified yet, can't autocomplete a container name
        return []

    ns = ctx.params.get("namespace") or c_project

    pod = ctx.args[0]

    container_listing = []
    for path in c_paths:
        container_dir = os.path.join(path, "namespaces", ns, "pods", pod)
        if os.path.isdir(container_dir):
            containers = os.listdir(container_dir)
            if containers:
                container_listing.extend(containers)

    suggestions = [
        c for c in container_listing if incomplete in c and not c.endswith(".yaml")
    ]  # skip .yaml files
    return suggestions
Ejemplo n.º 3
0
def cmd(name):
    cfg = config.get()
    c_paths = dget(cfg, ["paths"])
    c_project = dget(cfg, ["project"])

    # print current project
    if name is None:
        if c_project is None:
            print("No project selected")
        else:
            print("Using project {}".format(c_project))
    # set current project
    else:
        if name == c_project:
            print("Already using project {}".format(c_project))
        else:
            select_project = None
            for path in c_paths:
                projs_in_path = locate_project(path, tell="names")
                if name in projs_in_path:
                    select_project = name
                    break
            if select_project:
                print("Now using project {}".format(select_project))
                config.save(project=name)
            else:
                lg.error("Project {} not found in {} must-gather paths".format(
                    name, len(c_paths)))
Ejemplo n.º 4
0
def show_mg_info(cfile=None):
    """
    Shows the info of current selected must-gather(s)
    """
    lg.debug("FUNC_INIT: {}".format(locals()))

    cfg = config.get(cfile=cfile)
    lg.debug("Loaded config file: {}".format(cfg))

    paths = cfg["paths"]
    project = cfg["project"]

    out = lg.opt(colors=True).success

    if "cwd" in cfg and cfg["cwd"]:
        out("<e>-=[CWD Mode]=-</>")
        out("")

    if len(paths) > 1:
        out("<e>-=[MultiDir Mode]=-</>")
        out("")
        out("<e>Selected must-gather paths:</>")
        i = 1
        for path in paths:
            out(" <e>[{}]</> {}".format(i, _hide_hash(path)))
            i = i + 1
            _show_info(path)
        out("")
        out("<e>Current Project:</> {}".format(project))

    elif len(paths) == 1:
        out("<e>Selected must-gather:</> {}".format(_hide_hash(paths[0])))
        _show_info(paths[0])
        out("     <e>Current Project:</> {}".format(project))
Ejemplo n.º 5
0
def test_config_save_get(tmpdir):
    omg_config = tmpdir.join(".omgconfig")
    config.save(paths=["/test/path"], project="testproject", cfile=omg_config)
    cfg = config.get(cfile=omg_config)

    assert cfg["paths"] == ["/test/path"]
    assert cfg["project"] == "testproject"
Ejemplo n.º 6
0
def mc_extract(m):

    cfg = config.get()
    paths = cfg["paths"]

    if m:
        mc_names = list(m)
    else:
        mc_names = []

    all_mcs = get_all_resources({"mc": mc_names})

    # {1: {"mc": [...]}, 2: {"mc": [...] }}
    for i, mc_res in all_mcs.items():

        mg_path = paths[i - 1]
        emc_path = os.path.join(mg_path, "extracted-machine-configs")

        # {"mc": [{"res": {}, "yfile_ts": "..."}, ... ]}
        for _, mc_data in mc_res.items():
            if mc_data:
                try:
                    os.makedirs(emc_path, exist_ok=True)
                except PermissionError as e:
                    lg.warning(e)
                    continue
                for mc in mc_data:
                    mc_rd = mc["res"]
                    _write_mc(emc_path, mc_rd)
Ejemplo n.º 7
0
 def _get_all_projects():
     cfg = config.get()
     c_paths = dget(cfg, ["paths"])
     if c_paths:
         projects = []
         for path in c_paths:
             projects.extend(locate_project(path, tell="names"))
         return projects
     return []
Ejemplo n.º 8
0
def get_all_resources(parsed_objects, ns=None):
    """Get resources from all paths

    Args:
        parsed_objects (dict): Parsed object
        ns (string): Namespace/project

    Returns:
        list:   for each r_type, list of resources from each path
                (list of dict of list)
                For example:
                    [
                        # resources_from_path1
                        {   'pod': [ res1, res2 ... ],
                            'svc': [ res1, ... ],
                            ...
                        },
                        # resources_from_path2
                        ...
                    ]
    """
    lg.debug("FUNC_INIT: {}".format(locals()))

    cfg = config.get()
    paths = cfg["paths"]

    # Resources dicts from selected paths
    # resd_from_paths = []
    resd_from_paths = {}

    i = 0
    for path in paths:
        i += 1
        resd = {}
        for r_type in parsed_objects:
            r_names = parsed_objects[r_type]

            try:
                res = load_res(path, r_type, r_names, ns)
            except NameSpaceRequired as e:
                lg.error(e)
                raise SystemExit(1)
            except UnkownResourceType:
                lg.error("Unknow resource type: {}".format(r_type))
                raise SystemExit(1)
            else:
                resd[r_type] = res
        # resd_from_paths.append(resd)
        resd_from_paths[i] = resd
    return resd_from_paths
Ejemplo n.º 9
0
def o_raw(resd_from_paths, output):
    lg.debug("FUNC_INIT: {}".format(locals()))

    cfg = config.get()
    paths = cfg["paths"]

    for i, path_resd in resd_from_paths.items():
        all_res = []
        for r_type in path_resd:
            res = path_resd[r_type]
            if res:
                all_res.extend(res)

        if all_res:
            if len(all_res) == 1:
                out_res = dget(all_res[0], ["res"])
            elif len(all_res) > 1:
                out_res = {
                        "apiVersion": "v1",
                        "kind": "List",
                        "items": [dget(res, ["res"]) for res in all_res]
                    }
            else:
                continue

            if output == "yaml":
                print(yaml.dump(out_res))
            elif output == "json":
                print(json.dumps(out_res))
            elif output == "name":
                for res in all_res:
                    group = dget(res, ["rdef", "group"])
                    singular = dget(res, ["rdef", "singular"])
                    if group == "core":
                        out_type = singular
                    else:
                        out_type = str(singular) + "." + str(group)
                    name = dget(res, ["res", "metadata", "name"])
                    print(
                        str(out_type) + "/" + str(name)
                    )

            if (len(paths) > 1):
                lg.opt(colors=True).success("^^^<e>[{}]</>^^^\n".format(i))
Ejemplo n.º 10
0
def complete_pods(ctx, args, incomplete):
    """
    Callback for pod name (within a ns) autocompletion
    :return: List of matching pod names or empty list.
    """
    lg.remove()
    cfg = config.get()
    c_paths = dget(cfg, ["paths"])
    c_project = dget(cfg, ["project"])

    ns = ctx.params.get("namespace") or c_project
    suggestions = []
    for path in c_paths:
        pod_dir = os.path.join(path, "namespaces", ns, "pods")
        if os.path.isdir(pod_dir):
            pod_listing = os.listdir(pod_dir)
            if pod_listing:
                suggestions.extend([pod for pod in pod_listing if incomplete in pod])
    return suggestions
Ejemplo n.º 11
0
def cmd(objects, output, show_labels):
    lg.debug("FUNC_INIT: {}".format(locals()))

    # Parse objects
    try:
        parsed_objects = parse_get_args(objects)
    except ParseError as e:
        lg.error(e)
        return 2

    lg.debug("parsed_objects: {}".format(parsed_objects))

    # Set namespace
    ns = dget(config.get(), ["project"])

    lg.debug("Namespace resolved to: {}".format(ns))

    # Collect resources
    all_res_d = get_all_resources(parsed_objects, ns)

    # No resource type found e.g:
    # all_res_d == [{}, {}, ..<paths>.. ]
    if not any(all_res_d):
        lg.error("Unkown resource type")
        return 2

    # Resource type found, but no resources found e.g:
    # [{'pods': []}, {'pods': []}, ..<paths>..]
    if not any([
            bool(all_res_d[i][rtype]) for i in all_res_d
            for rtype in all_res_d[i]
    ]):
        print("No resources found")
        return 2

    # Pass the parsed object to respective output function
    if output in ["yaml", "json", "name"]:
        o_raw(all_res_d, output)
    elif output is None or output == "wide":
        o_table(all_res_d, ns, output, show_labels)
    else:
        lg.error("Unknow output type: {}".format(output))
Ejemplo n.º 12
0
def o_table(resd_from_paths, ns, output, show_labels):
    """Handles table output.
       Both simple (without -o) and wide (-o wide)

    Args:
        parsed_objects (dict):  Contains parsed dictionary of objects to get.
                                This dict is the one we get from parse.py module.

        ns (str): Namespace is needed if we are showing output for all-namespaces.

        output (str):   This is passed from click (-o). We need to know if the output
                        is simple (-o not set) or wide (-o wide).

        show_labels (bool):     This is passed from click (--show-labels)
    """
    lg.debug("FUNC_INIT: {}".format(locals()))

    cfg = config.get()
    paths = cfg["paths"]

    tablefmt = getenv("OMG_TABLE_FMT") or "plain"

    show_type = False
    if max([len(resd_from_paths[i]) for i in resd_from_paths]) > 1:
        show_type = True

    for i, path_resd in resd_from_paths.items():
        table_all_res = None
        for r_type in path_resd:
            res = path_resd[r_type]
            if res:
                res_table = build_table(res, ns, output, show_type,
                                        show_labels)
                if table_all_res:
                    table_all_res += [[""]] + res_table
                else:
                    table_all_res = res_table
        if table_all_res:
            print(tabulate(table_all_res, tablefmt=tablefmt))
            if (len(paths) > 1):
                lg.opt(colors=True).success("^^^<e>[{}]</>^^^\n".format(i))
Ejemplo n.º 13
0
def cmd(etcdctl_args, output):
    cfg = config.get()
    mg_paths = cfg["paths"]

    if output is None:
        output = "table"

    command = "_".join(etcdctl_args)
    etcd_file = os.path.join(
        "etcd_info", "{}.json".format(command))

    lg.debug("etcd_file: {}".format(etcd_file))

    etcd_cmd_paths = {}
    i = 1
    for p in mg_paths:
        ceph_cmd_path = os.path.join(p, etcd_file)
        if os.path.isfile(ceph_cmd_path):
            lg.info("Command output file found: {}".format(ceph_cmd_path))
            etcd_cmd_paths[i] = ceph_cmd_path
        i += 1
    if etcd_cmd_paths:
        for i, cp in etcd_cmd_paths.items():
            try:
                j_data = load_json(cp)
                table_mod = import_module(
                    "omg.components.etcdctl.output.{}".format(command))
                table_mod.etcdctl_out(j_data, output)
            except Exception as e:
                lg.warning("Error generating output for {}: {}".format(command, e))
                lg.success("\nHere is the raw file ({}):".format(cp))
                with open(cp, "r") as cf:
                    print(cf.read())
            if len(mg_paths) > 1:
                lg.opt(colors=True).success("^^^<e>[{}]</>^^^\n".format(i))
    else:
        suggestions = {}
        i = 1
        for p in mg_paths:
            try:
                files = os.listdir(os.path.join(p, "etcd_info"))
                file_match = "_".join(etcdctl_args)
                sugg = []
                sugg.extend([
                    "omg etcdctl " + f.replace("_", " ").replace(".json", "")
                    for f in files if f.startswith(file_match)])
                if sugg:
                    suggestions[i] = sugg
            except Exception:
                pass
            i += 1
        if suggestions:
            lg.success("\nNote: Output of following commands are available:\n")
            for i, sugg in suggestions.items():
                lg.success("\n".join(sugg))
                lg.opt(colors=True).success("^^^<e>[{}]</>^^^\n".format(i))
        else:
            lg.error(
                "Command output not found in any of the"
                " {} must-gather paths".format(len(mg_paths))
            )
Ejemplo n.º 14
0
def cmd(resource, container, previous):
    lg.debug("FUNC_INIT: {}".format(locals()))

    cfg = config.get()
    paths = dget(cfg, ["paths"])
    ns = dget(cfg, ["project"])

    if not paths:
        lg.error("No must-gather selected")
        raise SystemExit(1)

    if ns == "_all":
        lg.error("All Namespaces is not supported with `omg log ...` ")
        raise SystemExit(1)
    elif ns is None:
        lg.error("No namespace/project selected")
        raise SystemExit(1)

    if "/" in resource:
        r_type = resource.split("/")[0]
        pod = resource.split("/")[1]
        if r_type not in ["pod", "pods"]:
            lg.error("Can not print logs of type:", r_type)
            raise SystemExit(1)
    else:
        pod = resource

    if not ns:
        lg.error("Namespace/Project not set")
        raise SystemExit(1)

    log_files = []
    for path in paths:

        proj_path = os.path.join(path, "namespaces", ns)
        if not os.path.isdir(proj_path):
            continue

        pod_dir = os.path.join(proj_path, "pods", pod)
        if not os.path.isdir(pod_dir):
            # lg.warning("Pod directory not found: {}".format(pod_dir))
            continue

        con_dirs = [
            c for c in os.listdir(pod_dir)
            if os.path.isdir(os.path.join(pod_dir, c))
        ]

        if not con_dirs:
            lg.warning(
                "No container directory not found in {}".format(pod_dir))
            continue
        elif len(con_dirs) == 1:
            con_dir = con_dirs[0]
            if container and container != con_dir:
                lg.warning("Container directory {} not found in {}".format(
                    container, pod_dir))
                continue
        elif len(con_dirs) > 1:
            if container is None:
                lg.error("This pod has more than one containers:" +
                         str(con_dirs) + "\n"
                         "Use -c/--container to specify the container")
                raise SystemExit(1)
            elif container not in con_dirs:
                lg.warning("Container directory {} not found in {}".format(
                    container, pod_dir))
                continue
            else:
                con_dir = container

        if previous:
            log_files.append(
                os.path.join(pod_dir, con_dir, con_dir, "logs",
                             "previous.log"))
        else:
            log_files.append(
                os.path.join(pod_dir, con_dir, con_dir, "logs", "current.log"))

    if not log_files:
        lg.error("No log files found")

    for logfile in log_files:
        if not os.path.isfile(logfile):
            lg.warning("Log file not found: {}".format(logfile))
        else:
            lg.info(logfile)
            with open(logfile, "r") as lf:
                print(lf.read())
        if len(log_files) > 1:
            print("")
            print("~~~")
            print("")
Ejemplo n.º 15
0
def cmd(ceph_args, output, com):
    cfg = config.get()
    mg_paths = cfg["paths"]

    if output in ["json", "json-pretty"]:
        commands_dir = "must_gather_commands_json_output"
        json_add = "_--format_json-pretty"
    else:
        commands_dir = "must_gather_commands"
        json_add = ""

    file_name = "{}_{}{}".format(com, "_".join(ceph_args), json_add)
    if file_name.startswith("ceph_config_show_"):
        file_name = file_name.replace("ceph_config_show_", "config_")

    ceph_file = os.path.join("ceph", commands_dir, file_name)

    lg.debug("ceph_file: {}".format(ceph_file))

    ceph_cmd_paths = {}
    i = 1
    for p in mg_paths:
        ceph_cmd_path = os.path.join(p, ceph_file)
        if os.path.isfile(ceph_cmd_path):
            lg.info("Command output file found: {}".format(ceph_cmd_path))
            ceph_cmd_paths[i] = ceph_cmd_path
        i += 1

    if ceph_cmd_paths:
        for i, cp in ceph_cmd_paths.items():
            with open(cp, "r") as lf:
                print(lf.read())
            if len(mg_paths) > 1:
                lg.opt(colors=True).success("^^^<e>[{}]</>^^^\n".format(i))
    else:
        suggestions = {}
        i = 1
        for p in mg_paths:
            try:
                files = os.listdir(
                    os.path.join(p, "ceph", "must_gather_commands"))
                file_match = "{}_{}".format(com, "_".join(ceph_args))
                sugg = []
                sugg.extend([
                    "omg " + f.replace("_", " ") for f in files
                    if f.startswith(file_match)
                ])
                sugg.extend([
                    "omg ceph config show {}".format(f.replace("config_", ""))
                    for f in files if f.startswith("config_")
                ])
                if sugg:
                    suggestions[i] = sugg
            except Exception as e:
                lg.debug(e)
                pass
            i += 1
        if suggestions:
            lg.success("\nNote: Output of following commands are available:\n")
            for i, sugg in suggestions.items():
                lg.success("\n".join(sugg))
                lg.opt(colors=True).success("^^^<e>[{}]</>^^^\n".format(i))
        else:
            lg.error("Command output not found in any of the"
                     " {} must-gather paths".format(len(mg_paths)))
Ejemplo n.º 16
0
def test_config_get_no_config(caplog):
    with pytest.raises(SystemExit):
        config.get("/non/exitent/file")
    assert "You have not selected a must-gather" in caplog.text