Bug 1731898

Summary: RFE: support for LUKS key management in qemu-img & QMP
Product: Red Hat Enterprise Linux Advanced Virtualization Reporter: Daniel Berrangé <berrange>
Component: qemu-kvmAssignee: Maxim Levitsky <mlevitsk>
qemu-kvm sub component: LUKS QA Contact: Xueqiang Wei <xuwei>
Status: CLOSED ERRATA Docs Contact:
Severity: medium    
Priority: medium CC: coli, ddepaula, knoel, mlevitsk, virt-maint
Version: 8.0Keywords: FutureFeature, Triaged
Target Milestone: rc   
Target Release: 8.0   
Hardware: All   
OS: All   
Whiteboard:
Fixed In Version: qemu-kvm-5.0.0-2.module+el8.3.0+7379+0505d6ca Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2020-11-17 17:45:27 UTC Type: Feature Request
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
luks_key_management.sh
none
luks-inside-qcow2_key_management.sh none

Description Daniel Berrangé 2019-07-22 10:56:29 UTC
Description of problem:
The LUKS encryption format supports multiple key slots. This allows multiple distinct passphrases to be used to unlock the same master encryption key. It also allows for replacement of the passphrases, by adding a new one then removing the old one. This is supported in the 'cryptsetup' tool via several key management commands.

When QEMU is being used with a raw LUKS volume, admins can still use the cryptsetup tool to do key management, however, when LUKS is used in qcow2 this is not practical, because the LUKS header will not be in the place that cryptsetup is expecting.

There is thus a need to support key management in the qemu-img command. We need two commands

 - crypto-add-key
   
   Needs to take an image file path, a key slot number, and the ID of a secret object providing the new passphrase.
   Key slot could be made optional to let us pick a free slot

 - crypto-remove-key

   Needs to take an image file path, and either a key slot number, or the ID of a secret object providing the new passphrase.

   If given a key slot, remove that exact slot
   If given a passphrase, try to unlock each key slot until one succeeds, then remove that one.

   We MUST NOT allow the last key slot to be removed, without explicit confirmation in some way. Perhaps --force option

It is unsafe to use qemu-img on an image used by a running guest, so we also likely need to have QMP + HMP commands which expose the exact same functionality as qemu-img for key slot mgmt.

Comment 2 Ademar Reis 2020-02-05 23:01:16 UTC
QEMU has been recently split into sub-components and as a one-time operation to avoid breakage of tools, we are setting the QEMU sub-component of this BZ to "General". Please review and change the sub-component if necessary the next time you review this BZ. Thanks

Comment 3 John Ferlan 2020-02-06 13:54:20 UTC
Still working on coming to an agreement on the API/QMP syntax, most recent posting upstream:

https://lists.nongnu.org/archive/html/qemu-devel/2020-01/msg07639.html

Also see: http://etherpad.corp.redhat.com/luks-api for some recent thoughts

Comment 4 John Ferlan 2020-03-12 11:59:15 UTC
v2 posted upstream: https://lists.nongnu.org/archive/html/qemu-devel/2020-03/msg01838.html

Comment 7 John Ferlan 2020-06-08 15:03:33 UTC
v8: https://lists.nongnu.org/archive/html/qemu-devel/2020-06/msg01812.html

was placed on Max's maintainer queue today for inclusion in qemu-5.1 which will be backported into RHEL AV 8.3.0

As soon as the code is officially merged upstream, I'll move to POST, set devel_ack+, etc.

Comment 8 Danilo de Paula 2020-07-16 20:10:46 UTC
This commit is already being included in the current rebase.

So moving to MODIFIED

Comment 9 Xueqiang Wei 2020-07-30 15:44:57 UTC
Tested with qemu-kvm-5.0.0-2.module+el8.3.0+7379+0505d6ca, all work as expected.


Versions:
kernel-4.18.0-222.el8.x86_64
qemu-kvm-5.0.0-2.module+el8.3.0+7379+0505d6ca


For luks format:
1. create a luks image
# qemu-img create -f luks --object secret,id=sec0,data=redhat  -o key-secret=sec0  base.luks 1G

2. add a new password to a free keyslot

 # qemu-img amend --object secret,id=sec1,data=redhat1 --object secret,id=sec0,data=redhat -o keyslot=1,state=active,new-secret=sec1  --image-opts driver=luks,key-secret=sec0,file.filename=base.luks

# qemu-img amend --object secret,id=sec2,data=redhat2 --object secret,id=sec1,data=redhat1 -o state=active,new-secret=sec2  --image-opts driver=luks,key-secret=sec1,file.filename=base.luks

# qemu-img amend --object secret,id=sec3,data=redhat3 --object secret,id=sec0,data=redhat -o state=active,new-secret=sec3 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'

# qemu-img amend --object secret,id=sec3,data=redhat3 --object secret,id=sec1,data=redhat1 -o keyslot=4,state=active,new-secret=sec3 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec1"}'

# qemu-img amend --object secret,id=sec5,data=redhat5 --object secret,id=sec0,data=redhat -o keyslot=5,state=active,new-secret=sec5 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'

# qemu-img amend --object secret,id=sec6,data=redhat6 --object secret,id=sec0,data=redhat -o keyslot=6,state=active,new-secret=sec6 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o keyslot=7,state=active,new-secret=sec7,iter-time=10 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'


Negative test:
# qemu-img amend --object secret,id=sec3,data=redhat3 --object secret,id=sec0,data=redhat -o keyslot=3,state=active,new-secret=sec3 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'
qemu-img: Refusing to overwrite active keyslot 3 - please erase it first

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o keyslot=8,state=active,new-secret=sec7 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'
qemu-img: Invalid keyslot 8 specified, must be between 0 and 7

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o state=active,new-secret=sec7 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'
qemu-img: Can't add a keyslot - all keyslots are in use

