-
Notifications
You must be signed in to change notification settings - Fork 22
/
app.py
185 lines (145 loc) · 5.34 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
from os import environ, path
from glob import glob
import paramiko
import scp
import sys
import math
import re
import tempfile
import os
envs = environ
INPUT_HOST = envs.get("INPUT_HOST")
INPUT_PORT = int(envs.get("INPUT_PORT", "22"))
INPUT_USER = envs.get("INPUT_USER")
INPUT_PASS = envs.get("INPUT_PASS")
INPUT_KEY = envs.get("INPUT_KEY")
INPUT_CONNECT_TIMEOUT = envs.get("INPUT_CONNECT_TIMEOUT", "30s")
INPUT_SCP = envs.get("INPUT_SCP")
INPUT_FIRST_SSH = envs.get("INPUT_FIRST_SSH")
INPUT_LAST_SSH = envs.get("INPUT_LAST_SSH")
seconds_per_unit = {"s": 1, "m": 60, "h": 3600, "d": 86400, "w": 604800, "M": 86400*30}
pattern_seconds_per_unit = re.compile(r'^(' + "|".join(['\\d+'+k for k in seconds_per_unit.keys()]) + ')$')
def convert_to_seconds(s):
if s is None:
return 30
if isinstance(s, str):
return int(s[:-1]) * seconds_per_unit[s[-1]] if pattern_seconds_per_unit.search(s) else 30
if (isinstance(s, int) or isinstance(s, float)) and not math.isnan(s):
return round(s)
return 30
strips = [" ", "\"", " ", "'", " "]
def strip_and_parse_envs(p):
if not p:
return None
for c in strips:
p = p.strip(c)
return path.expandvars(p) if p != "." else f"{path.realpath(p)}/*"
def connect(callback=None):
tmp = tempfile.NamedTemporaryFile(delete=False)
try:
ssh = paramiko.SSHClient()
p_key = None
if INPUT_KEY:
tmp.write(INPUT_KEY.encode())
tmp.close()
p_key = paramiko.RSAKey.from_private_key_file(filename=tmp.name)
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(INPUT_HOST, port=INPUT_PORT, username=INPUT_USER,
pkey=p_key, password=INPUT_PASS,
timeout=convert_to_seconds(INPUT_CONNECT_TIMEOUT))
except Exception as err:
print(f"Connect error\n{err}")
sys.exit(1)
else:
if callback:
callback(ssh)
finally:
os.unlink(tmp.name)
tmp.close()
# Define progress callback that prints the current percentage completed for the file
def progress(filename, size, sent):
sys.stdout.write(f"{filename}... {float(sent)/float(size)*100:.2f}%\n")
def ssh_process(ssh, input_ssh):
commands = [c.strip() for c in input_ssh.splitlines() if c is not None]
command_str = ""
l = len(commands)
for i in range(len(commands)):
c = path.expandvars(commands[i])
if c == "":
continue
if c.endswith('&&') or c.endswith('||') or c.endswith(';'):
c = c[0:-2] if i == (l-1) else c
else:
c = f"{c} &&" if i < (l-1) else c
command_str = f"{command_str} {c}"
command_str = command_str.strip()
print(command_str)
stdin, stdout, stderr = ssh.exec_command(command_str)
ssh_exit_status = stdout.channel.recv_exit_status()
out = "".join(stdout.readlines())
out = out.strip() if out is not None else None
if out:
print(f"Success: \n{out}")
err = "".join(stderr.readlines())
err = err.strip() if err is not None else None
if err:
print(f"Error: \n{err}")
if ssh_exit_status != 0:
print(f"ssh exit status: {ssh_exit_status}")
sys.exit(1)
pass
def scp_process(ssh, input_scp):
copy_list = []
for c in input_scp.splitlines():
if not c:
continue
l2r = c.split("=>")
if len(l2r) == 2:
local = strip_and_parse_envs(l2r[0])
remote = strip_and_parse_envs(l2r[1])
if local and remote:
copy_list.append({"l": local, "r": remote})
continue
print(f"SCP ignored {c.strip()}")
print(copy_list)
if len(copy_list) <= 0:
print("SCP no copy list found")
return
with scp.SCPClient(ssh.get_transport(), progress=progress, sanitize=lambda x: x) as conn:
for l2r in copy_list:
remote = l2r.get('r')
try:
ssh.exec_command(f"mkdir -p {remote}")
except Exception as err:
print(f"Remote mkdir error. Can't create {remote}\n{err}")
sys.exit(1)
for f in [f for f in glob(l2r.get('l'))]:
try:
conn.put(f, remote_path=remote, recursive=True)
print(f"{f} -> {remote}")
except Exception as err:
print(f"Scp error. Can't copy {f} on {remote}\n{err}")
sys.exit(1)
pass
def processes():
if INPUT_KEY is None and INPUT_PASS is None:
print("SSH-SCP-SSH invalid (Key/Passwd)")
return
if not INPUT_FIRST_SSH:
print("SSH-SCP-SSH no first_ssh input found")
else:
print("+++++++++++++++++++Pipeline: RUNNING FIRST SSH+++++++++++++++++++")
connect(lambda c: ssh_process(c, INPUT_FIRST_SSH))
if not INPUT_SCP:
print("SSH-SCP-SSH no scp input found")
else:
print("+++++++++++++++++++Pipeline: RUNNING SCP+++++++++++++++++++")
connect(lambda c: scp_process(c, INPUT_SCP))
if not INPUT_LAST_SSH:
print("SSH-SCP-SSH no last_ssh input found")
else:
print("+++++++++++++++++++Pipeline: RUNNING LAST SSH+++++++++++++++++++")
connect(lambda c: ssh_process(c, INPUT_LAST_SSH))
pass
if __name__ == '__main__':
processes()