qemu_img.py 26.0 KB
Newer Older
L
Lucas Meneghel Rodrigues 已提交
1
import os
2 3
import time
import re
L
Lucas Meneghel Rodrigues 已提交
4 5
import logging
import commands
6 7
import shutil
import tempfile
8

X
Xu Han 已提交
9
from avocado.utils import process
10

X
Xu Han 已提交
11
from virttest import error_context
12 13 14 15 16
from virttest import utils_misc
from virttest import env_process
from virttest import storage
from virttest import data_dir
from virttest import gluster
17 18


X
Xu Han 已提交
19
@error_context.context_aware
20
def run(test, params, env):
21 22 23 24 25
    """
    'qemu-img' functions test:
    1) Judge what subcommand is going to be tested
    2) Run subcommand test

L
Lucas Meneghel Rodrigues 已提交
26 27 28
    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
29
    """
30 31
    qemu_img_binary = utils_misc.get_qemu_img_binary(params)
    cmd = qemu_img_binary
32
    if not os.path.exists(cmd):
X
Xu Han 已提交
33
        test.error("Binary of 'qemu-img' not found")
34
    image_format = params["image_format"]
35
    image_size = params.get("image_size", "10G")
F
Feng Yang 已提交
36
    enable_gluster = params.get("enable_gluster", "no") == "yes"
37
    image_name = storage.get_image_filename(params, data_dir.get_data_dir())
38

F
Feng Yang 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
    def remove(path):
        try:
            os.remove(path)
        except OSError:
            pass

    def _get_image_filename(img_name, enable_gluster=False, img_fmt=None):
        """
        Generate an image path.

        :param image_name: Force name of image.
        :param enable_gluster: Enable gluster or not.
        :param image_format: Format for image.
        """
        if enable_gluster:
            gluster_uri = gluster.create_gluster_uri(params)
            image_filename = "%s%s" % (gluster_uri, img_name)
            if img_fmt:
                image_filename += ".%s" % img_fmt
        else:
            if img_fmt:
                img_name = "%s.%s" % (img_name, img_fmt)
            image_filename = utils_misc.get_path(data_dir.get_data_dir(),
                                                 img_name)
        return image_filename

65 66 67 68
    def _check(cmd, img):
        """
        Simple 'qemu-img check' function implementation.

L
Lucas Meneghel Rodrigues 已提交
69 70
        :param cmd: qemu-img base command.
        :param img: image to be checked
71 72
        """
        cmd += " check %s" % img
X
Xu Han 已提交
73 74
        error_context.context("Checking image '%s' by command '%s'"
                              % (img, cmd), logging.info)
75
        try:
X
Xu Han 已提交
76 77
            output = process.system_output(cmd, verbose=False)
        except process.CmdError, err:
78
            if "does not support checks" in str(err):
79 80
                return (True, "")
            else:
81
                return (False, str(err))
82 83 84 85 86 87 88 89 90
        return (True, output)

    def check_test(cmd):
        """
        Subcommand 'qemu-img check' test.

        This tests will 'dd' to create a specified size file, and check it.
        Then convert it to supported image_format in each loop and check again.

L
Lucas Meneghel Rodrigues 已提交
91
        :param cmd: qemu-img base command.
92
        """
F
Feng Yang 已提交
93 94
        test_image = _get_image_filename(params["image_name_dd"],
                                         enable_gluster)
95
        create_image_cmd = params["create_image_cmd"]
96
        create_image_cmd = create_image_cmd % test_image
97
        msg = " Create image %s by command %s" % (test_image, create_image_cmd)
X
Xu Han 已提交
98
        error_context.context(msg, logging.info)
X
Xu Han 已提交
99
        process.system(create_image_cmd, verbose=False, shell=True)
100 101
        status, output = _check(cmd, test_image)
        if not status:
X
Xu Han 已提交
102 103
            test.fail("Check image '%s' failed with error: %s" %
                      (test_image, output))
104
        for fmt in params["supported_image_formats"].split():
105 106
            output_image = test_image + ".%s" % fmt
            _convert(cmd, fmt, test_image, output_image)
107 108
            status, output = _check(cmd, output_image)
            if not status:
X
Xu Han 已提交
109 110
                test.fail("Check image '%s' got error: %s" %
                          (output_image, output))
