blob: 29a56f04986d73b71ec0690ed9f8b883ae5eb42b [file] [log] [blame]
Ievgeniia Zadorozhna84023022021-12-30 13:00:41 +02001from io import StringIO
2import logging
3import select
4import utils
5import paramiko
6import time
7import os
8
9logger = logging.getLogger(__name__)
10
11# Suppress paramiko logging
12logging.getLogger("paramiko").setLevel(logging.WARNING)
13
14
15class SSHTransport(object):
16 def __init__(self, address, username, password=None,
17 private_key=None, look_for_keys=False, *args, **kwargs):
18
19 self.address = address
20 self.username = username
21 self.password = password
22 if private_key is not None:
23 self.private_key = paramiko.RSAKey.from_private_key(
24 StringIO(private_key))
25 else:
26 self.private_key = None
27
28 self.look_for_keys = look_for_keys
29 self.buf_size = 1024
30 self.channel_timeout = 10.0
31
32 def _get_ssh_connection(self):
33 ssh = paramiko.SSHClient()
34 ssh.set_missing_host_key_policy(
35 paramiko.AutoAddPolicy())
36 ssh.connect(self.address, username=self.username,
37 password=self.password, pkey=self.private_key,
38 timeout=self.channel_timeout)
39 logger.debug("Successfully connected to: {0}".format(self.address))
40 return ssh
41
42 def _get_sftp_connection(self):
43 transport = paramiko.Transport((self.address, 22))
44 transport.connect(username=self.username,
45 password=self.password,
46 pkey=self.private_key)
47
48 return paramiko.SFTPClient.from_transport(transport)
49
50 def exec_sync(self, cmd):
51 logger.debug("Executing {0} on host {1}".format(cmd, self.address))
52 ssh = self._get_ssh_connection()
53 transport = ssh.get_transport()
54 channel = transport.open_session()
55 channel.fileno()
56 channel.exec_command(cmd)
57 channel.shutdown_write()
58 out_data = []
59 err_data = []
60 poll = select.poll()
61 poll.register(channel, select.POLLIN)
62
63 while True:
64 ready = poll.poll(self.channel_timeout)
65 if not any(ready):
66 continue
67 if not ready[0]:
68 continue
69 out_chunk = err_chunk = None
70 if channel.recv_ready():
71 out_chunk = channel.recv(self.buf_size)
72 out_data += out_chunk,
73 if channel.recv_stderr_ready():
74 err_chunk = channel.recv_stderr(self.buf_size)
75 err_data += err_chunk,
76 if channel.closed and not err_chunk and not out_chunk:
77 break
78 exit_status = channel.recv_exit_status()
79 logger.debug("Command {0} executed with status: {1}"
80 .format(cmd, exit_status))
81 return (exit_status, b" ".join(out_data).strip(),
82 b" ".join(err_data).strip())
83
84 def exec_command(self, cmd):
85 exit_status, stdout, stderr = self.exec_sync(cmd)
86 return stdout
87
88 def check_call(self, command, error_info=None, expected=None,
89 raise_on_err=True):
90 """Execute command and check for return code
91 :type command: str
92 :type error_info: str
93 :type expected: list
94 :type raise_on_err: bool
95 :rtype: ExecResult
96 :raises: DevopsCalledProcessError
97 """
98 if expected is None:
99 expected = [0]
100 ret = self.exec_sync(command)
101 exit_code, stdout_str, stderr_str = ret
102 if exit_code not in expected:
103 message = (
104 "{append}Command '{cmd}' returned exit code {code} while "
105 "expected {expected}\n"
106 "\tSTDOUT:\n"
107 "{stdout}"
108 "\n\tSTDERR:\n"
109 "{stderr}".format(
110 append=error_info + '\n' if error_info else '',
111 cmd=command,
112 code=exit_code,
113 expected=expected,
114 stdout=stdout_str,
115 stderr=stderr_str
116 ))
117 logger.error(message)
118 if raise_on_err:
119 exit()
120 return ret
121
122 def put_file(self, source_path, destination_path):
123 sftp = self._get_sftp_connection()
124 sftp.put(source_path, destination_path)
125 sftp.close()
126
127 def put_iperf3_deb_packages_at_vms(self, source_directory,
128 destination_directory):
129 iperf_deb_files = [f for f in os.listdir(source_directory)
130 if "deb" in f]
131 if not iperf_deb_files:
132 raise BaseException(
133 "iperf3 *.deb packages are not found locally at path {}. "
134 "Please recheck 'iperf_deb_package_dir_path' variable in "
135 "global_config.yaml and check *.deb packages are manually "
136 "copied there.".format(source_directory))
137 for f in iperf_deb_files:
138 source_abs_path = "{}/{}".format(source_directory, f)
139 dest_abs_path = "{}/{}".format(destination_directory, f)
140 self.put_file(source_abs_path, dest_abs_path)
141
142 def get_file(self, source_path, destination_path):
143 sftp = self._get_sftp_connection()
144 sftp.get(source_path, destination_path)
145 sftp.close()
146
147 def _is_timed_out(self, start_time, timeout):
148 return (time.time() - timeout) > start_time
149
150 def check_vm_is_reachable_ssh(self, floating_ip, timeout=500, sleep=5):
151 bsleep = sleep
152 ssh = paramiko.SSHClient()
153 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
154 _start_time = time.time()
155 attempts = 0
156 while True:
157 try:
158 ssh.connect(floating_ip, username=self.username,
159 password=self.password, pkey=self.private_key,
160 timeout=self.channel_timeout)
161 logger.info("VM with FIP {} is reachable via SSH. Success!"
162 "".format(floating_ip))
163 return True
164 except Exception as e:
165 ssh.close()
166 if self._is_timed_out(_start_time, timeout):
167 logger.info("VM with FIP {} is not reachable via SSH. "
168 "See details: {}".format(floating_ip, e))
169 raise TimeoutError(
170 "\nFailed to establish authenticated ssh connection "
171 "to {} after {} attempts during {} seconds.\n{}"
172 "".format(floating_ip, attempts, timeout, e))
173 attempts += 1
174 logger.info("Failed to establish authenticated ssh connection "
175 "to {}. Number attempts: {}. Retry after {} "
176 "seconds.".format(floating_ip, attempts, bsleep))
177 time.sleep(bsleep)
178
179
180class prepare_iperf(object):
181
182 def __init__(self, fip, user='ubuntu', password='password',
183 private_key=None):
184
185 transport = SSHTransport(fip, user, password, private_key)
186 config = utils.get_configuration()
187
188 # Install iperf3 using apt or downloaded deb package
189 internet_at_vms = utils.get_configuration().get("internet_at_vms")
190 if internet_at_vms.lower() == 'false':
191 logger.info("Copying offline iperf3 deb packages, installing...")
192 path_to_iperf_deb = (config.get('iperf_deb_package_dir_path') or
193 "/artifacts/mos-spt/")
194 home_ubuntu = "/home/ubuntu/"
195 transport.put_iperf3_deb_packages_at_vms(path_to_iperf_deb,
196 home_ubuntu)
197 transport.exec_command('sudo dpkg -i {}*.deb'.format(home_ubuntu))
198 else:
199 logger.info("Installing iperf3 using apt")
200 preparation_cmd = config.get('iperf_prep_string') or ['']
201 transport.exec_command(preparation_cmd)
202 transport.exec_command('sudo apt-get update;'
203 'sudo apt-get install -y iperf3')
204
205 # Log whether iperf is installed with version
206 check = transport.exec_command('dpkg -l | grep iperf3')
207 logger.debug(check.decode('utf-8'))
208
209 # Staring iperf server
210 transport.exec_command('nohup iperf3 -s > file 2>&1 &')