# qemu-img info base.luks 
image: base.luks
file format: luks
virtual size: 1 GiB (1073741824 bytes)
disk size: 1.97 MiB
encrypted: yes
Format specific information:
    ivgen alg: plain64
    hash alg: sha256
    cipher alg: aes-256
    uuid: 3c7d59fc-201a-4d4a-8f1d-aec15e1a2a6d
    cipher mode: xts
    slots:
        [0]:
            active: true
            iters: 890434
            key offset: 4096
            stripes: 4000
        [1]:
            active: true
            iters: 860052
            key offset: 262144
            stripes: 4000
        [2]:
            active: true
            iters: 873812
            key offset: 520192
            stripes: 4000
        [3]:
            active: true
            iters: 873812
            key offset: 778240
            stripes: 4000
        [4]:
            active: true
            iters: 876148
            key offset: 1036288
            stripes: 4000
        [5]:
            active: true
            iters: 850012
            key offset: 1294336
            stripes: 4000
        [6]:
            active: true
            iters: 884426
            key offset: 1552384
            stripes: 4000
        [7]:
            active: true
            iters: 3424
            key offset: 1810432
            stripes: 4000
    payload offset: 2068480
    master key iters: 215488


3. erase a keyslot, usually by giving the password that should be erased, 
   and erasing all the keyslots that match the password, or by giving a keyslot index.

3.1 erase by giving a keyslot index
# qemu-img amend --object secret,id=sec0,data=redhat -o state=inactive,keyslot=7 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'

3.2 erase by giving the password
# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o keyslot=7,state=active,new-secret=sec7,iter-time=10 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'

info:
[7]:
    active: true
    iters: 3424
    key offset: 1810432
    stripes: 4000

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o state=inactive,old-secret=sec7 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'

info:
[7]:
    active: false
    key offset: 1810432

# qemu-img amend --object secret,id=sec3,data=redhat3 --object secret,id=sec0,data=redhat -o state=inactive,old-secret=sec3 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'

info:
[3]:
    active: false
    key offset: 778240
[4]:
    active: false
    key offset: 1036288

3.3 erase all keyslots

# qemu-img amend --object secret,id=sec0,data=redhat -o state=inactive,keyslot=0 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec0"}'
# qemu-img amend --object secret,id=sec7,data=redhat7 -o state=inactive,keyslot=1 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec7"}'
 # qemu-img amend --object secret,id=sec7,data=redhat7 -o state=inactive,keyslot=2 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec7"}'
# qemu-img amend --object secret,id=sec7,data=redhat7 -o state=inactive,keyslot=5 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec7"}'
# qemu-img amend --object secret,id=sec7,data=redhat7 -o state=inactive,keyslot=6 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec7"}'


Negative test:
# qemu-img amend --object secret,id=sec7,data=redhat7 -o state=inactive,keyslot=7 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec7"}'
qemu-img: Attempt to erase the only active keyslot 7 which will erase all the data in the image irreversibly - refusing operatio

# qemu-img amend --object secret,id=sec7,data=redhat7 --force  -o state=inactive,keyslot=7 'json:{"file": {"driver": "file", "filename": "base.luks"}, "driver": "luks", "key-secret": "sec7"}'

# qemu-img info base.luks 
image: base.luks
file format: luks
virtual size: 1 GiB (1073741824 bytes)
disk size: 1.97 MiB
encrypted: yes
Format specific information:
    ivgen alg: plain64
    hash alg: sha256
    cipher alg: aes-256
    uuid: 3c7d59fc-201a-4d4a-8f1d-aec15e1a2a6d
    cipher mode: xts
    slots:
        [0]:
            active: false
            key offset: 4096
        [1]:
            active: false
            key offset: 262144
        [2]:
            active: false
            key offset: 520192
        [3]:
            active: false
            key offset: 778240
        [4]:
            active: false
            key offset: 1036288
        [5]:
            active: false
            key offset: 1294336
        [6]:
            active: false
            key offset: 1552384
        [7]:
            active: false
            key offset: 1810432
    payload offset: 2068480
    master key iters: 215488



For luks-inside-qcow2 format:

1. create a luks-inside-qcow2 image
# qemu-img create --object secret,id=sec0,data=redhat -f qcow2 -o encrypt.format=luks,encrypt.key-secret=sec0 base.qcow2 1G

2. add a new password to a free keyslot
# qemu-img amend --object secret,id=sec1,data=redhat1 --object secret,id=sec0,data=redhat -o encrypt.keyslot=1,encrypt.state=active,encrypt.new-secret=sec1,encrypt.iter-time=10 --image-opts driver=qcow2,encrypt.key-secret=sec0,file.filename=base.qcow2

# qemu-img amend --object secret,id=sec2,data=redhat2 --object secret,id=sec1,data=redhat1 -o encrypt.state=active,encrypt.new-secret=sec2 --image-opts driver=qcow2,encrypt.key-secret=sec1,file.filename=base.qcow2

# qemu-img amend --object secret,id=sec3,data=redhat3 --object secret,id=sec0,data=redhat -o encrypt.state=active,encrypt.new-secret=sec3 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'

# qemu-img amend --object secret,id=sec3,data=redhat3 --object secret,id=sec1,data=redhat1 -o encrypt.keyslot=4,encrypt.state=active,encrypt.new-secret=sec3 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec1"}'

# qemu-img amend --object secret,id=sec5,data=redhat5 --object secret,id=sec0,data=redhat -o encrypt.keyslot=5,encrypt.state=active,encrypt.new-secret=sec5 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'

# qemu-img amend --object secret,id=sec6,data=redhat6 --object secret,id=sec0,data=redhat -o encrypt.keyslot=6,encrypt.state=active,encrypt.new-secret=sec6 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o encrypt.keyslot=7,encrypt.state=active,encrypt.new-secret=sec7,encrypt.iter-time=10 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'


Negative test:
# qemu-img amend --object secret,id=sec3,data=redhat3 --object secret,id=sec0,data=redhat -o encrypt.keyslot=3,encrypt.state=active,encrypt.new-secret=sec3 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'
qemu-img: Refusing to overwrite active keyslot 3 - please erase it first

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o encrypt.keyslot=8,encrypt.state=active,encrypt.new-secret=sec7 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'
qemu-img: Invalid keyslot 8 specified, must be between 0 and 7

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o encrypt.state=active,encrypt.new-secret=sec7 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'
qemu-img: Can't add a keyslot - all keyslots are in use