F
Feng Yang 已提交
111 112
            remove(output_image)
        remove(test_image)
113 114

    def _create(cmd, img_name, fmt, img_size=None, base_img=None,
115
                base_img_fmt=None, encrypted="no",
116
                preallocated="off", cluster_size=None):
117 118 119
        """
        Simple wrapper of 'qemu-img create'

L
Lucas Meneghel Rodrigues 已提交
120 121 122 123 124 125 126
        :param cmd: qemu-img base command.
        :param img_name: name of the image file
        :param fmt: image format
        :param img_size:  image size
        :param base_img: base image if create a snapshot image
        :param base_img_fmt: base image format if create a snapshot image
        :param encrypted: indicates whether the created image is encrypted
127 128 129
        :param preallocated: if preallocation when create image,
                             allowed values: off, metadata. Default is "off"
        :param cluster_size: the cluster size for the image
130 131
        """
        cmd += " create"
132

133 134 135 136 137 138
        if encrypted == "yes":
            cmd += " -e"
        if base_img:
            cmd += " -b %s" % base_img
            if base_img_fmt:
                cmd += " -F %s" % base_img_fmt
139

140
        cmd += " -f %s" % fmt
141 142 143 144 145 146 147

        options = []
        if preallocated != "off":
            options.append("preallocation=%s" % preallocated)
        if cluster_size is not None:
            options.append("cluster_size=%s" % cluster_size)
        if options:
148
            cmd += " -o %s" % ",".join(options)
149

150 151 152
        cmd += " %s" % img_name
        if img_size:
            cmd += " %s" % img_size
153

154
        msg = "Creating image %s by command %s" % (img_name, cmd)
X
Xu Han 已提交
155 156
        error_context.context(msg, logging.info)
        process.system(cmd, verbose=False)
157 158
        status, out = _check(qemu_img_binary, img_name)
        if not status:
X
Xu Han 已提交
159
            test.fail("Check image '%s' got error: %s" % (img_name, out))
160 161 162 163 164

    def create_test(cmd):
        """
        Subcommand 'qemu-img create' test.

L
Lucas Meneghel Rodrigues 已提交
165
        :param cmd: qemu-img base command.
166
        """
167
        image_large = params["image_name_large"]
168 169
        device = params.get("device")
        if not device:
F
Feng Yang 已提交
170 171
            img = _get_image_filename(image_large, enable_gluster,
                                      image_format)
172 173
        else:
            img = device
174
        _create(cmd, img_name=img, fmt=image_format,
175
                img_size=params["image_size_large"],
176 177
                preallocated=params.get("preallocated", "off"),
                cluster_size=params.get("image_cluster_size"))
F
Feng Yang 已提交
178
        remove(img)
179

180 181 182 183 184 185 186 187 188
    def send_signal(timeout=360):
        """
        send signal "SIGUSR1" to qemu-img without the option -p
        to report progress
        """
        logging.info("Send signal to qemu-img")
        end_time = time.time() + timeout
        while time.time() < end_time:
            time.sleep(1)
X
Xu Han 已提交
189
            status = process.system("kill -SIGUSR1 `pidof qemu-img`",
X
Xu Han 已提交
190
                                    ignore_status=True, shell=True)
191 192 193 194 195 196 197 198 199 200 201 202
            if status == 0:
                return None
        logging.info("Fail to get pid of qemu-img")

    def check_command_output(CmdResult):
        """
        Check standard error or standard output of command
        : param CmdResult: a list of CmdResult objects
        """
        logging.info("Check result of command")
        check_output = params.get("check_output", "exit_status")
        if not hasattr(CmdResult, check_output):
X
Xu Han 已提交
203
            test.error("Unknown check output '%s'" % check_output)
204 205 206 207 208
        output = getattr(CmdResult, check_output)
        if check_output == "exit_status" and output == 0:
            return None
        if check_output == "exit_status" and output != 0:
            err_msg = "Get nonzero exit status(%d) '%s'"
X
Xu Han 已提交
209
            test.fail(err_msg % (output, CmdResult.command))
210 211 212 213
        pattern = params.get("command_result_pattern")
        if not re.findall(pattern, output):
            err_msg = "Fail to get expected result!"
            err_msg += "Output: %s, expected pattern: %s" % (output, pattern)
