koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 1 | import time |
koder aka kdanilov | 4ec0f71 | 2015-02-19 19:19:27 -0800 | [diff] [blame] | 2 | import socket |
koder aka kdanilov | dda86d3 | 2015-03-16 11:20:04 +0200 | [diff] [blame] | 3 | import os.path |
| 4 | import getpass |
koder aka kdanilov | e21d747 | 2015-02-14 19:02:04 -0800 | [diff] [blame] | 5 | import logging |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 6 | import threading |
| 7 | import contextlib |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 8 | import multiprocessing |
| 9 | |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 10 | import paramiko |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 11 | |
koder aka kdanilov | e21d747 | 2015-02-14 19:02:04 -0800 | [diff] [blame] | 12 | |
| 13 | logger = logging.getLogger("io-perf-tool") |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 14 | |
| 15 | |
| 16 | def get_barrier(count, threaded=False): |
| 17 | if threaded: |
| 18 | class val(object): |
| 19 | value = count |
| 20 | cond = threading.Condition() |
| 21 | else: |
| 22 | val = multiprocessing.Value('i', count) |
| 23 | cond = multiprocessing.Condition() |
koder aka kdanilov | 4643fd6 | 2015-02-10 16:20:13 -0800 | [diff] [blame] | 24 | |
| 25 | def closure(timeout): |
| 26 | with cond: |
| 27 | val.value -= 1 |
| 28 | if val.value == 0: |
| 29 | cond.notify_all() |
| 30 | else: |
| 31 | cond.wait(timeout) |
| 32 | return val.value == 0 |
| 33 | |
| 34 | return closure |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 35 | |
| 36 | |
koder aka kdanilov | 4ec0f71 | 2015-02-19 19:19:27 -0800 | [diff] [blame] | 37 | def ssh_connect(creds, retry_count=60, timeout=1): |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 38 | ssh = paramiko.SSHClient() |
| 39 | ssh.load_host_keys('/dev/null') |
| 40 | ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
| 41 | ssh.known_hosts = None |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 42 | for i in range(retry_count): |
| 43 | try: |
koder aka kdanilov | dda86d3 | 2015-03-16 11:20:04 +0200 | [diff] [blame] | 44 | if creds.user is None: |
| 45 | user = getpass.getuser() |
| 46 | else: |
| 47 | user = creds.user |
| 48 | |
koder aka kdanilov | 4ec0f71 | 2015-02-19 19:19:27 -0800 | [diff] [blame] | 49 | if creds.passwd is not None: |
| 50 | ssh.connect(creds.host, |
koder aka kdanilov | dda86d3 | 2015-03-16 11:20:04 +0200 | [diff] [blame] | 51 | username=user, |
koder aka kdanilov | 4ec0f71 | 2015-02-19 19:19:27 -0800 | [diff] [blame] | 52 | password=creds.passwd, |
| 53 | port=creds.port, |
| 54 | allow_agent=False, |
| 55 | look_for_keys=False) |
| 56 | return ssh |
| 57 | |
| 58 | if creds.key_file is not None: |
| 59 | ssh.connect(creds.host, |
koder aka kdanilov | dda86d3 | 2015-03-16 11:20:04 +0200 | [diff] [blame] | 60 | username=user, |
koder aka kdanilov | 4ec0f71 | 2015-02-19 19:19:27 -0800 | [diff] [blame] | 61 | key_filename=creds.key_file, |
| 62 | look_for_keys=False, |
| 63 | port=creds.port) |
| 64 | return ssh |
koder aka kdanilov | dda86d3 | 2015-03-16 11:20:04 +0200 | [diff] [blame] | 65 | |
| 66 | key_file = os.path.expanduser('~/.ssh/id_rsa') |
| 67 | ssh.connect(creds.host, |
| 68 | username=user, |
| 69 | key_filename=key_file, |
| 70 | look_for_keys=False, |
| 71 | port=creds.port) |
| 72 | return ssh |
| 73 | # raise ValueError("Wrong credentials {0}".format(creds.__dict__)) |
koder aka kdanilov | 4ec0f71 | 2015-02-19 19:19:27 -0800 | [diff] [blame] | 74 | except paramiko.PasswordRequiredException: |
| 75 | raise |
| 76 | except socket.error: |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 77 | if i == retry_count - 1: |
| 78 | raise |
| 79 | time.sleep(timeout) |
| 80 | |
| 81 | |
| 82 | def wait_on_barrier(barrier, latest_start_time): |
| 83 | if barrier is not None: |
| 84 | if latest_start_time is not None: |
| 85 | timeout = latest_start_time - time.time() |
| 86 | else: |
| 87 | timeout = None |
| 88 | |
| 89 | if timeout is not None and timeout > 0: |
| 90 | msg = "Ready and waiting on barrier. " + \ |
| 91 | "Will wait at most {0} seconds" |
koder aka kdanilov | e21d747 | 2015-02-14 19:02:04 -0800 | [diff] [blame] | 92 | logger.debug(msg.format(int(timeout))) |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 93 | |
| 94 | if not barrier(timeout): |
koder aka kdanilov | e21d747 | 2015-02-14 19:02:04 -0800 | [diff] [blame] | 95 | logger.debug("Barrier timeouted") |
koder aka kdanilov | 4ec0f71 | 2015-02-19 19:19:27 -0800 | [diff] [blame] | 96 | else: |
| 97 | logger.debug("Passing barrier, starting test") |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 98 | |
| 99 | |
| 100 | @contextlib.contextmanager |
| 101 | def log_error(action, types=(Exception,)): |
| 102 | if not action.startswith("!"): |
koder aka kdanilov | e21d747 | 2015-02-14 19:02:04 -0800 | [diff] [blame] | 103 | logger.debug("Starts : " + action) |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 104 | else: |
| 105 | action = action[1:] |
| 106 | |
| 107 | try: |
| 108 | yield |
| 109 | except Exception as exc: |
| 110 | if isinstance(exc, types) and not isinstance(exc, StopIteration): |
| 111 | templ = "Error during {0} stage: {1}" |
koder aka kdanilov | e21d747 | 2015-02-14 19:02:04 -0800 | [diff] [blame] | 112 | logger.debug(templ.format(action, exc.message)) |
koder aka kdanilov | 7acd6bd | 2015-02-12 14:28:30 -0800 | [diff] [blame] | 113 | raise |
| 114 | |
| 115 | |
| 116 | def run_over_ssh(conn, cmd): |
| 117 | "should be replaces by normal implementation, with select" |
| 118 | |
| 119 | stdin, stdout, stderr = conn.exec_command(cmd) |
| 120 | out = stdout.read() |
| 121 | err = stderr.read() |
| 122 | code = stdout.channel.recv_exit_status() |
| 123 | return code, out, err |
koder aka kdanilov | 83cd713 | 2015-02-14 21:37:14 -0800 | [diff] [blame] | 124 | |
| 125 | |
koder aka kdanilov | 6e2ae79 | 2015-03-04 18:02:24 -0800 | [diff] [blame] | 126 | def kb_to_ssize(ssize): |
| 127 | size_ext = { |
| 128 | 4: 'P', |
| 129 | 3: 'T', |
| 130 | 2: 'G', |
| 131 | 1: 'M', |
| 132 | 0: 'K' |
| 133 | } |
| 134 | |
| 135 | for idx in reversed(sorted(size_ext)): |
| 136 | if ssize > 1024 ** idx: |
| 137 | ext = size_ext[idx] |
| 138 | return "{0}{1}".format(int(ssize / 1024 ** idx), ext) |
| 139 | raise ValueError("Can't convert {0} to kb".format(ssize)) |
| 140 | |
| 141 | |
koder aka kdanilov | 83cd713 | 2015-02-14 21:37:14 -0800 | [diff] [blame] | 142 | def ssize_to_kb(ssize): |
| 143 | try: |
| 144 | smap = dict(k=1, K=1, M=1024, m=1024, G=1024**2, g=1024**2) |
| 145 | for ext, coef in smap.items(): |
| 146 | if ssize.endswith(ext): |
| 147 | return int(ssize[:-1]) * coef |
| 148 | |
| 149 | if int(ssize) % 1024 != 0: |
| 150 | raise ValueError() |
| 151 | |
| 152 | return int(ssize) / 1024 |
| 153 | |
| 154 | except (ValueError, TypeError, AttributeError): |
| 155 | tmpl = "Unknow size format {0!r} (or size not multiples 1024)" |
| 156 | raise ValueError(tmpl.format(ssize)) |
koder aka kdanilov | 8ad6e81 | 2015-03-22 14:42:18 +0200 | [diff] [blame^] | 157 | |
| 158 | |
| 159 | def ssize_to_b(ssize): |
| 160 | try: |
| 161 | smap = dict(k=1, K=1, M=1024, m=1024, G=1024**2, g=1024**2) |
| 162 | for ext, coef in smap.items(): |
| 163 | if ssize.endswith(ext): |
| 164 | return int(ssize[:-1]) * coef * 1024 |
| 165 | |
| 166 | return int(ssize) |
| 167 | except (ValueError, TypeError, AttributeError): |
| 168 | tmpl = "Unknow size format {0!r} (or size not multiples 1024)" |
| 169 | raise ValueError(tmpl.format(ssize)) |