# qemu-img info base.qcow2 
image: base.qcow2
file format: qcow2
virtual size: 1 GiB (1073741824 bytes)
disk size: 2.25 MiB
encrypted: yes
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    encrypt:
        ivgen alg: plain64
        hash alg: sha256
        cipher alg: aes-256
        uuid: 93856bee-95e4-4424-b84d-690c609c36bf
        format: luks
        cipher mode: xts
        slots:
            [0]:
                active: true
                iters: 879676
                key offset: 4096
                stripes: 4000
            [1]:
                active: true
                iters: 4289
                key offset: 262144
                stripes: 4000
            [2]:
                active: true
                iters: 879676
                key offset: 520192
                stripes: 4000
            [3]:
                active: true
                iters: 691308
                key offset: 778240
                stripes: 4000
            [4]:
                active: true
                iters: 880860
                key offset: 1036288
                stripes: 4000
            [5]:
                active: true
                iters: 715458
                key offset: 1294336
                stripes: 4000
            [6]:
                active: true
                iters: 888020
                key offset: 1552384
                stripes: 4000
            [7]:
                active: true
                iters: 3569
                key offset: 1810432
                stripes: 4000
        payload offset: 2068480
        master key iters: 222527
    corrupt: false

3. erase a keyslot, usually by giving the password that should be erased, 
   and erasing all the keyslots that match the password, or by giving a keyslot index.

3.1 erase by giving a keyslot index
# qemu-img amend --object secret,id=sec0,data=redhat -o encrypt.state=inactive,encrypt.keyslot=7 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'

info:
[7]:
    active: false
    key offset: 1810432

3.2 erase by giving the password
# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o encrypt.keyslot=7,encrypt.state=active,encrypt.new-secret=sec7,encrypt.iter-time=10 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'

info:
[7]:
    active: true
    iters: 3424
    key offset: 1810432
    stripes: 4000

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o encrypt.state=inactive,encrypt.old-secret=sec7 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'

info:
[7]:
    active: false
    key offset: 1810432

# qemu-img amend --object secret,id=sec3,data=redhat3 --object secret,id=sec0,data=redhat -o encrypt.state=inactive,encrypt.old-secret=sec3 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'

info:
[3]:
    active: false
    key offset: 778240
[4]:
    active: false
    key offset: 1036288


3.3 erase all keyslots

# qemu-img amend --object secret,id=sec7,data=redhat7 --object secret,id=sec0,data=redhat -o encrypt.keyslot=7,encrypt.state=active,encrypt.new-secret=sec7,encrypt.iter-time=10 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'

# qemu-img amend --object secret,id=sec0,data=redhat -o encrypt.state=inactive,encrypt.keyslot=0 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec0"}'
# qemu-img amend --object secret,id=sec7,data=redhat7 -o encrypt.state=inactive,encrypt.keyslot=1 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec7"}'
 # qemu-img amend --object secret,id=sec7,data=redhat7 -o encrypt.state=inactive,encrypt.keyslot=2 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec7"}'
# qemu-img amend --object secret,id=sec7,data=redhat7 -o encrypt.state=inactive,encrypt.keyslot=5 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec7"}'
# qemu-img amend --object secret,id=sec7,data=redhat7 -o encrypt.state=inactive,encrypt.keyslot=6 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec7"}'


Negative test:
# qemu-img amend --object secret,id=sec7,data=redhat7 -o encrypt.state=inactive,encrypt.keyslot=7 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec7"}'
qemu-img: Attempt to erase the only active keyslot 7 which will erase all the data in the image irreversibly - refusing operatio

# qemu-img amend --object secret,id=sec7,data=redhat7 --force  -o encrypt.state=inactive,encrypt.keyslot=7 'json:{"file": {"driver": "file", "filename": "base.qcow2"}, "driver": "qcow2", "encrypt.key-secret": "sec7"}'

# qemu-img info base.qcow2 
image: base.qcow2
file format: qcow2
virtual size: 1 GiB (1073741824 bytes)
disk size: 2.25 MiB
encrypted: yes
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    encrypt:
        ivgen alg: plain64
        hash alg: sha256
        cipher alg: aes-256
        uuid: 2478a445-f24f-4b6b-8044-d14d6c560ade
        format: luks
        cipher mode: xts
        slots:
            [0]:
                active: false
                key offset: 4096
            [1]:
                active: false
                key offset: 262144
            [2]:
                active: false
                key offset: 520192
            [3]:
                active: false
                key offset: 778240
            [4]:
                active: false
                key offset: 1036288
            [5]:
                active: false
                key offset: 1294336
            [6]:
                active: false
                key offset: 1552384
            [7]:
                active: false
                key offset: 1810432
        payload offset: 2068480
        master key iters: 225525
    corrupt: false


Tested luks format with x-blockdev-amend:

1. boot a guest with luks format image, please refer to attachment for luks_key_management.sh

2. connect qmp monitor and add 7 objects

# nc -U /var/tmp/avocado_6ftwctpx/monitor-qmpmonitor1-20200723-125549-jROGE8iW

{"execute":"qmp_capabilities"}

