1287 lines
59 KiB
HTML
1287 lines
59 KiB
HTML
|
<!doctype html>
|
|||
|
<html lang="en">
|
|||
|
<head>
|
|||
|
<meta charset="utf-8">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
|||
|
<meta name="generator" content="pdoc 0.10.0" />
|
|||
|
<title>conn API documentation</title>
|
|||
|
<meta name="description" content="" />
|
|||
|
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
|||
|
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
|||
|
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
|||
|
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
|||
|
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<main>
|
|||
|
<article id="content">
|
|||
|
<header>
|
|||
|
<h1 class="title">Package <code>conn</code></h1>
|
|||
|
</header>
|
|||
|
<section id="section-intro">
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">#!/usr/bin/env python3
|
|||
|
'''
|
|||
|
'''
|
|||
|
from .core import node,nodes
|
|||
|
from .configfile import configfile
|
|||
|
from .connapp import connapp
|
|||
|
from pkg_resources import get_distribution
|
|||
|
|
|||
|
__all__ = ["node", "nodes", "configfile"]
|
|||
|
__version__ = "2.0.10"
|
|||
|
__author__ = "Federico Luzzi"
|
|||
|
__pdoc__ = {
|
|||
|
'core': False,
|
|||
|
'connapp': False,
|
|||
|
}</code></pre>
|
|||
|
</details>
|
|||
|
</section>
|
|||
|
<section>
|
|||
|
</section>
|
|||
|
<section>
|
|||
|
</section>
|
|||
|
<section>
|
|||
|
</section>
|
|||
|
<section>
|
|||
|
<h2 class="section-title" id="header-classes">Classes</h2>
|
|||
|
<dl>
|
|||
|
<dt id="conn.configfile"><code class="flex name class">
|
|||
|
<span>class <span class="ident">configfile</span></span>
|
|||
|
<span>(</span><span>conf=None, *, key=None)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">class configfile:
|
|||
|
|
|||
|
def __init__(self, conf = None, *, key = None):
|
|||
|
home = os.path.expanduser("~")
|
|||
|
self.defaultdir = home + '/.config/conn'
|
|||
|
self.defaultfile = self.defaultdir + '/config.json'
|
|||
|
self.defaultkey = self.defaultdir + '/.osk'
|
|||
|
Path(self.defaultdir).mkdir(parents=True, exist_ok=True)
|
|||
|
if conf == None:
|
|||
|
self.file = self.defaultfile
|
|||
|
else:
|
|||
|
self.file = conf
|
|||
|
if key == None:
|
|||
|
self.key = self.defaultkey
|
|||
|
else:
|
|||
|
self.key = key
|
|||
|
if os.path.exists(self.file):
|
|||
|
config = self.loadconfig(self.file)
|
|||
|
else:
|
|||
|
config = self.createconfig(self.file)
|
|||
|
self.config = config["config"]
|
|||
|
self.connections = config["connections"]
|
|||
|
self.profiles = config["profiles"]
|
|||
|
if not os.path.exists(self.key):
|
|||
|
self.createkey(self.key)
|
|||
|
self.privatekey = RSA.import_key(open(self.key).read())
|
|||
|
self.publickey = self.privatekey.publickey()
|
|||
|
|
|||
|
|
|||
|
def loadconfig(self, conf):
|
|||
|
jsonconf = open(conf)
|
|||
|
return json.load(jsonconf)
|
|||
|
|
|||
|
def createconfig(self, conf):
|
|||
|
defaultconfig = {'config': {'case': False, 'idletime': 30}, 'connections': {}, 'profiles': { "default": { "host":"", "protocol":"ssh", "port":"", "user":"", "password":"", "options":"", "logs":"" }}}
|
|||
|
if not os.path.exists(conf):
|
|||
|
with open(conf, "w") as f:
|
|||
|
json.dump(defaultconfig, f, indent = 4)
|
|||
|
f.close()
|
|||
|
os.chmod(conf, 0o600)
|
|||
|
jsonconf = open(conf)
|
|||
|
return json.load(jsonconf)
|
|||
|
|
|||
|
def saveconfig(self, conf):
|
|||
|
newconfig = {"config":{}, "connections": {}, "profiles": {}}
|
|||
|
newconfig["config"] = self.config
|
|||
|
newconfig["connections"] = self.connections
|
|||
|
newconfig["profiles"] = self.profiles
|
|||
|
with open(conf, "w") as f:
|
|||
|
json.dump(newconfig, f, indent = 4)
|
|||
|
f.close()
|
|||
|
|
|||
|
def createkey(self, keyfile):
|
|||
|
key = RSA.generate(2048)
|
|||
|
with open(keyfile,'wb') as f:
|
|||
|
f.write(key.export_key('PEM'))
|
|||
|
f.close()
|
|||
|
os.chmod(keyfile, 0o600)
|
|||
|
|
|||
|
def _explode_unique(self, unique):
|
|||
|
uniques = unique.split("@")
|
|||
|
if not unique.startswith("@"):
|
|||
|
result = {"id": uniques[0]}
|
|||
|
else:
|
|||
|
result = {}
|
|||
|
if len(uniques) == 2:
|
|||
|
result["folder"] = uniques[1]
|
|||
|
if result["folder"] == "":
|
|||
|
return False
|
|||
|
elif len(uniques) == 3:
|
|||
|
result["folder"] = uniques[2]
|
|||
|
result["subfolder"] = uniques[1]
|
|||
|
if result["folder"] == "" or result["subfolder"] == "":
|
|||
|
return False
|
|||
|
elif len(uniques) > 3:
|
|||
|
return False
|
|||
|
return result
|
|||
|
|
|||
|
def getitem(self, unique, keys = None):
|
|||
|
uniques = self._explode_unique(unique)
|
|||
|
if unique.startswith("@"):
|
|||
|
if uniques.keys() >= {"folder", "subfolder"}:
|
|||
|
folder = self.connections[uniques["folder"]][uniques["subfolder"]]
|
|||
|
else:
|
|||
|
folder = self.connections[uniques["folder"]]
|
|||
|
newfolder = folder.copy()
|
|||
|
newfolder.pop("type")
|
|||
|
for node in newfolder.keys():
|
|||
|
if "type" in newfolder[node].keys():
|
|||
|
newfolder[node].pop("type")
|
|||
|
if keys == None:
|
|||
|
return newfolder
|
|||
|
else:
|
|||
|
f_newfolder = dict((k, newfolder[k]) for k in keys)
|
|||
|
return f_newfolder
|
|||
|
else:
|
|||
|
if uniques.keys() >= {"folder", "subfolder"}:
|
|||
|
node = self.connections[uniques["folder"]][uniques["subfolder"]][uniques["id"]]
|
|||
|
elif "folder" in uniques.keys():
|
|||
|
node = self.connections[uniques["folder"]][uniques["id"]]
|
|||
|
else:
|
|||
|
node = self.connections[uniques["id"]]
|
|||
|
newnode = node.copy()
|
|||
|
newnode.pop("type")
|
|||
|
return newnode
|
|||
|
|
|||
|
def _connections_add(self,*, id, host, folder='', subfolder='', options='', logs='', password='', port='', protocol='', user='', type = "connection" ):
|
|||
|
if folder == '':
|
|||
|
self.connections[id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "type": type}
|
|||
|
elif folder != '' and subfolder == '':
|
|||
|
self.connections[folder][id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "type": type}
|
|||
|
elif folder != '' and subfolder != '':
|
|||
|
self.connections[folder][subfolder][id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user, "type": type}
|
|||
|
|
|||
|
|
|||
|
def _connections_del(self,*, id, folder='', subfolder=''):
|
|||
|
if folder == '':
|
|||
|
del self.connections[id]
|
|||
|
elif folder != '' and subfolder == '':
|
|||
|
del self.connections[folder][id]
|
|||
|
elif folder != '' and subfolder != '':
|
|||
|
del self.connections[folder][subfolder][id]
|
|||
|
|
|||
|
def _folder_add(self,*, folder, subfolder = ''):
|
|||
|
if subfolder == '':
|
|||
|
if folder not in self.connections:
|
|||
|
self.connections[folder] = {"type": "folder"}
|
|||
|
else:
|
|||
|
if subfolder not in self.connections[folder]:
|
|||
|
self.connections[folder][subfolder] = {"type": "subfolder"}
|
|||
|
|
|||
|
def _folder_del(self,*, folder, subfolder=''):
|
|||
|
if subfolder == '':
|
|||
|
del self.connections[folder]
|
|||
|
else:
|
|||
|
del self.connections[folder][subfolder]
|
|||
|
|
|||
|
|
|||
|
def _profiles_add(self,*, id, host = '', options='', logs='', password='', port='', protocol='', user='' ):
|
|||
|
self.profiles[id] = {"host": host, "options": options, "logs": logs, "password": password, "port": port, "protocol": protocol, "user": user}
|
|||
|
|
|||
|
|
|||
|
def _profiles_del(self,*, id ):
|
|||
|
del self.profiles[id]</code></pre>
|
|||
|
</details>
|
|||
|
<h3>Methods</h3>
|
|||
|
<dl>
|
|||
|
<dt id="conn.configfile.createconfig"><code class="name flex">
|
|||
|
<span>def <span class="ident">createconfig</span></span>(<span>self, conf)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def createconfig(self, conf):
|
|||
|
defaultconfig = {'config': {'case': False, 'idletime': 30}, 'connections': {}, 'profiles': { "default": { "host":"", "protocol":"ssh", "port":"", "user":"", "password":"", "options":"", "logs":"" }}}
|
|||
|
if not os.path.exists(conf):
|
|||
|
with open(conf, "w") as f:
|
|||
|
json.dump(defaultconfig, f, indent = 4)
|
|||
|
f.close()
|
|||
|
os.chmod(conf, 0o600)
|
|||
|
jsonconf = open(conf)
|
|||
|
return json.load(jsonconf)</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
<dt id="conn.configfile.createkey"><code class="name flex">
|
|||
|
<span>def <span class="ident">createkey</span></span>(<span>self, keyfile)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def createkey(self, keyfile):
|
|||
|
key = RSA.generate(2048)
|
|||
|
with open(keyfile,'wb') as f:
|
|||
|
f.write(key.export_key('PEM'))
|
|||
|
f.close()
|
|||
|
os.chmod(keyfile, 0o600)</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
<dt id="conn.configfile.getitem"><code class="name flex">
|
|||
|
<span>def <span class="ident">getitem</span></span>(<span>self, unique, keys=None)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def getitem(self, unique, keys = None):
|
|||
|
uniques = self._explode_unique(unique)
|
|||
|
if unique.startswith("@"):
|
|||
|
if uniques.keys() >= {"folder", "subfolder"}:
|
|||
|
folder = self.connections[uniques["folder"]][uniques["subfolder"]]
|
|||
|
else:
|
|||
|
folder = self.connections[uniques["folder"]]
|
|||
|
newfolder = folder.copy()
|
|||
|
newfolder.pop("type")
|
|||
|
for node in newfolder.keys():
|
|||
|
if "type" in newfolder[node].keys():
|
|||
|
newfolder[node].pop("type")
|
|||
|
if keys == None:
|
|||
|
return newfolder
|
|||
|
else:
|
|||
|
f_newfolder = dict((k, newfolder[k]) for k in keys)
|
|||
|
return f_newfolder
|
|||
|
else:
|
|||
|
if uniques.keys() >= {"folder", "subfolder"}:
|
|||
|
node = self.connections[uniques["folder"]][uniques["subfolder"]][uniques["id"]]
|
|||
|
elif "folder" in uniques.keys():
|
|||
|
node = self.connections[uniques["folder"]][uniques["id"]]
|
|||
|
else:
|
|||
|
node = self.connections[uniques["id"]]
|
|||
|
newnode = node.copy()
|
|||
|
newnode.pop("type")
|
|||
|
return newnode</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
<dt id="conn.configfile.loadconfig"><code class="name flex">
|
|||
|
<span>def <span class="ident">loadconfig</span></span>(<span>self, conf)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def loadconfig(self, conf):
|
|||
|
jsonconf = open(conf)
|
|||
|
return json.load(jsonconf)</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
<dt id="conn.configfile.saveconfig"><code class="name flex">
|
|||
|
<span>def <span class="ident">saveconfig</span></span>(<span>self, conf)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def saveconfig(self, conf):
|
|||
|
newconfig = {"config":{}, "connections": {}, "profiles": {}}
|
|||
|
newconfig["config"] = self.config
|
|||
|
newconfig["connections"] = self.connections
|
|||
|
newconfig["profiles"] = self.profiles
|
|||
|
with open(conf, "w") as f:
|
|||
|
json.dump(newconfig, f, indent = 4)
|
|||
|
f.close()</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
</dl>
|
|||
|
</dd>
|
|||
|
<dt id="conn.node"><code class="flex name class">
|
|||
|
<span>class <span class="ident">node</span></span>
|
|||
|
<span>(</span><span>unique, host, options='', logs='', password='', port='', protocol='', user='', config='')</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"><p>This class generates a node object. Containts all the information and methods to connect and interact with a device using ssh or telnet.</p>
|
|||
|
<p>Attributes:
|
|||
|
</p>
|
|||
|
<pre><code>- output (str) -- Output of the commands you ran with run or test
|
|||
|
-- method.
|
|||
|
- result(bool) -- True if expected value is found after running
|
|||
|
-- the commands using test method.
|
|||
|
</code></pre>
|
|||
|
<p>Parameters:
|
|||
|
</p>
|
|||
|
<pre><code>- unique (str) -- Unique name to assign to the node.
|
|||
|
- host (str) -- IP address or hostname of the node.
|
|||
|
</code></pre>
|
|||
|
<p>Optional Parameters:
|
|||
|
</p>
|
|||
|
<pre><code>- options (str) -- Additional options to pass the ssh/telnet for
|
|||
|
-- connection.
|
|||
|
- logs (str) -- Path/file for storing the logs. You can use
|
|||
|
-- ${unique},${host}, ${port}, ${user}, ${protocol}
|
|||
|
-- as variables.
|
|||
|
- password (str) -- Encrypted or plaintext password.
|
|||
|
- port (str) -- Port to connect to node, default 22 for ssh and 23
|
|||
|
-- for telnet.
|
|||
|
- protocol (str) -- Select ssh or telnet. Default is ssh.
|
|||
|
- user (str) -- Username to of the node.
|
|||
|
- config (obj) -- Pass the object created with class configfile with
|
|||
|
-- key for decryption and extra configuration if you
|
|||
|
-- are using connection manager.
|
|||
|
</code></pre></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">class node:
|
|||
|
''' This class generates a node object. Containts all the information and methods to connect and interact with a device using ssh or telnet.
|
|||
|
|
|||
|
Attributes:
|
|||
|
|
|||
|
- output (str) -- Output of the commands you ran with run or test
|
|||
|
-- method.
|
|||
|
- result(bool) -- True if expected value is found after running
|
|||
|
-- the commands using test method.
|
|||
|
'''
|
|||
|
|
|||
|
def __init__(self, unique, host, options='', logs='', password='', port='', protocol='', user='', config=''):
|
|||
|
'''
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
- unique (str) -- Unique name to assign to the node.
|
|||
|
- host (str) -- IP address or hostname of the node.
|
|||
|
|
|||
|
Optional Parameters:
|
|||
|
|
|||
|
- options (str) -- Additional options to pass the ssh/telnet for
|
|||
|
-- connection.
|
|||
|
- logs (str) -- Path/file for storing the logs. You can use
|
|||
|
-- ${unique},${host}, ${port}, ${user}, ${protocol}
|
|||
|
-- as variables.
|
|||
|
- password (str) -- Encrypted or plaintext password.
|
|||
|
- port (str) -- Port to connect to node, default 22 for ssh and 23
|
|||
|
-- for telnet.
|
|||
|
- protocol (str) -- Select ssh or telnet. Default is ssh.
|
|||
|
- user (str) -- Username to of the node.
|
|||
|
- config (obj) -- Pass the object created with class configfile with
|
|||
|
-- key for decryption and extra configuration if you
|
|||
|
-- are using connection manager.
|
|||
|
'''
|
|||
|
if config == '':
|
|||
|
self.idletime = 0
|
|||
|
self.key = None
|
|||
|
else:
|
|||
|
self.idletime = config.config["idletime"]
|
|||
|
self.key = config.key
|
|||
|
self.unique = unique
|
|||
|
attr = {"host": host, "logs": logs, "options":options, "port": port, "protocol": protocol, "user": user}
|
|||
|
for key in attr:
|
|||
|
profile = re.search("^@(.*)", attr[key])
|
|||
|
if profile and config != '':
|
|||
|
setattr(self,key,config.profiles[profile.group(1)][key])
|
|||
|
elif attr[key] == '' and key == "protocol":
|
|||
|
try:
|
|||
|
setattr(self,key,config.profiles["default"][key])
|
|||
|
except:
|
|||
|
setattr(self,key,"ssh")
|
|||
|
else:
|
|||
|
setattr(self,key,attr[key])
|
|||
|
if isinstance(password,list):
|
|||
|
self.password = []
|
|||
|
for i, s in enumerate(password):
|
|||
|
profile = re.search("^@(.*)", password[i])
|
|||
|
if profile and config != '':
|
|||
|
self.password.append(config.profiles[profile.group(1)]["password"])
|
|||
|
else:
|
|||
|
self.password = [password]
|
|||
|
|
|||
|
def __passtx(self, passwords, *, keyfile=None):
|
|||
|
# decrypts passwords, used by other methdos.
|
|||
|
dpass = []
|
|||
|
if keyfile is None:
|
|||
|
keyfile = self.key
|
|||
|
if keyfile is not None:
|
|||
|
key = RSA.import_key(open(keyfile).read())
|
|||
|
decryptor = PKCS1_OAEP.new(key)
|
|||
|
for passwd in passwords:
|
|||
|
if not re.match('^b[\"\'].+[\"\']$', passwd):
|
|||
|
dpass.append(passwd)
|
|||
|
else:
|
|||
|
try:
|
|||
|
decrypted = decryptor.decrypt(ast.literal_eval(passwd)).decode("utf-8")
|
|||
|
dpass.append(decrypted)
|
|||
|
except:
|
|||
|
raise ValueError("Missing or corrupted key")
|
|||
|
return dpass
|
|||
|
|
|||
|
|
|||
|
|
|||
|
def _logfile(self, logfile = None):
|
|||
|
# translate logs variables and generate logs path.
|
|||
|
if logfile == None:
|
|||
|
logfile = self.logs
|
|||
|
logfile = logfile.replace("${unique}", self.unique)
|
|||
|
logfile = logfile.replace("${host}", self.host)
|
|||
|
logfile = logfile.replace("${port}", self.port)
|
|||
|
logfile = logfile.replace("${user}", self.user)
|
|||
|
logfile = logfile.replace("${protocol}", self.protocol)
|
|||
|
now = datetime.datetime.now()
|
|||
|
dateconf = re.search(r'\$\{date \'(.*)\'}', logfile)
|
|||
|
if dateconf:
|
|||
|
logfile = re.sub(r'\$\{date (.*)}',now.strftime(dateconf.group(1)), logfile)
|
|||
|
return logfile
|
|||
|
|
|||
|
def _logclean(self, logfile, var = False):
|
|||
|
#Remove special ascii characters and other stuff from logfile.
|
|||
|
if var == False:
|
|||
|
t = open(logfile, "r").read()
|
|||
|
else:
|
|||
|
t = logfile
|
|||
|
t = t.replace("\n","",1).replace("\a","")
|
|||
|
t = t.replace('\n\n', '\n')
|
|||
|
t = re.sub(r'.\[K', '', t)
|
|||
|
while True:
|
|||
|
tb = re.sub('.\b', '', t, count=1)
|
|||
|
if len(t) == len(tb):
|
|||
|
break
|
|||
|
t = tb
|
|||
|
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/ ]*[@-~])')
|
|||
|
t = ansi_escape.sub('', t)
|
|||
|
if var == False:
|
|||
|
d = open(logfile, "w")
|
|||
|
d.write(t)
|
|||
|
d.close()
|
|||
|
return
|
|||
|
else:
|
|||
|
return t
|
|||
|
|
|||
|
def interact(self, debug = False):
|
|||
|
'''
|
|||
|
Allow user to interact with the node directly, mostly used by connection manager.
|
|||
|
|
|||
|
Optional Parameters:
|
|||
|
|
|||
|
- debug (bool) -- If True, display all the connecting information
|
|||
|
-- before interact. Default False.
|
|||
|
'''
|
|||
|
connect = self._connect(debug = debug)
|
|||
|
if connect == True:
|
|||
|
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)))
|
|||
|
print("Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
|||
|
if 'logfile' in dir(self):
|
|||
|
self.child.logfile_read = open(self.logfile, "wb")
|
|||
|
elif debug:
|
|||
|
self.child.logfile_read = None
|
|||
|
if 'missingtext' in dir(self):
|
|||
|
print(self.child.after.decode(), end='')
|
|||
|
self.child.interact()
|
|||
|
if "logfile" in dir(self) and not debug:
|
|||
|
self._logclean(self.logfile)
|
|||
|
else:
|
|||
|
print(connect)
|
|||
|
exit(1)
|
|||
|
|
|||
|
def run(self, commands,*, folder = '', prompt = r'>$|#$|\$$|>.$|#.$|\$.$', stdout = False):
|
|||
|
'''
|
|||
|
Run a command or list of commands on the node and return the output.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
- commands (str/list) -- Commands to run on the node. Should be
|
|||
|
-- str or a list of str.
|
|||
|
|
|||
|
Optional Named Parameters:
|
|||
|
|
|||
|
- folder (str) -- Path where output log should be stored, leave
|
|||
|
-- empty to disable logging.
|
|||
|
- prompt (str) -- Prompt to be expected after a command is finished
|
|||
|
-- running. Usually linux uses ">" or EOF while
|
|||
|
-- routers use ">" or "#". The default value should
|
|||
|
-- work for most nodes. Change it if your connection
|
|||
|
-- need some special symbol.
|
|||
|
- stdout (bool) -- Set True to send the command output to stdout.
|
|||
|
-- default False.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
str -> Output of the commands you ran on the node.
|
|||
|
|
|||
|
'''
|
|||
|
connect = self._connect()
|
|||
|
if connect == True:
|
|||
|
expects = [prompt, pexpect.EOF]
|
|||
|
output = ''
|
|||
|
if isinstance(commands, list):
|
|||
|
for c in commands:
|
|||
|
result = self.child.expect(expects)
|
|||
|
self.child.sendline(c)
|
|||
|
if result == 0:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
if result == 1:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
else:
|
|||
|
result = self.child.expect(expects)
|
|||
|
self.child.sendline(commands)
|
|||
|
if result == 0:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
if result == 1:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
result = self.child.expect(expects)
|
|||
|
if result == 0:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
if result == 1:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
self.child.close()
|
|||
|
output = output.lstrip()
|
|||
|
if stdout == True:
|
|||
|
print(output)
|
|||
|
if folder != '':
|
|||
|
with open(folder + "/" + self.unique, "w") as f:
|
|||
|
f.write(output)
|
|||
|
f.close()
|
|||
|
self._logclean(folder + "/" + self.unique)
|
|||
|
self.output = output
|
|||
|
return output
|
|||
|
else:
|
|||
|
self.output = connect
|
|||
|
return connect
|
|||
|
|
|||
|
def test(self, commands, expected, *, prompt = r'>$|#$|\$$|>.$|#.$|\$.$'):
|
|||
|
'''
|
|||
|
Run a command or list of commands on the node, then check if expected value appears on the output after the last command.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
- commands (str/list) -- Commands to run on the node. Should be
|
|||
|
-- str or list of str.
|
|||
|
- expected (str) -- Expected text to appear after running
|
|||
|
-- all the commands on the node.
|
|||
|
|
|||
|
Optional Named Parameters:
|
|||
|
|
|||
|
- prompt (str) -- Prompt to be expected after a command is finished
|
|||
|
-- running. Usually linux uses ">" or EOF while
|
|||
|
-- routers use ">" or "#". The default value should
|
|||
|
-- work for most nodes. Change it if your connection
|
|||
|
-- need some special symbol.
|
|||
|
|
|||
|
### Returns:
|
|||
|
bool -- true if expected value is found after running the commands
|
|||
|
false if prompt is found before.
|
|||
|
|
|||
|
'''
|
|||
|
connect = self._connect()
|
|||
|
if connect == True:
|
|||
|
expects = [prompt, pexpect.EOF]
|
|||
|
output = ''
|
|||
|
if isinstance(commands, list):
|
|||
|
for c in commands:
|
|||
|
result = self.child.expect(expects)
|
|||
|
self.child.sendline(c)
|
|||
|
if result == 0:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
if result == 1:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
else:
|
|||
|
self.child.expect(expects)
|
|||
|
self.child.sendline(commands)
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
expects = [expected, prompt, pexpect.EOF]
|
|||
|
results = self.child.expect(expects)
|
|||
|
if results == 0:
|
|||
|
self.child.close()
|
|||
|
self.result = True
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
output = output.lstrip()
|
|||
|
self.output = output
|
|||
|
return True
|
|||
|
if results in [1, 2]:
|
|||
|
self.child.close()
|
|||
|
self.result = False
|
|||
|
if results == 1:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
elif results == 2:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
output = output.lstrip()
|
|||
|
self.output = output
|
|||
|
return False
|
|||
|
else:
|
|||
|
self.result = None
|
|||
|
self.output = connect
|
|||
|
return connect
|
|||
|
|
|||
|
def _connect(self, debug = False):
|
|||
|
# 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.idletime > 0:
|
|||
|
cmd = cmd + " -o ServerAliveInterval=" + str(self.idletime)
|
|||
|
if self.user == '':
|
|||
|
cmd = cmd + " -t {}".format(self.host)
|
|||
|
else:
|
|||
|
cmd = cmd + " -t {}".format("@".join([self.user,self.host]))
|
|||
|
if self.port != '':
|
|||
|
cmd = cmd + " -p " + self.port
|
|||
|
if self.options != '':
|
|||
|
cmd = cmd + " " + self.options
|
|||
|
if self.logs != '':
|
|||
|
self.logfile = self._logfile()
|
|||
|
if self.password[0] != '':
|
|||
|
passwords = self.__passtx(self.password)
|
|||
|
else:
|
|||
|
passwords = []
|
|||
|
expects = ['yes/no', 'refused', 'supported', 'cipher', 'sage', 'timeout', 'unavailable', 'closed', '[p|P]assword:|[u|U]sername:', r'>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, "No route to host", "resolve hostname", "no matching host key"]
|
|||
|
elif self.protocol == "telnet":
|
|||
|
cmd = "telnet " + self.host
|
|||
|
if self.port != '':
|
|||
|
cmd = cmd + " " + self.port
|
|||
|
if self.options != '':
|
|||
|
cmd = cmd + " " + self.options
|
|||
|
if self.logs != '':
|
|||
|
self.logfile = self._logfile()
|
|||
|
if self.password[0] != '':
|
|||
|
passwords = self.__passtx(self.password)
|
|||
|
else:
|
|||
|
passwords = []
|
|||
|
expects = ['[u|U]sername:', 'refused', 'supported', 'cipher', 'sage', 'timeout', 'unavailable', 'closed', '[p|P]assword:', r'>$|#$|\$$|>.$|#.$|\$.$', 'suspend', pexpect.EOF, "No route to host", "resolve hostname", "no matching host key"]
|
|||
|
else:
|
|||
|
raise ValueError("Invalid protocol: " + self.protocol)
|
|||
|
child = pexpect.spawn(cmd)
|
|||
|
if debug:
|
|||
|
child.logfile_read = sys.stdout.buffer
|
|||
|
if len(passwords) > 0:
|
|||
|
loops = len(passwords)
|
|||
|
else:
|
|||
|
loops = 1
|
|||
|
endloop = False
|
|||
|
for i in range(0, loops):
|
|||
|
while True:
|
|||
|
results = child.expect(expects)
|
|||
|
if results == 0:
|
|||
|
if self.protocol == "ssh":
|
|||
|
child.sendline('yes')
|
|||
|
elif self.protocol == "telnet":
|
|||
|
if self.user != '':
|
|||
|
child.sendline(self.user)
|
|||
|
else:
|
|||
|
self.missingtext = True
|
|||
|
break
|
|||
|
if results in [1, 2, 3, 4, 5, 6, 7, 12, 13, 14]:
|
|||
|
child.close()
|
|||
|
return "Connection failed code:" + str(results)
|
|||
|
if results == 8:
|
|||
|
if len(passwords) > 0:
|
|||
|
child.sendline(passwords[i])
|
|||
|
else:
|
|||
|
self.missingtext = True
|
|||
|
break
|
|||
|
if results in [9, 11]:
|
|||
|
endloop = True
|
|||
|
child.sendline()
|
|||
|
break
|
|||
|
if results == 10:
|
|||
|
child.sendline("\r")
|
|||
|
sleep(2)
|
|||
|
if endloop:
|
|||
|
break
|
|||
|
child.readline(0)
|
|||
|
self.child = child
|
|||
|
return True</code></pre>
|
|||
|
</details>
|
|||
|
<h3>Methods</h3>
|
|||
|
<dl>
|
|||
|
<dt id="conn.node.interact"><code class="name flex">
|
|||
|
<span>def <span class="ident">interact</span></span>(<span>self, debug=False)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"><p>Allow user to interact with the node directly, mostly used by connection manager.</p>
|
|||
|
<p>Optional Parameters:
|
|||
|
</p>
|
|||
|
<pre><code>- debug (bool) -- If True, display all the connecting information
|
|||
|
-- before interact. Default False.
|
|||
|
</code></pre></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def interact(self, debug = False):
|
|||
|
'''
|
|||
|
Allow user to interact with the node directly, mostly used by connection manager.
|
|||
|
|
|||
|
Optional Parameters:
|
|||
|
|
|||
|
- debug (bool) -- If True, display all the connecting information
|
|||
|
-- before interact. Default False.
|
|||
|
'''
|
|||
|
connect = self._connect(debug = debug)
|
|||
|
if connect == True:
|
|||
|
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)))
|
|||
|
print("Connected to " + self.unique + " at " + self.host + (":" if self.port != '' else '') + self.port + " via: " + self.protocol)
|
|||
|
if 'logfile' in dir(self):
|
|||
|
self.child.logfile_read = open(self.logfile, "wb")
|
|||
|
elif debug:
|
|||
|
self.child.logfile_read = None
|
|||
|
if 'missingtext' in dir(self):
|
|||
|
print(self.child.after.decode(), end='')
|
|||
|
self.child.interact()
|
|||
|
if "logfile" in dir(self) and not debug:
|
|||
|
self._logclean(self.logfile)
|
|||
|
else:
|
|||
|
print(connect)
|
|||
|
exit(1)</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
<dt id="conn.node.run"><code class="name flex">
|
|||
|
<span>def <span class="ident">run</span></span>(<span>self, commands, *, folder='', prompt='>$|#$|\\$$|>.$|#.$|\\$.$', stdout=False)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"><p>Run a command or list of commands on the node and return the output.</p>
|
|||
|
<p>Parameters:
|
|||
|
</p>
|
|||
|
<pre><code>- commands (str/list) -- Commands to run on the node. Should be
|
|||
|
-- str or a list of str.
|
|||
|
</code></pre>
|
|||
|
<p>Optional Named Parameters:
|
|||
|
</p>
|
|||
|
<pre><code>- folder (str) -- Path where output log should be stored, leave
|
|||
|
-- empty to disable logging.
|
|||
|
- prompt (str) -- Prompt to be expected after a command is finished
|
|||
|
-- running. Usually linux uses ">" or EOF while
|
|||
|
-- routers use ">" or "#". The default value should
|
|||
|
-- work for most nodes. Change it if your connection
|
|||
|
-- need some special symbol.
|
|||
|
- stdout (bool) -- Set True to send the command output to stdout.
|
|||
|
-- default False.
|
|||
|
</code></pre>
|
|||
|
<p>Returns:
|
|||
|
</p>
|
|||
|
<pre><code>str -> Output of the commands you ran on the node.
|
|||
|
</code></pre></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def run(self, commands,*, folder = '', prompt = r'>$|#$|\$$|>.$|#.$|\$.$', stdout = False):
|
|||
|
'''
|
|||
|
Run a command or list of commands on the node and return the output.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
- commands (str/list) -- Commands to run on the node. Should be
|
|||
|
-- str or a list of str.
|
|||
|
|
|||
|
Optional Named Parameters:
|
|||
|
|
|||
|
- folder (str) -- Path where output log should be stored, leave
|
|||
|
-- empty to disable logging.
|
|||
|
- prompt (str) -- Prompt to be expected after a command is finished
|
|||
|
-- running. Usually linux uses ">" or EOF while
|
|||
|
-- routers use ">" or "#". The default value should
|
|||
|
-- work for most nodes. Change it if your connection
|
|||
|
-- need some special symbol.
|
|||
|
- stdout (bool) -- Set True to send the command output to stdout.
|
|||
|
-- default False.
|
|||
|
|
|||
|
Returns:
|
|||
|
|
|||
|
str -> Output of the commands you ran on the node.
|
|||
|
|
|||
|
'''
|
|||
|
connect = self._connect()
|
|||
|
if connect == True:
|
|||
|
expects = [prompt, pexpect.EOF]
|
|||
|
output = ''
|
|||
|
if isinstance(commands, list):
|
|||
|
for c in commands:
|
|||
|
result = self.child.expect(expects)
|
|||
|
self.child.sendline(c)
|
|||
|
if result == 0:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
if result == 1:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
else:
|
|||
|
result = self.child.expect(expects)
|
|||
|
self.child.sendline(commands)
|
|||
|
if result == 0:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
if result == 1:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
result = self.child.expect(expects)
|
|||
|
if result == 0:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
if result == 1:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
self.child.close()
|
|||
|
output = output.lstrip()
|
|||
|
if stdout == True:
|
|||
|
print(output)
|
|||
|
if folder != '':
|
|||
|
with open(folder + "/" + self.unique, "w") as f:
|
|||
|
f.write(output)
|
|||
|
f.close()
|
|||
|
self._logclean(folder + "/" + self.unique)
|
|||
|
self.output = output
|
|||
|
return output
|
|||
|
else:
|
|||
|
self.output = connect
|
|||
|
return connect</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
<dt id="conn.node.test"><code class="name flex">
|
|||
|
<span>def <span class="ident">test</span></span>(<span>self, commands, expected, *, prompt='>$|#$|\\$$|>.$|#.$|\\$.$')</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"><p>Run a command or list of commands on the node, then check if expected value appears on the output after the last command.</p>
|
|||
|
<p>Parameters:
|
|||
|
</p>
|
|||
|
<pre><code>- commands (str/list) -- Commands to run on the node. Should be
|
|||
|
-- str or list of str.
|
|||
|
- expected (str) -- Expected text to appear after running
|
|||
|
-- all the commands on the node.
|
|||
|
</code></pre>
|
|||
|
<p>Optional Named Parameters: </p>
|
|||
|
<pre><code>- prompt (str) -- Prompt to be expected after a command is finished
|
|||
|
-- running. Usually linux uses ">" or EOF while
|
|||
|
-- routers use ">" or "#". The default value should
|
|||
|
-- work for most nodes. Change it if your connection
|
|||
|
-- need some special symbol.
|
|||
|
</code></pre>
|
|||
|
<h3 id="returns">Returns:</h3>
|
|||
|
<pre><code>bool -- true if expected value is found after running the commands
|
|||
|
false if prompt is found before.
|
|||
|
</code></pre></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def test(self, commands, expected, *, prompt = r'>$|#$|\$$|>.$|#.$|\$.$'):
|
|||
|
'''
|
|||
|
Run a command or list of commands on the node, then check if expected value appears on the output after the last command.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
- commands (str/list) -- Commands to run on the node. Should be
|
|||
|
-- str or list of str.
|
|||
|
- expected (str) -- Expected text to appear after running
|
|||
|
-- all the commands on the node.
|
|||
|
|
|||
|
Optional Named Parameters:
|
|||
|
|
|||
|
- prompt (str) -- Prompt to be expected after a command is finished
|
|||
|
-- running. Usually linux uses ">" or EOF while
|
|||
|
-- routers use ">" or "#". The default value should
|
|||
|
-- work for most nodes. Change it if your connection
|
|||
|
-- need some special symbol.
|
|||
|
|
|||
|
### Returns:
|
|||
|
bool -- true if expected value is found after running the commands
|
|||
|
false if prompt is found before.
|
|||
|
|
|||
|
'''
|
|||
|
connect = self._connect()
|
|||
|
if connect == True:
|
|||
|
expects = [prompt, pexpect.EOF]
|
|||
|
output = ''
|
|||
|
if isinstance(commands, list):
|
|||
|
for c in commands:
|
|||
|
result = self.child.expect(expects)
|
|||
|
self.child.sendline(c)
|
|||
|
if result == 0:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
if result == 1:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
else:
|
|||
|
self.child.expect(expects)
|
|||
|
self.child.sendline(commands)
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
expects = [expected, prompt, pexpect.EOF]
|
|||
|
results = self.child.expect(expects)
|
|||
|
if results == 0:
|
|||
|
self.child.close()
|
|||
|
self.result = True
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
output = output.lstrip()
|
|||
|
self.output = output
|
|||
|
return True
|
|||
|
if results in [1, 2]:
|
|||
|
self.child.close()
|
|||
|
self.result = False
|
|||
|
if results == 1:
|
|||
|
output = output + self.child.before.decode() + self.child.after.decode()
|
|||
|
elif results == 2:
|
|||
|
output = output + self.child.before.decode()
|
|||
|
output = output.lstrip()
|
|||
|
self.output = output
|
|||
|
return False
|
|||
|
else:
|
|||
|
self.result = None
|
|||
|
self.output = connect
|
|||
|
return connect</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
</dl>
|
|||
|
</dd>
|
|||
|
<dt id="conn.nodes"><code class="flex name class">
|
|||
|
<span>class <span class="ident">nodes</span></span>
|
|||
|
<span>(</span><span>nodes: dict, config='')</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"><p>This class generates a nodes object. Contains a list of node class objects and methods to run multiple tasks on nodes simultaneously.</p>
|
|||
|
<h3 id="attributes">Attributes:</h3>
|
|||
|
<pre><code>- nodelist (list): List of node class objects passed to the init
|
|||
|
function.
|
|||
|
|
|||
|
- output (dict): Dictionary formed by nodes unique as keys,
|
|||
|
output of the commands you ran on the node as
|
|||
|
value. Created after running methods run or test.
|
|||
|
|
|||
|
- result (dict): Dictionary formed by nodes unique as keys, value
|
|||
|
is True if expected value is found after running
|
|||
|
the commands, False if prompt is found before.
|
|||
|
Created after running method test.
|
|||
|
|
|||
|
- <unique> (obj): For each item in nodelist, there is an attribute
|
|||
|
generated with the node unique.
|
|||
|
</code></pre>
|
|||
|
<h3 id="parameters">Parameters:</h3>
|
|||
|
<pre><code>- nodes (dict): Dictionary formed by node information:
|
|||
|
Keys: Unique name for each node.
|
|||
|
Mandatory Subkeys: host(str).
|
|||
|
Optional Subkeys: options(str), logs(str), password(str),
|
|||
|
port(str), protocol(str), user(str).
|
|||
|
For reference on subkeys check node class.
|
|||
|
</code></pre>
|
|||
|
<p>Optional Parameters:
|
|||
|
</p>
|
|||
|
<pre><code>- config (obj): Pass the object created with class configfile with key
|
|||
|
for decryption and extra configuration if you are using
|
|||
|
connection manager.
|
|||
|
</code></pre></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">class nodes:
|
|||
|
''' This class generates a nodes object. Contains a list of node class objects and methods to run multiple tasks on nodes simultaneously.
|
|||
|
|
|||
|
### Attributes:
|
|||
|
|
|||
|
- nodelist (list): List of node class objects passed to the init
|
|||
|
function.
|
|||
|
|
|||
|
- output (dict): Dictionary formed by nodes unique as keys,
|
|||
|
output of the commands you ran on the node as
|
|||
|
value. Created after running methods run or test.
|
|||
|
|
|||
|
- result (dict): Dictionary formed by nodes unique as keys, value
|
|||
|
is True if expected value is found after running
|
|||
|
the commands, False if prompt is found before.
|
|||
|
Created after running method test.
|
|||
|
|
|||
|
- <unique> (obj): For each item in nodelist, there is an attribute
|
|||
|
generated with the node unique.
|
|||
|
'''
|
|||
|
|
|||
|
def __init__(self, nodes: dict, config = ''):
|
|||
|
'''
|
|||
|
### Parameters:
|
|||
|
|
|||
|
- nodes (dict): Dictionary formed by node information:
|
|||
|
Keys: Unique name for each node.
|
|||
|
Mandatory Subkeys: host(str).
|
|||
|
Optional Subkeys: options(str), logs(str), password(str),
|
|||
|
port(str), protocol(str), user(str).
|
|||
|
For reference on subkeys check node class.
|
|||
|
|
|||
|
Optional Parameters:
|
|||
|
|
|||
|
- config (obj): Pass the object created with class configfile with key
|
|||
|
for decryption and extra configuration if you are using
|
|||
|
connection manager.
|
|||
|
'''
|
|||
|
self.nodelist = []
|
|||
|
self.config = config
|
|||
|
for n in nodes:
|
|||
|
this = node(n, **nodes[n], config = config)
|
|||
|
self.nodelist.append(this)
|
|||
|
setattr(self,n,this)
|
|||
|
|
|||
|
|
|||
|
def _splitlist(self, lst, n):
|
|||
|
#split a list in lists of n members.
|
|||
|
for i in range(0, len(lst), n):
|
|||
|
yield lst[i:i + n]
|
|||
|
|
|||
|
|
|||
|
def run(self, commands,*, folder = None, prompt = None, stdout = None, parallel = 10):
|
|||
|
'''
|
|||
|
Run a command or list of commands on all the nodes in nodelist.
|
|||
|
|
|||
|
Parameters:
|
|||
|
commands (str/list): Commands to run on the node. Should be a str or a list of str.
|
|||
|
|
|||
|
Optional Named Parameters:
|
|||
|
folder (str): Path where output log should be stored, leave empty to disable logging.
|
|||
|
prompt (str): Prompt to be expected after a command is finished running. Usually linux uses ">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol.
|
|||
|
stdout (bool): Set True to send the command output to stdout. default False.
|
|||
|
parallel (int): Number of nodes to run the commands simultaneously. Default is 10, if there are more nodes that this value, nodes are groups in groups with max this number of members.
|
|||
|
|
|||
|
Returns:
|
|||
|
dict: Dictionary formed by nodes unique as keys, Output of the commands you ran on the node as value.
|
|||
|
|
|||
|
'''
|
|||
|
args = {}
|
|||
|
args["commands"] = commands
|
|||
|
if folder != None:
|
|||
|
args["folder"] = folder
|
|||
|
if prompt != None:
|
|||
|
args["prompt"] = prompt
|
|||
|
if stdout != None:
|
|||
|
args["stdout"] = stdout
|
|||
|
output = {}
|
|||
|
tasks = []
|
|||
|
for n in self.nodelist:
|
|||
|
tasks.append(threading.Thread(target=n.run, kwargs=args))
|
|||
|
taskslist = list(self._splitlist(tasks, parallel))
|
|||
|
for t in taskslist:
|
|||
|
for i in t:
|
|||
|
i.start()
|
|||
|
for i in t:
|
|||
|
i.join()
|
|||
|
for i in self.nodelist:
|
|||
|
output[i.unique] = i.output
|
|||
|
self.output = output
|
|||
|
return output
|
|||
|
|
|||
|
def test(self, commands, expected, *, prompt = None, parallel = 10):
|
|||
|
'''
|
|||
|
Run a command or list of commands on all the nodes in nodelist, then check if expected value appears on the output after the last command.
|
|||
|
|
|||
|
Parameters:
|
|||
|
commands (str/list): Commands to run on the node. Should be a str or a list of str.
|
|||
|
commands (str): Expected text to appear after running all the commands on the node.
|
|||
|
|
|||
|
Optional Named Parameters:
|
|||
|
prompt (str): Prompt to be expected after a command is finished running. Usually linux uses ">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol.
|
|||
|
|
|||
|
Returns:
|
|||
|
dict: Dictionary formed by nodes unique as keys, value is True if expected value is found after running the commands, False if prompt is found before.
|
|||
|
|
|||
|
'''
|
|||
|
args = {}
|
|||
|
args["commands"] = commands
|
|||
|
args["expected"] = expected
|
|||
|
if prompt != None:
|
|||
|
args["prompt"] = prompt
|
|||
|
output = {}
|
|||
|
result = {}
|
|||
|
tasks = []
|
|||
|
for n in self.nodelist:
|
|||
|
tasks.append(threading.Thread(target=n.test, kwargs=args))
|
|||
|
taskslist = list(self._splitlist(tasks, parallel))
|
|||
|
for t in taskslist:
|
|||
|
for i in t:
|
|||
|
i.start()
|
|||
|
for i in t:
|
|||
|
i.join()
|
|||
|
for i in self.nodelist:
|
|||
|
result[i.unique] = i.result
|
|||
|
output[i.unique] = i.output
|
|||
|
self.output = output
|
|||
|
self.result = result
|
|||
|
return result</code></pre>
|
|||
|
</details>
|
|||
|
<h3>Methods</h3>
|
|||
|
<dl>
|
|||
|
<dt id="conn.nodes.run"><code class="name flex">
|
|||
|
<span>def <span class="ident">run</span></span>(<span>self, commands, *, folder=None, prompt=None, stdout=None, parallel=10)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"><p>Run a command or list of commands on all the nodes in nodelist.</p>
|
|||
|
<p>Parameters:<br>
|
|||
|
commands (str/list): Commands to run on the node. Should be a str or a list of str.</p>
|
|||
|
<p>Optional Named Parameters:<br>
|
|||
|
folder
|
|||
|
(str): Path where output log should be stored, leave empty to disable logging.<br>
|
|||
|
prompt
|
|||
|
(str): Prompt to be expected after a command is finished running. Usually linux uses
|
|||
|
">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol.<br>
|
|||
|
stdout
|
|||
|
(bool): Set True to send the command output to stdout. default False.<br>
|
|||
|
parallel (int): Number of nodes to run the commands simultaneously. Default is 10, if there are more nodes that this value, nodes are groups in groups with max this number of members.</p>
|
|||
|
<p>Returns:<br>
|
|||
|
dict: Dictionary formed by nodes unique as keys, Output of the commands you ran on the node as value.</p></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def run(self, commands,*, folder = None, prompt = None, stdout = None, parallel = 10):
|
|||
|
'''
|
|||
|
Run a command or list of commands on all the nodes in nodelist.
|
|||
|
|
|||
|
Parameters:
|
|||
|
commands (str/list): Commands to run on the node. Should be a str or a list of str.
|
|||
|
|
|||
|
Optional Named Parameters:
|
|||
|
folder (str): Path where output log should be stored, leave empty to disable logging.
|
|||
|
prompt (str): Prompt to be expected after a command is finished running. Usually linux uses ">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol.
|
|||
|
stdout (bool): Set True to send the command output to stdout. default False.
|
|||
|
parallel (int): Number of nodes to run the commands simultaneously. Default is 10, if there are more nodes that this value, nodes are groups in groups with max this number of members.
|
|||
|
|
|||
|
Returns:
|
|||
|
dict: Dictionary formed by nodes unique as keys, Output of the commands you ran on the node as value.
|
|||
|
|
|||
|
'''
|
|||
|
args = {}
|
|||
|
args["commands"] = commands
|
|||
|
if folder != None:
|
|||
|
args["folder"] = folder
|
|||
|
if prompt != None:
|
|||
|
args["prompt"] = prompt
|
|||
|
if stdout != None:
|
|||
|
args["stdout"] = stdout
|
|||
|
output = {}
|
|||
|
tasks = []
|
|||
|
for n in self.nodelist:
|
|||
|
tasks.append(threading.Thread(target=n.run, kwargs=args))
|
|||
|
taskslist = list(self._splitlist(tasks, parallel))
|
|||
|
for t in taskslist:
|
|||
|
for i in t:
|
|||
|
i.start()
|
|||
|
for i in t:
|
|||
|
i.join()
|
|||
|
for i in self.nodelist:
|
|||
|
output[i.unique] = i.output
|
|||
|
self.output = output
|
|||
|
return output</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
<dt id="conn.nodes.test"><code class="name flex">
|
|||
|
<span>def <span class="ident">test</span></span>(<span>self, commands, expected, *, prompt=None, parallel=10)</span>
|
|||
|
</code></dt>
|
|||
|
<dd>
|
|||
|
<div class="desc"><p>Run a command or list of commands on all the nodes in nodelist, then check if expected value appears on the output after the last command.</p>
|
|||
|
<p>Parameters:<br>
|
|||
|
commands (str/list): Commands to run on the node. Should be a str or a list of str.<br>
|
|||
|
commands (str): Expected text to appear after running all the commands on the node.</p>
|
|||
|
<p>Optional Named Parameters:<br>
|
|||
|
prompt
|
|||
|
(str): Prompt to be expected after a command is finished running. Usually linux uses
|
|||
|
">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol.</p>
|
|||
|
<p>Returns:<br>
|
|||
|
dict: Dictionary formed by nodes unique as keys, value is True if expected value is found after running the commands, False if prompt is found before.</p></div>
|
|||
|
<details class="source">
|
|||
|
<summary>
|
|||
|
<span>Expand source code</span>
|
|||
|
</summary>
|
|||
|
<pre><code class="python">def test(self, commands, expected, *, prompt = None, parallel = 10):
|
|||
|
'''
|
|||
|
Run a command or list of commands on all the nodes in nodelist, then check if expected value appears on the output after the last command.
|
|||
|
|
|||
|
Parameters:
|
|||
|
commands (str/list): Commands to run on the node. Should be a str or a list of str.
|
|||
|
commands (str): Expected text to appear after running all the commands on the node.
|
|||
|
|
|||
|
Optional Named Parameters:
|
|||
|
prompt (str): Prompt to be expected after a command is finished running. Usually linux uses ">" or EOF while routers use ">" or "#". The default value should work for most nodes. Change it if your connection need some special symbol.
|
|||
|
|
|||
|
Returns:
|
|||
|
dict: Dictionary formed by nodes unique as keys, value is True if expected value is found after running the commands, False if prompt is found before.
|
|||
|
|
|||
|
'''
|
|||
|
args = {}
|
|||
|
args["commands"] = commands
|
|||
|
args["expected"] = expected
|
|||
|
if prompt != None:
|
|||
|
args["prompt"] = prompt
|
|||
|
output = {}
|
|||
|
result = {}
|
|||
|
tasks = []
|
|||
|
for n in self.nodelist:
|
|||
|
tasks.append(threading.Thread(target=n.test, kwargs=args))
|
|||
|
taskslist = list(self._splitlist(tasks, parallel))
|
|||
|
for t in taskslist:
|
|||
|
for i in t:
|
|||
|
i.start()
|
|||
|
for i in t:
|
|||
|
i.join()
|
|||
|
for i in self.nodelist:
|
|||
|
result[i.unique] = i.result
|
|||
|
output[i.unique] = i.output
|
|||
|
self.output = output
|
|||
|
self.result = result
|
|||
|
return result</code></pre>
|
|||
|
</details>
|
|||
|
</dd>
|
|||
|
</dl>
|
|||
|
</dd>
|
|||
|
</dl>
|
|||
|
</section>
|
|||
|
</article>
|
|||
|
<nav id="sidebar">
|
|||
|
<h1>Index</h1>
|
|||
|
<div class="toc">
|
|||
|
<ul></ul>
|
|||
|
</div>
|
|||
|
<ul id="index">
|
|||
|
<li><h3><a href="#header-classes">Classes</a></h3>
|
|||
|
<ul>
|
|||
|
<li>
|
|||
|
<h4><code><a title="conn.configfile" href="#conn.configfile">configfile</a></code></h4>
|
|||
|
<ul class="">
|
|||
|
<li><code><a title="conn.configfile.createconfig" href="#conn.configfile.createconfig">createconfig</a></code></li>
|
|||
|
<li><code><a title="conn.configfile.createkey" href="#conn.configfile.createkey">createkey</a></code></li>
|
|||
|
<li><code><a title="conn.configfile.getitem" href="#conn.configfile.getitem">getitem</a></code></li>
|
|||
|
<li><code><a title="conn.configfile.loadconfig" href="#conn.configfile.loadconfig">loadconfig</a></code></li>
|
|||
|
<li><code><a title="conn.configfile.saveconfig" href="#conn.configfile.saveconfig">saveconfig</a></code></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<h4><code><a title="conn.node" href="#conn.node">node</a></code></h4>
|
|||
|
<ul class="">
|
|||
|
<li><code><a title="conn.node.interact" href="#conn.node.interact">interact</a></code></li>
|
|||
|
<li><code><a title="conn.node.run" href="#conn.node.run">run</a></code></li>
|
|||
|
<li><code><a title="conn.node.test" href="#conn.node.test">test</a></code></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li>
|
|||
|
<h4><code><a title="conn.nodes" href="#conn.nodes">nodes</a></code></h4>
|
|||
|
<ul class="">
|
|||
|
<li><code><a title="conn.nodes.run" href="#conn.nodes.run">run</a></code></li>
|
|||
|
<li><code><a title="conn.nodes.test" href="#conn.nodes.test">test</a></code></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
</nav>
|
|||
|
</main>
|
|||
|
<footer id="footer">
|
|||
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
|||
|
</footer>
|
|||
|
</body>
|
|||
|
</html>
|