xref: /openbmc/qemu/tests/qemu-iotests/219 (revision bdebdc712b06ba82e103d617c335830682cde242)
1*bdebdc71SKevin Wolf#!/usr/bin/env python
2*bdebdc71SKevin Wolf#
3*bdebdc71SKevin Wolf# Copyright (C) 2018 Red Hat, Inc.
4*bdebdc71SKevin Wolf#
5*bdebdc71SKevin Wolf# This program is free software; you can redistribute it and/or modify
6*bdebdc71SKevin Wolf# it under the terms of the GNU General Public License as published by
7*bdebdc71SKevin Wolf# the Free Software Foundation; either version 2 of the License, or
8*bdebdc71SKevin Wolf# (at your option) any later version.
9*bdebdc71SKevin Wolf#
10*bdebdc71SKevin Wolf# This program is distributed in the hope that it will be useful,
11*bdebdc71SKevin Wolf# but WITHOUT ANY WARRANTY; without even the implied warranty of
12*bdebdc71SKevin Wolf# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*bdebdc71SKevin Wolf# GNU General Public License for more details.
14*bdebdc71SKevin Wolf#
15*bdebdc71SKevin Wolf# You should have received a copy of the GNU General Public License
16*bdebdc71SKevin Wolf# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17*bdebdc71SKevin Wolf#
18*bdebdc71SKevin Wolf# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
19*bdebdc71SKevin Wolf#
20*bdebdc71SKevin Wolf# Check using the job-* QMP commands with block jobs
21*bdebdc71SKevin Wolf
22*bdebdc71SKevin Wolfimport iotests
23*bdebdc71SKevin Wolf
24*bdebdc71SKevin Wolfiotests.verify_image_format(supported_fmts=['qcow2'])
25*bdebdc71SKevin Wolf
26*bdebdc71SKevin Wolfdef pause_wait(vm, job_id):
27*bdebdc71SKevin Wolf    with iotests.Timeout(3, "Timeout waiting for job to pause"):
28*bdebdc71SKevin Wolf        while True:
29*bdebdc71SKevin Wolf            result = vm.qmp('query-jobs')
30*bdebdc71SKevin Wolf            for job in result['return']:
31*bdebdc71SKevin Wolf                if job['id'] == job_id and job['status'] in ['paused', 'standby']:
32*bdebdc71SKevin Wolf                    return job
33*bdebdc71SKevin Wolf
34*bdebdc71SKevin Wolf# Test that block-job-pause/resume and job-pause/resume can be mixed
35*bdebdc71SKevin Wolfdef test_pause_resume(vm):
36*bdebdc71SKevin Wolf    for pause_cmd, pause_arg in [('block-job-pause', 'device'),
37*bdebdc71SKevin Wolf                                 ('job-pause', 'id')]:
38*bdebdc71SKevin Wolf        for resume_cmd, resume_arg in [('block-job-resume', 'device'),
39*bdebdc71SKevin Wolf                                       ('job-resume', 'id')]:
40*bdebdc71SKevin Wolf            iotests.log('=== Testing %s/%s ===' % (pause_cmd, resume_cmd))
41*bdebdc71SKevin Wolf
42*bdebdc71SKevin Wolf            iotests.log(vm.qmp(pause_cmd, **{pause_arg: 'job0'}))
43*bdebdc71SKevin Wolf            pause_wait(vm, 'job0')
44*bdebdc71SKevin Wolf            iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
45*bdebdc71SKevin Wolf            iotests.log(vm.qmp('query-jobs'))
46*bdebdc71SKevin Wolf
47*bdebdc71SKevin Wolf            iotests.log(vm.qmp(resume_cmd, **{resume_arg: 'job0'}))
48*bdebdc71SKevin Wolf            iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
49*bdebdc71SKevin Wolf            iotests.log(vm.qmp('query-jobs'))
50*bdebdc71SKevin Wolf
51*bdebdc71SKevin Wolfdef test_job_lifecycle(vm, job, job_args, has_ready=False):
52*bdebdc71SKevin Wolf    iotests.log('')
53*bdebdc71SKevin Wolf    iotests.log('')
54*bdebdc71SKevin Wolf    iotests.log('Starting block job: %s (auto-finalize: %s; auto-dismiss: %s)' %
55*bdebdc71SKevin Wolf                (job,
56*bdebdc71SKevin Wolf                 job_args.get('auto-finalize', True),
57*bdebdc71SKevin Wolf                 job_args.get('auto-dismiss', True)))
58*bdebdc71SKevin Wolf    iotests.log(vm.qmp(job, job_id='job0', **job_args))
59*bdebdc71SKevin Wolf
60*bdebdc71SKevin Wolf    # Depending on the storage, the first request may or may not have completed
61*bdebdc71SKevin Wolf    # yet, so filter out the progress. Later query-job calls don't need the
62*bdebdc71SKevin Wolf    # filtering because the progress is made deterministic by the block job
63*bdebdc71SKevin Wolf    # speed
64*bdebdc71SKevin Wolf    result = vm.qmp('query-jobs')
65*bdebdc71SKevin Wolf    for j in result['return']:
66*bdebdc71SKevin Wolf        del j['current-progress']
67*bdebdc71SKevin Wolf    iotests.log(result)
68*bdebdc71SKevin Wolf
69*bdebdc71SKevin Wolf    # undefined -> created -> running
70*bdebdc71SKevin Wolf    iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
71*bdebdc71SKevin Wolf    iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
72*bdebdc71SKevin Wolf
73*bdebdc71SKevin Wolf    # RUNNING state:
74*bdebdc71SKevin Wolf    # pause/resume should work, complete/finalize/dismiss should error out
75*bdebdc71SKevin Wolf    iotests.log('')
76*bdebdc71SKevin Wolf    iotests.log('Pause/resume in RUNNING')
77*bdebdc71SKevin Wolf    test_pause_resume(vm)
78*bdebdc71SKevin Wolf
79*bdebdc71SKevin Wolf    iotests.log(vm.qmp('job-complete', id='job0'))
80*bdebdc71SKevin Wolf    iotests.log(vm.qmp('job-finalize', id='job0'))
81*bdebdc71SKevin Wolf    iotests.log(vm.qmp('job-dismiss', id='job0'))
82*bdebdc71SKevin Wolf
83*bdebdc71SKevin Wolf    iotests.log(vm.qmp('block-job-complete', device='job0'))
84*bdebdc71SKevin Wolf    iotests.log(vm.qmp('block-job-finalize', id='job0'))
85*bdebdc71SKevin Wolf    iotests.log(vm.qmp('block-job-dismiss', id='job0'))
86*bdebdc71SKevin Wolf
87*bdebdc71SKevin Wolf    # Let the job complete (or transition to READY if it supports that)
88*bdebdc71SKevin Wolf    iotests.log(vm.qmp('block-job-set-speed', device='job0', speed=0))
89*bdebdc71SKevin Wolf    if has_ready:
90*bdebdc71SKevin Wolf        iotests.log('')
91*bdebdc71SKevin Wolf        iotests.log('Waiting for READY state...')
92*bdebdc71SKevin Wolf        vm.event_wait('BLOCK_JOB_READY')
93*bdebdc71SKevin Wolf        iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
94*bdebdc71SKevin Wolf        iotests.log(vm.qmp('query-jobs'))
95*bdebdc71SKevin Wolf
96*bdebdc71SKevin Wolf        # READY state:
97*bdebdc71SKevin Wolf        # pause/resume/complete should work, finalize/dismiss should error out
98*bdebdc71SKevin Wolf        iotests.log('')
99*bdebdc71SKevin Wolf        iotests.log('Pause/resume in READY')
100*bdebdc71SKevin Wolf        test_pause_resume(vm)
101*bdebdc71SKevin Wolf
102*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-finalize', id='job0'))
103*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-dismiss', id='job0'))
104*bdebdc71SKevin Wolf
105*bdebdc71SKevin Wolf        iotests.log(vm.qmp('block-job-finalize', id='job0'))
106*bdebdc71SKevin Wolf        iotests.log(vm.qmp('block-job-dismiss', id='job0'))
107*bdebdc71SKevin Wolf
108*bdebdc71SKevin Wolf        # Transition to WAITING
109*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-complete', id='job0'))
110*bdebdc71SKevin Wolf
111*bdebdc71SKevin Wolf    # Move to WAITING and PENDING state
112*bdebdc71SKevin Wolf    iotests.log('')
113*bdebdc71SKevin Wolf    iotests.log('Waiting for PENDING state...')
114*bdebdc71SKevin Wolf    iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
115*bdebdc71SKevin Wolf    iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
116*bdebdc71SKevin Wolf
117*bdebdc71SKevin Wolf    if not job_args.get('auto-finalize', True):
118*bdebdc71SKevin Wolf        # PENDING state:
119*bdebdc71SKevin Wolf        # finalize should work, pause/complete/dismiss should error out
120*bdebdc71SKevin Wolf        iotests.log(vm.qmp('query-jobs'))
121*bdebdc71SKevin Wolf
122*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-pause', id='job0'))
123*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-complete', id='job0'))
124*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-dismiss', id='job0'))
125*bdebdc71SKevin Wolf
126*bdebdc71SKevin Wolf        iotests.log(vm.qmp('block-job-pause', device='job0'))
127*bdebdc71SKevin Wolf        iotests.log(vm.qmp('block-job-complete', device='job0'))
128*bdebdc71SKevin Wolf        iotests.log(vm.qmp('block-job-dismiss', id='job0'))
129*bdebdc71SKevin Wolf
130*bdebdc71SKevin Wolf        # Transition to CONCLUDED
131*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-finalize', id='job0'))
132*bdebdc71SKevin Wolf
133*bdebdc71SKevin Wolf
134*bdebdc71SKevin Wolf    # Move to CONCLUDED state
135*bdebdc71SKevin Wolf    iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
136*bdebdc71SKevin Wolf
137*bdebdc71SKevin Wolf    if not job_args.get('auto-dismiss', True):
138*bdebdc71SKevin Wolf        # CONCLUDED state:
139*bdebdc71SKevin Wolf        # dismiss should work, pause/complete/finalize should error out
140*bdebdc71SKevin Wolf        iotests.log(vm.qmp('query-jobs'))
141*bdebdc71SKevin Wolf
142*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-pause', id='job0'))
143*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-complete', id='job0'))
144*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-finalize', id='job0'))
145*bdebdc71SKevin Wolf
146*bdebdc71SKevin Wolf        iotests.log(vm.qmp('block-job-pause', device='job0'))
147*bdebdc71SKevin Wolf        iotests.log(vm.qmp('block-job-complete', device='job0'))
148*bdebdc71SKevin Wolf        iotests.log(vm.qmp('block-job-finalize', id='job0'))
149*bdebdc71SKevin Wolf
150*bdebdc71SKevin Wolf        # Transition to NULL
151*bdebdc71SKevin Wolf        iotests.log(vm.qmp('job-dismiss', id='job0'))
152*bdebdc71SKevin Wolf
153*bdebdc71SKevin Wolf    # Move to NULL state
154*bdebdc71SKevin Wolf    iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
155*bdebdc71SKevin Wolf    iotests.log(vm.qmp('query-jobs'))
156*bdebdc71SKevin Wolf
157*bdebdc71SKevin Wolf
158*bdebdc71SKevin Wolfwith iotests.FilePath('disk.img') as disk_path, \
159*bdebdc71SKevin Wolf     iotests.FilePath('copy.img') as copy_path, \
160*bdebdc71SKevin Wolf     iotests.VM() as vm:
161*bdebdc71SKevin Wolf
162*bdebdc71SKevin Wolf    img_size = '4M'
163*bdebdc71SKevin Wolf    iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, img_size)
164*bdebdc71SKevin Wolf    iotests.qemu_io('-c', 'write 0 %s' % (img_size),
165*bdebdc71SKevin Wolf                    '-f', iotests.imgfmt, disk_path)
166*bdebdc71SKevin Wolf
167*bdebdc71SKevin Wolf    iotests.log('Launching VM...')
168*bdebdc71SKevin Wolf    vm.add_blockdev(vm.qmp_to_opts({
169*bdebdc71SKevin Wolf        'driver': iotests.imgfmt,
170*bdebdc71SKevin Wolf        'node-name': 'drive0-node',
171*bdebdc71SKevin Wolf        'file': {
172*bdebdc71SKevin Wolf            'driver': 'file',
173*bdebdc71SKevin Wolf            'filename': disk_path,
174*bdebdc71SKevin Wolf        },
175*bdebdc71SKevin Wolf    }))
176*bdebdc71SKevin Wolf    vm.launch()
177*bdebdc71SKevin Wolf
178*bdebdc71SKevin Wolf    # In order to keep things deterministic (especially progress in query-job,
179*bdebdc71SKevin Wolf    # but related to this also automatic state transitions like job
180*bdebdc71SKevin Wolf    # completion), but still get pause points often enough to avoid making this
181*bdebdc71SKevin Wolf    # test very slow, it's important to have the right ratio between speed and
182*bdebdc71SKevin Wolf    # buf_size.
183*bdebdc71SKevin Wolf    #
184*bdebdc71SKevin Wolf    # For backup, buf_size is hard-coded to the source image cluster size (64k),
185*bdebdc71SKevin Wolf    # so we'll pick the same for mirror. The slice time, i.e. the granularity
186*bdebdc71SKevin Wolf    # of the rate limiting is 100ms. With a speed of 256k per second, we can
187*bdebdc71SKevin Wolf    # get four pause points per second. This gives us 250ms per iteration,
188*bdebdc71SKevin Wolf    # which should be enough to stay deterministic.
189*bdebdc71SKevin Wolf
190*bdebdc71SKevin Wolf    test_job_lifecycle(vm, 'drive-mirror', has_ready=True, job_args={
191*bdebdc71SKevin Wolf        'device': 'drive0-node',
192*bdebdc71SKevin Wolf        'target': copy_path,
193*bdebdc71SKevin Wolf        'sync': 'full',
194*bdebdc71SKevin Wolf        'speed': 262144,
195*bdebdc71SKevin Wolf        'buf_size': 65536,
196*bdebdc71SKevin Wolf    })
197*bdebdc71SKevin Wolf
198*bdebdc71SKevin Wolf    for auto_finalize in [True, False]:
199*bdebdc71SKevin Wolf        for auto_dismiss in [True, False]:
200*bdebdc71SKevin Wolf            test_job_lifecycle(vm, 'drive-backup', job_args={
201*bdebdc71SKevin Wolf                'device': 'drive0-node',
202*bdebdc71SKevin Wolf                'target': copy_path,
203*bdebdc71SKevin Wolf                'sync': 'full',
204*bdebdc71SKevin Wolf                'speed': 262144,
205*bdebdc71SKevin Wolf                'auto-finalize': auto_finalize,
206*bdebdc71SKevin Wolf                'auto-dismiss': auto_dismiss,
207*bdebdc71SKevin Wolf            })
208*bdebdc71SKevin Wolf
209*bdebdc71SKevin Wolf    vm.shutdown()
210