X
Xu Han 已提交
214
            test.fail(err_msg)
215

216
    def _convert(cmd, output_fmt, img_name, output_filename,
L
Lucas Meneghel Rodrigues 已提交
217
                 fmt=None, compressed="no", encrypted="no"):
218 219 220
        """
        Simple wrapper of 'qemu-img convert' function.

L
Lucas Meneghel Rodrigues 已提交
221 222 223 224 225 226 227
        :param cmd: qemu-img base command.
        :param output_fmt: the output format of converted image
        :param img_name: image name that to be converted
        :param output_filename: output image name that converted
        :param fmt: output image format
        :param compressed: whether output image is compressed
        :param encrypted: whether output image is encrypted
228 229 230 231 232 233
        """
        cmd += " convert"
        if compressed == "yes":
            cmd += " -c"
        if encrypted == "yes":
            cmd += " -e"
234 235 236
        show_progress = params.get("show_progress", "")
        if show_progress == "on":
            cmd += " -p"
237 238 239
        if fmt:
            cmd += " -f %s" % fmt
        cmd += " -O %s" % output_fmt
240 241 242 243 244 245 246 247
        options = params.get("qemu_img_options")
        if options:
            options = options.split()
            cmd += " -o "
            for option in options:
                value = params.get(option)
                cmd += "%s=%s," % (option, value)
            cmd = cmd.rstrip(",")
248
        cmd += " %s %s" % (img_name, output_filename)
249 250
        msg = "Converting '%s' from format '%s'" % (img_name, fmt)
        msg += " to '%s'" % output_fmt
X
Xu Han 已提交
251
        error_context.context(msg, logging.info)
252
        if show_progress == "off":
X
Xu Han 已提交
253
            bg = utils_misc.InterruptedThread(send_signal)
254
            bg.start()
X
Xu Han 已提交
255
        check_command_output(process.run(cmd, ignore_status=True))
256 257 258 259 260

    def convert_test(cmd):
        """
        Subcommand 'qemu-img convert' test.

L
Lucas Meneghel Rodrigues 已提交
261
        :param cmd: qemu-img base command.
262
        """
263
        dest_img_fmt = params["dest_image_format"]
264 265
        output_filename = "%s.converted_%s.%s" % (image_name,
                                                  dest_img_fmt, dest_img_fmt)
266 267

        _convert(cmd, dest_img_fmt, image_name, output_filename,
L
Lucas Meneghel Rodrigues 已提交
268
                 image_format, params["compressed"], params["encrypted"])
269 270 271 272
        orig_img_name = params.get("image_name")
        img_name = "%s.%s.converted_%s" % (orig_img_name,
                                           image_format, dest_img_fmt)
        _boot(img_name, dest_img_fmt)
273 274

        if dest_img_fmt == "qcow2":
275 276
            status, output = _check(cmd, output_filename)
            if status:
F
Feng Yang 已提交
277
                remove(output_filename)
278
            else:
X
Xu Han 已提交
279 280
                test.fail("Check image '%s' failed with error: %s" %
                          (output_filename, output))
281
        else:
F
Feng Yang 已提交
282
            remove(output_filename)
283 284 285 286 287

    def _info(cmd, img, sub_info=None, fmt=None):
        """
        Simple wrapper of 'qemu-img info'.

L
Lucas Meneghel Rodrigues 已提交
288 289 290 291
        :param cmd: qemu-img base command.
        :param img: image file
        :param sub_info: sub info, say 'backing file'
        :param fmt: image format
292 293 294 295 296 297 298
        """
        cmd += " info"
        if fmt:
            cmd += " -f %s" % fmt
        cmd += " %s" % img

        try:
X
Xu Han 已提交
299 300
            output = process.system_output(cmd)
        except process.CmdError, err:
301
            logging.error("Get info of image '%s' failed: %s", img, str(err))
302 303 304 305 306 307 308
            return None

        if not sub_info:
            return output

        sub_info += ": (.*)"
        matches = re.findall(sub_info, output)
309 310 311
        if "virtual size" in sub_info:
            p = re.compile(r'\.0*(G|K)$')
            return p.sub(r'\1', matches[0].split()[0])
