def _show_info(path): out = lg.opt(colors=True).success proj_count = len(locate_project(path, "yamls")) out(" <e>Projects:</> {}".format(proj_count)) try: infra = load_res(path, "infrastructure") if infra: api_url = [ dget(i, ["res", "status", "apiServerURL"]) for i in infra ] platform = [dget(i, ["res", "status", "platform"]) for i in infra] out(" <e>API URL:</> {}".format(api_url)) out(" <e>Platform:</> {}".format(platform)) c_ver = load_res(path, "clusterversion") if c_ver: cluster_id = [ dget(cv, ["res", "spec", "clusterID"]) for cv in c_ver ] desired_v = [ dget(cv, ["res", "status", "desired", "version"]) for cv in c_ver ] out(" <e>Cluster ID:</> {}".format(cluster_id)) out(" <e>Desired Version:</> {}".format(desired_v)) out("") except Exception as e: lg.warning("Error loading cluster info: {}".format(e))
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
def _suggest_type(incomplete_type): """ Match type based on incomplete string """ all_rdefs = [] all_rdefs.extend(RDEFS) all_rdefs.extend(get_generated_rdefs()) all_types = set() for rdef in all_rdefs: singular = dget(rdef, ["singular"]) plural = dget(rdef, ["plural"]) # shortNames = dget(rdef, ["shortNames"]) group = dget(rdef, ["group"]) if group != "core": all_types.add(plural + "." + group) else: all_types.add(singular) all_types.add(plural) # if shortNames: # all_types.update(shortNames) match = [f for f in all_types if f.startswith(incomplete_type)] return match
def save(paths=None, project=None, cfile=None): """Save config to file Args: paths (list[str], optional): Must-gather paths. Defaults to None. project ([type], optional): Project. Defaults to None. cfile ([type], optional): Config file. Defaults to None. """ try: config = _load_config(cfile) except (NoMgSelected, InvalidConfig): c_paths = None c_project = None else: c_paths = dget(config, ["paths"]) c_project = dget(config, ["project"]) if paths: save_paths = paths else: save_paths = c_paths if project: save_project = project else: save_project = c_project _dump_config({"paths": save_paths, "project": save_project}, cfile)
def _col_ready(res): cont_total = len(dget(res, ["res", "spec", "containers"], "")) cont_ready = len([ r for r in dget(res, ["res", "status", "containerStatuses"], "") if dget(r, ["ready"]) is True ]) return "{}/{}".format(cont_ready, cont_total)
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)))
def _col_duration(res): st = dget(res, ["res", "status", "startTime"]) ct = dget(res, ["res", "status", "completionTime"]) if st and ct: return age(st, ct, ts1_type="iso", ts2_type="iso") else: return ""
def _load_config(cfile): """Load config from file. If file doesn't exist MgConfigNotFound is raised. Args: cfile (str): Config file Returns: dict: Config dict """ lg.debug("FUNC_INIT: {}".format(locals())) if not cfile: cfile = _default_cfile config = {"paths": None, "project": None} if path.isfile(cfile): try: with open(cfile, "r") as c_f: lg.debug("Loading config from: {}".format(cfile)) lconf = yaml.safe_load(c_f) lg.debug("Loaded config from file: {}".format(lconf)) config["paths"] = dget(lconf, ["paths"], None) config["project"] = dget(lconf, ["project"], None) except Exception as e: raise InvalidConfig(e) if not dget(config, ["paths"], None): raise NoMgSelected( "Please select a must-gather (omg use </path/to/must-gather>)") return config
def etcdctl_out(j_data, output): if output == "json": print(json.dumps(j_data, indent=2)) else: head = ["ENDPOINT", "HEALTH", "TOOK", "ERROR"] body = [] for jd in j_data: body.append([ dget(jd, ["endpoint"], "?"), dget(jd, ["health"], "?"), dget(jd, ["took"], "?"), dget(jd, ["error"], ""), ]) if output == "table": print(tabulate(body, head, tablefmt="psql")) elif output is None or output == "simple": for row in body: if row[3] == "": print("{} is healthy: " "successfully committed proposal: took = {}".format( row[0], row[2])) else: print("{} is unhealthy: " "failed to commit proposal: {}".format( row[0], row[3]))
def _col_object(res): obj = "{}/{}".format(dget(res, ["res", "involvedObject", "kind"], ""), dget(res, ["res", "involvedObject", "name"], "")) if obj == "/": return "<none>" else: return obj
def _col_claim(res): claim = "{}/{}".format( dget(res, ["res", "spec", "claimRef", "namespace"], ""), dget(res, ["res", "spec", "claimRef", "name"], "")) if claim == "/": return "" else: return claim
def _col_external_ip(res): en = dget(res, ["res", "spec", "externalName"]) if en: return en ei = dget(res, ["res", "spec", "externalIP"]) if ei: return ei return "<none>"
def _col_name_wtype(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"], "") return "{}/{}".format(out_type, name)
def _col_eip(res): eip = "<none>" addresses = dget(res, ["res", "status", "addresses"]) if addresses: for adr in addresses: if dget(adr, ["type"]) == "ExternalIP": eip = dget(adr, ["address"]) break return eip
def _col_since(res): conds = dget(res, ["res", "status", "conditions"]) if conds: ltt = [ c["lastTransitionTime"] for c in conds if c["type"] == "Available" ] if ltt: yfile_ts = dget(res, ["yfile_ts"]) return age(ltt[0], yfile_ts) return "Unknown"
def _col_triggered_by(res): triggers = dget(res, ["res", "spec", "triggers"], []) trig_list = [] for trig in triggers: if trig["type"] == "ConfigChange": trig_list.append("config") elif trig["type"] == "ImageChange": img = dget(trig, ["imageChangeParams", "from", "name"]) trig_list.append("image({})".format(img)) else: trig_list.append(str(trig["type"])) return ",".join(trig_list)
def _col_status(res): status = "Unknown" conds = dget(res, ["res", "status", "conditions"]) if conds: for c in conds: if dget(c, ["type"]) == "Ready": if dget(c, ["status"]) == "True": status = "Ready" elif dget(c, ["status"]) == "False": status = "NotReady" if dget(res, ["res", "spec", "unschedulable"]): status += ",SchedulingDisabled" return status
def _write_mc(emc_path, mc): lg.debug("Writing MC with keys: {}".format(mc.keys())) lg.trace("{}".format(mc)) mc_name = dget(mc, ["metadata", "name"]) mc_config = dget(mc, ["spec", "config"]) if not (mc_name and mc_config): lg.warning("Skipping invalid MachineConfig") return mc_path = os.path.join(emc_path, mc_name) os.makedirs(mc_path, exist_ok=True) # storage storage = dget(mc, ["spec", "config", "storage"]) if storage: storage_path = os.path.join(mc_path, "storage") if "files" in storage: for fi in storage["files"]: path = fi["path"] rel_fil = path[1:] rel_dir = os.path.dirname(rel_fil) abs_dir = os.path.join(storage_path, rel_dir) abs_fil = os.path.join(storage_path, rel_fil) os.makedirs(abs_dir, exist_ok=True) with open(abs_fil, "w") as fh: print(abs_fil) fh.write(decode(fi["contents"]["source"])) # systemd systemd_u = dget(mc, ["spec", "config", "systemd", "units"]) if systemd_u: for unit in systemd_u: dropins = dget(systemd_u, ["dropins"]) if dropins: systemd_path = os.path.join( mc_path, "systemd/" + dget(unit, ["name"], "") + ".d") for d_unit in dropins: _write_unit(systemd_path, d_unit) if dget(unit, ["name"]) and dget(unit, ["contents"]): systemd_path = os.path.join(mc_path, "systemd") _write_unit(systemd_path, unit) # passwd passwd = dget(mc, ["spec", "config", "passwd"]) if passwd: passwd_path = os.path.join(mc_path, "passwd") if "users" in passwd: for user in passwd["users"]: os.makedirs(passwd_path, exist_ok=True) name = user["name"] abs_fil = os.path.join(passwd_path, name) with open(abs_fil, "w") as fh: print(abs_fil) fh.write(yaml.dump(user))
def _col_status(res): conds = dget(res, ["res", "status", "conditions"]) if conds: status = [c["message"] for c in conds if c["type"] == "Progressing"] if status: return status[0] return "Unknown"
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 []
def _col_version(res): vers = dget(res, ["res", "status", "versions"]) if vers: operator_v = [v["version"] for v in vers if v["name"] == "operator"] if operator_v: return operator_v[0] return ""
def _col_updated(res): conds = dget(res, ["res", "status", "conditions"]) if conds: updated = [c["status"] for c in conds if c["type"] == "Updated"] if updated: return updated[0] return "Unknown"
def _col_available(res): conds = dget(res, ["res", "status", "conditions"]) if conds: available = [c["status"] for c in conds if c["type"] == "Available"] if available: return available[0] return "Unknown"
def _col_degraded(res): conds = dget(res, ["res", "status", "conditions"]) if conds: degraded = [c["status"] for c in conds if c["type"] == "Degraded"] if degraded: return degraded[0] return "Unknown"
def _col_progressing(res): conds = dget(res, ["res", "status", "conditions"]) if conds: prog = [c["status"] for c in conds if c["type"] == "Progressing"] if prog: return prog[0] return "Unknown"
def _col_version(res): hist = dget(res, ["res", "status", "history"]) if hist: cluster_v = [h["version"] for h in hist if h["state"] == "Completed"] if cluster_v: return cluster_v[0] return ""
def _col_containers(res): conts = [ c["name"] for c in dget(res, ["res", "spec", "template", "spec", "containers"]) ] if conts: return ",".join(conts) return ""
def _col_access_modes(res): am = dget(res, ["res", "spec", "accessModes"], []) return ",".join([ a.replace("Read", "R").replace("Write", "W").replace("Many", "X").replace("Once", "O") for a in am ])
def _col_images(res): images = [ c["image"] for c in dget(res, ["res", "spec", "template", "spec", "containers"]) ] if images: return ",".join(images) return ""
def _col_roles(res): roles = [] labels = dget(res, ["res", "metadata", "labels"]) if labels: for label in labels: if label.startswith("node-role.kubernetes.io/"): roles.append(label.split("/")[1]) return ",".join(roles)