-
-
Notifications
You must be signed in to change notification settings - Fork 49
Expand file tree
/
Copy pathclient.py
More file actions
114 lines (99 loc) 路 3.48 KB
/
Copy pathclient.py
File metadata and controls
114 lines (99 loc) 路 3.48 KB
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
"""Client to handle connections and actions executed against a remote host."""
from os import system
import subprocess as sp
from typing import List
from paramiko import AutoAddPolicy, RSAKey, SSHClient
from paramiko.auth_handler import AuthenticationException, SSHException
from scp import SCPClient, SCPException
from log import LOGGER
class RemoteClient:
"""Client to interact with a remote host via SSH & SCP."""
def __init__(
self,
host: str,
user: str,
password: str,
ssh_key_filepath: str,
remote_path: str,
):
self.host = host
self.user = user
self.password = password
self.ssh_key_filepath = ssh_key_filepath
self.remote_path = remote_path
self.client = None
self._upload_ssh_key()
@property
def connection(self):
"""Open connection to remote host. """
try:
client = SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(AutoAddPolicy())
client.connect(
self.host,
username=self.user,
password=self.password,
key_filename=self.ssh_key_filepath,
timeout=5000,
)
return client
except AuthenticationException as e:
LOGGER.error(
f"Authentication failed: did you remember to create an SSH key? {e}"
)
raise e
@property
def scp(self) -> SCPClient:
conn = self.connection
return SCPClient(conn.get_transport())
def _get_ssh_key(self):
""" Fetch locally stored SSH key."""
try:
self.ssh_key = RSAKey.from_private_key_file(self.ssh_key_filepath)
LOGGER.info(f"Found SSH key at self {self.ssh_key_filepath}")
return self.ssh_key
except SSHException as e:
LOGGER.error(e)
def _upload_ssh_key(self):
try:
sp.getoutput(
f"ssh-copy-id -i {self.ssh_key_filepath}.pub {self.user}@{self.host}>/dev/null 2>&1"
)
LOGGER.info(f"{self.ssh_key_filepath} uploaded to {self.host}")
except FileNotFoundError as error:
LOGGER.error(error)
def disconnect(self):
"""Close SSH & SCP connection."""
if self.connection:
self.client.close()
if self.scp:
self.scp.close()
def bulk_upload(self, files: List[str]):
"""
Upload multiple files to a remote directory.
:param files: List of local files to be uploaded.
:type files: List[str]
"""
try:
self.scp.put(files, remote_path=self.remote_path)
LOGGER.info(
f"Finished uploading {len(files)} files to {self.remote_path} on {self.host}"
)
except SCPException as e:
raise e
def download_file(self, file: str):
"""Download file from remote host."""
self.scp.get(file)
def execute_commands(self, commands: List[str]):
"""
Execute multiple commands in succession.
:param commands: List of unix commands as strings.
:type commands: List[str]
"""
for cmd in commands:
stdin, stdout, stderr = self.client.exec_command(cmd)
stdout.channel.recv_exit_status()
response = stdout.readlines()
for line in response:
LOGGER.info(f"INPUT: {cmd} | OUTPUT: {line}")