312 313 314 315 316 317 318 319
        if matches:
            return matches[0]
        return None

    def info_test(cmd):
        """
        Subcommand 'qemu-img info' test.

L
Lucas Meneghel Rodrigues 已提交
320
        :param cmd: qemu-img base command.
321 322 323
        """
        img_info = _info(cmd, image_name)
        logging.info("Info of image '%s':\n%s", image_name, img_info)
324
        if image_format not in img_info:
X
Xu Han 已提交
325 326
            test.fail("Got unexpected format of image '%s'"
                      " in info test" % image_name)
327
        if image_size not in img_info:
X
Xu Han 已提交
328 329
            test.fail("Got unexpected size of image '%s'"
                      " in info test" % image_name)
330 331 332 333 334

    def snapshot_test(cmd):
        """
        Subcommand 'qemu-img snapshot' test.

L
Lucas Meneghel Rodrigues 已提交
335
        :param cmd: qemu-img base command.
336 337 338 339 340 341
        """
        cmd += " snapshot"
        for i in range(2):
            crtcmd = cmd
            sn_name = "snapshot%d" % i
            crtcmd += " -c %s %s" % (sn_name, image_name)
342
            msg = "Created snapshot '%s' in '%s' by command %s" % (sn_name,
F
Feng Yang 已提交
343 344
                                                                   image_name,
                                                                   crtcmd)
X
Xu Han 已提交
345
            error_context.context(msg, logging.info)
346 347
            status, output = commands.getstatusoutput(crtcmd)
            if status != 0:
X
Xu Han 已提交
348 349
                test.fail("Create snapshot failed via command: %s;"
                          "Output is: %s" % (crtcmd, output))
350 351
        listcmd = cmd
        listcmd += " -l %s" % image_name
352 353
        status, out = commands.getstatusoutput(listcmd)
        if not ("snapshot0" in out and "snapshot1" in out and status == 0):
X
Xu Han 已提交
354 355
            test.fail("Snapshot created failed or missed;"
                      "snapshot list is: \n%s" % out)
356 357 358 359
        for i in range(2):
            sn_name = "snapshot%d" % i
            delcmd = cmd
            delcmd += " -d %s %s" % (sn_name, image_name)
360
            msg = "Delete snapshot '%s' by command %s" % (sn_name, delcmd)
X
Xu Han 已提交
361
            error_context.context(msg, logging.info)
362 363
            status, output = commands.getstatusoutput(delcmd)
            if status != 0:
X
Xu Han 已提交
364 365
                test.fail("Delete snapshot '%s' failed: %s" %
                          (sn_name, output))
366 367 368 369

    def commit_test(cmd):
        """
        Subcommand 'qemu-img commit' test.
C
Cong Li 已提交
370 371 372
        1) Create a overlay file of the qemu harddisk specified by image_name.
        2) Start a VM using the overlay file as its harddisk.
        3) Touch a file "commit_testfile" in the overlay file, and shutdown the
373
           VM.
C
Cong Li 已提交
374
        4) Commit the change to the backing harddisk by executing
375
           "qemu-img commit" command.
C
Cong Li 已提交
376 377
        5) Start the VM using the backing harddisk.
        6) Check if the file "commit_testfile" exists.
378

L
Lucas Meneghel Rodrigues 已提交
379
        :param cmd: qemu-img base command.
380 381 382
        """

        logging.info("Commit testing started!")
F
Feng Yang 已提交
383 384 385
        image_name = storage.get_image_filename(params,
                                                data_dir.get_data_dir())
        pre_name = '.'.join(image_name.split('.')[:-1])
386
        image_format = params.get("image_format", "qcow2")
F
Feng Yang 已提交
387
        overlay_file_name = "%s_overlay.%s" % (pre_name, image_format)
388 389 390 391 392 393 394 395
        file_create_cmd = params.get("file_create_cmd",
                                     "touch /commit_testfile")
        file_info_cmd = params.get("file_info_cmd",
                                   "ls / | grep commit_testfile")
        file_exist_chk_cmd = params.get("file_exist_chk_cmd",
                                        "[ -e /commit_testfile ] && echo $?")
        file_del_cmd = params.get("file_del_cmd",
                                  "rm -f /commit_testfile")
396
        try:
C
Cong Li 已提交
397
            # Remove the existing overlay file
F
Feng Yang 已提交
398 399
            if os.path.isfile(overlay_file_name):
                remove(overlay_file_name)
400

