| 1 | #!/usr/bin/env python3 |
| 2 | # group: rw |
| 3 | # |
| 4 | # Test ssh image creation |
| 5 | # |
| 6 | # Copyright (C) 2018 Red Hat, Inc. |
| 7 | # |
| 8 | # Creator/Owner: Kevin Wolf <kwolf@redhat.com> |
| 9 | # |
| 10 | # This program is free software; you can redistribute it and/or modify |
| 11 | # it under the terms of the GNU General Public License as published by |
| 12 | # the Free Software Foundation; either version 2 of the License, or |
| 13 | # (at your option) any later version. |
| 14 | # |
| 15 | # This program is distributed in the hope that it will be useful, |
| 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | # GNU General Public License for more details. |
| 19 | # |
| 20 | # You should have received a copy of the GNU General Public License |
| 21 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 22 | # |
| 23 | |
| 24 | import iotests |
| 25 | import subprocess |
| 26 | import re |
| 27 | |
| 28 | iotests.script_initialize( |
| 29 | supported_fmts=['raw'], |
| 30 | supported_protocols=['ssh'], |
| 31 | ) |
| 32 | |
| 33 | def filter_hash(qmsg): |
| 34 | def _filter(key, value): |
| 35 | if key == 'hash' and re.match('[0-9a-f]+', value): |
| 36 | return 'HASH' |
| 37 | return value |
| 38 | if isinstance(qmsg, str): |
| 39 | # Strip key type and fingerprint |
| 40 | p = r"\S+ (key fingerprint) '(md5|sha1|sha256):[0-9a-f]+'" |
| 41 | return re.sub(p, r"\1 '\2:HASH'", qmsg) |
| 42 | else: |
| 43 | return iotests.filter_qmp(qmsg, _filter) |
| 44 | |
| 45 | def blockdev_create(vm, options): |
| 46 | vm.blockdev_create(options, filters=[iotests.filter_qmp_testfiles, filter_hash]) |
| 47 | |
| 48 | with iotests.FilePath('t.img') as disk_path, \ |
| 49 | iotests.VM() as vm: |
| 50 | |
| 51 | remote_path = iotests.remote_filename(disk_path) |
| 52 | |
| 53 | # |
| 54 | # Successful image creation (defaults) |
| 55 | # |
| 56 | iotests.log("=== Successful image creation (defaults) ===") |
| 57 | iotests.log("") |
| 58 | |
| 59 | vm.launch() |
| 60 | blockdev_create(vm, { 'driver': 'ssh', |
| 61 | 'location': { |
| 62 | 'path': disk_path, |
| 63 | 'server': { |
| 64 | 'host': '127.0.0.1', |
| 65 | 'port': '22' |
| 66 | } |
| 67 | }, |
| 68 | 'size': 4194304 }) |
| 69 | vm.shutdown() |
| 70 | |
| 71 | iotests.img_info_log(remote_path) |
| 72 | iotests.log("") |
| 73 | iotests.img_info_log(disk_path) |
| 74 | |
| 75 | # |
| 76 | # Test host-key-check options |
| 77 | # |
| 78 | iotests.log("=== Test host-key-check options ===") |
| 79 | iotests.log("") |
| 80 | |
| 81 | iotests.log("--- no host key checking --") |
| 82 | iotests.log("") |
| 83 | |
| 84 | vm.launch() |
| 85 | blockdev_create(vm, { 'driver': 'ssh', |
| 86 | 'location': { |
| 87 | 'path': disk_path, |
| 88 | 'server': { |
| 89 | 'host': '127.0.0.1', |
| 90 | 'port': '22' |
| 91 | }, |
| 92 | 'host-key-check': { |
| 93 | 'mode': 'none' |
| 94 | } |
| 95 | }, |
| 96 | 'size': 8388608 }) |
| 97 | vm.shutdown() |
| 98 | |
| 99 | iotests.img_info_log(remote_path) |
| 100 | |
| 101 | iotests.log("--- known_hosts key checking --") |
| 102 | iotests.log("") |
| 103 | |
| 104 | vm.launch() |
| 105 | blockdev_create(vm, { 'driver': 'ssh', |
| 106 | 'location': { |
| 107 | 'path': disk_path, |
| 108 | 'server': { |
| 109 | 'host': '127.0.0.1', |
| 110 | 'port': '22' |
| 111 | }, |
| 112 | 'host-key-check': { |
| 113 | 'mode': 'known_hosts' |
| 114 | } |
| 115 | }, |
| 116 | 'size': 4194304 }) |
| 117 | vm.shutdown() |
| 118 | |
| 119 | iotests.img_info_log(remote_path) |
| 120 | |
| 121 | keys = subprocess.check_output( |
| 122 | 'ssh-keyscan 127.0.0.1 2>/dev/null | grep -v "^#" | ' + |
| 123 | 'cut -d" " -f3', |
| 124 | shell=True).rstrip().decode('ascii').split('\n') |
| 125 | |
| 126 | # Mappings of base64 representations to digests |
| 127 | md5_keys = {} |
| 128 | sha1_keys = {} |
| 129 | sha256_keys = {} |
| 130 | |
| 131 | for key in keys: |
| 132 | md5_keys[key] = subprocess.check_output( |
| 133 | 'echo %s | base64 -d | md5sum -b | cut -d" " -f1' % key, |
| 134 | shell=True).rstrip().decode('ascii') |
| 135 | |
| 136 | sha1_keys[key] = subprocess.check_output( |
| 137 | 'echo %s | base64 -d | sha1sum -b | cut -d" " -f1' % key, |
| 138 | shell=True).rstrip().decode('ascii') |
| 139 | |
| 140 | sha256_keys[key] = subprocess.check_output( |
| 141 | 'echo %s | base64 -d | sha256sum -b | cut -d" " -f1' % key, |
| 142 | shell=True).rstrip().decode('ascii') |
| 143 | |
| 144 | vm.launch() |
| 145 | |
| 146 | # Find correct key first |
| 147 | matching_key = None |
| 148 | for key in keys: |
| 149 | result = vm.qmp('blockdev-add', |
| 150 | driver='ssh', node_name='node0', path=disk_path, |
| 151 | server={ |
| 152 | 'host': '127.0.0.1', |
| 153 | 'port': '22', |
| 154 | }, host_key_check={ |
| 155 | 'mode': 'hash', |
| 156 | 'type': 'md5', |
| 157 | 'hash': md5_keys[key], |
| 158 | }) |
| 159 | |
| 160 | if 'error' not in result: |
| 161 | vm.qmp('blockdev-del', node_name='node0') |
| 162 | matching_key = key |
| 163 | break |
| 164 | |
| 165 | if matching_key is None: |
| 166 | vm.shutdown() |
| 167 | iotests.notrun('Did not find a key that fits 127.0.0.1') |
| 168 | |
| 169 | iotests.log("--- explicit md5 key checking --") |
| 170 | iotests.log("") |
| 171 | |
| 172 | blockdev_create(vm, { 'driver': 'ssh', |
| 173 | 'location': { |
| 174 | 'path': disk_path, |
| 175 | 'server': { |
| 176 | 'host': '127.0.0.1', |
| 177 | 'port': '22' |
| 178 | }, |
| 179 | 'host-key-check': { |
| 180 | 'mode': 'hash', |
| 181 | 'type': 'md5', |
| 182 | 'hash': 'wrong', |
| 183 | } |
| 184 | }, |
| 185 | 'size': 2097152 }) |
| 186 | |
| 187 | blockdev_create(vm, { 'driver': 'ssh', |
| 188 | 'location': { |
| 189 | 'path': disk_path, |
| 190 | 'server': { |
| 191 | 'host': '127.0.0.1', |
| 192 | 'port': '22' |
| 193 | }, |
| 194 | 'host-key-check': { |
| 195 | 'mode': 'hash', |
| 196 | 'type': 'md5', |
| 197 | 'hash': md5_keys[matching_key], |
| 198 | } |
| 199 | }, |
| 200 | 'size': 8388608 }) |
| 201 | vm.shutdown() |
| 202 | |
| 203 | iotests.img_info_log(remote_path) |
| 204 | |
| 205 | iotests.log("--- explicit sha1 key checking --") |
| 206 | iotests.log("") |
| 207 | |
| 208 | vm.launch() |
| 209 | blockdev_create(vm, { 'driver': 'ssh', |
| 210 | 'location': { |
| 211 | 'path': disk_path, |
| 212 | 'server': { |
| 213 | 'host': '127.0.0.1', |
| 214 | 'port': '22' |
| 215 | }, |
| 216 | 'host-key-check': { |
| 217 | 'mode': 'hash', |
| 218 | 'type': 'sha1', |
| 219 | 'hash': 'wrong', |
| 220 | } |
| 221 | }, |
| 222 | 'size': 2097152 }) |
| 223 | blockdev_create(vm, { 'driver': 'ssh', |
| 224 | 'location': { |
| 225 | 'path': disk_path, |
| 226 | 'server': { |
| 227 | 'host': '127.0.0.1', |
| 228 | 'port': '22' |
| 229 | }, |
| 230 | 'host-key-check': { |
| 231 | 'mode': 'hash', |
| 232 | 'type': 'sha1', |
| 233 | 'hash': sha1_keys[matching_key], |
| 234 | } |
| 235 | }, |
| 236 | 'size': 4194304 }) |
| 237 | vm.shutdown() |
| 238 | |
| 239 | iotests.img_info_log(remote_path) |
| 240 | |
| 241 | iotests.log("--- explicit sha256 key checking --") |
| 242 | iotests.log("") |
| 243 | |
| 244 | vm.launch() |
| 245 | blockdev_create(vm, { 'driver': 'ssh', |
| 246 | 'location': { |
| 247 | 'path': disk_path, |
| 248 | 'server': { |
| 249 | 'host': '127.0.0.1', |
| 250 | 'port': '22' |
| 251 | }, |
| 252 | 'host-key-check': { |
| 253 | 'mode': 'hash', |
| 254 | 'type': 'sha256', |
| 255 | 'hash': 'wrong', |
| 256 | } |
| 257 | }, |
| 258 | 'size': 2097152 }) |
| 259 | blockdev_create(vm, { 'driver': 'ssh', |
| 260 | 'location': { |
| 261 | 'path': disk_path, |
| 262 | 'server': { |
| 263 | 'host': '127.0.0.1', |
| 264 | 'port': '22' |
| 265 | }, |
| 266 | 'host-key-check': { |
| 267 | 'mode': 'hash', |
| 268 | 'type': 'sha256', |
| 269 | 'hash': sha256_keys[matching_key], |
| 270 | } |
| 271 | }, |
| 272 | 'size': 4194304 }) |
| 273 | vm.shutdown() |
| 274 | |
| 275 | iotests.img_info_log(remote_path) |
| 276 | |
| 277 | # |
| 278 | # Invalid path and user |
| 279 | # |
| 280 | iotests.log("=== Invalid path and user ===") |
| 281 | iotests.log("") |
| 282 | |
| 283 | vm.launch() |
| 284 | blockdev_create(vm, { 'driver': 'ssh', |
| 285 | 'location': { |
| 286 | 'path': '/this/is/not/an/existing/path', |
| 287 | 'server': { |
| 288 | 'host': '127.0.0.1', |
| 289 | 'port': '22' |
| 290 | }, |
| 291 | 'host-key-check': { |
| 292 | 'mode': 'none' |
| 293 | } |
| 294 | }, |
| 295 | 'size': 4194304 }) |
| 296 | blockdev_create(vm, { 'driver': 'ssh', |
| 297 | 'location': { |
| 298 | 'path': disk_path, |
| 299 | 'user': 'invalid user', |
| 300 | 'server': { |
| 301 | 'host': '127.0.0.1', |
| 302 | 'port': '22' |
| 303 | }, |
| 304 | 'host-key-check': { |
| 305 | 'mode': 'none' |
| 306 | } |
| 307 | }, |
| 308 | 'size': 4194304 }) |
| 309 | vm.shutdown() |