Add new jumphost feature to nodes
bug fix when adding a node without name
This commit is contained in:
parent
d6880d5956
commit
fd883a4821
@ -1,2 +1,2 @@
|
|||||||
__version__ = "3.6.4"
|
__version__ = "3.7.0b1"
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ class configfile:
|
|||||||
|
|
||||||
def _createconfig(self, conf):
|
def _createconfig(self, conf):
|
||||||
#Create config file
|
#Create config file
|
||||||
defaultconfig = {'config': {'case': False, 'idletime': 30, 'fzf': False}, 'connections': {}, 'profiles': { "default": { "host":"", "protocol":"ssh", "port":"", "user":"", "password":"", "options":"", "logs":"", "tags": "" }}}
|
defaultconfig = {'config': {'case': False, 'idletime': 30, 'fzf': False}, 'connections': {}, 'profiles': { "default": { "host":"", "protocol":"ssh", "port":"", "user":"", "password":"", "options":"", "logs":"", "tags": "", "jumphost":""}}}
|
||||||
if not os.path.exists(conf):
|
if not os.path.exists(conf):
|
||||||
with open(conf, "w") as f:
|
with open(conf, "w") as f:
|
||||||
json.dump(defaultconfig, f, indent = 4)
|
json.dump(defaultconfig, f, indent = 4)
|
||||||
@ -238,14 +238,14 @@ class configfile:
|
|||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
def _connections_add(self,*, id, host, folder='', subfolder='', options='', logs='', password='', port='', protocol='', user='', tags='', type = "connection" ):
|
def _connections_add(self,*, id, host, folder='', subfolder='', options='', logs='', password='', port='', protocol='', user='', tags='', jumphost='', type = "connection" ):
|
||||||
#Add connection from config
|
#Add connection from config
|
||||||
if folder == '':
|
if folder == '':
|
||||||
self.connections[id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "tags": tags,"type": type}
|
self.connections[id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "tags": tags,"jumphost": jumphost,"type": type}
|
||||||
elif folder != '' and subfolder == '':
|
elif folder != '' and subfolder == '':
|
||||||
self.connections[folder][id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "tags": tags, "type": type}
|
self.connections[folder][id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "tags": tags, "jumphost": jumphost, "type": type}
|
||||||
elif folder != '' and subfolder != '':
|
elif folder != '' and subfolder != '':
|
||||||
self.connections[folder][subfolder][id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "tags": tags, "type": type}
|
self.connections[folder][subfolder][id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "tags": tags, "jumphost": jumphost, "type": type}
|
||||||
|
|
||||||
|
|
||||||
def _connections_del(self,*, id, folder='', subfolder=''):
|
def _connections_del(self,*, id, folder='', subfolder=''):
|
||||||
@ -274,9 +274,9 @@ class configfile:
|
|||||||
del self.connections[folder][subfolder]
|
del self.connections[folder][subfolder]
|
||||||
|
|
||||||
|
|
||||||
def _profiles_add(self,*, id, host = '', options='', logs='', password='', port='', protocol='', user='', tags='' ):
|
def _profiles_add(self,*, id, host = '', options='', logs='', password='', port='', protocol='', user='', tags='', jumphost='' ):
|
||||||
#Add profile from config
|
#Add profile from config
|
||||||
self.profiles[id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "tags": tags}
|
self.profiles[id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "tags": tags, "jumphost": jumphost}
|
||||||
|
|
||||||
|
|
||||||
def _profiles_del(self,*, id ):
|
def _profiles_del(self,*, id ):
|
||||||
|
@ -539,6 +539,7 @@ class connapp:
|
|||||||
newnode["options"] = newnodes["options"]
|
newnode["options"] = newnodes["options"]
|
||||||
newnode["logs"] = newnodes["logs"]
|
newnode["logs"] = newnodes["logs"]
|
||||||
newnode["tags"] = newnodes["tags"]
|
newnode["tags"] = newnodes["tags"]
|
||||||
|
newnode["jumphost"] = newnodes["jumphost"]
|
||||||
newnode["user"] = newnodes["user"]
|
newnode["user"] = newnodes["user"]
|
||||||
newnode["password"] = newnodes["password"]
|
newnode["password"] = newnodes["password"]
|
||||||
count +=1
|
count +=1
|
||||||
@ -992,6 +993,23 @@ class connapp:
|
|||||||
raise inquirer.errors.ValidationError("", reason="Tags should be a python dictionary.".format(current))
|
raise inquirer.errors.ValidationError("", reason="Tags should be a python dictionary.".format(current))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _jumphost_validation(self, answers, current):
|
||||||
|
#Validation for Jumphost in inquirer when managing nodes
|
||||||
|
if current.startswith("@"):
|
||||||
|
if current[1:] not in self.profiles:
|
||||||
|
raise inquirer.errors.ValidationError("", reason="Profile {} don't exist".format(current))
|
||||||
|
elif current != "":
|
||||||
|
if current not in self.nodes :
|
||||||
|
raise inquirer.errors.ValidationError("", reason="Node {} don't exist.".format(current))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _profile_jumphost_validation(self, answers, current):
|
||||||
|
#Validation for Jumphost in inquirer when managing profiles
|
||||||
|
if current != "":
|
||||||
|
if current not in self.nodes :
|
||||||
|
raise inquirer.errors.ValidationError("", reason="Node {} don't exist.".format(current))
|
||||||
|
return True
|
||||||
|
|
||||||
def _default_validation(self, answers, current):
|
def _default_validation(self, answers, current):
|
||||||
#Default validation type used in multiples questions in inquirer
|
#Default validation type used in multiples questions in inquirer
|
||||||
if current.startswith("@"):
|
if current.startswith("@"):
|
||||||
@ -1039,6 +1057,7 @@ class connapp:
|
|||||||
questions.append(inquirer.Confirm("options", message="Edit Options?"))
|
questions.append(inquirer.Confirm("options", message="Edit Options?"))
|
||||||
questions.append(inquirer.Confirm("logs", message="Edit logging path/file?"))
|
questions.append(inquirer.Confirm("logs", message="Edit logging path/file?"))
|
||||||
questions.append(inquirer.Confirm("tags", message="Edit tags?"))
|
questions.append(inquirer.Confirm("tags", message="Edit tags?"))
|
||||||
|
questions.append(inquirer.Confirm("jumphost", message="Edit jumphost?"))
|
||||||
questions.append(inquirer.Confirm("user", message="Edit User?"))
|
questions.append(inquirer.Confirm("user", message="Edit User?"))
|
||||||
questions.append(inquirer.Confirm("password", message="Edit password?"))
|
questions.append(inquirer.Confirm("password", message="Edit password?"))
|
||||||
answers = inquirer.prompt(questions)
|
answers = inquirer.prompt(questions)
|
||||||
@ -1050,11 +1069,13 @@ class connapp:
|
|||||||
defaults = self.config.getitem(unique)
|
defaults = self.config.getitem(unique)
|
||||||
if "tags" not in defaults:
|
if "tags" not in defaults:
|
||||||
defaults["tags"] = ""
|
defaults["tags"] = ""
|
||||||
|
if "jumphost" not in defaults:
|
||||||
|
defaults["jumphost"] = ""
|
||||||
except:
|
except:
|
||||||
defaults = { "host":"", "protocol":"", "port":"", "user":"", "options":"", "logs":"" , "tags":"", "password":""}
|
defaults = { "host":"", "protocol":"", "port":"", "user":"", "options":"", "logs":"" , "tags":"", "password":"", "jumphost":""}
|
||||||
node = {}
|
node = {}
|
||||||
if edit == None:
|
if edit == None:
|
||||||
edit = { "host":True, "protocol":True, "port":True, "user":True, "password": True,"options":True, "logs":True, "tags":True }
|
edit = { "host":True, "protocol":True, "port":True, "user":True, "password": True,"options":True, "logs":True, "tags":True, "jumphost":True }
|
||||||
questions = []
|
questions = []
|
||||||
if edit["host"]:
|
if edit["host"]:
|
||||||
questions.append(inquirer.Text("host", message="Add Hostname or IP", validate=self._host_validation, default=defaults["host"]))
|
questions.append(inquirer.Text("host", message="Add Hostname or IP", validate=self._host_validation, default=defaults["host"]))
|
||||||
@ -1080,6 +1101,10 @@ class connapp:
|
|||||||
questions.append(inquirer.Text("tags", message="Add tags dictionary", validate=self._tags_validation, default=str(defaults["tags"]).replace("{","{{").replace("}","}}")))
|
questions.append(inquirer.Text("tags", message="Add tags dictionary", validate=self._tags_validation, default=str(defaults["tags"]).replace("{","{{").replace("}","}}")))
|
||||||
else:
|
else:
|
||||||
node["tags"] = defaults["tags"]
|
node["tags"] = defaults["tags"]
|
||||||
|
if edit["jumphost"]:
|
||||||
|
questions.append(inquirer.Text("jumphost", message="Add Jumphost node", validate=self._jumphost_validation, default=str(defaults["jumphost"]).replace("{","{{").replace("}","}}")))
|
||||||
|
else:
|
||||||
|
node["jumphost"] = defaults["jumphost"]
|
||||||
if edit["user"]:
|
if edit["user"]:
|
||||||
questions.append(inquirer.Text("user", message="Pick username", validate=self._default_validation, default=defaults["user"]))
|
questions.append(inquirer.Text("user", message="Pick username", validate=self._default_validation, default=defaults["user"]))
|
||||||
else:
|
else:
|
||||||
@ -1118,11 +1143,13 @@ class connapp:
|
|||||||
defaults = self.config.profiles[unique]
|
defaults = self.config.profiles[unique]
|
||||||
if "tags" not in defaults:
|
if "tags" not in defaults:
|
||||||
defaults["tags"] = ""
|
defaults["tags"] = ""
|
||||||
|
if "jumphost" not in defaults:
|
||||||
|
defaults["jumphost"] = ""
|
||||||
except:
|
except:
|
||||||
defaults = { "host":"", "protocol":"", "port":"", "user":"", "options":"", "logs":"", "tags": "" }
|
defaults = { "host":"", "protocol":"", "port":"", "user":"", "options":"", "logs":"", "tags": "", "jumphost": ""}
|
||||||
profile = {}
|
profile = {}
|
||||||
if edit == None:
|
if edit == None:
|
||||||
edit = { "host":True, "protocol":True, "port":True, "user":True, "password": True,"options":True, "logs":True, "tags":True }
|
edit = { "host":True, "protocol":True, "port":True, "user":True, "password": True,"options":True, "logs":True, "tags":True, "jumphost":True }
|
||||||
questions = []
|
questions = []
|
||||||
if edit["host"]:
|
if edit["host"]:
|
||||||
questions.append(inquirer.Text("host", message="Add Hostname or IP", default=defaults["host"]))
|
questions.append(inquirer.Text("host", message="Add Hostname or IP", default=defaults["host"]))
|
||||||
@ -1148,6 +1175,10 @@ class connapp:
|
|||||||
questions.append(inquirer.Text("tags", message="Add tags dictionary", validate=self._profile_tags_validation, default=str(defaults["tags"]).replace("{","{{").replace("}","}}")))
|
questions.append(inquirer.Text("tags", message="Add tags dictionary", validate=self._profile_tags_validation, default=str(defaults["tags"]).replace("{","{{").replace("}","}}")))
|
||||||
else:
|
else:
|
||||||
profile["tags"] = defaults["tags"]
|
profile["tags"] = defaults["tags"]
|
||||||
|
if edit["jumphost"]:
|
||||||
|
questions.append(inquirer.Text("jumphost", message="Add Jumphost node", validate=self._profile_jumphost_validation, default=str(defaults["jumphost"]).replace("{","{{").replace("}","}}")))
|
||||||
|
else:
|
||||||
|
profile["jumphost"] = defaults["jumphost"]
|
||||||
if edit["user"]:
|
if edit["user"]:
|
||||||
questions.append(inquirer.Text("user", message="Pick username", default=defaults["user"]))
|
questions.append(inquirer.Text("user", message="Pick username", default=defaults["user"]))
|
||||||
else:
|
else:
|
||||||
@ -1179,6 +1210,7 @@ class connapp:
|
|||||||
questions.append(inquirer.Text("options", message="Pass extra options to protocol", validate=self._default_validation))
|
questions.append(inquirer.Text("options", message="Pass extra options to protocol", validate=self._default_validation))
|
||||||
questions.append(inquirer.Text("logs", message="Pick logging path/file ", validate=self._default_validation))
|
questions.append(inquirer.Text("logs", message="Pick logging path/file ", validate=self._default_validation))
|
||||||
questions.append(inquirer.Text("tags", message="Add tags dictionary", validate=self._tags_validation))
|
questions.append(inquirer.Text("tags", message="Add tags dictionary", validate=self._tags_validation))
|
||||||
|
questions.append(inquirer.Text("jumphost", message="Add Jumphost node", validate=self._jumphost_validation))
|
||||||
questions.append(inquirer.Text("user", message="Pick username", validate=self._default_validation))
|
questions.append(inquirer.Text("user", message="Pick username", validate=self._default_validation))
|
||||||
questions.append(inquirer.List("password", message="Password: Use a local password, no password or a list of profiles to reference?", choices=["Local Password", "Profiles", "No Password"]))
|
questions.append(inquirer.List("password", message="Password: Use a local password, no password or a list of profiles to reference?", choices=["Local Password", "Profiles", "No Password"]))
|
||||||
answer = inquirer.prompt(questions)
|
answer = inquirer.prompt(questions)
|
||||||
@ -1201,6 +1233,8 @@ class connapp:
|
|||||||
return answer
|
return answer
|
||||||
|
|
||||||
def _type_node(self, arg_value, pat=re.compile(r"^[0-9a-zA-Z_.$@#-]+$")):
|
def _type_node(self, arg_value, pat=re.compile(r"^[0-9a-zA-Z_.$@#-]+$")):
|
||||||
|
if arg_value == None:
|
||||||
|
raise ValueError("Missing argument node")
|
||||||
if not pat.match(arg_value):
|
if not pat.match(arg_value):
|
||||||
raise ValueError(f"Argument error: {arg_value}")
|
raise ValueError(f"Argument error: {arg_value}")
|
||||||
return arg_value
|
return arg_value
|
||||||
|
@ -33,7 +33,7 @@ class node:
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, unique, host, options='', logs='', password='', port='', protocol='', user='', config='', tags=''):
|
def __init__(self, unique, host, options='', logs='', password='', port='', protocol='', user='', config='', tags='', jumphost=''):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
### Parameters:
|
### Parameters:
|
||||||
@ -66,6 +66,8 @@ class node:
|
|||||||
|
|
||||||
- tags (dict) : Tags useful for automation and personal porpuse
|
- tags (dict) : Tags useful for automation and personal porpuse
|
||||||
like "os", "prompt" and "screenleght_command"
|
like "os", "prompt" and "screenleght_command"
|
||||||
|
|
||||||
|
- jumphost (str): Reference another node to be used as a jumphost
|
||||||
'''
|
'''
|
||||||
if config == '':
|
if config == '':
|
||||||
self.idletime = 0
|
self.idletime = 0
|
||||||
@ -74,7 +76,7 @@ class node:
|
|||||||
self.idletime = config.config["idletime"]
|
self.idletime = config.config["idletime"]
|
||||||
self.key = config.key
|
self.key = config.key
|
||||||
self.unique = unique
|
self.unique = unique
|
||||||
attr = {"host": host, "logs": logs, "options":options, "port": port, "protocol": protocol, "user": user, "tags": tags}
|
attr = {"host": host, "logs": logs, "options":options, "port": port, "protocol": protocol, "user": user, "tags": tags, "jumphost": jumphost}
|
||||||
for key in attr:
|
for key in attr:
|
||||||
profile = re.search("^@(.*)", str(attr[key]))
|
profile = re.search("^@(.*)", str(attr[key]))
|
||||||
if profile and config != '':
|
if profile and config != '':
|
||||||
@ -97,6 +99,45 @@ class node:
|
|||||||
self.password.append(config.profiles[profile.group(1)]["password"])
|
self.password.append(config.profiles[profile.group(1)]["password"])
|
||||||
else:
|
else:
|
||||||
self.password = [password]
|
self.password = [password]
|
||||||
|
if self.jumphost != "" and config != '':
|
||||||
|
self.jumphost = config.getitem(self.jumphost)
|
||||||
|
for key in self.jumphost:
|
||||||
|
profile = re.search("^@(.*)", str(self.jumphost[key]))
|
||||||
|
if profile:
|
||||||
|
try:
|
||||||
|
self.jumphost[key] = config.profiles[profile.group(1)][key]
|
||||||
|
except:
|
||||||
|
self.jumphost[key] = ""
|
||||||
|
elif self.jumphost[key] == '' and key == "protocol":
|
||||||
|
try:
|
||||||
|
self.jumphost[key] = config.profiles["default"][key]
|
||||||
|
except:
|
||||||
|
self.jumphost[key] = "ssh"
|
||||||
|
if isinstance(self.jumphost["password"],list):
|
||||||
|
jumphost_password = []
|
||||||
|
for i, s in enumerate(self.jumphost["password"]):
|
||||||
|
profile = re.search("^@(.*)", self.jumphost["password"][i])
|
||||||
|
if profile:
|
||||||
|
jumphost_password.append(config.profiles[profile.group(1)]["password"])
|
||||||
|
self.jumphost["password"] = jumphost_password
|
||||||
|
else:
|
||||||
|
self.jumphost["password"] = [self.jumphost["password"]]
|
||||||
|
if self.jumphost["password"] != [""]:
|
||||||
|
self.password = self.jumphost["password"] + self.password
|
||||||
|
|
||||||
|
if self.jumphost["protocol"] == "ssh":
|
||||||
|
jumphost_cmd = self.jumphost["protocol"] + " -W %h:%p"
|
||||||
|
if self.port != '':
|
||||||
|
jumphost_cmd = jumphost_cmd + " -p " + self.jumphost["port"]
|
||||||
|
if self.options != '':
|
||||||
|
jumphost_cmd = jumphost_cmd + " " + self.jumphost["options"]
|
||||||
|
if self.user == '':
|
||||||
|
jumphost_cmd = jumphost_cmd + " {}".format(self.jumphost["host"])
|
||||||
|
else:
|
||||||
|
jumphost_cmd = jumphost_cmd + " {}".format("@".join([self.jumphost["user"],self.jumphost["host"]]))
|
||||||
|
self.jumphost = f"-o ProxyCommand=\"{jumphost_cmd}\""
|
||||||
|
else:
|
||||||
|
self.jumphost = ""
|
||||||
|
|
||||||
def _passtx(self, passwords, *, keyfile=None):
|
def _passtx(self, passwords, *, keyfile=None):
|
||||||
# decrypts passwords, used by other methdos.
|
# decrypts passwords, used by other methdos.
|
||||||
@ -203,8 +244,8 @@ class node:
|
|||||||
'''
|
'''
|
||||||
connect = self._connect(debug = debug)
|
connect = self._connect(debug = debug)
|
||||||
if connect == True:
|
if connect == True:
|
||||||
# size = re.search('columns=([0-9]+).*lines=([0-9]+)',str(os.get_terminal_size()))
|
size = re.search('columns=([0-9]+).*lines=([0-9]+)',str(os.get_terminal_size()))
|
||||||
# self.child.setwinsize(int(size.group(2)),int(size.group(1)))
|
self.child.setwinsize(int(size.group(2)),int(size.group(1)))
|
||||||
print("Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
print("Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
||||||
if 'logfile' in dir(self):
|
if 'logfile' in dir(self):
|
||||||
# Initialize self.mylog
|
# Initialize self.mylog
|
||||||
@ -431,6 +472,8 @@ class node:
|
|||||||
cmd = cmd + " " + self.options
|
cmd = cmd + " " + self.options
|
||||||
if self.logs != '':
|
if self.logs != '':
|
||||||
self.logfile = self._logfile()
|
self.logfile = self._logfile()
|
||||||
|
if self.jumphost != '':
|
||||||
|
cmd = cmd + " " + self.jumphost
|
||||||
if self.password[0] != '':
|
if self.password[0] != '':
|
||||||
passwords = self._passtx(self.password)
|
passwords = self._passtx(self.password)
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user