def get_ip_(name, glob, uri, config): # TODO: add user@hostname connection output storm_ = get_storm_instance(config) if uri: res = storm_.list_entries(search=name) if res: for entry in res: # host = entry.get('host') _user = entry.get("options").get( "user", get_default("user", storm_.defaults) ) _host = entry.get("options").get("hostname", "[hostname_not_specified]") _port = entry.get("options").get( "port", get_default("port", storm_.defaults) ) print(colored(f"{_user}@{_host}:{_port}", "green")) else: cprint(f"No entry found matching '{name}'", "error") else: ips = storm_.get_hostname(name, glob=glob) if ips: for ip in ips: print(colored(ip, "green")) else: cprint(f"No entry found matching '{name}'", "error")
def completion_(): path_completion = Path("~/.bash_completion.d/storm_completion") cprint( "Run this in bash shell. (You need to source the script somehwere...", "info" ) click.echo("") click.secho(f"_STORM_COMPLETE=bash_source storm > {path_completion}", fg="green") click.echo("")
def run_command_(name, cmd, editor, pick_editor): if not editor: if cmd: print(f"Run '{cmd}' on '{name}'") else: cprint("No command provided", "error") else: cmd = click.edit(editor=pick_editor) print(f"Run '{cmd}' on '{name}'")
def delete_(name, config): storm_ = get_storm_instance(config) try: storm_.delete_entry(name) cprint(f"hostname '{name}' deleted successfully.", "success") except ValueError as error: cprint(error, "error") sys.exit(1)
def copy_ids_(name, config): storm_ = get_storm_instance(config) ip = storm_.get_hostname(name, glob=False) if len(ip) == 1 and ping(ip[0]): res = ssh_copy_id(name) if res: cprint(f"Added key to authorized file", "success") else: cprint(f"Could not add key", "error")
def speed_test_(name, payload, config): storm_ = get_storm_instance(config) entries = storm_.list_entries(order=True, search=name) if entries: for entry in entries: if entry.get("host") == name: sshc = get_ssh_connection(entry) status = sshc.open() if status is True: res = speed_test(sshc, payload) if res: cprint(res, "success") else: cprint("", "failed")
def ssh_connnect_(name, config): # todo: add ssh options storm_ = get_storm_instance(config) if name is None: entries = storm_.list_entries(order=True) entries_names = [ name_.get("host") for name_ in entries if name_.get("host") != "*" ] name = iterfzf(entries_names, multi=False) entries = storm_.list_entries(order=True, search=name) else: entries = storm_.list_entries(order=True, search=name) # todo: create better method to get ssh parameters # something something.... # entries = storm_.search_host(name, exact_search=False) # # def get_params_ssh(entries_): # result_length = len(entries_) # if result_length == 0: # return False # elif result_length == 1: # return entries_[0] # else: # out = [] # for entry in entries_: # out.append(entry) # return out # res = get_params_ssh(entries) if entries: for entry in entries: if entry.get("host") == name: sshc = get_ssh_connection(entry) status = sshc.open() if status is True: sshc.interactive() sshc.close() cprint("Closed the session", "success") else: cprint(f"No entries found for '{name}'", "error")
def edit_(name, connection_uri, id_file, options, config): options = [i for i in options] storm_ = get_storm_instance(config) try: if "," in name: name = " ".join(name.split(",")) user, host, port = parse( connection_uri, user=get_default("user", storm_.defaults), port=get_default("port", storm_.defaults), ) storm_.edit_entry(name, host, user, port, id_file, options) cprint(f"'{name}' updated successfully.", "success") except ValueError as error: cprint(error, "error") sys.exit(1)
def list_macs_(): data = get_storm_config() mac_list = data.get("macs") if not mac_list: cprint(f"Could not find macs key in config file.", "error") return False cprint("HOST | MAC | BROADCAST IP", "info") print( f"{colored('HOST', 'green')}: " f"{colored('MAC', 'cyan')} " f"{colored('BROADCAST IP', 'yellow')}" ) for k, v in mac_list.items(): print( f"{colored(k, 'green')}: " f"{colored(v.get('mac'), 'cyan')} " f"{colored(v.get('br_ip'), 'yellow')}" ) print()
def add_(name, connection_uri, copy_id, id_file, options, config): options = [i for i in options] storm_ = get_storm_instance(config) try: if "@" in name: raise InvalidValueError user, host, port = parse( connection_uri, user=get_default("user", storm_.defaults), port=get_default("port", storm_.defaults), ) storm_.add_entry(name, host, user, port, id_file, options) try: if copy_id: if ping(host): ret = ssh_copy_id(name) if ret: cprint(f"ssh key added to host '{name}'", "success") else: cprint( f"Could not add ssh key to host '{name}', The host is not reachable", "error", ) except Exception as error: cprint(str(error), "error") sys.exit(1) cprint( f"'{name}' added to your ssh config. " f"you can connect to it by typing \nssh {name}", "success", ) except ValueError as error: cprint(str(error), "error") sys.exit(1)
def check_server_(name, config): storm_ = get_storm_instance(config) if name: entries = storm_.list_entries(order=True, search=name[0]) else: entries = storm_.list_entries(order=True) if entries: entries_to_check = [] if entries and len(entries) > 1: entries_names = [ name_.get("host") for name_ in entries if name_.get("host") != "*" ] # entries_names = [f"{name_.get('host')} {name_.get('options').get('user')}@{name_.get('options').get('hostname')}" for name_ in entries if name_.get('host') != "*"] entries_names = ["all"] + entries_names selected = iterfzf(entries_names, multi=True) if selected: if "all" in selected: entries_to_check = entries else: for entry in entries: if entry.get("host") in selected: entries_to_check.append(entry) else: entries_to_check = entries for entry in entries_to_check: if entry.get("host") == name: sshc = get_ssh_connection(entry) status = sshc.open() if status is True: get_server_info(sshc) sshc.close() else: cprint(status, "error") else: cprint(f"host: {name} not found", "error")
def wake_host_(name, ip, mac, config): if not name and not mac and not ip: cprint("You need to provide either a hostname or mac or ip") return False if name: name = name[0] data = get_storm_config() storm_ = get_storm_instance(config) # todo: refactor the redundant magic packet send!! :) looool if not name: if ip and mac: send_magic_packet(mac, ip_address=ip) elif mac: send_magic_packet(mac) elif ip: send_magic_packet(ip_address=ip) else: mac_list = data.get("macs") if not mac_list: cprint(f"Could not find macs key in config file.", "error") return False br_mac = mac_list.get(name) if not br_mac: cprint(f"Could not find mac entry for '{name}' in config file.", "error") return False mac = br_mac.get("mac") ip_br = br_mac.get("br_ip") if isinstance(ip_br, str): ip_br = [ip_br] [ip_config] = storm_.get_hostname(name, glob=False) if ip_config: send_magic_packet(mac, ip_address=ip_config) for ip_ in ip_br: send_magic_packet(mac, ip_address=ip_)
def list_items_(name, config): storm_ = get_storm_instance(config) col = HostColors() try: padding = storm_.get_padding() head = "Listing entries: " if not name: head += "All" entry_list = storm_.list_entries(order=True) cprint(colored(head, "cyan")) else: entry_list = storm_.list_entries(order=True, search=name[0]) if entry_list: head += f"Matching '{name[0]}'" cprint(colored(head, "cyan")) else: cprint(f"Could not find entries matching '{name[0]}'.", "error") return result, result_stack = "", "" for host in entry_list: if host.get("type") == "entry": if not host.get("host") == "*": _user = host.get("options").get( "user", get_default("user", storm_.defaults) ) _host = host.get("options").get( "hostname", "[hostname_not_specified]" ) _port = host.get("options").get( "port", get_default("port", storm_.defaults) ) result += ( f"{colored(host['host'].ljust(padding), 'green')}" f"\t->\t" f"{colored(_user, col.user(_user))}" f"{colored('@', 'green')}" f"{colored(_host, col.host(_host))}" f"{colored(':', 'green')}" f"{colored(_port, col.port(_port))}" ) extra = False for key, value in six.iteritems(host.get("options")): if key not in ["user", "hostname", "port"]: if not extra: custom_options = colored("\t[options] ", "white") result += " {0}".format(custom_options) extra = True if isinstance(value, Sequence): if isinstance(value, builtins.list): value = ",".join(value) result += "{0}={1} ".format(key, value) if extra: result = result[0:-1] result += "\n" # \n else: result_stack = colored( " (*) General options: \n", "green", attrs=[ "bold", ], ) for key, value in six.iteritems(host.get("options")): if isinstance(value, type([])): result_stack += "\t {0}: ".format(colored(key, "magenta")) result_stack += ", ".join(value) result_stack += "\n" else: result_stack += "\t {0}: {1}\n".format( colored(key, "magenta"), value, ) result_stack = result_stack[0:-1] + "\n" result += result_stack cprint(result) except ValueError as error: cprint(str(error), "error") sys.exit(1)
def version_(): cprint(__version__, "info")
def add_mac_(name, mac, broadcast_ip, force, config): # todo: change name in mac config when entry changed ssh_config_file = Path("~/.ssh/config").expanduser() storm_ = get_storm_instance(ssh_config_file) try: data = get_storm_config() except FileNotFoundError: return False if not re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", mac.lower()): cprint(f"Mac address '{mac}' has wrong format.", "error") return False if not storm_.is_host_in(name): cprint(f"Ssh config has no entry called '{name}'.", "error") return False if not data.get("macs"): cprint(f"Missing mac key in storm config.", "error") return False else: entry = data.get("macs").get(name) if entry and entry == mac: cprint( f"Entry for '{name}' already exists with same mac address '{mac}'.", "success", ) return True elif entry and entry != mac: cprint( f"Entry for '{name}' already exists with different mac address '{entry}'.", "info", ) if force: cprint(f"Overwriting entry", "info") else: cprint(f"Use --force to overwrite", "info") return False new_entry = {name: {"mac": mac, "br_ip": [broadcast_ip]}} data["macs"].update(new_entry) write_storm_config(data) cprint("Entry added.", "success")
def ping_host_(name, glob, n, config): storm_ = get_storm_instance(config) to_ping = [] if not name: entries = storm_.host_list() selected = iterfzf(entries, multi=True, mouse=True) # TODO: refactor this bullshit redundancy if selected is None or selected == "": cprint(f"None selected", "error") exit(0) for entry in selected: host_name, ip = entry.split(">>>") host_name = host_name.strip() ip = ip.strip() to_ping.append([host_name, ip]) else: ips = storm_.get_hostname(name[0], glob=glob) if ips: for ip in ips: host_name = storm_.get_host_by_ip(ip) if len(host_name) > 1: cprint(f"Multiple hosts for ip {ip} found. {host_name}", "error") exit(0) to_ping.append([host_name, ip]) else: cprint(f"No hosts found matching '{name[0]}'", "error") exit(0) for host in to_ping: host_name = host[0] ip = host[1] if ping(ip, n): cprint(f"{host_name} ({ip})", "success") else: if ping(ip, 1): cprint(f"{host_name} ({ip})", "success") else: cprint(f"{host_name} ({ip})", "error")