C
Cong Li 已提交
401
            # Create the new overlay file
F
Feng Yang 已提交
402 403 404
            create_cmd = "%s create -b %s -f %s %s" % (cmd, image_name,
                                                       image_format,
                                                       overlay_file_name)
C
Cong Li 已提交
405
            msg = "Create overlay file by command: %s" % create_cmd
X
Xu Han 已提交
406
            error_context.context(msg, logging.info)
407
            try:
X
Xu Han 已提交
408 409 410
                process.system(create_cmd, verbose=False)
            except process.CmdError:
                test.fail("Could not create a overlay file!")
411
            logging.info("overlay file (%s) created!" % overlay_file_name)
412

C
Cong Li 已提交
413
            # Set the qemu harddisk to the overlay file
L
Lucas Meneghel Rodrigues 已提交
414 415
            logging.info(
                "Original image_name is: %s", params.get('image_name'))
416
            params['image_name'] = '.'.join(overlay_file_name.split('.')[:-1])
417 418 419
            logging.info("Param image_name changed to: %s",
                         params.get('image_name'))

C
Cong Li 已提交
420
            msg = "Start a new VM, using overlay file as its harddisk"
X
Xu Han 已提交
421
            error_context.context(msg, logging.info)
422
            vm_name = params['main_vm']
423 424
            env_process.preprocess_vm(test, params, env, vm_name)
            vm = env.get_vm(vm_name)
425
            vm.verify_alive()
426 427 428
            timeout = int(params.get("login_timeout", 360))
            session = vm.wait_for_login(timeout=timeout)

C
Cong Li 已提交
429
            # Do some changes to the overlay_file harddisk
430
            try:
431 432 433 434 435
                output = session.cmd(file_create_cmd)
                logging.info("Output of %s: %s", file_create_cmd, output)
                output = session.cmd(file_info_cmd)
                logging.info("Output of %s: %s", file_info_cmd, output)
            except Exception, err:
X
Xu Han 已提交
436 437
                test.fail("Could not create commit_testfile in the "
                          "overlay file %s" % err)
438 439
            vm.destroy()

L
Lucas Meneghel Rodrigues 已提交
440
            # Execute the commit command
F
Feng Yang 已提交
441 442
            cmitcmd = "%s commit -f %s %s" % (cmd, image_format,
                                              overlay_file_name)
X
Xu Han 已提交
443 444
            error_context.context("Committing image by command %s" % cmitcmd,
                                  logging.info)
445
            try:
X
Xu Han 已提交
446 447 448
                process.system(cmitcmd, verbose=False)
            except process.CmdError:
                test.fail("Could not commit the overlay file")
449
            logging.info("overlay file (%s) committed!" % overlay_file_name)
450

451
            msg = "Start a new VM, using image_name as its harddisk"
X
Xu Han 已提交
452
            error_context.context(msg, logging.info)
453
            params['image_name'] = pre_name
454
            vm_name = params['main_vm']
455 456
            env_process.preprocess_vm(test, params, env, vm_name)
            vm = env.get_vm(vm_name)
457
            vm.verify_alive()
458 459 460
            timeout = int(params.get("login_timeout", 360))
            session = vm.wait_for_login(timeout=timeout)
            try:
461 462 463
                output = session.cmd(file_exist_chk_cmd)
                logging.info("Output of %s: %s", file_exist_chk_cmd, output)
                session.cmd(file_del_cmd)
464
            except Exception:
X
Xu Han 已提交
465
                test.fail("Could not find commit_testfile after a commit")
466 467 468
            vm.destroy()

        finally:
C
Cong Li 已提交
469
            # Remove the overlay file
F
Feng Yang 已提交
470 471
            if os.path.isfile(overlay_file_name):
                remove(overlay_file_name)
472 473 474 475 476

    def _rebase(cmd, img_name, base_img, backing_fmt, mode="unsafe"):
        """
        Simple wrapper of 'qemu-img rebase'.

L
Lucas Meneghel Rodrigues 已提交
477 478 479 480 481
        :param cmd: qemu-img base command.
        :param img_name: image name to be rebased
        :param base_img: indicates the base image
        :param backing_fmt: the format of base image
        :param mode: rebase mode: safe mode, unsafe mode
482 483
        """
        cmd += " rebase"
484
        show_progress = params.get("show_progress", "")
