4 # Test LUKS volume with detached header
6 # Copyright (C) 2024 SmartX Inc.
9 # Hyman Huang <yong.huang@smartx.com>
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
36 image_size = 128 * 1024 * 1024
38 luks_img = os.path.join(iotests.test_dir, "luks.img")
39 detached_header_img1 = os.path.join(iotests.test_dir, "detached_header.img1")
40 detached_header_img2 = os.path.join(iotests.test_dir, "detached_header.img2")
41 detached_payload_raw_img = os.path.join(
42 iotests.test_dir, "detached_payload_raw.img"
44 detached_payload_qcow2_img = os.path.join(
45 iotests.test_dir, "detached_payload_qcow2.img"
47 detached_header_raw_img = "json:" + json.dumps(
50 "file": {"filename": detached_payload_raw_img},
52 "filename": detached_header_img1,
56 detached_header_qcow2_img = "json:" + json.dumps(
59 "file": {"filename": detached_payload_qcow2_img},
60 "header": {"filename": detached_header_img2},
64 secret_obj = "secret,id=sec0,data=foo"
65 luks_opts = "key-secret=sec0"
68 class TestDetachedLUKSHeader(QMPTestCase):
69 def setUp(self) -> None:
70 self.vm = iotests.VM()
71 self.vm.add_object(secret_obj)
74 # 1. Create the normal LUKS disk with 128M size
75 self.vm.blockdev_create(
76 {"driver": "file", "filename": luks_img, "size": 0}
82 node_name="luks-1-storage",
84 result = self.vm.blockdev_create(
87 "file": "luks-1-storage",
94 self.assertEqual(result, None)
96 # 2. Create the LUKS disk with detached header (raw)
98 # Create detached LUKS header
99 self.vm.blockdev_create(
100 {"driver": "file", "filename": detached_header_img1, "size": 0}
105 filename=detached_header_img1,
106 node_name="luks-2-header-storage",
109 # Create detached LUKS raw payload
110 self.vm.blockdev_create(
111 {"driver": "file", "filename": detached_payload_raw_img, "size": 0}
116 filename=detached_payload_raw_img,
117 node_name="luks-2-payload-storage",
120 # Format LUKS disk with detached header
121 result = self.vm.blockdev_create(
124 "header": "luks-2-header-storage",
125 "file": "luks-2-payload-storage",
126 "key-secret": "sec0",
127 "preallocation": "full",
132 self.assertEqual(result, None)
136 # 3. Create the LUKS disk with detached header (qcow2)
138 # Create detached LUKS header using qemu-img
139 res = qemu_img_create(
147 "detached-header=true",
148 detached_header_img2,
150 assert res.returncode == 0
152 # Create detached LUKS qcow2 payload
153 res = qemu_img_create(
154 "-f", "qcow2", detached_payload_qcow2_img, str(image_size)
156 assert res.returncode == 0
158 def tearDown(self) -> None:
160 os.remove(detached_header_img1)
161 os.remove(detached_header_img2)
162 os.remove(detached_payload_raw_img)
163 os.remove(detached_payload_qcow2_img)
165 # Check if there was any qemu-io run that failed
166 if "Pattern verification failed" in self.vm.get_log():
167 print("ERROR: Pattern verification failed:")
168 print(self.vm.get_log())
169 self.fail("qemu-io pattern verification failed")
171 def test_img_creation(self) -> None:
172 # Check if the images created above are expected
174 data = qemu_img_info(luks_img)["format-specific"]
175 self.assertEqual(data["type"], imgfmt)
176 self.assertEqual(data["data"]["detached-header"], False)
178 data = qemu_img_info(detached_header_raw_img)["format-specific"]
179 self.assertEqual(data["type"], imgfmt)
180 self.assertEqual(data["data"]["detached-header"], True)
182 data = qemu_img_info(detached_header_qcow2_img)["format-specific"]
183 self.assertEqual(data["type"], imgfmt)
184 self.assertEqual(data["data"]["detached-header"], True)
186 # Check if preallocation works
187 size = qemu_img_info(detached_payload_raw_img)["actual-size"]
188 self.assertGreaterEqual(size, image_size)
190 def test_detached_luks_header(self) -> None:
193 # 1. Add the disk created above
195 # Add normal LUKS disk
200 node_name="luks-1-storage",
202 result = self.vm.qmp_log(
205 file="luks-1-storage",
207 node_name="luks-1-format",
210 # Expected result{ "return": {} }
211 self.assert_qmp(result, "return", {})
213 # Add detached LUKS header with raw payload
217 filename=detached_header_img1,
218 node_name="luks-header1-storage",
224 filename=detached_payload_raw_img,
225 node_name="luks-2-payload-raw-storage",
228 result = self.vm.qmp_log(
231 header="luks-header1-storage",
232 file="luks-2-payload-raw-storage",
234 node_name="luks-2-payload-raw-format",
236 self.assert_qmp(result, "return", {})
238 # Add detached LUKS header with qcow2 payload
242 filename=detached_header_img2,
243 node_name="luks-header2-storage",
249 filename=detached_payload_qcow2_img,
250 node_name="luks-3-payload-qcow2-storage",
253 result = self.vm.qmp_log(
256 header="luks-header2-storage",
257 file="luks-3-payload-qcow2-storage",
259 node_name="luks-3-payload-qcow2-format",
261 self.assert_qmp(result, "return", {})
265 # Do some I/O to the image to see whether it still works
266 # (Pattern verification will be checked by tearDown())
269 result = self.vm.qmp_log(
270 "human-monitor-command",
271 command_line='qemu-io luks-1-format "write -P 40 0 64k"',
273 self.assert_qmp(result, "return", "")
275 result = self.vm.qmp_log(
276 "human-monitor-command",
277 command_line='qemu-io luks-1-format "read -P 40 0 64k"',
279 self.assert_qmp(result, "return", "")
281 # Detached LUKS header with raw payload
282 cmd = 'qemu-io luks-2-payload-raw-format "write -P 41 0 64k"'
283 result = self.vm.qmp(
284 "human-monitor-command",
287 self.assert_qmp(result, "return", "")
289 cmd = 'qemu-io luks-2-payload-raw-format "read -P 41 0 64k"'
290 result = self.vm.qmp(
291 "human-monitor-command",
294 self.assert_qmp(result, "return", "")
296 # Detached LUKS header with qcow2 payload
297 cmd = 'qemu-io luks-3-payload-qcow2-format "write -P 42 0 64k"'
298 result = self.vm.qmp(
299 "human-monitor-command",
302 self.assert_qmp(result, "return", "")
304 cmd = 'qemu-io luks-3-payload-qcow2-format "read -P 42 0 64k"'
305 result = self.vm.qmp(
306 "human-monitor-command",
309 self.assert_qmp(result, "return", "")
314 if __name__ == "__main__":
315 # Test image creation and I/O
316 iotests.main(supported_fmts=["luks"], supported_protocols=["file"])