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