From b3418d48dec7a39aa5d8d04c7d734b7b87d6ecf0 Mon Sep 17 00:00:00 2001 From: fluzzi Date: Sat, 19 Mar 2022 20:41:35 -0300 Subject: [PATCH] start cli app --- conn/__init__.py | 6 ++-- conn/configfile.py | 11 +++--- conn/connapp.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++ conn/core.py | 14 +++----- conn/tools.py | 8 ++--- test.py | 23 ++++++++----- 6 files changed, 112 insertions(+), 33 deletions(-) create mode 100755 conn/connapp.py diff --git a/conn/__init__.py b/conn/__init__.py index 773c8e7..4882d8c 100644 --- a/conn/__init__.py +++ b/conn/__init__.py @@ -1,7 +1,9 @@ +#!/usr/bin/env python3 + from conn.core import node from conn.configfile import configfile -import conn.tools +from conn.connapp import connapp __version__ = "2.0" -__all__ = [node, configfile, tools] +__all__ = [node, configfile, connapp] diff --git a/conn/configfile.py b/conn/configfile.py index 37834ca..e865620 100755 --- a/conn/configfile.py +++ b/conn/configfile.py @@ -1,17 +1,12 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 #Imports import yaml import os import re -from . import tools from Crypto.PublicKey import RSA -#Constants - -#Variables - -#functions and clsses +#functions and classes class configfile: @@ -78,6 +73,8 @@ class configfile: elif len(uniques) == 3: result["folder"] = uniques[2] result["subfolder"] = uniques[1] + elif len(uniques) > 3: + return False return result def _connections_add(self,*, id, host, folder='', subfolder='', options='', logs='', password='', port='', protocol='', user='' ): diff --git a/conn/connapp.py b/conn/connapp.py new file mode 100755 index 0000000..a7da545 --- /dev/null +++ b/conn/connapp.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +#Imports +import os +import re +from Crypto.PublicKey import RSA +from Crypto.Cipher import PKCS1_OAEP +import ast +import argparse + +#functions and classes + +class connapp: + + def __init__(self, config, node): + self.node = node + self.config = config + self.nodes = self._getallnodes() + parser = argparse.ArgumentParser(prog = "conn", description = "SSH and Telnet connection manager", formatter_class=argparse.RawTextHelpFormatter) + crud = parser.add_mutually_exclusive_group() + parser.add_argument("node", metavar="node|folder", nargs='?', default=None, action='store', type=self._type, help="node[@subfolder][@folder]\nRecursively search in folders and subfolders if not specified\n[@subfolder][@folder]\nShow all available connections globaly or in specified path") + crud.add_argument("--add", dest="action", action='append_const', help="Add new node[@subfolder][@folder]", const="add") + crud.add_argument("--del", "--rm", dest="action", action='append_const', help="Delete node[@subfolder][@folder]", const="del") + crud.add_argument("--mod", "--edit", dest="action", action='append_const', help="Modify node[@subfolder][@folder]", const="mod") + crud.add_argument("--show", dest="action", action='append_const', help="Show node[@subfolder][@folder]", const="show") + crud.add_argument("--mv", dest="action", nargs=2, action=self.store_type, help="Move node[@subfolder][@folder] dest_node[@subfolder][@folder]", default="mv", type=self._type) + crud.add_argument("--cp", dest="action", nargs=2, action=self.store_type, help="Copy node[@subfolder][@folder] new_node[@subfolder][@folder]", default="cp", type=self._type) + crud.add_argument("--ls", dest="action", action='store', choices=["nodes","folders"], help="List nodes or folders", default=False) + crud.add_argument("--bulk", const="bulk", dest="action", action='append_const', help="Add nodes in bulk") + self.parser = parser.parse_args() + print(vars(self.parser)) + # if self.parser.node == False: + # print("todos") + # else: + # print(self.parser.node) + + def _node_type(self, arg_value, pat=re.compile(r"^[0-9a-zA-Z_.$@#-]+$")): + if not pat.match(arg_value): + raise argparse.ArgumentTypeError + uniques = self.config._explode_unique(arg_value) + if uniques == False: + raise argparse.ArgumentTypeError + return uniques + + def _type(self, arg_value, pat=re.compile(r"^[0-9a-zA-Z_.$@#-]+$"), arg = "node"): + if not pat.match(arg_value): + raise argparse.ArgumentTypeError + uniques = self.config._explode_unique(arg_value) + if uniques == False: + raise argparse.ArgumentTypeError + if arg == "node": + return uniques + else: + return arg + + class store_type(argparse.Action): + def __call__(self, parser, args, values, option_string=None): + result = [self.default] + result.extend(values) + setattr(args, self.dest, result) + + def _getallnodes(self): + nodes = [] + layer1 = [k for k,v in self.config.connections.items() if isinstance(v, dict) and v["type"] == "connection"] + folders = [k for k,v in self.config.connections.items() if isinstance(v, dict) and v["type"] == "folder"] + nodes.extend(layer1) + for f in folders: + layer2 = [k + "@" + f for k,v in self.config.connections[f].items() if isinstance(v, dict) and v["type"] == "connection"] + nodes.extend(layer2) + subfolders = [k for k,v in self.config.connections[f].items() if isinstance(v, dict) and v["type"] == "subfolder"] + for s in subfolders: + layer3 = [k + "@" + s + "@" + f for k,v in self.config.connections[f][s].items() if isinstance(v, dict) and v["type"] == "connection"] + nodes.extend(layer3) + return nodes + + def encrypt(password, keyfile=None): + if keyfile is None: + home = os.path.expanduser("~") + keyfile = home + '/.config/conn/.osk' + key = RSA.import_key(open(keyfile).read()) + publickey = key.publickey() + encryptor = PKCS1_OAEP.new(publickey) + password = encryptor.encrypt(password.encode("utf-8")) + return password diff --git a/conn/core.py b/conn/core.py index 89d3ba8..ebf4cd2 100755 --- a/conn/core.py +++ b/conn/core.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 #Imports import yaml import os @@ -10,14 +10,8 @@ import ast from time import sleep import datetime import sys -from conn import tools -from .configfile import configfile -#Constants - -#Variables - -#functions and clsses +#functions and classes class node: def __init__(self, unique, host, options='', logs='', password='', port='', protocol='', type='', user='', config=''): @@ -118,7 +112,7 @@ class node: self.child.logfile_read = open(self.logfile, "wb") # self.child.logfile = sys.stdout.buffer if 'missingtext' in dir(self): - print(child.after.decode(), end='') + print(self.child.after.decode(), end='') self.child.interact() if "logfile" in dir(self): self._logclean(self.logfile) @@ -126,6 +120,8 @@ class node: def run(self, commands,*, folder = '', prompt = '>$|#$|\$.$', stdout = False): connect = self._connect() if connect == True: + winsize = self.child.getwinsize() + self.child.setwinsize(65535,winsize[1]) output = '' if isinstance(commands, list): for c in commands: diff --git a/conn/tools.py b/conn/tools.py index 3b877eb..bab2574 100755 --- a/conn/tools.py +++ b/conn/tools.py @@ -1,15 +1,11 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 #Imports import os from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP import ast -#Constants - -#Variables - -#functions and clsses +#functions and classes def encrypt(password, keyfile=None): if keyfile is None: diff --git a/test.py b/test.py index 39c9044..240ea23 100755 --- a/test.py +++ b/test.py @@ -1,13 +1,14 @@ #!/usr/bin/python3 import conn -import yaml conf = conn.configfile("test.yaml") # *** # conf._connections_del(id = "zab3mu", folder="teco") # conf._connections_add(id = "zzztest", folder="teco" ,host = "10.21.96.45", user="sarabada") +# conf._connections_add(id = "layer1",host = "10.21.96.45", user="sarabada") # conf._folder_add(folder="zzz") -# conf._folder_add(folder="zzz", subfolder="achus") +# conf._folder_add(folder="home", subfolder="achus") +# conf._connections_add(id = "layer3", folder="home", subfolder="achus",host = "10.21.96.45", user="sarabada") # conf._connections_add(id = "zzztec", subfolder="achus", folder="zzz" ,host = "10.21.96.45") # conf._connections_add(id = "zzztec", subfolder="achus", folder="zzz" ,host = "10.21.96.45", options=" saracatanga") # conf._folder_del(folder = "zzz", subfolder = "achus") @@ -17,17 +18,21 @@ conf = conn.configfile("test.yaml") # print(yaml.dump(conf.profiles)) # conf.saveconfig("test.yaml") # *** +# test = conn.node("test", "10.21.96.45") # xr=conn.node("xr@home", **conf.connections["home"]["xr"], config=conf) # ios=conn.node("ios@home", **conf.connections["home"]["ios"], config=conf) # norman = conn.node("norman@home", **conf.connections["home"]["norman"], config=conf) # eve = conn.node("eve@home", **conf.connections["home"]["eve"], config=conf) -router228 = conn.node("router228@bbva", **conf.connections["bbva"]["router228"], config=conf) +# router228 = conn.node("router228@bbva", **conf.connections["bbva"]["router228"], config=conf) # router228.interact() -router228.run(["term len 0","show ip int br"]) -# xr.run(["term len 0","show ip bgp", "show ip bgp summ"], folder="test") -# ios.run(["term len 0","show ip bgp", "show ip bgp summ"]) -# norman.run(["ls -la", "pwd"], folder = "test") +# router228.run(["term len 0","show ip int br"]) +# xroutput = xr.run(["show ip bgp", "show ip bgp summ"], folder="test") +# ios.run("show run") +# norman.run(["ls -la", "pwd"]) # test = eve.run(["ls -la", "pwd"]) -print(router228.output) +# print(norman.output) +# print(xroutput) # xr.interact() - +# test.interact() +# *** +conn.connapp(conf, conn.node)