From cd8ddc9c29115f6f8428fc17fbded67f0ce99004 Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Mon, 8 Jul 2019 15:25:57 +0100 Subject: [PATCH 11/39] block/ssh: Implement .bdrv_refresh_filename() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Pino Toscano Message-id: <20190708152601.21123-7-ptoscano@redhat.com> Patchwork-id: 89417 O-Subject: [RHEL-8.1.0 qemu-kvm PATCH v3 06/10] block/ssh: Implement .bdrv_refresh_filename() Bugzilla: 1513367 RH-Acked-by: Philippe Mathieu-Daudé RH-Acked-by: Max Reitz RH-Acked-by: Miroslav Rezanina RH-Acked-by: Markus Armbruster From: Max Reitz This requires some changes to keep iotests 104 and 207 working. qemu-img info in 104 will now return a filename including the user name and the port, which need to be filtered by adjusting REMOTE_TEST_DIR in common.rc. This additional information has to be marked optional, however (which is simple as REMOTE_TEST_DIR is a regex), because otherwise 197 and 215 would fail: They use it (indirectly) to filter qemu-img create output which contains a backing filename they have passed to it -- which probably does not contain a user name or port number. The problem in 207 is a nice one to have: qemu-img info used to return json:{} filenames, but with this patch it returns nice plain ones. We now need to adjust the filtering to hide the user name (and port number while we are at it). The simplest way to do this is to include both in iotests.remote_filename() so that bdrv_refresh_filename() will not change it, and then iotests.img_info_log() will filter it correctly automatically. Signed-off-by: Max Reitz Tested-by: Richard W.M. Jones Message-id: 20190225190828.17726-2-mreitz@redhat.com Signed-off-by: Max Reitz (cherry picked from commit b8c1f90118ee81090ff9093790f88bf335132814) This patch was modified for the lack of 998b3a1e5a2dd23bf89a853e15fab, by adding the 'QDict *options' parameter to ssh_refresh_filename(), matching the requested prototype, and setting bs->full_open_options to the specified option (following the hint of Max Reitz). Signed-off-by: Pino Toscano Signed-off-by: Danilo C. L. de Paula --- block/ssh.c | 55 +++++++++++++++++++++++++++++++++++++++---- tests/qemu-iotests/207 | 10 ++++---- tests/qemu-iotests/207.out | 10 ++++---- tests/qemu-iotests/common.rc | 2 +- tests/qemu-iotests/iotests.py | 2 +- 5 files changed, 62 insertions(+), 17 deletions(-) diff --git a/block/ssh.c b/block/ssh.c index 89abce0..f0ef874 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -75,6 +75,14 @@ typedef struct BDRVSSHState { /* Used to warn if 'flush' is not supported. */ bool unsafe_flush_warning; + + /* + * Store the user name for ssh_refresh_filename() because the + * default depends on the system you are on -- therefore, when we + * generate a filename, it should always contain the user name we + * are actually using. + */ + char *user; } BDRVSSHState; static void ssh_state_init(BDRVSSHState *s) @@ -87,6 +95,8 @@ static void ssh_state_init(BDRVSSHState *s) static void ssh_state_free(BDRVSSHState *s) { + g_free(s->user); + if (s->sftp_handle) { libssh2_sftp_close(s->sftp_handle); } @@ -628,14 +638,13 @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts, int ssh_flags, int creat_mode, Error **errp) { int r, ret; - const char *user; long port = 0; if (opts->has_user) { - user = opts->user; + s->user = g_strdup(opts->user); } else { - user = g_get_user_name(); - if (!user) { + s->user = g_strdup(g_get_user_name()); + if (!s->user) { error_setg_errno(errp, errno, "Can't get user name"); ret = -errno; goto err; @@ -685,7 +694,7 @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts, } /* Authenticate. */ - ret = authenticate(s, user, errp); + ret = authenticate(s, s->user, errp); if (ret < 0) { goto err; } @@ -1240,6 +1249,41 @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset, return ssh_grow_file(s, offset, errp); } +static void ssh_refresh_filename(BlockDriverState *bs, QDict *options) +{ + BDRVSSHState *s = bs->opaque; + const char *path, *host_key_check; + int ret; + + qdict_put_str(options, "driver", "ssh"); + bs->full_open_options = qobject_ref(options); + + /* + * None of these options can be represented in a plain "host:port" + * format, so if any was given, we have to abort. + */ + if (s->inet->has_ipv4 || s->inet->has_ipv6 || s->inet->has_to || + s->inet->has_numeric) + { + return; + } + + path = qdict_get_try_str(bs->full_open_options, "path"); + assert(path); /* mandatory option */ + + host_key_check = qdict_get_try_str(bs->full_open_options, "host_key_check"); + + ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "ssh://%s@%s:%s%s%s%s", + s->user, s->inet->host, s->inet->port, path, + host_key_check ? "?host_key_check=" : "", + host_key_check ?: ""); + if (ret >= sizeof(bs->exact_filename)) { + /* An overflow makes the filename unusable, so do not report any */ + bs->exact_filename[0] = '\0'; + } +} + static BlockDriver bdrv_ssh = { .format_name = "ssh", .protocol_name = "ssh", @@ -1255,6 +1299,7 @@ static BlockDriver bdrv_ssh = { .bdrv_getlength = ssh_getlength, .bdrv_co_truncate = ssh_co_truncate, .bdrv_co_flush_to_disk = ssh_co_flush, + .bdrv_refresh_filename = ssh_refresh_filename, .create_opts = &ssh_create_opts, }; diff --git a/tests/qemu-iotests/207 b/tests/qemu-iotests/207 index 444ae23..8202bd1 100755 --- a/tests/qemu-iotests/207 +++ b/tests/qemu-iotests/207 @@ -62,7 +62,7 @@ with iotests.FilePath('t.img') as disk_path, \ 'size': 4194304 }) vm.shutdown() - iotests.img_info_log(remote_path, filter_path=disk_path) + iotests.img_info_log(remote_path) iotests.log("") iotests.img_info_log(disk_path) @@ -87,7 +87,7 @@ with iotests.FilePath('t.img') as disk_path, \ 'size': 8388608 }) vm.shutdown() - iotests.img_info_log(remote_path, filter_path=disk_path) + iotests.img_info_log(remote_path) vm.launch() blockdev_create(vm, { 'driver': 'ssh', @@ -104,7 +104,7 @@ with iotests.FilePath('t.img') as disk_path, \ 'size': 4194304 }) vm.shutdown() - iotests.img_info_log(remote_path, filter_path=disk_path) + iotests.img_info_log(remote_path) md5_key = subprocess.check_output( 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' + @@ -142,7 +142,7 @@ with iotests.FilePath('t.img') as disk_path, \ 'size': 8388608 }) vm.shutdown() - iotests.img_info_log(remote_path, filter_path=disk_path) + iotests.img_info_log(remote_path) sha1_key = subprocess.check_output( 'ssh-keyscan -t rsa 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' + @@ -180,7 +180,7 @@ with iotests.FilePath('t.img') as disk_path, \ 'size': 4194304 }) vm.shutdown() - iotests.img_info_log(remote_path, filter_path=disk_path) + iotests.img_info_log(remote_path) # # Invalid path and user diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out index 078b7e6..fc131a6 100644 --- a/tests/qemu-iotests/207.out +++ b/tests/qemu-iotests/207.out @@ -5,7 +5,7 @@ {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} {u'return': {}} -image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} +image: TEST_IMG file format: IMGFMT virtual size: 4.0M (4194304 bytes) @@ -21,7 +21,7 @@ virtual size: 4.0M (4194304 bytes) {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} {u'return': {}} -image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} +image: TEST_IMG file format: IMGFMT virtual size: 8.0M (8388608 bytes) @@ -30,7 +30,7 @@ virtual size: 8.0M (8388608 bytes) {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} {u'return': {}} -image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} +image: TEST_IMG file format: IMGFMT virtual size: 4.0M (4194304 bytes) @@ -45,7 +45,7 @@ Job failed: remote host key does not match host_key_check 'wrong' {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} {u'return': {}} -image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} +image: TEST_IMG file format: IMGFMT virtual size: 8.0M (8388608 bytes) @@ -60,7 +60,7 @@ Job failed: remote host key does not match host_key_check 'wrong' {'execute': 'job-dismiss', 'arguments': {'id': 'job0'}} {u'return': {}} -image: json:{"driver": "IMGFMT", "file": {"server.host": "127.0.0.1", "server.port": "22", "driver": "ssh", "path": "TEST_IMG"}} +image: TEST_IMG file format: IMGFMT virtual size: 4.0M (4194304 bytes) diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 6490c8d..9ff8fa1 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -145,7 +145,7 @@ else TEST_IMG="nbd:127.0.0.1:10810" elif [ "$IMGPROTO" = "ssh" ]; then TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT - REMOTE_TEST_DIR="ssh://127.0.0.1$TEST_DIR" + REMOTE_TEST_DIR="ssh://\\($USER@\\)\\?127.0.0.1\\(:[0-9]\\+\\)\\?$TEST_DIR" TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE" elif [ "$IMGPROTO" = "nfs" ]; then TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 4e67fbb..0f6980a 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -325,7 +325,7 @@ def remote_filename(path): if imgproto == 'file': return path elif imgproto == 'ssh': - return "ssh://127.0.0.1%s" % (path) + return "ssh://%s@127.0.0.1:22%s" % (os.environ.get('USER'), path) else: raise Exception("Protocol %s not supported" % (imgproto)) -- 1.8.3.1