485 486
        if mode == "unsafe":
            cmd += " -u"
487 488
        if show_progress == "on":
            cmd += " -p"
489
        cmd += " -b %s -F %s %s" % (base_img, backing_fmt, img_name)
490
        msg = "Trying to rebase '%s' to '%s' by command %s" % (img_name,
L
Lucas Meneghel Rodrigues 已提交
491
                                                               base_img, cmd)
X
Xu Han 已提交
492
        error_context.context(msg, logging.info)
493
        if show_progress == "off":
X
Xu Han 已提交
494
            bg = utils_misc.InterruptedThread(send_signal)
495
            bg.start()
X
Xu Han 已提交
496
        check_command_output(process.run(cmd))
497 498 499 500 501 502 503 504 505 506

    def rebase_test(cmd):
        """
        Subcommand 'qemu-img rebase' test

        Change the backing file of a snapshot image in "unsafe mode":
        Assume the previous backing file had missed and we just have to change
        reference of snapshot to new one. After change the backing file of a
        snapshot image in unsafe mode, the snapshot should work still.

L
Lucas Meneghel Rodrigues 已提交
507
        :param cmd: qemu-img base command.
508
        """
X
Xu Han 已提交
509 510 511 512
        if 'rebase' not in process.system_output(cmd + ' --help',
                                                 ignore_status=True):
            test.cancel("Current kvm user space version does not"
                        " support 'rebase' subcommand")
513
        sn_fmt = params.get("snapshot_format", "qcow2")
514
        sn1 = params["image_name_snapshot1"]
F
Feng Yang 已提交
515
        sn1 = _get_image_filename(sn1, enable_gluster, sn_fmt)
516
        base_img = storage.get_image_filename(params, data_dir.get_data_dir())
517 518 519
        _create(cmd, sn1, sn_fmt, base_img=base_img, base_img_fmt=image_format)

        # Create snapshot2 based on snapshot1
520
        sn2 = params["image_name_snapshot2"]
F
Feng Yang 已提交
521
        sn2 = _get_image_filename(sn2, enable_gluster, sn_fmt)
522 523
        _create(cmd, sn2, sn_fmt, base_img=sn1, base_img_fmt=sn_fmt)

524
        rebase_mode = params.get("rebase_mode", "safe")
525
        if rebase_mode == "unsafe":
F
Feng Yang 已提交
526
            remove(sn1)
527 528

        _rebase(cmd, sn2, base_img, image_format, mode=rebase_mode)
529
        # Boot snapshot image after rebase
F
Feng Yang 已提交
530 531
        img_format = sn2.split('.')[-1]
        img_name = ".".join(sn2.split('.')[:-1])
532
        _boot(img_name, img_format)
533 534 535

        # Check sn2's format and backing_file
        actual_base_img = _info(cmd, sn2, "backing file")
536
        base_img_name = os.path.basename(base_img)
537
        if base_img_name not in actual_base_img:
X
Xu Han 已提交
538 539 540
            test.fail("After rebase the backing_file of 'sn2' is "
                      "'%s' which is not expected as '%s'"
                      % (actual_base_img, base_img_name))
541 542
        status, output = _check(cmd, sn2)
        if not status:
X
Xu Han 已提交
543 544
            test.fail("Check image '%s' failed after rebase;"
                      "got error: %s" % (sn2, output))
F
Feng Yang 已提交
545 546
        remove(sn2)
        remove(sn1)
547

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
    def _amend(cmd, img_name, img_fmt, options):
        """
        Simple wrapper of 'qemu-img amend'.

        :param cmd: qemu-img base command
        :param img_name: image name that should be amended
        :param img_fmt: image format
        :param options: a comma separated list of format specific options
        """

        msg = "Amend '%s' with options '%s'" % (img_name, options)
        cmd += " amend"
        if img_fmt:
            cmd += " -f %s" % img_fmt
        cache = params.get("cache_mode", '')
        if cache:
            cmd += " -t %s" % cache
        if options:
            cmd += " -o "
            for option in options:
                cmd += "%s=%s," % (option, params.get(option))
            cmd = cmd.rstrip(',')
        cmd += " %s" % img_name
