| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| package org.apache.cloudstack.utils.qemu; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.File; |
| import com.cloud.utils.script.Script; |
| |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.UUID; |
| |
| import org.junit.Assert; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| |
| import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat; |
| import org.libvirt.LibvirtException; |
| |
| @Ignore |
| public class QemuImgTest { |
| |
| @Test |
| public void testCreateAndInfo() throws QemuImgException, LibvirtException { |
| String filename = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| /* 10TB virtual_size */ |
| long size = 10995116277760l; |
| QemuImgFile file = new QemuImgFile(filename, size, PhysicalDiskFormat.QCOW2); |
| |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(file); |
| Map<String, String> info = qemu.info(file); |
| |
| if (info == null) { |
| fail("We didn't get any information back from qemu-img"); |
| } |
| |
| Long infoSize = Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE)); |
| assertEquals(Long.valueOf(size), Long.valueOf(infoSize)); |
| |
| String infoPath = info.get(QemuImg.IMAGE); |
| assertEquals(filename, infoPath); |
| |
| File f = new File(filename); |
| f.delete(); |
| |
| } |
| |
| @Test |
| public void testCreateAndInfoWithOptions() throws QemuImgException, LibvirtException { |
| String filename = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| /* 10TB virtual_size */ |
| long size = 10995116277760l; |
| QemuImgFile file = new QemuImgFile(filename, size, PhysicalDiskFormat.QCOW2); |
| String clusterSize = "131072"; |
| Map<String, String> options = new HashMap<String, String>(); |
| |
| options.put("cluster_size", clusterSize); |
| |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(file, options); |
| Map<String, String> info = qemu.info(file); |
| |
| Long infoSize = Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE)); |
| assertEquals(Long.valueOf(size), Long.valueOf(infoSize)); |
| |
| String infoPath = info.get(QemuImg.IMAGE); |
| assertEquals(filename, infoPath); |
| |
| String infoClusterSize = info.get(QemuImg.CLUSTER_SIZE); |
| assertEquals(clusterSize, infoClusterSize); |
| |
| File f = new File(filename); |
| f.delete(); |
| |
| } |
| |
| @Test |
| public void testCreateWithSecretObject() throws QemuImgException, LibvirtException { |
| Path testFile = Paths.get("/tmp/", UUID.randomUUID().toString()).normalize().toAbsolutePath(); |
| long size = 1<<30; // 1 Gi |
| |
| Map<QemuObject.ObjectParameter, String> objectParams = new HashMap<>(); |
| objectParams.put(QemuObject.ObjectParameter.ID, "sec0"); |
| objectParams.put(QemuObject.ObjectParameter.DATA, UUID.randomUUID().toString()); |
| |
| Map<String, String> options = new HashMap<String, String>(); |
| |
| options.put(QemuImg.ENCRYPT_FORMAT, "luks"); |
| options.put(QemuImg.ENCRYPT_KEY_SECRET, "sec0"); |
| |
| List<QemuObject> qObjects = new ArrayList<>(); |
| qObjects.add(new QemuObject(QemuObject.ObjectType.SECRET, objectParams)); |
| |
| QemuImgFile file = new QemuImgFile(testFile.toString(), size, PhysicalDiskFormat.QCOW2); |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(file, null, options, qObjects); |
| |
| Map<String, String> info = qemu.info(file); |
| assertEquals("yes", info.get("encrypted")); |
| |
| assertTrue(testFile.toFile().delete()); |
| } |
| |
| @Test |
| public void testCreateSparseVolume() throws QemuImgException, LibvirtException { |
| String filename = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| /* 10TB virtual_size */ |
| long size = 10995116277760l; |
| QemuImgFile file = new QemuImgFile(filename, size, PhysicalDiskFormat.QCOW2); |
| String preallocation = "metadata"; |
| Map<String, String> options = new HashMap<String, String>(); |
| |
| options.put("preallocation", preallocation); |
| |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(file, options); |
| |
| String allocatedSize = Script.runSimpleBashScript(String.format("ls -alhs %s | awk '{print $1}'", file)); |
| String declaredSize = Script.runSimpleBashScript(String.format("ls -alhs %s | awk '{print $6}'", file)); |
| |
| assertFalse(allocatedSize.equals(declaredSize)); |
| |
| File f = new File(filename); |
| f.delete(); |
| |
| } |
| |
| @Test |
| public void testCreateAndResize() throws QemuImgException, LibvirtException { |
| String filename = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| long startSize = 20480; |
| long endSize = 40960; |
| QemuImgFile file = new QemuImgFile(filename, startSize, PhysicalDiskFormat.QCOW2); |
| |
| try { |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(file); |
| qemu.resize(file, endSize); |
| Map<String, String> info = qemu.info(file); |
| |
| if (info == null) { |
| fail("We didn't get any information back from qemu-img"); |
| } |
| |
| Long infoSize = Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE)); |
| assertEquals(Long.valueOf(endSize), Long.valueOf(infoSize)); |
| } catch (QemuImgException e) { |
| fail(e.getMessage()); |
| } |
| |
| File f = new File(filename); |
| f.delete(); |
| |
| } |
| |
| @Test |
| public void testCreateAndResizeDeltaPositive() throws QemuImgException, LibvirtException { |
| String filename = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| long startSize = 20480; |
| long increment = 20480; |
| QemuImgFile file = new QemuImgFile(filename, startSize, PhysicalDiskFormat.RAW); |
| |
| try { |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(file); |
| qemu.resize(file, increment, true); |
| Map<String, String> info = qemu.info(file); |
| |
| if (info == null) { |
| fail("We didn't get any information back from qemu-img"); |
| } |
| |
| Long infoSize = Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE)); |
| assertEquals(Long.valueOf(startSize + increment), Long.valueOf(infoSize)); |
| } catch (QemuImgException e) { |
| fail(e.getMessage()); |
| } |
| |
| File f = new File(filename); |
| f.delete(); |
| } |
| |
| @Test |
| public void testCreateAndResizeDeltaNegative() throws QemuImgException, LibvirtException { |
| String filename = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| long startSize = 81920; |
| long increment = -40960; |
| QemuImgFile file = new QemuImgFile(filename, startSize, PhysicalDiskFormat.RAW); |
| |
| try { |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(file); |
| qemu.resize(file, increment, true); |
| Map<String, String> info = qemu.info(file); |
| |
| if (info == null) { |
| fail("We didn't get any information back from qemu-img"); |
| } |
| |
| Long infoSize = Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE)); |
| assertEquals(Long.valueOf(startSize + increment), Long.valueOf(infoSize)); |
| } catch (QemuImgException e) { |
| fail(e.getMessage()); |
| } |
| |
| File f = new File(filename); |
| f.delete(); |
| } |
| |
| @Test(expected = QemuImgException.class) |
| public void testCreateAndResizeFail() throws QemuImgException, LibvirtException { |
| String filename = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| long startSize = 20480; |
| |
| /* Negative new size, expect failure */ |
| long endSize = -1; |
| QemuImgFile file = new QemuImgFile(filename, startSize, PhysicalDiskFormat.QCOW2); |
| |
| QemuImg qemu = new QemuImg(0); |
| try { |
| qemu.create(file); |
| qemu.resize(file, endSize); |
| } finally { |
| File f = new File(filename); |
| f.delete(); |
| } |
| } |
| |
| @Test(expected = QemuImgException.class) |
| public void testCreateAndResizeZero() throws QemuImgException, LibvirtException { |
| String filename = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| long startSize = 20480; |
| QemuImgFile file = new QemuImgFile(filename, 20480, PhysicalDiskFormat.QCOW2); |
| |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(file); |
| qemu.resize(file, 0); |
| |
| File f = new File(filename); |
| f.delete(); |
| |
| } |
| |
| @Test |
| public void testCreateWithBackingFile() throws QemuImgException, LibvirtException { |
| String firstFileName = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| String secondFileName = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| QemuImgFile firstFile = new QemuImgFile(firstFileName, 20480, PhysicalDiskFormat.QCOW2); |
| QemuImgFile secondFile = new QemuImgFile(secondFileName, PhysicalDiskFormat.QCOW2); |
| |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(firstFile); |
| qemu.create(secondFile, firstFile); |
| |
| Map<String, String> info = qemu.info(secondFile); |
| if (info == null) { |
| fail("We didn't get any information back from qemu-img"); |
| } |
| |
| String backingFile = info.get(QemuImg.BACKING_FILE); |
| if (backingFile == null) { |
| fail("The second file does not have a property backing_file! Create failed?"); |
| } |
| } |
| |
| @Test |
| public void testConvertBasic() throws QemuImgException, LibvirtException { |
| long srcSize = 20480; |
| String srcFileName = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| String destFileName = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| |
| QemuImgFile srcFile = new QemuImgFile(srcFileName, srcSize); |
| QemuImgFile destFile = new QemuImgFile(destFileName); |
| |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(srcFile); |
| qemu.convert(srcFile, destFile); |
| Map<String, String> info = qemu.info(destFile); |
| if (info == null) { |
| fail("We didn't get any information back from qemu-img"); |
| } |
| |
| File sf = new File(srcFileName); |
| sf.delete(); |
| |
| File df = new File(destFileName); |
| df.delete(); |
| |
| } |
| |
| @Test |
| public void testConvertAdvanced() throws QemuImgException, LibvirtException { |
| long srcSize = 4019200; |
| String srcFileName = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| String destFileName = "/tmp/" + UUID.randomUUID() + ".qcow2"; |
| PhysicalDiskFormat srcFormat = PhysicalDiskFormat.RAW; |
| PhysicalDiskFormat destFormat = PhysicalDiskFormat.QCOW2; |
| |
| QemuImgFile srcFile = new QemuImgFile(srcFileName, srcSize, srcFormat); |
| QemuImgFile destFile = new QemuImgFile(destFileName, destFormat); |
| |
| QemuImg qemu = new QemuImg(0); |
| qemu.create(srcFile); |
| qemu.convert(srcFile, destFile); |
| |
| Map<String, String> info = qemu.info(destFile); |
| |
| PhysicalDiskFormat infoFormat = PhysicalDiskFormat.valueOf(info.get(QemuImg.FILE_FORMAT).toUpperCase()); |
| assertEquals(destFormat, infoFormat); |
| |
| Long infoSize = Long.parseLong(info.get(QemuImg.VIRTUAL_SIZE)); |
| assertEquals(Long.valueOf(srcSize), Long.valueOf(infoSize)); |
| |
| File sf = new File(srcFileName); |
| sf.delete(); |
| |
| File df = new File(destFileName); |
| df.delete(); |
| |
| } |
| |
| @Test |
| public void testHelpSupportsImageFormat() throws QemuImgException, LibvirtException { |
| String partialHelp = "Parameters to dd subcommand:\n" + |
| " 'bs=BYTES' read and write up to BYTES bytes at a time (default: 512)\n" + |
| " 'count=N' copy only N input blocks\n" + |
| " 'if=FILE' read from FILE\n" + |
| " 'of=FILE' write to FILE\n" + |
| " 'skip=N' skip N bs-sized blocks at the start of input\n" + |
| "\n" + |
| "Supported formats: cloop copy-on-read file ftp ftps host_cdrom host_device https iser luks nbd nvme parallels qcow qcow2 qed quorum raw rbd ssh throttle vdi vhdx vmdk vpc vvfat\n" + |
| "\n" + |
| "See <https://qemu.org/contribute/report-a-bug> for how to report bugs.\n" + |
| "More information on the QEMU project at <https://qemu.org>."; |
| Assert.assertTrue("should support luks", QemuImg.helpSupportsImageFormat(partialHelp, PhysicalDiskFormat.LUKS)); |
| Assert.assertTrue("should support qcow2", QemuImg.helpSupportsImageFormat(partialHelp, PhysicalDiskFormat.QCOW2)); |
| Assert.assertFalse("should not support http", QemuImg.helpSupportsImageFormat(partialHelp, PhysicalDiskFormat.SHEEPDOG)); |
| } |
| } |