diff --git a/README.md b/README.md index 15a0167..17d4430 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ print(result) ### Usage: ``` -usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] +usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp] conn {profile,move,mv,copy,cp,list,ls,bulk,config} ... positional arguments: @@ -124,6 +124,7 @@ positional arguments: -e, --mod, --edit Modify node[@subfolder][@folder] -s, --show Show node[@subfolder][@folder] -d, --debug Display all conections steps + -t, --sftp Connects using sftp instead of ssh ``` ### Commands: diff --git a/connpy/__init__.py b/connpy/__init__.py index 8cdd75c..f80fa9d 100644 --- a/connpy/__init__.py +++ b/connpy/__init__.py @@ -16,7 +16,7 @@ Connpy is a connection manager that allows you to store nodes to connect them fa ### Usage ``` -usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] +usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp] conn {profile,move,mv,copy,cp,list,ls,bulk,config} ... positional arguments: @@ -32,6 +32,7 @@ Options: -e, --mod, --edit Modify node[@subfolder][@folder] -s, --show Show node[@subfolder][@folder] -d, --debug Display all conections steps + -t, --sftp Connects using sftp instead of ssh Commands: profile Manage profiles diff --git a/connpy/_version.py b/connpy/_version.py index 936bd8b..e492243 100644 --- a/connpy/_version.py +++ b/connpy/_version.py @@ -1,2 +1,2 @@ -__version__ = "3.6.1" +__version__ = "3.6.2" diff --git a/connpy/connapp.py b/connpy/connapp.py index 5492e44..068ffbb 100755 --- a/connpy/connapp.py +++ b/connpy/connapp.py @@ -78,7 +78,8 @@ class connapp: nodecrud.add_argument("-r","--del", "--rm", dest="action", action="store_const", help="Delete node[@subfolder][@folder] or [@subfolder]@folder", const="del", default="connect") nodecrud.add_argument("-e","--mod", "--edit", dest="action", action="store_const", help="Modify node[@subfolder][@folder]", const="mod", default="connect") nodecrud.add_argument("-s","--show", dest="action", action="store_const", help="Show node[@subfolder][@folder]", const="show", default="connect") - nodecrud.add_argument("-d","--debug", dest="action", action="store_const", help="Display all conections steps", const="debug", default="connect") + nodecrud.add_argument("-d","--debug", dest="debug", action="store_true", help="Display all conections steps") + nodeparser.add_argument("-t","--sftp", dest="sftp", action="store_true", help="Connects using sftp instead of ssh") nodeparser.set_defaults(func=self._func_node) #PROFILEPARSER profileparser = subparsers.add_parser("profile", help="Manage profiles") @@ -169,7 +170,7 @@ class connapp: #Function called when connecting or managing nodes. if not self.case and args.data != None: args.data = args.data.lower() - actions = {"version": self._version, "connect": self._connect, "debug": self._connect, "add": self._add, "del": self._del, "mod": self._mod, "show": self._show} + actions = {"version": self._version, "connect": self._connect, "add": self._add, "del": self._del, "mod": self._mod, "show": self._show} return actions.get(args.action)(args) def _version(self, args): @@ -196,7 +197,9 @@ class connapp: exit(7) node = self.config.getitem(matches[0]) node = self.node(matches[0],**node, config = self.config) - if args.action == "debug": + if args.sftp: + node.protocol = "sftp" + if args.debug: node.interact(debug = True) else: node.interact() @@ -1212,7 +1215,7 @@ class connapp: if type == "node": return "node[@subfolder][@folder]\nConnect to specific node or show all matching nodes\n[@subfolder][@folder]\nShow all available connections globaly or in specified path" if type == "usage": - return "conn [-h] [--add | --del | --mod | --show | --debug] [node|folder]\n conn {profile,move,mv,copy,cp,list,ls,bulk,config} ..." + return "conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp]\n conn {profile,move,mv,copy,cp,list,ls,bulk,config} ..." if type == "end": return "Commands:\n profile Manage profiles\n move (mv) Move node\n copy (cp) Copy node\n list (ls) List profiles, nodes or folders\n bulk Add nodes in bulk\n export Export connection folder to Yaml file\n import Import connection folder to config from Yaml file\n run Run scripts or commands on nodes\n config Manage app config\n api Start and stop connpy api\n ai Make request to an AI" if type == "bashcompletion": diff --git a/connpy/core.py b/connpy/core.py index c6f1dd6..a156996 100755 --- a/connpy/core.py +++ b/connpy/core.py @@ -418,16 +418,15 @@ class node: def _connect(self, debug = False, timeout = 10, max_attempts = 3): # Method to connect to the node, it parse all the information, create the ssh/telnet command and login to the node. - if self.protocol == "ssh": - cmd = "ssh" + if self.protocol in ["ssh", "sftp"]: + cmd = self.protocol if self.idletime > 0: cmd = cmd + " -o ServerAliveInterval=" + str(self.idletime) - if self.user == '': - cmd = cmd + " {}".format(self.host) - else: - cmd = cmd + " {}".format("@".join([self.user,self.host])) if self.port != '': - cmd = cmd + " -p " + self.port + if self.protocol == "ssh": + cmd = cmd + " -p " + self.port + elif self.protocol == "sftp": + cmd = cmd + " -P " + self.port if self.options != '': cmd = cmd + " " + self.options if self.logs != '': @@ -436,6 +435,10 @@ class node: passwords = self._passtx(self.password) else: passwords = [] + if self.user == '': + cmd = cmd + " {}".format(self.host) + else: + cmd = cmd + " {}".format("@".join([self.user,self.host])) expects = ['yes/no', 'refused', 'supported', 'cipher', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', '[p|P]assword:|[u|U]sername:', r'>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching"] elif self.protocol == "telnet": cmd = "telnet " + self.host @@ -468,7 +471,7 @@ class node: while True: results = child.expect(expects, timeout=timeout) if results == 0: - if self.protocol == "ssh": + if self.protocol in ["ssh", "sftp"]: child.sendline('yes') elif self.protocol == "telnet": if self.user != '': @@ -487,7 +490,7 @@ class node: after = "Connection timeout" else: after = child.after.decode() - return ("Connection failed code:" + str(results) + "\n" + child.before.decode() + after + child.readline().decode()).rstrip() + return ("Connection failed code:" + str(results) + "\n" + child.before.decode().lstrip() + after + child.readline().decode()).rstrip() if results == 8: if len(passwords) > 0: child.sendline(passwords[i]) diff --git a/docs/connpy/index.html b/docs/connpy/index.html index aed6d86..9f68869 100644 --- a/docs/connpy/index.html +++ b/docs/connpy/index.html @@ -35,7 +35,7 @@ - Much more!