{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec1", "props": { "data": "redhat1"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec2", "props": { "data": "redhat2"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec3", "props": { "data": "redhat3"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec4", "props": { "data": "redhat4"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec5", "props": { "data": "redhat5"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec6", "props": { "data": "redhat6"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec7", "props": { "data": "redhat7"}}}

3. add a new password to a free keyslot

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key1", "options": { "driver": "luks", "state": "active", "new-secret": "sec7", "keyslot": 1, "iter-time": 10}}}
{"timestamp": {"seconds": 1596104814, "microseconds": 608443}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596104814, "microseconds": 608590}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key1"}}
{"return": {}}
{"timestamp": {"seconds": 1596104820, "microseconds": 482144}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596104820, "microseconds": 482279}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596104820, "microseconds": 482372}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key1"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key1"}}
{"timestamp": {"seconds": 1596104921, "microseconds": 701966}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key1"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key2", "options": { "driver": "luks", "state": "active", "new-secret": "sec7"}}}
{"timestamp": {"seconds": 1596106401, "microseconds": 603851}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key2"}}
{"timestamp": {"seconds": 1596106401, "microseconds": 604200}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key2"}}
{"return": {}}
{"timestamp": {"seconds": 1596106409, "microseconds": 910307}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key2"}}
{"timestamp": {"seconds": 1596106409, "microseconds": 910444}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key2"}}
{"timestamp": {"seconds": 1596106409, "microseconds": 910491}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key2"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key2"}}
{"timestamp": {"seconds": 1596106441, "microseconds": 920753}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key2"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key3", "options": { "driver": "luks", "state": "active", "new-secret": "sec3", "keyslot": 3}}}
{"timestamp": {"seconds": 1596106961, "microseconds": 882156}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key3"}}
{"timestamp": {"seconds": 1596106961, "microseconds": 882304}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key3"}}
{"return": {}}
{"timestamp": {"seconds": 1596106970, "microseconds": 359754}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key3"}}
{"timestamp": {"seconds": 1596106970, "microseconds": 359883}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key3"}}
{"timestamp": {"seconds": 1596106970, "microseconds": 359936}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key3"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key3"}}
{"timestamp": {"seconds": 1596106975, "microseconds": 944564}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key3"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key4", "options": { "driver": "luks", "state": "active", "new-secret": "sec4", "keyslot": 4, "iter-time": 10}}}
{"timestamp": {"seconds": 1596107028, "microseconds": 913743}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key4"}}
{"timestamp": {"seconds": 1596107028, "microseconds": 913912}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key4"}}
{"return": {}}
{"timestamp": {"seconds": 1596107034, "microseconds": 958500}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key4"}}
{"timestamp": {"seconds": 1596107034, "microseconds": 958592}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key4"}}
{"timestamp": {"seconds": 1596107034, "microseconds": 958648}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key4"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key4"}}
{"timestamp": {"seconds": 1596107042, "microseconds": 55254}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key4"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key5", "options": { "driver": "luks", "state": "active", "new-secret": "sec5", "keyslot": 5, "iter-time": 10}}}
{"timestamp": {"seconds": 1596107085, "microseconds": 641469}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key5"}}
{"timestamp": {"seconds": 1596107085, "microseconds": 641909}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key5"}}
{"return": {}}
{"timestamp": {"seconds": 1596107091, "microseconds": 729870}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key5"}}
{"timestamp": {"seconds": 1596107091, "microseconds": 729981}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key5"}}
{"timestamp": {"seconds": 1596107091, "microseconds": 730034}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key5"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key5"}}
{"timestamp": {"seconds": 1596107103, "microseconds": 640083}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key5"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key6", "options": { "driver": "luks", "state": "active", "new-secret": "sec6", "keyslot": 6, "iter-time": 10}}}
{"timestamp": {"seconds": 1596107163, "microseconds": 824493}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key6"}}
{"timestamp": {"seconds": 1596107163, "microseconds": 824688}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key6"}}
{"return": {}}
{"timestamp": {"seconds": 1596107169, "microseconds": 692193}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key6"}}
{"timestamp": {"seconds": 1596107169, "microseconds": 692283}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key6"}}
{"timestamp": {"seconds": 1596107169, "microseconds": 692337}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key6"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key6"}}
{"timestamp": {"seconds": 1596107181, "microseconds": 937568}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key6"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key7", "options": { "driver": "luks", "state": "active", "new-secret": "sec7", "keyslot": 7, "iter-time": 10}}}
{"timestamp": {"seconds": 1596107213, "microseconds": 223352}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key7"}}
{"timestamp": {"seconds": 1596107213, "microseconds": 223532}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key7"}}
{"return": {}}
{"timestamp": {"seconds": 1596107219, "microseconds": 241911}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key7"}}
{"timestamp": {"seconds": 1596107219, "microseconds": 242265}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key7"}}
{"timestamp": {"seconds": 1596107219, "microseconds": 242362}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key7"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key7"}}
{"timestamp": {"seconds": 1596107225, "microseconds": 205708}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key7"}}
{"return": {}}

check info:
# qemu-img info -U /home/kvm_autotest_root/images/rhel830-64-virtio.luks
image: /home/kvm_autotest_root/images/rhel830-64-virtio.luks
file format: luks
virtual size: 20 GiB (21474836480 bytes)
disk size: 20 GiB
encrypted: yes
Format specific information:
    ivgen alg: plain64
    hash alg: sha256
    cipher alg: aes-256
    uuid: 8bd6a1b9-f992-48ec-9e95-fe203a5213a5
    cipher mode: xts
    slots:
        [0]:
            active: true
            iters: 1733154
            key offset: 4096
            stripes: 4000
        [1]:
            active: true
            iters: 4211
            key offset: 262144
            stripes: 4000
        [2]:
            active: true
            iters: 848910
            key offset: 520192
            stripes: 4000
        [3]:
            active: true
            iters: 841282
            key offset: 778240
            stripes: 4000
        [4]:
            active: true
            iters: 4195
            key offset: 1036288
            stripes: 4000
        [5]:
            active: true
            iters: 4266
            key offset: 1294336
            stripes: 4000
        [6]:
            active: true
            iters: 4250
            key offset: 1552384
            stripes: 4000
        [7]:
            active: true
            iters: 4195
            key offset: 1810432
            stripes: 4000
    payload offset: 2068480
    master key iters: 429147


Negative test:
(1) add a new password to an occupied keyslot
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key1", "options": { "driver": "luks", "state": "active", "new-secret": "sec7", "keyslot": 1, "iter-time": 10}}}
{"timestamp": {"seconds": 1596105593, "microseconds": 766343}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596105593, "microseconds": 766519}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key1"}}
{"return": {}}
{"timestamp": {"seconds": 1596105593, "microseconds": 785755}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596105593, "microseconds": 785861}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key1"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key1"}}
{"timestamp": {"seconds": 1596105640, "microseconds": 154983}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key1"}}
{"return": {}}

(2) add a new password to a non-existing keyslot
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key8", "options": { "driver": "luks", "state": "active", "new-secret": "sec7", "keyslot": 8, "iter-time": 10}}}
{"timestamp": {"seconds": 1596107324, "microseconds": 260351}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key8"}}
{"timestamp": {"seconds": 1596107324, "microseconds": 260526}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key8"}}
{"return": {}}
{"timestamp": {"seconds": 1596107324, "microseconds": 281098}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_add_key8"}}
{"timestamp": {"seconds": 1596107324, "microseconds": 281224}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key8"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key8"}}
{"timestamp": {"seconds": 1596107340, "microseconds": 440579}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key8"}}
{"return": {}}

(3) add a new password to the keyslot when all keyslots are occupied
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key9", "options": { "driver": "luks", "state": "active", "new-secret": "sec7"}}}
{"timestamp": {"seconds": 1596107361, "microseconds": 612778}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key9"}}
{"timestamp": {"seconds": 1596107361, "microseconds": 612946}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key9"}}
{"return": {}}
{"timestamp": {"seconds": 1596107361, "microseconds": 633146}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_add_key9"}}
{"timestamp": {"seconds": 1596107361, "microseconds": 633260}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key9"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key9"}}
{"timestamp": {"seconds": 1596107394, "microseconds": 628887}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key9"}}
{"return": {}}


4. erase a keyslot, usually by giving the password that should be erased, 
   and erasing all the keyslots that match the password, or by giving a keyslot index.
4.1 erase by giving a keyslot index
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_erase_key3", "options": { "driver": "luks", "state": "inactive", "keyslot": 3}}}
{"timestamp": {"seconds": 1596108630, "microseconds": 713614}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key3"}}
{"timestamp": {"seconds": 1596108630, "microseconds": 713772}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key3"}}
{"return": {}}
{"timestamp": {"seconds": 1596108631, "microseconds": 628357}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key3"}}
{"timestamp": {"seconds": 1596108631, "microseconds": 628520}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key3"}}
{"timestamp": {"seconds": 1596108631, "microseconds": 628572}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key3"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key3"}}
{"timestamp": {"seconds": 1596108664, "microseconds": 563955}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key3"}}
{"return": {}}

info:
[3]:
    active: false
    key offset: 778240

4.2 erase by giving the password

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_erase_key7", "options": { "driver": "luks", "state": "inactive", "old-secret": "sec7"}}}
{"timestamp": {"seconds": 1596109038, "microseconds": 386201}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key7"}}
{"timestamp": {"seconds": 1596109038, "microseconds": 386375}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key7"}}
{"return": {}}
{"timestamp": {"seconds": 1596109050, "microseconds": 957832}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key7"}}
{"timestamp": {"seconds": 1596109050, "microseconds": 957933}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key7"}}
{"timestamp": {"seconds": 1596109050, "microseconds": 958152}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key7"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key7"}}
{"timestamp": {"seconds": 1596109060, "microseconds": 690741}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key7"}}
{"return": {}}

info:
[1]:
    active: false
    key offset: 262144
[2]:
    active: false
    key offset: 520192
[7]:
    active: false
    key offset: 1810432


4.3 erase all keyslots

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_erase_key4", "options": { "driver": "luks", "state": "inactive", "old-secret": "sec4"}}}
{"timestamp": {"seconds": 1596109752, "microseconds": 572939}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key4"}}
{"timestamp": {"seconds": 1596109752, "microseconds": 573170}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key4"}}
{"return": {}}
{"timestamp": {"seconds": 1596109760, "microseconds": 427700}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key4"}}
{"timestamp": {"seconds": 1596109760, "microseconds": 428037}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key4"}}
{"timestamp": {"seconds": 1596109760, "microseconds": 428136}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key4"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key4"}}
{"timestamp": {"seconds": 1596109768, "microseconds": 89129}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key4"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_erase_key5", "options": { "driver": "luks", "state": "inactive", "keyslot": 5}}}
{"timestamp": {"seconds": 1596109890, "microseconds": 431293}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key5"}}
{"timestamp": {"seconds": 1596109890, "microseconds": 431474}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key5"}}
{"return": {}}
{"timestamp": {"seconds": 1596109891, "microseconds": 767174}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key5"}}
{"timestamp": {"seconds": 1596109891, "microseconds": 767341}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key5"}}
{"timestamp": {"seconds": 1596109891, "microseconds": 767485}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key5"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key5"}}
{"timestamp": {"seconds": 1596109902, "microseconds": 247613}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key5"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_erase_key6", "options": { "driver": "luks", "state": "inactive", "keyslot": 6}}}
{"timestamp": {"seconds": 1596109945, "microseconds": 506458}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key6"}}
{"timestamp": {"seconds": 1596109945, "microseconds": 506636}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key6"}}
{"return": {}}
{"timestamp": {"seconds": 1596109946, "microseconds": 522808}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key6"}}
{"timestamp": {"seconds": 1596109946, "microseconds": 522948}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key6"}}
{"timestamp": {"seconds": 1596109946, "microseconds": 523039}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key6"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key6"}}
{"timestamp": {"seconds": 1596109959, "microseconds": 574565}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key6"}}
{"return": {}}


4.4 negative test
(1) erase the last keyslot:

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_erase_key0", "options": { "driver": "luks", "state": "inactive", "keyslot": 0}}}
{"timestamp": {"seconds": 1596110161, "microseconds": 605279}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596110161, "microseconds": 605466}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key0"}}
{"return": {}}
{"timestamp": {"seconds": 1596110161, "microseconds": 633785}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596110161, "microseconds": 634109}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key0"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596110175, "microseconds": 707425}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key0"}}
{"return": {}}

(2) force to erase the last keyslot:
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_erase_key0", "options": { "driver": "luks", "state": "inactive", "keyslot": 0}, "force": true}}
{"timestamp": {"seconds": 1596110528, "microseconds": 660137}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596110528, "microseconds": 660312}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key0"}}
{"return": {}}
{"timestamp": {"seconds": 1596110529, "microseconds": 533925}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596110529, "microseconds": 534007}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596110529, "microseconds": 534055}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key0"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596110547, "microseconds": 272526}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key0"}}
{"return": {}}

check info:
# qemu-img info -U /home/kvm_autotest_root/images/rhel830-64-virtio.luks
image: /home/kvm_autotest_root/images/rhel830-64-virtio.luks
file format: luks
virtual size: 20 GiB (21474836480 bytes)
disk size: 20 GiB
encrypted: yes
Format specific information:
    ivgen alg: plain64
    hash alg: sha256
    cipher alg: aes-256
    uuid: 8bd6a1b9-f992-48ec-9e95-fe203a5213a5
    cipher mode: xts
    slots:
        [0]:
            active: false
            key offset: 4096
        [1]:
            active: false
            key offset: 262144
        [2]:
            active: false
            key offset: 520192
        [3]:
            active: false
            key offset: 778240
        [4]:
            active: false
            key offset: 1036288
        [5]:
            active: false
            key offset: 1294336
        [6]:
            active: false
            key offset: 1552384
        [7]:
            active: false
            key offset: 1810432
    payload offset: 2068480
    master key iters: 429147



Tested luks-inside-qcow2 format with x-blockdev-amend:

1. create a luks-inside-qcow2 image, and boot it as a data image. Please refer to attachment for luks-inside-qcow2_key_management.sh

# qemu-img create --object secret,id=data1,data=redhat -f qcow2 -o encrypt.format=luks,encrypt.key-secret=data1 data.qcow2 1G

2. add 7 objects for testing
# nc -U /var/tmp/avocado_6ftwctpx/monitor-qmpmonitor1-20200723-125549-jROGE8iW

{"execute":"qmp_capabilities"}

{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec1", "props": { "data": "redhat1"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec2", "props": { "data": "redhat2"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec3", "props": { "data": "redhat3"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec4", "props": { "data": "redhat4"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec5", "props": { "data": "redhat5"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec6", "props": { "data": "redhat6"}}}
{ "execute": "object-add", "arguments": {"qom-type": "secret", "id": "sec7", "props": { "data": "redhat7"}}}


3. add a new password to a free keyslot

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key1", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec7", "keyslot": 1, "iter-time": 10, "format": "luks"}}}}
{"timestamp": {"seconds": 1596116496, "microseconds": 202977}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596116496, "microseconds": 203155}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key1"}}
{"return": {}}
{"timestamp": {"seconds": 1596116499, "microseconds": 276501}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596116499, "microseconds": 276632}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596116499, "microseconds": 276680}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key1"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key1"}}
{"timestamp": {"seconds": 1596116513, "microseconds": 429951}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key1"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key2", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec7", "format": "luks"}}}}
{"timestamp": {"seconds": 1596117043, "microseconds": 815819}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key2"}}
{"timestamp": {"seconds": 1596117043, "microseconds": 815992}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key2"}}
{"return": {}}
{"timestamp": {"seconds": 1596117049, "microseconds": 413210}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key2"}}
{"timestamp": {"seconds": 1596117049, "microseconds": 413354}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key2"}}
{"timestamp": {"seconds": 1596117049, "microseconds": 413413}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key2"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key2"}}
{"timestamp": {"seconds": 1596117074, "microseconds": 819948}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key2"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key3", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec3", "keyslot": 3, "format": "luks"}}}}
{"timestamp": {"seconds": 1596117164, "microseconds": 11468}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key3"}}
{"timestamp": {"seconds": 1596117164, "microseconds": 11626}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key3"}}
{"return": {}}
{"timestamp": {"seconds": 1596117169, "microseconds": 704603}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key3"}}
{"timestamp": {"seconds": 1596117169, "microseconds": 704834}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key3"}}
{"timestamp": {"seconds": 1596117169, "microseconds": 704945}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key3"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key3"}}
{"timestamp": {"seconds": 1596117174, "microseconds": 442699}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key3"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key4", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec4", "keyslot": 4, "iter-time": 10, "format": "luks"}}}}
{"timestamp": {"seconds": 1596117197, "microseconds": 591176}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key4"}}
{"timestamp": {"seconds": 1596117197, "microseconds": 591367}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key4"}}
{"return": {}}
{"timestamp": {"seconds": 1596117201, "microseconds": 31202}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key4"}}
{"timestamp": {"seconds": 1596117201, "microseconds": 31291}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key4"}}
{"timestamp": {"seconds": 1596117201, "microseconds": 31338}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key4"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key4"}}
{"timestamp": {"seconds": 1596117209, "microseconds": 345647}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key4"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key5", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec7", "keyslot": 5, "iter-time": 10, "format": "luks"}}}}
{"timestamp": {"seconds": 1596117281, "microseconds": 782659}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key5"}}
{"timestamp": {"seconds": 1596117281, "microseconds": 782863}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key5"}}
{"return": {}}
{"timestamp": {"seconds": 1596117284, "microseconds": 978266}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key5"}}
{"timestamp": {"seconds": 1596117284, "microseconds": 978370}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key5"}}
{"timestamp": {"seconds": 1596117284, "microseconds": 978438}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key5"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key5"}}
{"timestamp": {"seconds": 1596117294, "microseconds": 83059}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key5"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key6", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec6", "keyslot": 6, "iter-time": 10, "format": "luks"}}}}
{"timestamp": {"seconds": 1596117317, "microseconds": 264047}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key6"}}
{"timestamp": {"seconds": 1596117317, "microseconds": 264203}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key6"}}
{"return": {}}
{"timestamp": {"seconds": 1596117320, "microseconds": 465458}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key6"}}
{"timestamp": {"seconds": 1596117320, "microseconds": 465660}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key6"}}
{"timestamp": {"seconds": 1596117320, "microseconds": 465762}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key6"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key6"}}
{"timestamp": {"seconds": 1596117327, "microseconds": 732858}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key6"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key7", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec7", "keyslot": 7, "iter-time": 10, "format": "luks"}}}}
{"timestamp": {"seconds": 1596117361, "microseconds": 667961}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key7"}}
{"timestamp": {"seconds": 1596117361, "microseconds": 668111}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key7"}}
{"return": {}}
{"timestamp": {"seconds": 1596117364, "microseconds": 789984}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_add_key7"}}
{"timestamp": {"seconds": 1596117364, "microseconds": 790079}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_add_key7"}}
{"timestamp": {"seconds": 1596117364, "microseconds": 790127}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key7"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key7"}}
{"timestamp": {"seconds": 1596117373, "microseconds": 883974}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key7"}}
{"return": {}}

check info:
# qemu-img info -U /home/kvm_autotest_root/images/data.qcow2 
image: /home/kvm_autotest_root/images/data.qcow2
file format: qcow2
virtual size: 1 GiB (1073741824 bytes)
disk size: 2.25 MiB
encrypted: yes
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    encrypt:
        ivgen alg: plain64
        hash alg: sha256
        cipher alg: aes-256
        uuid: ecc00c5a-ece0-43c7-8fe5-10c4402898c8
        format: luks
        cipher mode: xts
        slots:
            [0]:
                active: true
                iters: 715768
                key offset: 4096
                stripes: 4000
            [1]:
                active: true
                iters: 4250
                key offset: 262144
                stripes: 4000
            [2]:
                active: true
                iters: 856678
                key offset: 520192
                stripes: 4000
            [3]:
                active: true
                iters: 853332
                key offset: 778240
                stripes: 4000
            [4]:
                active: true
                iters: 4322
                key offset: 1036288
                stripes: 4000
            [5]:
                active: true
                iters: 4250
                key offset: 1294336
                stripes: 4000
            [6]:
                active: true
                iters: 4305
                key offset: 1552384
                stripes: 4000
            [7]:
                active: true
                iters: 4239
                key offset: 1810432
                stripes: 4000
        payload offset: 2068480
        master key iters: 154858
    corrupt: false


Negative test:
(1) add a new password to an occupied keyslot
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key1", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec7", "keyslot": 1, "iter-time": 10, "format": "luks"}}}}
{"timestamp": {"seconds": 1596117579, "microseconds": 862452}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596117579, "microseconds": 862635}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key1"}}
{"return": {}}
{"timestamp": {"seconds": 1596117579, "microseconds": 862887}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596117579, "microseconds": 862997}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key1"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key1"}}
{"timestamp": {"seconds": 1596117593, "microseconds": 768711}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key1"}}
{"return": {}}

(2) add a new password to a non-existing keyslot
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key8", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec7", "keyslot": 8, "iter-time": 10, "format": "luks"}}}}
{"timestamp": {"seconds": 1596117621, "microseconds": 581651}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key8"}}
{"timestamp": {"seconds": 1596117621, "microseconds": 581819}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key8"}}
{"return": {}}
{"timestamp": {"seconds": 1596117621, "microseconds": 582029}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_add_key8"}}
{"timestamp": {"seconds": 1596117621, "microseconds": 582132}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key8"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key8"}}
{"timestamp": {"seconds": 1596117631, "microseconds": 838894}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key8"}}
{"return": {}}

(3) add a new password to the keyslot when all keyslots are occupied
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_add_key9", "options": { "driver": "qcow2", "encrypt": {"state": "active", "new-secret": "sec7", "format": "luks"}}}}
{"timestamp": {"seconds": 1596117666, "microseconds": 459601}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key9"}}
{"timestamp": {"seconds": 1596117666, "microseconds": 459774}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key9"}}
{"return": {}}
{"timestamp": {"seconds": 1596117666, "microseconds": 459972}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_add_key9"}}
{"timestamp": {"seconds": 1596117666, "microseconds": 460081}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key9"}}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key9"}}
{"timestamp": {"seconds": 1596117676, "microseconds": 871413}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key9"}}
{"return": {}}


4. erase a keyslot, usually by giving the password that should be erased, 
   and erasing all the keyslots that match the password, or by giving a keyslot index.

4.1 erase by giving a keyslot index
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_erase_key3", "options": { "driver": "qcow2", "encrypt": {"state": "inactive", "keyslot": 3, "format": "luks"}}}}
{"timestamp": {"seconds": 1596118147, "microseconds": 292670}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key3"}}
{"timestamp": {"seconds": 1596118147, "microseconds": 292919}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key3"}}
{"return": {}}
{"timestamp": {"seconds": 1596118148, "microseconds": 26263}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key3"}}
{"timestamp": {"seconds": 1596118148, "microseconds": 26336}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key3"}}
{"timestamp": {"seconds": 1596118148, "microseconds": 26385}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key3"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key3"}}
{"timestamp": {"seconds": 1596118160, "microseconds": 390678}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key3"}}
{"return": {}}

info:
[3]:
    active: false
    key offset: 778240

4.2 erase by giving the password
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_erase_key7", "options": { "driver": "qcow2", "encrypt": {"state": "inactive", "old-secret": "sec7", "format": "luks"}}}}
{"timestamp": {"seconds": 1596118217, "microseconds": 152982}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key7"}}
{"timestamp": {"seconds": 1596118217, "microseconds": 153421}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key7"}}
{"return": {}}
{"timestamp": {"seconds": 1596118226, "microseconds": 251746}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key7"}}
{"timestamp": {"seconds": 1596118226, "microseconds": 251932}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key7"}}
{"timestamp": {"seconds": 1596118226, "microseconds": 252034}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key7"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key7"}}
{"timestamp": {"seconds": 1596118231, "microseconds": 535472}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key7"}}
{"return": {}}

info:
[1]:
    active: false
    key offset: 262144
[2]:
    active: false
    key offset: 520192
[5]:
    active: false
    key offset: 1294336  
[7]:
    active: false
    key offset: 1810432

4.3 erase all keyslots
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_erase_key4", "options": { "driver": "qcow2", "encrypt": {"state": "inactive", "old-secret": "sec4", "format": "luks"}}}}
{"timestamp": {"seconds": 1596118424, "microseconds": 633413}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key4"}}
{"timestamp": {"seconds": 1596118424, "microseconds": 633572}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key4"}}
{"return": {}}
{"timestamp": {"seconds": 1596118428, "microseconds": 199278}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key4"}}
{"timestamp": {"seconds": 1596118428, "microseconds": 199443}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key4"}}
{"timestamp": {"seconds": 1596118428, "microseconds": 199514}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key4"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key4"}}
{"timestamp": {"seconds": 1596118440, "microseconds": 879017}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key4"}}
{"return": {}}

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_erase_key6", "options": { "driver": "qcow2", "encrypt": {"state": "inactive", "keyslot": 6, "format": "luks"}}}}
{"timestamp": {"seconds": 1596118473, "microseconds": 914108}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key6"}}
{"timestamp": {"seconds": 1596118473, "microseconds": 914281}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key6"}}
{"return": {}}
{"timestamp": {"seconds": 1596118474, "microseconds": 705887}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key6"}}
{"timestamp": {"seconds": 1596118474, "microseconds": 705997}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key6"}}
{"timestamp": {"seconds": 1596118474, "microseconds": 706046}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key6"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key6"}}
{"timestamp": {"seconds": 1596118483, "microseconds": 380794}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key6"}}
{"return": {}}

4.4 negative test
(1) erase the last keyslot
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_erase_key0", "options": { "driver": "qcow2", "encrypt": {"state": "inactive", "keyslot": 0, "format": "luks"}}}}
{"timestamp": {"seconds": 1596118569, "microseconds": 113568}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596118569, "microseconds": 113733}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key0"}}
{"return": {}}
{"timestamp": {"seconds": 1596118569, "microseconds": 113943}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596118569, "microseconds": 114048}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key0"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596118581, "microseconds": 657056}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key0"}}
{"return": {}}

(2) force to erase the last keyslot
{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_data1", "job-id": "job_erase_key0", "options": { "driver": "qcow2", "encrypt": {"state": "inactive", "keyslot": 0, "format": "luks"}}, "force": true}}
{"timestamp": {"seconds": 1596118697, "microseconds": 654484}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596118697, "microseconds": 654899}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_erase_key0"}}
{"return": {}}
{"timestamp": {"seconds": 1596118698, "microseconds": 429514}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596118698, "microseconds": 429604}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596118698, "microseconds": 429646}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_erase_key0"}}

{"execute": "job-dismiss", "arguments": {"id": "job_erase_key0"}}
{"timestamp": {"seconds": 1596118709, "microseconds": 620865}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_erase_key0"}}
{"return": {}}

check info:
# qemu-img info -U /home/kvm_autotest_root/images/data.qcow2 
image: /home/kvm_autotest_root/images/data.qcow2
file format: qcow2
virtual size: 1 GiB (1073741824 bytes)
disk size: 2.25 MiB
encrypted: yes
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    encrypt:
        ivgen alg: plain64
        hash alg: sha256
        cipher alg: aes-256
        uuid: ecc00c5a-ece0-43c7-8fe5-10c4402898c8
        format: luks
        cipher mode: xts
        slots:
            [0]:
                active: false
                key offset: 4096
            [1]:
                active: false
                key offset: 262144
            [2]:
                active: false
                key offset: 520192
            [3]:
                active: false
                key offset: 778240
            [4]:
                active: false
                key offset: 1036288
            [5]:
                active: false
                key offset: 1294336
            [6]:
                active: false
                key offset: 1552384
            [7]:
                active: false
                key offset: 1810432
        payload offset: 2068480
        master key iters: 154858
    corrupt: false



	
Hi Maxim,

As above logs, they all work as expexted. 


I just have one question:
The message is clear when doing negative test with "qemu-img amend". But tested them with "x-blockdev-amend", there's no clear message. I just found "status": "aborting" in output.

Is that OK, will it be updated in the future?

e.g. 
qemu-img: Refusing to overwrite active keyslot 3 - please erase it first
qemu-img: Invalid keyslot 8 specified, must be between 0 and 7
qemu-img: Can't add a keyslot - all keyslots are in use

e.g.
{"timestamp": {"seconds": 1596105593, "microseconds": 785755}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_add_key1"}}

Comment 10 Xueqiang Wei 2020-07-30 15:49:05 UTC
Created attachment 1702969 [details]
luks_key_management.sh

Comment 11 Xueqiang Wei 2020-07-30 15:49:36 UTC
Created attachment 1702970 [details]
luks-inside-qcow2_key_management.sh

Comment 12 Maxim Levitsky 2020-08-02 05:30:57 UTC
It should work. In the iotests that I wrote I do see errors when job fails.

The qemu iotest framework seems to wait for JOB_STATUS_CHANGE with status=aborting,
and then do 'query-jobs' qmp command, find the job by id there, and locate 'error' field which is then printed.

>        while True:
>            ev = filter_qmp_event(self.events_wait(events, timeout=wait))
>            if ev['event'] != 'JOB_STATUS_CHANGE':
>                log(ev)
>                continue
>            status = ev['data']['status']
>            if status == 'aborting':
>                result = self.qmp('query-jobs')
>                for j in result['return']:
>                    if j['id'] == job:
>                        error = j['error']
>                        log('Job failed: %s' % (j['error']))
>            elif status == 'ready':
>                self.qmp_log('job-complete', id=job)
>            elif status == 'pending' and not auto_finalize:
>                if pre_finalize:
>                    pre_finalize()
>                if cancel:
>                    self.qmp_log('job-cancel', id=job)
>                else:
>                    self.qmp_log('job-finalize', id=job)
>            elif status == 'concluded' and not auto_dismiss:
>                self.qmp_log('job-dismiss', id=job)
>            elif status == 'null':
>                return error


Does lack of error happen differently that other block jobs, e.g blockdev_create?

Best regards,
     Maxim Levitsky

Comment 13 Xueqiang Wei 2020-08-03 02:05:47 UTC
(In reply to Maxim Levitsky from comment #12)
> It should work. In the iotests that I wrote I do see errors when job fails.
> 
> The qemu iotest framework seems to wait for JOB_STATUS_CHANGE with
> status=aborting,
> and then do 'query-jobs' qmp command, find the job by id there, and locate
> 'error' field which is then printed.
> 
> >        while True:
> >            ev = filter_qmp_event(self.events_wait(events, timeout=wait))
> >            if ev['event'] != 'JOB_STATUS_CHANGE':
> >                log(ev)
> >                continue
> >            status = ev['data']['status']
> >            if status == 'aborting':
> >                result = self.qmp('query-jobs')
> >                for j in result['return']:
> >                    if j['id'] == job:
> >                        error = j['error']
> >                        log('Job failed: %s' % (j['error']))
> >            elif status == 'ready':
> >                self.qmp_log('job-complete', id=job)
> >            elif status == 'pending' and not auto_finalize:
> >                if pre_finalize:
> >                    pre_finalize()
> >                if cancel:
> >                    self.qmp_log('job-cancel', id=job)
> >                else:
> >                    self.qmp_log('job-finalize', id=job)
> >            elif status == 'concluded' and not auto_dismiss:
> >                self.qmp_log('job-dismiss', id=job)
> >            elif status == 'null':
> >                return error
> 
> 
> Does lack of error happen differently that other block jobs, e.g
> blockdev_create?
> 
> Best regards,
>      Maxim Levitsky



Maxim,

Thanks, I works well. I lack of the step "query-jobs".


add a new password to an occupied keyslot

{"execute": "x-blockdev-amend", "arguments": {"node-name": "drive_image1", "job-id": "job_add_key1", "options": { "driver": "luks", "state": "active", "new-secret": "sec7", "keyslot": 1, "iter-time": 10}}}
{"timestamp": {"seconds": 1596418624, "microseconds": 503071}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596418624, "microseconds": 503202}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job_add_key1"}}
{"return": {}}
{"timestamp": {"seconds": 1596418624, "microseconds": 523698}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job_add_key1"}}
{"timestamp": {"seconds": 1596418624, "microseconds": 523817}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job_add_key1"}}

{"execute": "query-jobs"}
{"return": [{"current-progress": 1, "status": "concluded", "total-progress": 1, "type": "amend", "id": "job_add_key1", "error": "Refusing to overwrite active keyslot 1 - please erase it first"}]}

{"execute": "job-dismiss", "arguments": {"id": "job_add_key1"}}
{"timestamp": {"seconds": 1596419006, "microseconds": 388408}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job_add_key1"}}
{"return": {}}

Comment 16 Xueqiang Wei 2020-08-13 09:41:38 UTC
According to Comment 9 and Comment 13, set status to VERIFIED. Thanks.

Comment 19 errata-xmlrpc 2020-11-17 17:45:27 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (virt:8.3 bug fix and enhancement update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2020:5137