X
Xu Han 已提交
571 572
        error_context.context(msg, logging.info)
        check_command_output(process.run(cmd, ignore_status=True))
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595

    def amend_test(cmd):
        """
        Subcommand 'qemu-img amend' test
        Amend the image format specific options for the image file

        :param cmd: qemu-img base command.
        """
        img_name = params.get("image_name_stg")
        img_fmt = params.get("image_format_stg", "qcow2")
        options = params.get("qemu_img_options", "").split()
        check_output = params.get("check_output", "exit_status")
        img = _get_image_filename(img_name, img_fmt=img_fmt)
        _amend(cmd, img, img_fmt, options)
        if check_output == "exit_status":
            for option in options:
                expect = params.get(option)
                if option == "size":
                    option = "virtual size"
                actual = _info(cmd, img, option)
                if actual is not None and actual != expect:
                    msg = "Get wrong %s from image %s!" % (option, img_name)
                    msg += "Expect: %s, actual: %s" % (expect, actual)
X
Xu Han 已提交
596
                    test.fail(msg)
597 598
        status, output = _check(cmd, img)
        if not status:
X
Xu Han 已提交
599 600
            test.fail("Check image '%s' failed after rebase;"
                      "got error: %s" % (img, output))
601

602 603 604 605 606 607 608
    def _boot(img_name, img_fmt):
        """
        Boot test:
        1) Login guest
        2) Run dd in rhel guest
        3) Shutdown guest

L
Lucas Meneghel Rodrigues 已提交
609 610
        :param img_name: image name
        :param img_fmt: image format
611 612 613 614 615
        """
        params['image_name'] = img_name
        params['image_format'] = img_fmt
        image_name = "%s.%s" % (img_name, img_fmt)
        msg = "Try to boot vm with image %s" % image_name
X
Xu Han 已提交
616
        error_context.context(msg, logging.info)
617 618 619 620 621 622 623 624 625 626 627 628
        vm_name = params.get("main_vm")
        dd_timeout = int(params.get("dd_timeout", 60))
        params['vms'] = vm_name
        env_process.preprocess_vm(test, params, env, vm_name)
        vm = env.get_vm(params.get("main_vm"))
        vm.verify_alive()
        login_timeout = int(params.get("login_timeout", 360))
        session = vm.wait_for_login(timeout=login_timeout)

        # Run dd in linux guest
        if params.get("os_type") == 'linux':
            cmd = "dd if=/dev/zero of=/mnt/test bs=1000 count=1000"
X
Xu Han 已提交
629
            status = session.cmd_status(cmd, timeout=dd_timeout)
630
            if status != 0:
X
Xu Han 已提交
631
                test.error("dd failed")
632

X
Xu Han 已提交
633
        error_context.context("Shutdown guest", logging.info)
634
        try:
X
Xu Tian 已提交
635 636 637 638 639 640 641
            vm.graceful_shutdown(timeout=login_timeout)
        except Exception:
            image_filename = _get_image_filename(img_name,
                                                 enable_gluster,
                                                 img_fmt)
            backup_img_chain(image_filename)
            raise
642
        finally:
X
Xu Tian 已提交
643
            vm.destroy(gracefully=True)
X
Xu Han 已提交
644
            process.system("sync")
645

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
    def backup_img_chain(image_file):
        """
        Backup whole image in a image chain;
        """
        mount_point = tempfile.mkdtemp(dir=test.resultsdir)
        qemu_img = utils_misc.get_qemu_img_binary(params)
        if enable_gluster:
            g_uri = gluster.create_gluster_uri(params)
            gluster.glusterfs_mount(g_uri, mount_point)
            image_name = os.path.basename(image_file)
            image_file = os.path.join(mount_point, image_name)
        logging.warn("backup %s to %s" % (image_file, test.resultsdir))
        shutil.copy(image_file, test.resultsdir)
        backing_file = _info(qemu_img, image_file, "backing file", None)
        if backing_file:
            backup_img_chain(backing_file)
        elif enable_gluster:
            utils_misc.umount(g_uri, mount_point,
                              "glusterfs", False,
                              "fuse.glusterfs")
            shutil.rmtree(mount_point)
        return None

669
    # Here starts test
670
    subcommand = params["subcommand"]
X
Xu Han 已提交
671
    error_context.context("Running %s_test(cmd)" % subcommand, logging.info)
672
    eval("%s_test(cmd)" % subcommand)