Usage

-
usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder]
+
usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp]
        conn {profile,move,mv,copy,cp,list,ls,bulk,config} ...
 
 positional arguments:
@@ -51,6 +51,7 @@ Options:
   -e, --mod, --edit  Modify node[@subfolder][@folder]
   -s, --show         Show node[@subfolder][@folder]
   -d, --debug        Display all conections steps
+  -t, --sftp         Connects using sftp instead of ssh
 
 Commands:
   profile        Manage profiles
@@ -269,7 +270,7 @@ Connpy is a connection manager that allows you to store nodes to connect them fa
 
 ### Usage
 ```
-usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder]
+usage: conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp]
        conn {profile,move,mv,copy,cp,list,ls,bulk,config} ...
 
 positional arguments:
@@ -285,6 +286,7 @@ Options:
   -e, --mod, --edit  Modify node[@subfolder][@folder]
   -s, --show         Show node[@subfolder][@folder]
   -d, --debug        Display all conections steps
+  -t, --sftp         Connects using sftp instead of ssh
 
 Commands:
   profile        Manage profiles
@@ -1869,7 +1871,8 @@ Categorize the user's request based on the operation they want to perform on
         nodecrud.add_argument("-r","--del", "--rm", dest="action", action="store_const", help="Delete node[@subfolder][@folder] or [@subfolder]@folder", const="del", default="connect")
         nodecrud.add_argument("-e","--mod", "--edit", dest="action", action="store_const", help="Modify node[@subfolder][@folder]", const="mod", default="connect")
         nodecrud.add_argument("-s","--show", dest="action", action="store_const", help="Show node[@subfolder][@folder]", const="show", default="connect")
-        nodecrud.add_argument("-d","--debug", dest="action", action="store_const", help="Display all conections steps", const="debug", default="connect")
+        nodecrud.add_argument("-d","--debug", dest="debug", action="store_true", help="Display all conections steps")
+        nodeparser.add_argument("-t","--sftp", dest="sftp", action="store_true", help="Connects using sftp instead of ssh")
         nodeparser.set_defaults(func=self._func_node)
         #PROFILEPARSER
         profileparser = subparsers.add_parser("profile", help="Manage profiles") 
@@ -1960,7 +1963,7 @@ Categorize the user's request based on the operation they want to perform on
         #Function called when connecting or managing nodes.
         if not self.case and args.data != None:
             args.data = args.data.lower()
-        actions = {"version": self._version, "connect": self._connect, "debug": self._connect, "add": self._add, "del": self._del, "mod": self._mod, "show": self._show}
+        actions = {"version": self._version, "connect": self._connect, "add": self._add, "del": self._del, "mod": self._mod, "show": self._show}
         return actions.get(args.action)(args)
 
     def _version(self, args):
@@ -1987,7 +1990,9 @@ Categorize the user's request based on the operation they want to perform on
             exit(7)
         node = self.config.getitem(matches[0])
         node = self.node(matches[0],**node, config = self.config)
-        if args.action == "debug":
+        if args.sftp:
+            node.protocol = "sftp"
+        if args.debug:
             node.interact(debug = True)
         else:
             node.interact()
@@ -3003,7 +3008,7 @@ Categorize the user's request based on the operation they want to perform on
         if type == "node":
             return "node[@subfolder][@folder]\nConnect to specific node or show all matching nodes\n[@subfolder][@folder]\nShow all available connections globaly or in specified path"
         if type == "usage":
-            return "conn [-h] [--add | --del | --mod | --show | --debug] [node|folder]\n       conn {profile,move,mv,copy,cp,list,ls,bulk,config} ..."
+            return "conn [-h] [--add | --del | --mod | --show | --debug] [node|folder] [--sftp]\n       conn {profile,move,mv,copy,cp,list,ls,bulk,config} ..."
         if type == "end":
             return "Commands:\n  profile        Manage profiles\n  move (mv)      Move node\n  copy (cp)      Copy node\n  list (ls)      List profiles, nodes or folders\n  bulk           Add nodes in bulk\n  export         Export connection folder to Yaml file\n  import         Import connection folder to config from Yaml file\n  run            Run scripts or commands on nodes\n  config         Manage app config\n  api            Start and stop connpy api\n  ai             Make request to an AI"
         if type == "bashcompletion":
@@ -3235,7 +3240,8 @@ tasks:
     nodecrud.add_argument("-r","--del", "--rm", dest="action", action="store_const", help="Delete node[@subfolder][@folder] or [@subfolder]@folder", const="del", default="connect")
     nodecrud.add_argument("-e","--mod", "--edit", dest="action", action="store_const", help="Modify node[@subfolder][@folder]", const="mod", default="connect")
     nodecrud.add_argument("-s","--show", dest="action", action="store_const", help="Show node[@subfolder][@folder]", const="show", default="connect")
-    nodecrud.add_argument("-d","--debug", dest="action", action="store_const", help="Display all conections steps", const="debug", default="connect")
+    nodecrud.add_argument("-d","--debug", dest="debug", action="store_true", help="Display all conections steps")
+    nodeparser.add_argument("-t","--sftp", dest="sftp", action="store_true", help="Connects using sftp instead of ssh")
     nodeparser.set_defaults(func=self._func_node)
     #PROFILEPARSER
     profileparser = subparsers.add_parser("profile", help="Manage profiles") 
@@ -3770,16 +3776,15 @@ tasks:
 
     def _connect(self, debug = False, timeout = 10, max_attempts = 3):
         # Method to connect to the node, it parse all the information, create the ssh/telnet command and login to the node.
-        if self.protocol == "ssh":
-            cmd = "ssh"
+        if self.protocol in ["ssh", "sftp"]:
+            cmd = self.protocol
             if self.idletime > 0:
                 cmd = cmd + " -o ServerAliveInterval=" + str(self.idletime)
-            if self.user == '':
-                cmd = cmd + " {}".format(self.host)
-            else:
-                cmd = cmd + " {}".format("@".join([self.user,self.host]))
             if self.port != '':
-                cmd = cmd + " -p " + self.port
+                if self.protocol == "ssh":
+                    cmd = cmd + " -p " + self.port
+                elif self.protocol == "sftp":
+                    cmd = cmd + " -P " + self.port
             if self.options != '':
                 cmd = cmd + " " + self.options
             if self.logs != '':
@@ -3788,6 +3793,10 @@ tasks:
                 passwords = self._passtx(self.password)
             else:
                 passwords = []
+            if self.user == '':
+                cmd = cmd + " {}".format(self.host)
+            else:
+                cmd = cmd + " {}".format("@".join([self.user,self.host]))
             expects = ['yes/no', 'refused', 'supported', 'cipher', 'ssh-keygen.*\"', 'timeout|timed.out', 'unavailable', 'closed', '[p|P]assword:|[u|U]sername:', r'>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, pexpect.TIMEOUT, "No route to host", "resolve hostname", "no matching"]
         elif self.protocol == "telnet":
             cmd = "telnet " + self.host
@@ -3820,7 +3829,7 @@ tasks:
                 while True:
                     results = child.expect(expects, timeout=timeout)
                     if results == 0:
-                        if self.protocol == "ssh":
+                        if self.protocol in ["ssh", "sftp"]:
                             child.sendline('yes')
                         elif self.protocol == "telnet":
                             if self.user != '':
@@ -3839,7 +3848,7 @@ tasks:
                                 after = "Connection timeout"
                             else:
                                 after = child.after.decode()
-                        return ("Connection failed code:" + str(results) + "\n" + child.before.decode() + after + child.readline().decode()).rstrip()
+                        return ("Connection failed code:" + str(results) + "\n" + child.before.decode().lstrip() + after + child.readline().decode()).rstrip()
                     if results == 8:
                         if len(passwords) > 0:
                             child.sendline(passwords[i])