|  | #!/usr/bin/env python3 | 
|  | # group: rw | 
|  | # | 
|  | # Test ssh image creation | 
|  | # | 
|  | # Copyright (C) 2018 Red Hat, Inc. | 
|  | # | 
|  | # Creator/Owner: Kevin Wolf <kwolf@redhat.com> | 
|  | # | 
|  | # This program is free software; you can redistribute it and/or modify | 
|  | # it under the terms of the GNU General Public License as published by | 
|  | # the Free Software Foundation; either version 2 of the License, or | 
|  | # (at your option) any later version. | 
|  | # | 
|  | # This program is distributed in the hope that it will be useful, | 
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | # GNU General Public License for more details. | 
|  | # | 
|  | # You should have received a copy of the GNU General Public License | 
|  | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|  | # | 
|  |  | 
|  | import iotests | 
|  | import subprocess | 
|  | import re | 
|  |  | 
|  | iotests.script_initialize( | 
|  | supported_fmts=['raw'], | 
|  | supported_protocols=['ssh'], | 
|  | ) | 
|  |  | 
|  | def filter_hash(qmsg): | 
|  | def _filter(key, value): | 
|  | if key == 'hash' and re.match('[0-9a-f]+', value): | 
|  | return 'HASH' | 
|  | return value | 
|  | if isinstance(qmsg, str): | 
|  | # Strip key type and fingerprint | 
|  | p = r"\S+ (key fingerprint) '(md5|sha1|sha256):[0-9a-f]+'" | 
|  | return re.sub(p, r"\1 '\2:HASH'", qmsg) | 
|  | else: | 
|  | return iotests.filter_qmp(qmsg, _filter) | 
|  |  | 
|  | def blockdev_create(vm, options): | 
|  | vm.blockdev_create(options, filters=[iotests.filter_qmp_testfiles, filter_hash]) | 
|  |  | 
|  | with iotests.FilePath('t.img') as disk_path, \ | 
|  | iotests.VM() as vm: | 
|  |  | 
|  | remote_path = iotests.remote_filename(disk_path) | 
|  |  | 
|  | # | 
|  | # Successful image creation (defaults) | 
|  | # | 
|  | iotests.log("=== Successful image creation (defaults) ===") | 
|  | iotests.log("") | 
|  |  | 
|  | vm.launch() | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | } | 
|  | }, | 
|  | 'size': 4194304 }) | 
|  | vm.shutdown() | 
|  |  | 
|  | iotests.img_info_log(remote_path) | 
|  | iotests.log("") | 
|  | iotests.img_info_log(disk_path) | 
|  |  | 
|  | # | 
|  | # Test host-key-check options | 
|  | # | 
|  | iotests.log("=== Test host-key-check options ===") | 
|  | iotests.log("") | 
|  |  | 
|  | iotests.log("--- no host key checking --") | 
|  | iotests.log("") | 
|  |  | 
|  | vm.launch() | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'none' | 
|  | } | 
|  | }, | 
|  | 'size': 8388608 }) | 
|  | vm.shutdown() | 
|  |  | 
|  | iotests.img_info_log(remote_path) | 
|  |  | 
|  | iotests.log("--- known_hosts key checking --") | 
|  | iotests.log("") | 
|  |  | 
|  | vm.launch() | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'known_hosts' | 
|  | } | 
|  | }, | 
|  | 'size': 4194304 }) | 
|  | vm.shutdown() | 
|  |  | 
|  | iotests.img_info_log(remote_path) | 
|  |  | 
|  | keys = subprocess.check_output( | 
|  | 'ssh-keyscan 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' + | 
|  | 'cut -d" " -f3', | 
|  | shell=True).rstrip().decode('ascii').split('\n') | 
|  |  | 
|  | # Mappings of base64 representations to digests | 
|  | md5_keys = {} | 
|  | sha1_keys = {} | 
|  | sha256_keys = {} | 
|  |  | 
|  | for key in keys: | 
|  | md5_keys[key] = subprocess.check_output( | 
|  | 'echo %s | base64 -d | md5sum -b | cut -d" " -f1' % key, | 
|  | shell=True).rstrip().decode('ascii') | 
|  |  | 
|  | sha1_keys[key] = subprocess.check_output( | 
|  | 'echo %s | base64 -d | sha1sum -b | cut -d" " -f1' % key, | 
|  | shell=True).rstrip().decode('ascii') | 
|  |  | 
|  | sha256_keys[key] = subprocess.check_output( | 
|  | 'echo %s | base64 -d | sha256sum -b | cut -d" " -f1' % key, | 
|  | shell=True).rstrip().decode('ascii') | 
|  |  | 
|  | vm.launch() | 
|  |  | 
|  | # Find correct key first | 
|  | matching_key = None | 
|  | for key in keys: | 
|  | result = vm.qmp('blockdev-add', | 
|  | driver='ssh', node_name='node0', path=disk_path, | 
|  | server={ | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22', | 
|  | }, host_key_check={ | 
|  | 'mode': 'hash', | 
|  | 'type': 'md5', | 
|  | 'hash': md5_keys[key], | 
|  | }) | 
|  |  | 
|  | if 'error' not in result: | 
|  | vm.qmp('blockdev-del', node_name='node0') | 
|  | matching_key = key | 
|  | break | 
|  |  | 
|  | if matching_key is None: | 
|  | vm.shutdown() | 
|  | iotests.notrun('Did not find a key that fits 127.0.0.1') | 
|  |  | 
|  | iotests.log("--- explicit md5 key checking --") | 
|  | iotests.log("") | 
|  |  | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'hash', | 
|  | 'type': 'md5', | 
|  | 'hash': 'wrong', | 
|  | } | 
|  | }, | 
|  | 'size': 2097152 }) | 
|  |  | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'hash', | 
|  | 'type': 'md5', | 
|  | 'hash': md5_keys[matching_key], | 
|  | } | 
|  | }, | 
|  | 'size': 8388608 }) | 
|  | vm.shutdown() | 
|  |  | 
|  | iotests.img_info_log(remote_path) | 
|  |  | 
|  | iotests.log("--- explicit sha1 key checking --") | 
|  | iotests.log("") | 
|  |  | 
|  | vm.launch() | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'hash', | 
|  | 'type': 'sha1', | 
|  | 'hash': 'wrong', | 
|  | } | 
|  | }, | 
|  | 'size': 2097152 }) | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'hash', | 
|  | 'type': 'sha1', | 
|  | 'hash': sha1_keys[matching_key], | 
|  | } | 
|  | }, | 
|  | 'size': 4194304 }) | 
|  | vm.shutdown() | 
|  |  | 
|  | iotests.img_info_log(remote_path) | 
|  |  | 
|  | iotests.log("--- explicit sha256 key checking --") | 
|  | iotests.log("") | 
|  |  | 
|  | vm.launch() | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'hash', | 
|  | 'type': 'sha256', | 
|  | 'hash': 'wrong', | 
|  | } | 
|  | }, | 
|  | 'size': 2097152 }) | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'hash', | 
|  | 'type': 'sha256', | 
|  | 'hash': sha256_keys[matching_key], | 
|  | } | 
|  | }, | 
|  | 'size': 4194304 }) | 
|  | vm.shutdown() | 
|  |  | 
|  | iotests.img_info_log(remote_path) | 
|  |  | 
|  | # | 
|  | # Invalid path and user | 
|  | # | 
|  | iotests.log("=== Invalid path and user ===") | 
|  | iotests.log("") | 
|  |  | 
|  | vm.launch() | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': '/this/is/not/an/existing/path', | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'none' | 
|  | } | 
|  | }, | 
|  | 'size': 4194304 }) | 
|  | blockdev_create(vm, { 'driver': 'ssh', | 
|  | 'location': { | 
|  | 'path': disk_path, | 
|  | 'user': 'invalid user', | 
|  | 'server': { | 
|  | 'host': '127.0.0.1', | 
|  | 'port': '22' | 
|  | }, | 
|  | 'host-key-check': { | 
|  | 'mode': 'none' | 
|  | } | 
|  | }, | 
|  | 'size': 4194304 }) | 
|  | vm.shutdown() |