matchDiskFormat = supportedImageFormat -> supportedImageFormat.toString()
+ .equalsIgnoreCase( this.toString() );
+ return supportedImageFormats.stream().anyMatch( matchDiskFormat );
+ }
+
+ /**
+ * Returns default (preferred) disk image format for the specified virtualizer.
+ *
+ * @param virt virtualizer for that the default disk image should be determined.
+ * @return default (preferred) disk image format.
+ */
+ public static ImageFormat defaultForVirtualizer( Virtualizer virt )
+ {
+ if ( virt == null ) {
+ return null;
+ } else {
+ return ImageFormat.defaultForVirtualizer( virt.virtId );
+ }
+ }
+
+ /**
+ * Returns default (preferred) disk image format for the specified virtualizer.
+ *
+ * @param virtId ID of a virtualizer for that the default disk image should be determined.
+ * @return default (preferred) disk image format.
+ */
+ public static ImageFormat defaultForVirtualizer( String virtId )
+ {
+ ImageFormat imgFormat = null;
+
+ if ( TConst.VIRT_DOCKER.equals( virtId ) ) {
+ imgFormat = NONE;
+ } else if ( TConst.VIRT_QEMU.equals( virtId ) ) {
+ imgFormat = QCOW2;
+ } else if ( TConst.VIRT_VIRTUALBOX.equals( virtId ) ) {
+ imgFormat = VDI;
+ } else if ( TConst.VIRT_VMWARE.equals( virtId ) ) {
+ imgFormat = VMDK;
+ }
+
+ return imgFormat;
+ }
+
+ @Override
+ public String toString()
+ {
+ return this.getExtension();
+ }
+ }
+}
diff --git a/src/main/java/org/openslx/virtualization/disk/DiskImageException.java b/src/main/java/org/openslx/virtualization/disk/DiskImageException.java
new file mode 100644
index 0000000..db62917
--- /dev/null
+++ b/src/main/java/org/openslx/virtualization/disk/DiskImageException.java
@@ -0,0 +1,25 @@
+package org.openslx.virtualization.disk;
+
+/**
+ * An exception for faulty disk image handling.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class DiskImageException extends Exception
+{
+ /**
+ * Version number for serialization.
+ */
+ private static final long serialVersionUID = 5464286488698331909L;
+
+ /**
+ * Creates a disk image exception including an error message.
+ *
+ * @param errorMsg message to describe a disk image error.
+ */
+ public DiskImageException( String errorMsg )
+ {
+ super( errorMsg );
+ }
+}
diff --git a/src/main/java/org/openslx/virtualization/disk/DiskImageQcow2.java b/src/main/java/org/openslx/virtualization/disk/DiskImageQcow2.java
new file mode 100644
index 0000000..a007e1c
--- /dev/null
+++ b/src/main/java/org/openslx/virtualization/disk/DiskImageQcow2.java
@@ -0,0 +1,232 @@
+package org.openslx.virtualization.disk;
+
+import java.io.RandomAccessFile;
+
+import org.openslx.virtualization.Version;
+
+/**
+ * QCOW2 disk image for virtual machines.
+ *
+ * A QCOW2 disk image consists of a header, one L1 table and several L2 tables used for lookup data
+ * clusters in the file via a two-level lookup. The QCOW2 header contains the following fields:
+ *
+ *
+ * QCOW2 (version 2 and 3) header format:
+ *
+ * magic (4 byte)
+ * version (4 byte)
+ * backing_file_offset (8 byte)
+ * backing_file_size (4 byte)
+ * cluster_bits (4 byte)
+ * size (8 byte)
+ * crypt_method (4 byte)
+ * l1_size (4 byte)
+ * l1_table_offset (8 byte)
+ * refcount_table_offset (8 byte)
+ * refcount_table_clusters (4 byte)
+ * nb_snapshots (4 byte)
+ * snapshots_offset (8 byte)
+ * incompatible_features (8 byte) [*]
+ * compatible_features (8 byte) [*]
+ * autoclear_features (8 byte) [*]
+ * refcount_order (8 byte) [*]
+ * header_length (4 byte) [*]
+ *
+ * [*] these fields are only available in the QCOW2 version 3 header format
+ *
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class DiskImageQcow2 extends DiskImage
+{
+ /**
+ * Big endian representation of the big endian QCOW2 magic bytes QFI\xFB
.
+ */
+ private static final int QCOW2_MAGIC = 0x514649fb;
+
+ /**
+ * Creates a new QCOW2 disk image from an existing QCOW2 image file.
+ *
+ * @param diskImage file to a QCOW2 disk storing the image content.
+ */
+ DiskImageQcow2( RandomAccessFile diskImage )
+ {
+ super( diskImage );
+ }
+
+ /**
+ * Probe specified file with unknown format to be a QCOW2 disk image file.
+ *
+ * @param diskImage file with unknown format that should be probed.
+ * @return state whether file is a QCOW2 disk image or not.
+ *
+ * @throws DiskImageException cannot probe specified file with unknown format.
+ */
+ public static boolean probe( RandomAccessFile diskImage ) throws DiskImageException
+ {
+ final boolean isQcow2ImageFormat;
+
+ // goto the beginning of the disk image to read the disk image
+ final int diskImageMagic = DiskImageUtils.readInt( diskImage, 0 );
+
+ // check if disk image's magic bytes can be found
+ if ( diskImageMagic == DiskImageQcow2.QCOW2_MAGIC ) {
+ isQcow2ImageFormat = true;
+ } else {
+ isQcow2ImageFormat = false;
+ }
+
+ return isQcow2ImageFormat;
+ }
+
+ @Override
+ public boolean isStandalone() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+ final long qcowBackingFileOffset = DiskImageUtils.readLong( diskFile, 8 );
+ final boolean qcowStandalone;
+
+ // check if QCOW2 image does not refer to any backing file
+ if ( qcowBackingFileOffset == 0 ) {
+ qcowStandalone = true;
+ } else {
+ qcowStandalone = false;
+ }
+
+ return qcowStandalone;
+ }
+
+ @Override
+ public boolean isCompressed() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+ final boolean qcowUseExtendedL2;
+ boolean qcowCompressed = false;
+
+ // check if QCOW2 image uses extended L2 tables
+ // extended L2 tables are only possible in QCOW2 version 3 header format
+ if ( this.getVersion().getMajor() >= Short.valueOf( "3" ) ) {
+ // read incompatible feature bits
+ final long qcowIncompatibleFeatures = DiskImageUtils.readLong( diskFile, 72 );
+
+ // support for extended L2 tables is enabled if bit 4 is set
+ qcowUseExtendedL2 = ( ( ( qcowIncompatibleFeatures & 0x000000000010 ) >>> 4 ) == 1 );
+ } else {
+ qcowUseExtendedL2 = false;
+ }
+
+ // get number of entries in L1 table
+ final int qcowL1TableSize = DiskImageUtils.readInt( diskFile, 36 );
+
+ // check if a valid L1 table is present
+ if ( qcowL1TableSize > 0 ) {
+ // QCOW2 image contains active L1 table with more than 0 entries: l1_size > 0
+ // search for first L2 table and its first entry to get compression bit
+
+ // get cluster bits to calculate the cluster size
+ final int qcowClusterBits = DiskImageUtils.readInt( diskFile, 20 );
+ final int qcowClusterSize = ( 1 << qcowClusterBits );
+
+ // entries of a L1 table have always the size of 8 byte (64 bit)
+ final int qcowL1TableEntrySize = 8;
+
+ // entries of a L2 table have either the size of 8 or 16 byte (64 or 128 bit)
+ final int qcowL2TableEntrySize = ( qcowUseExtendedL2 ) ? 16 : 8;
+
+ // calculate number of L2 table entries
+ final int qcowL2TableSize = qcowClusterSize / qcowL2TableEntrySize;
+
+ // get offset of L1 table
+ final long qcowL1TableOffset = DiskImageUtils.readLong( diskFile, 40 );
+
+ // check for each L2 table referenced from an L1 table its entries
+ // until a compressed cluster descriptor is found
+ for ( long i = 0; i < qcowL1TableSize; i++ ) {
+ // get offset of current L2 table from the current L1 table entry
+ final long qcowL1TableEntryOffset = qcowL1TableOffset + ( i * qcowL1TableEntrySize );
+ final long qcowL1TableEntry = DiskImageUtils.readLong( diskFile, qcowL1TableEntryOffset );
+
+ // extract offset (bits 9 - 55) from L1 table entry
+ final long qcowL2TableOffset = ( qcowL1TableEntry & 0x00fffffffffffe00L );
+
+ if ( qcowL2TableOffset == 0 ) {
+ // L2 table and all clusters described by this L2 table are unallocated
+ continue;
+ }
+
+ // get each L2 table entry and check if it is a compressed cluster descriptor
+ for ( long j = 0; j < qcowL2TableSize; j++ ) {
+ // get current L2 table entry
+ final long qcowL2TableEntryOffset = qcowL2TableOffset + ( j * qcowL2TableEntrySize );
+ final long qcowL2TableEntry = DiskImageUtils.readLong( diskFile, qcowL2TableEntryOffset );
+
+ // extract cluster type (standard or compressed) (bit 62)
+ boolean qcowClusterCompressed = ( ( ( qcowL2TableEntry & 0x4000000000000000L ) >>> 62 ) == 1 );
+
+ // check if QCOW2 disk image contains at least one compressed cluster descriptor
+ if ( qcowClusterCompressed ) {
+ qcowCompressed = true;
+ break;
+ }
+ }
+
+ // terminate if one compressed cluster descriptor is already found
+ if ( qcowCompressed ) {
+ break;
+ }
+ }
+ } else {
+ // QCOW2 image does not contain an active L1 table with any entry: l1_size = 0
+ qcowCompressed = false;
+ }
+
+ return qcowCompressed;
+ }
+
+ @Override
+ public boolean isSnapshot() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+ final int qcowNumSnapshots = DiskImageUtils.readInt( diskFile, 56 );
+ final boolean qcowSnapshot;
+
+ // check if QCOW2 image contains at least one snapshot
+ if ( qcowNumSnapshots == 0 ) {
+ qcowSnapshot = true;
+ } else {
+ qcowSnapshot = false;
+ }
+
+ return qcowSnapshot;
+ }
+
+ @Override
+ public Version getVersion() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+ final int qcowVersion = DiskImageUtils.readInt( diskFile, 4 );
+
+ // check QCOW2 file format version
+ if ( qcowVersion < 2 || qcowVersion > 3 ) {
+ // QCOW2 disk image does not contain a valid QCOW2 version
+ final String errorMsg = new String( "Invalid QCOW2 version in header found!" );
+ throw new DiskImageException( errorMsg );
+ }
+
+ return new Version( Integer.valueOf( qcowVersion ).shortValue() );
+ }
+
+ @Override
+ public String getDescription() throws DiskImageException
+ {
+ // QCOW2 disk image format does not support any disk description
+ return null;
+ }
+
+ @Override
+ public ImageFormat getFormat()
+ {
+ return ImageFormat.QCOW2;
+ }
+}
diff --git a/src/main/java/org/openslx/virtualization/disk/DiskImageUtils.java b/src/main/java/org/openslx/virtualization/disk/DiskImageUtils.java
new file mode 100644
index 0000000..dc67548
--- /dev/null
+++ b/src/main/java/org/openslx/virtualization/disk/DiskImageUtils.java
@@ -0,0 +1,144 @@
+package org.openslx.virtualization.disk;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Utilities to parse disk image format elements and control versions of disk images.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class DiskImageUtils
+{
+ /**
+ * Returns the size of a specified disk image file.
+ *
+ * @param diskImage file to a disk storing the image content.
+ * @return size of the disk image file in bytes.
+ *
+ * @throws DiskImageException unable to obtain the size of the disk image file.
+ */
+ public static long getImageSize( RandomAccessFile diskImage ) throws DiskImageException
+ {
+ final long imageSize;
+
+ try {
+ imageSize = diskImage.length();
+ } catch ( IOException e ) {
+ throw new DiskImageException( e.getLocalizedMessage() );
+ }
+
+ return imageSize;
+ }
+
+ /**
+ * Reads two bytes ({@link Short}) at a given offset
from the specified disk image
+ * file.
+ *
+ * @param diskImage file to a disk storing the image content.
+ * @param offset offset in bytes for reading the two bytes.
+ * @return value of the two bytes from the disk image file as {@link Short}.
+ *
+ * @throws DiskImageException unable to read two bytes from the disk image file.
+ */
+ public static short readShort( RandomAccessFile diskImage, long offset ) throws DiskImageException
+ {
+ final long imageSize = DiskImageUtils.getImageSize( diskImage );
+ short value = 0;
+
+ if ( imageSize >= ( offset + Short.BYTES ) ) {
+ try {
+ diskImage.seek( offset );
+ value = diskImage.readShort();
+ } catch ( IOException e ) {
+ throw new DiskImageException( e.getLocalizedMessage() );
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Reads four bytes ({@link Integer}) at a given offset
from the specified disk
+ * image file.
+ *
+ * @param diskImage file to a disk storing the image content.
+ * @param offset offset in bytes for reading the four bytes.
+ * @return value of the four bytes from the disk image file as {@link Integer}.
+ *
+ * @throws DiskImageException unable to read four bytes from the disk image file.
+ */
+ public static int readInt( RandomAccessFile diskImage, long offset ) throws DiskImageException
+ {
+ final long imageSize = DiskImageUtils.getImageSize( diskImage );
+ int value = 0;
+
+ if ( imageSize >= ( offset + Integer.BYTES ) ) {
+ try {
+ diskImage.seek( offset );
+ value = diskImage.readInt();
+ } catch ( IOException e ) {
+ throw new DiskImageException( e.getLocalizedMessage() );
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Reads eight bytes ({@link Long}) at a given offset
from the specified disk image
+ * file.
+ *
+ * @param diskImage file to a disk storing the image content.
+ * @param offset offset in bytes for reading the eight bytes.
+ * @return value of the eight bytes from the disk image file as {@link Long}.
+ *
+ * @throws DiskImageException unable to read eight bytes from the disk image file.
+ */
+ public static long readLong( RandomAccessFile diskImage, long offset ) throws DiskImageException
+ {
+ final long imageSize = DiskImageUtils.getImageSize( diskImage );
+ long value = 0;
+
+ if ( imageSize >= ( offset + Long.BYTES ) ) {
+ try {
+ diskImage.seek( offset );
+ value = diskImage.readLong();
+ } catch ( IOException e ) {
+ throw new DiskImageException( e.getLocalizedMessage() );
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Reads a variable number of bytes (numBytes
) at a given offset
from the specified disk image file.
+ *
+ * @param diskImage file to a disk storing the image content.
+ * @param offset offset in bytes for reading numBytes
bytes.
+ * @param numBytes number of bytes to read at offset
.
+ * @return read bytes from the disk image file as {@link String}.
+ *
+ * @throws DiskImageException unable to read two bytes from the disk image file.
+ */
+ public static String readBytesAsString( RandomAccessFile diskImage, long offset, int numBytes )
+ throws DiskImageException
+ {
+ final long imageSize = DiskImageUtils.getImageSize( diskImage );
+ byte values[] = {};
+
+ if ( imageSize >= ( offset + numBytes ) ) {
+ try {
+ diskImage.seek( offset );
+ values = new byte[ numBytes ];
+ diskImage.readFully( values );
+ } catch ( IOException e ) {
+ throw new DiskImageException( e.getLocalizedMessage() );
+ }
+ }
+
+ return new String( values );
+ }
+}
diff --git a/src/main/java/org/openslx/virtualization/disk/DiskImageVdi.java b/src/main/java/org/openslx/virtualization/disk/DiskImageVdi.java
new file mode 100644
index 0000000..c564112
--- /dev/null
+++ b/src/main/java/org/openslx/virtualization/disk/DiskImageVdi.java
@@ -0,0 +1,105 @@
+package org.openslx.virtualization.disk;
+
+import java.io.RandomAccessFile;
+
+import org.openslx.virtualization.Version;
+
+/**
+ * VDI disk image for virtual machines.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class DiskImageVdi extends DiskImage
+{
+ /**
+ * Big endian representation of the little endian VDI magic bytes (signature).
+ */
+ private static final int VDI_MAGIC = 0x7f10dabe;
+
+ /**
+ * Creates a new VDI disk image from an existing VDI image file.
+ *
+ * @param diskImage file to a VDI disk storing the image content.
+ */
+ DiskImageVdi( RandomAccessFile diskImage )
+ {
+ super( diskImage );
+ }
+
+ /**
+ * Probe specified file with unknown format to be a VDI disk image file.
+ *
+ * @param diskImage file with unknown format that should be probed.
+ * @return state whether file is a VDI disk image or not.
+ *
+ * @throws DiskImageException cannot probe specified file with unknown format.
+ */
+ public static boolean probe( RandomAccessFile diskImage ) throws DiskImageException
+ {
+ final boolean isVdiImageFormat;
+
+ // goto the beginning of the disk image to read the magic bytes
+ // skip first 64 bytes (opening tag)
+ final int diskImageMagic = DiskImageUtils.readInt( diskImage, 64 );
+
+ // check if disk image's magic bytes can be found
+ if ( diskImageMagic == DiskImageVdi.VDI_MAGIC ) {
+ isVdiImageFormat = true;
+ } else {
+ isVdiImageFormat = false;
+ }
+
+ return isVdiImageFormat;
+ }
+
+ @Override
+ public boolean isStandalone() throws DiskImageException
+ {
+ // VDI does not seem to support split VDI files, so VDI files are always standalone
+ return true;
+ }
+
+ @Override
+ public boolean isCompressed() throws DiskImageException
+ {
+ // compression is done by sparsifying the disk files, there is no flag for it
+ return false;
+ }
+
+ @Override
+ public boolean isSnapshot() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+
+ // if parent UUID is set, the VDI file is a snapshot
+ final String parentUuid = DiskImageUtils.readBytesAsString( diskFile, 440, 16 );
+ final String zeroUuid = new String( new byte[ 16 ] );
+
+ return !zeroUuid.equals( parentUuid );
+ }
+
+ @Override
+ public Version getVersion() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+
+ final short vdiVersionMajor = Short.reverseBytes( DiskImageUtils.readShort( diskFile, 68 ) );
+ final short vdiVersionMinor = Short.reverseBytes( DiskImageUtils.readShort( diskFile, 70 ) );
+
+ return new Version( vdiVersionMajor, vdiVersionMinor );
+ }
+
+ @Override
+ public String getDescription() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+ return DiskImageUtils.readBytesAsString( diskFile, 84, 256 );
+ }
+
+ @Override
+ public ImageFormat getFormat()
+ {
+ return ImageFormat.VDI;
+ }
+}
diff --git a/src/main/java/org/openslx/virtualization/disk/DiskImageVmdk.java b/src/main/java/org/openslx/virtualization/disk/DiskImageVmdk.java
new file mode 100644
index 0000000..720ec37
--- /dev/null
+++ b/src/main/java/org/openslx/virtualization/disk/DiskImageVmdk.java
@@ -0,0 +1,281 @@
+package org.openslx.virtualization.disk;
+
+import java.io.RandomAccessFile;
+
+import org.openslx.util.Util;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationVmwareFileFormat;
+import org.openslx.virtualization.Version;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationException;
+
+/**
+ * VMDK (sparse extent) disk image for virtual machines.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class DiskImageVmdk extends DiskImage
+{
+ /**
+ * Big endian representation of the little endian magic bytes KDMV
.
+ */
+ private static final int VMDK_MAGIC = 0x4b444d56;
+
+ /**
+ * Size of a VMDK disk image data cluster in bytes.
+ */
+ private static final int VMDK_SECTOR_SIZE = 512;
+
+ /**
+ * Default hardware version of a VMDK disk image.
+ */
+ private static final int VMDK_DEFAULT_HW_VERSION = 10;
+
+ /**
+ * Stores disk configuration if VMDK disk image contains an embedded descriptor file.
+ */
+ private final VirtualizationConfigurationVmwareFileFormat vmdkConfig;
+
+ /**
+ * Creates a new VMDK disk image from an existing VMDK image file.
+ *
+ * @param diskImage file to a VMDK disk storing the image content.
+ *
+ * @throws DiskImageException parsing of the VMDK's embedded descriptor file failed.
+ */
+ DiskImageVmdk( RandomAccessFile diskImage ) throws DiskImageException
+ {
+ super( diskImage );
+
+ this.vmdkConfig = this.parseVmdkConfig();
+ }
+
+ /**
+ * Probe specified file with unknown format to be a VMDK disk image file.
+ *
+ * @param diskImage file with unknown format that should be probed.
+ * @return state whether file is a VMDK disk image or not.
+ *
+ * @throws DiskImageException cannot probe specified file with unknown format.
+ */
+ public static boolean probe( RandomAccessFile diskImage ) throws DiskImageException
+ {
+ final boolean isVmdkImageFormat;
+
+ // goto the beginning of the disk image to read the magic bytes
+ final int diskImageMagic = DiskImageUtils.readInt( diskImage, 0 );
+
+ // check if disk image's magic bytes can be found
+ if ( diskImageMagic == DiskImageVmdk.VMDK_MAGIC ) {
+ isVmdkImageFormat = true;
+ } else {
+ isVmdkImageFormat = false;
+ }
+
+ return isVmdkImageFormat;
+ }
+
+ /**
+ * Returns the creation type from the VMDK's embedded descriptor file.
+ *
+ * @return creation type from the VMDK's embedded descriptor file.
+ */
+ private String getCreationType()
+ {
+ final VirtualizationConfigurationVmwareFileFormat vmdkConfig = this.getVmdkConfig();
+ final String vmdkCreationType;
+
+ if ( vmdkConfig == null ) {
+ // VMDK disk image does not contain any descriptor file
+ // assume that the file is not stand alone
+ vmdkCreationType = null;
+ } else {
+ // VMDK disk image contains a descriptor file
+ // get creation type from the content of the descriptor file
+ vmdkCreationType = this.vmdkConfig.get( "createType" );
+ }
+
+ return vmdkCreationType;
+ }
+
+ /**
+ * Parse the configuration of the VMDK's embedded descriptor file.
+ *
+ * @return parsed configuration of the VMDK's embedded descriptor file.
+ *
+ * @throws DiskImageException parsing of the VMDK's embedded descriptor file failed.
+ */
+ protected VirtualizationConfigurationVmwareFileFormat parseVmdkConfig() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+ final VirtualizationConfigurationVmwareFileFormat vmdkConfig;
+
+ // get offset and size of descriptor file embedded into the VMDK disk image
+ final long vmdkDescriptorSectorOffset = Long.reverseBytes( DiskImageUtils.readLong( diskFile, 28 ) );
+ final long vmdkDescriptorSectorSize = Long.reverseBytes( DiskImageUtils.readLong( diskFile, 36 ) );
+
+ if ( vmdkDescriptorSectorOffset > 0 ) {
+ // get content of descriptor file embedded into the VMDK disk image
+ final long vmdkDescriptorOffset = vmdkDescriptorSectorOffset * DiskImageVmdk.VMDK_SECTOR_SIZE;
+ final long vmdkDescriptorSizeMax = vmdkDescriptorSectorSize * DiskImageVmdk.VMDK_SECTOR_SIZE;
+ final String descriptorStr = DiskImageUtils.readBytesAsString( diskFile, vmdkDescriptorOffset,
+ Long.valueOf( vmdkDescriptorSizeMax ).intValue() );
+
+ // get final length of the content within the sectors to be able to trim all 'zero' characters
+ final int vmdkDescriptorSize = descriptorStr.indexOf( 0 );
+
+ // if final length of the content is invalid, throw an exception
+ if ( vmdkDescriptorSize > vmdkDescriptorSizeMax || vmdkDescriptorSize < 0 ) {
+ final String errorMsg = new String( "Embedded descriptor size in VMDK disk image is invalid!" );
+ throw new DiskImageException( errorMsg );
+ }
+
+ // trim all 'zero' characters at the end of the descriptor content to avoid errors during parsing
+ final String configStr = descriptorStr.substring( 0, vmdkDescriptorSize );
+
+ // create configuration instance from content of the descriptor file
+ try {
+ vmdkConfig = new VirtualizationConfigurationVmwareFileFormat( configStr.getBytes(), vmdkDescriptorSize );
+ } catch ( VirtualizationConfigurationException e ) {
+ throw new DiskImageException( e.getLocalizedMessage() );
+ }
+ } else {
+ // there is no descriptor file embedded into the VMDK disk image
+ vmdkConfig = null;
+ }
+
+ return vmdkConfig;
+ }
+
+ /**
+ * Returns parsed configuration of the VMDK's embedded descriptor file.
+ *
+ * @return parsed configuration of the VMDK's embedded descriptor file.
+ */
+ protected VirtualizationConfigurationVmwareFileFormat getVmdkConfig()
+ {
+ return this.vmdkConfig;
+ }
+
+ /**
+ * Returns the hardware version from the VMDK's embedded descriptor file.
+ *
+ * If the VMDK's embedded descriptor file does not contain any hardware version configuration
+ * entry, the default hardware version (see {@link #VMDK_DEFAULT_HW_VERSION}) is returned.
+ *
+ * @return hardware version from the VMDK's embedded descriptor file.
+ *
+ * @throws DiskImageException unable to obtain the VMDK's hardware version of the disk image
+ * format.
+ */
+ public Version getHwVersion() throws DiskImageException
+ {
+ final VirtualizationConfigurationVmwareFileFormat vmdkConfig = this.getVmdkConfig();
+ final Version hwVersion;
+
+ if ( vmdkConfig != null ) {
+ // VMDK image contains a hardware version, so return parsed hardware version
+ // if hardware version cannot be parsed, return default hardware version
+ final String hwVersionStr = vmdkConfig.get( "ddb.virtualHWVersion" );
+
+ final int hwVersionMajor = Util.parseInt( hwVersionStr, DiskImageVmdk.VMDK_DEFAULT_HW_VERSION );
+ hwVersion = new Version( Integer.valueOf( hwVersionMajor ).shortValue() );
+ } else {
+ // VMDK image does not contain any hardware version, so return default hardware version
+ final int hwVersionMajor = DiskImageVmdk.VMDK_DEFAULT_HW_VERSION;
+ hwVersion = new Version( Integer.valueOf( hwVersionMajor ).shortValue() );
+ }
+
+ return hwVersion;
+ }
+
+ @Override
+ public boolean isStandalone() throws DiskImageException
+ {
+ final String vmdkCreationType = this.getCreationType();
+ final boolean vmdkStandalone;
+
+ if ( vmdkCreationType != null ) {
+ // creation type is defined, so check if VMDK disk image is a snapshot
+ if ( this.isSnapshot() ) {
+ // VMDK disk image is a snapshot and not stand alone
+ vmdkStandalone = false;
+ } else {
+ // VMDK disk image is not a snapshot
+ // determine stand alone disk image property
+ vmdkStandalone = vmdkCreationType.equalsIgnoreCase( "streamOptimized" ) ||
+ vmdkCreationType.equalsIgnoreCase( "monolithicSparse" );
+ }
+ } else {
+ // creation type is not defined
+ // assume that the file is not stand alone
+ vmdkStandalone = false;
+ }
+
+ return vmdkStandalone;
+ }
+
+ @Override
+ public boolean isCompressed() throws DiskImageException
+ {
+ final String vmdkCreationType = this.getCreationType();
+ final boolean vmdkCompressed;
+
+ if ( vmdkCreationType != null && vmdkCreationType.equalsIgnoreCase( "streamOptimized" ) ) {
+ // creation type is defined, and VMDK disk image is compressed
+ vmdkCompressed = true;
+ } else {
+ // creation type for compression is not defined
+ // assume that the file is not compressed
+ vmdkCompressed = false;
+ }
+
+ return vmdkCompressed;
+ }
+
+ @Override
+ public boolean isSnapshot() throws DiskImageException
+ {
+ final VirtualizationConfigurationVmwareFileFormat vmdkConfig = this.getVmdkConfig();
+ final boolean vmdkSnapshot;
+
+ if ( vmdkConfig == null ) {
+ // VMDK disk image does not contain any descriptor file
+ // assume that the file is not a snapshot
+ vmdkSnapshot = false;
+ } else {
+ // get parent CID to determine snapshot disk image property
+ final String parentCid = vmdkConfig.get( "parentCID" );
+
+ if ( parentCid != null && !parentCid.equalsIgnoreCase( "ffffffff" ) ) {
+ // link to parent content identifier is defined, so VMDK disk image is a snapshot
+ vmdkSnapshot = true;
+ } else {
+ // link to parent content identifier is not defined, so VMDK disk image is not a snapshot
+ vmdkSnapshot = false;
+ }
+ }
+
+ return vmdkSnapshot;
+ }
+
+ @Override
+ public Version getVersion() throws DiskImageException
+ {
+ final RandomAccessFile diskFile = this.getDiskImage();
+ final int vmdkVersion = Integer.reverseBytes( DiskImageUtils.readInt( diskFile, 4 ) );
+
+ return new Version( Integer.valueOf( vmdkVersion ).shortValue() );
+ }
+
+ @Override
+ public String getDescription() throws DiskImageException
+ {
+ return null;
+ }
+
+ @Override
+ public ImageFormat getFormat()
+ {
+ return ImageFormat.VMDK;
+ }
+}
diff --git a/src/main/java/org/openslx/virtualization/virtualizer/Virtualizer.java b/src/main/java/org/openslx/virtualization/virtualizer/Virtualizer.java
index ac3a4ec..ff24862 100644
--- a/src/main/java/org/openslx/virtualization/virtualizer/Virtualizer.java
+++ b/src/main/java/org/openslx/virtualization/virtualizer/Virtualizer.java
@@ -3,7 +3,7 @@ package org.openslx.virtualization.virtualizer;
import java.util.List;
import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
/**
* Representation of a virtualization system.
diff --git a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerDocker.java b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerDocker.java
index 673447b..06ac24e 100644
--- a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerDocker.java
+++ b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerDocker.java
@@ -6,8 +6,8 @@ import java.util.List;
import org.openslx.thrifthelper.TConst;
import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
+import org.openslx.virtualization.disk.DiskImage;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
/**
* Representation of the Docker virtualizer for application containers.
diff --git a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
index fcce392..d950111 100644
--- a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
+++ b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
@@ -6,8 +6,8 @@ import java.util.List;
import org.openslx.thrifthelper.TConst;
import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
+import org.openslx.virtualization.disk.DiskImage;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
/**
* Representation of the QEMU virtualizer for virtual machines.
diff --git a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerVirtualBox.java b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerVirtualBox.java
index 6be7cbf..ebb3b3f 100644
--- a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerVirtualBox.java
+++ b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerVirtualBox.java
@@ -6,8 +6,8 @@ import java.util.List;
import org.openslx.thrifthelper.TConst;
import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
+import org.openslx.virtualization.disk.DiskImage;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
/**
* Representation of the VirtualBox virtualizer for virtual machines.
diff --git a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerVmware.java b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerVmware.java
index 6e676f3..9fe31a5 100644
--- a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerVmware.java
+++ b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerVmware.java
@@ -6,8 +6,8 @@ import java.util.List;
import org.openslx.thrifthelper.TConst;
import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
+import org.openslx.virtualization.disk.DiskImage;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
/**
* Representation of the VMware virtualizer for virtual machines.
diff --git a/src/main/java/org/openslx/vm/disk/DiskImage.java b/src/main/java/org/openslx/vm/disk/DiskImage.java
deleted file mode 100644
index cf7df83..0000000
--- a/src/main/java/org/openslx/vm/disk/DiskImage.java
+++ /dev/null
@@ -1,253 +0,0 @@
-package org.openslx.vm.disk;
-
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.List;
-import java.util.function.Predicate;
-
-import org.openslx.bwlp.thrift.iface.Virtualizer;
-import org.openslx.thrifthelper.TConst;
-import org.openslx.util.Util;
-import org.openslx.virtualization.Version;
-
-/**
- * Disk image for virtual machines.
- *
- * @implNote This class is the abstract base class to implement various specific disk images (like
- * QCOW2 or VMDK).
- *
- * @author Manuel Bentele
- * @version 1.0
- */
-public abstract class DiskImage implements Closeable
-{
- /**
- * Stores the image file of the disk.
- */
- private RandomAccessFile diskImage = null;
-
- /**
- * Creates a new disk image from an existing image file with a known disk image format.
- *
- * @param diskImage file to a disk storing the image content.
- *
- * @implNote Do not use this constructor to create a new disk image from an image file with
- * unknown disk image format. Instead, use the factory method
- * {@link #newInstance(File)} to probe unknown disk image files before creation.
- */
- protected DiskImage( RandomAccessFile diskImage )
- {
- this.diskImage = diskImage;
- }
-
- /**
- * Returns the disk image file.
- *
- * @return the disk image file.
- */
- protected RandomAccessFile getDiskImage()
- {
- return this.diskImage;
- }
-
- /**
- * Checks whether disk image is standalone and do not depend on other files (e.g. snapshot
- * files).
- *
- * @return state whether disk image is standalone or not.
- *
- * @throws DiskImageException unable to check if disk image is standalone.
- */
- public abstract boolean isStandalone() throws DiskImageException;
-
- /**
- * Checks whether disk image is compressed.
- *
- * @return state whether disk image is compressed or not.
- *
- * @throws DiskImageException unable to check whether disk image is compressed.
- */
- public abstract boolean isCompressed() throws DiskImageException;
-
- /**
- * Checks whether disk image is a snapshot.
- *
- * @return state whether disk image is a snapshot or not.
- *
- * @throws DiskImageException unable to check whether disk image is a snapshot.
- */
- public abstract boolean isSnapshot() throws DiskImageException;
-
- /**
- * Returns the version of the disk image format.
- *
- * @return version of the disk image format.
- *
- * @throws DiskImageException unable to obtain version of the disk image format.
- */
- public abstract Version getVersion() throws DiskImageException;
-
- /**
- * Returns the disk image description.
- *
- * @return description of the disk image.
- *
- * @throws DiskImageException unable to obtain description of the disk image.
- */
- public abstract String getDescription() throws DiskImageException;
-
- /**
- * Returns the format of the disk image.
- *
- * @return format of the disk image.
- */
- public abstract ImageFormat getFormat();
-
- /**
- * Creates a new disk image from an existing image file with an unknown disk image format.
- *
- * @param diskImagePath file to a disk storing the image content.
- * @return concrete disk image instance.
- *
- * @throws FileNotFoundException cannot find specified disk image file.
- * @throws IOException cannot access the content of the disk image file.
- * @throws DiskImageException disk image file has an invalid and unknown disk image format.
- */
- public static DiskImage newInstance( File diskImagePath )
- throws FileNotFoundException, IOException, DiskImageException
- {
- // Make sure this doesn't escape the scope, in case instantiation fails - we can't know when the GC
- // would come along and close this file, which is problematic on Windows (blocking rename/delete)
- final RandomAccessFile fileHandle = new RandomAccessFile( diskImagePath, "r" );
-
- try {
- if ( DiskImageQcow2.probe( fileHandle ) ) {
- return new DiskImageQcow2( fileHandle );
- } else if ( DiskImageVdi.probe( fileHandle ) ) {
- return new DiskImageVdi( fileHandle );
- } else if ( DiskImageVmdk.probe( fileHandle ) ) {
- return new DiskImageVmdk( fileHandle );
- }
- } catch ( Exception e ) {
- Util.safeClose( fileHandle );
- throw e;
- }
- Util.safeClose( fileHandle );
- final String errorMsg = new String( "File '" + diskImagePath.getAbsolutePath() + "' is not a valid disk image!" );
- throw new DiskImageException( errorMsg );
- }
-
- @Override
- public void close() throws IOException
- {
- Util.safeClose( diskImage );
- }
-
- @Override
- protected void finalize() throws Throwable
- {
- close();
- }
-
- /**
- * Format of a disk image.
- *
- * @author Manuel Bentele
- * @version 1.0
- */
- public enum ImageFormat
- {
- // @formatter:off
- NONE ( "none" ),
- QCOW2( "qcow2" ),
- VDI ( "vdi" ),
- VMDK ( "vmdk" );
- // @formatter:on
-
- /**
- * Stores filename extension of the disk image format.
- */
- public final String extension;
-
- /**
- * Create new disk image format.
- *
- * @param extension filename extension of the disk image format.
- */
- ImageFormat( String extension )
- {
- this.extension = extension;
- }
-
- /**
- * Returns filename extension of the disk image.
- *
- * @return filename extension of the disk image.
- */
- public String getExtension()
- {
- return this.extension;
- }
-
- /**
- * Checks if the disk image format is supported by a virtualizer.
- *
- * @param supportedImageFormats list of supported disk image formats of a virtualizer.
- * @return true
if image type is supported by the virtualizer; otherwise
- * false
.
- */
- public boolean isSupportedbyVirtualizer( List supportedImageFormats )
- {
- Predicate matchDiskFormat = supportedImageFormat -> supportedImageFormat.toString()
- .equalsIgnoreCase( this.toString() );
- return supportedImageFormats.stream().anyMatch( matchDiskFormat );
- }
-
- /**
- * Returns default (preferred) disk image format for the specified virtualizer.
- *
- * @param virt virtualizer for that the default disk image should be determined.
- * @return default (preferred) disk image format.
- */
- public static ImageFormat defaultForVirtualizer( Virtualizer virt )
- {
- if ( virt == null ) {
- return null;
- } else {
- return ImageFormat.defaultForVirtualizer( virt.virtId );
- }
- }
-
- /**
- * Returns default (preferred) disk image format for the specified virtualizer.
- *
- * @param virtId ID of a virtualizer for that the default disk image should be determined.
- * @return default (preferred) disk image format.
- */
- public static ImageFormat defaultForVirtualizer( String virtId )
- {
- ImageFormat imgFormat = null;
-
- if ( TConst.VIRT_DOCKER.equals( virtId ) ) {
- imgFormat = NONE;
- } else if ( TConst.VIRT_QEMU.equals( virtId ) ) {
- imgFormat = QCOW2;
- } else if ( TConst.VIRT_VIRTUALBOX.equals( virtId ) ) {
- imgFormat = VDI;
- } else if ( TConst.VIRT_VMWARE.equals( virtId ) ) {
- imgFormat = VMDK;
- }
-
- return imgFormat;
- }
-
- @Override
- public String toString()
- {
- return this.getExtension();
- }
- }
-}
diff --git a/src/main/java/org/openslx/vm/disk/DiskImageException.java b/src/main/java/org/openslx/vm/disk/DiskImageException.java
deleted file mode 100644
index a98f963..0000000
--- a/src/main/java/org/openslx/vm/disk/DiskImageException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.openslx.vm.disk;
-
-/**
- * An exception for faulty disk image handling.
- *
- * @author Manuel Bentele
- * @version 1.0
- */
-public class DiskImageException extends Exception
-{
- /**
- * Version number for serialization.
- */
- private static final long serialVersionUID = 5464286488698331909L;
-
- /**
- * Creates a disk image exception including an error message.
- *
- * @param errorMsg message to describe a disk image error.
- */
- public DiskImageException( String errorMsg )
- {
- super( errorMsg );
- }
-}
diff --git a/src/main/java/org/openslx/vm/disk/DiskImageQcow2.java b/src/main/java/org/openslx/vm/disk/DiskImageQcow2.java
deleted file mode 100644
index e569708..0000000
--- a/src/main/java/org/openslx/vm/disk/DiskImageQcow2.java
+++ /dev/null
@@ -1,232 +0,0 @@
-package org.openslx.vm.disk;
-
-import java.io.RandomAccessFile;
-
-import org.openslx.virtualization.Version;
-
-/**
- * QCOW2 disk image for virtual machines.
- *
- * A QCOW2 disk image consists of a header, one L1 table and several L2 tables used for lookup data
- * clusters in the file via a two-level lookup. The QCOW2 header contains the following fields:
- *
- *
- * QCOW2 (version 2 and 3) header format:
- *
- * magic (4 byte)
- * version (4 byte)
- * backing_file_offset (8 byte)
- * backing_file_size (4 byte)
- * cluster_bits (4 byte)
- * size (8 byte)
- * crypt_method (4 byte)
- * l1_size (4 byte)
- * l1_table_offset (8 byte)
- * refcount_table_offset (8 byte)
- * refcount_table_clusters (4 byte)
- * nb_snapshots (4 byte)
- * snapshots_offset (8 byte)
- * incompatible_features (8 byte) [*]
- * compatible_features (8 byte) [*]
- * autoclear_features (8 byte) [*]
- * refcount_order (8 byte) [*]
- * header_length (4 byte) [*]
- *
- * [*] these fields are only available in the QCOW2 version 3 header format
- *
- *
- * @author Manuel Bentele
- * @version 1.0
- */
-public class DiskImageQcow2 extends DiskImage
-{
- /**
- * Big endian representation of the big endian QCOW2 magic bytes QFI\xFB
.
- */
- private static final int QCOW2_MAGIC = 0x514649fb;
-
- /**
- * Creates a new QCOW2 disk image from an existing QCOW2 image file.
- *
- * @param diskImage file to a QCOW2 disk storing the image content.
- */
- DiskImageQcow2( RandomAccessFile diskImage )
- {
- super( diskImage );
- }
-
- /**
- * Probe specified file with unknown format to be a QCOW2 disk image file.
- *
- * @param diskImage file with unknown format that should be probed.
- * @return state whether file is a QCOW2 disk image or not.
- *
- * @throws DiskImageException cannot probe specified file with unknown format.
- */
- public static boolean probe( RandomAccessFile diskImage ) throws DiskImageException
- {
- final boolean isQcow2ImageFormat;
-
- // goto the beginning of the disk image to read the disk image
- final int diskImageMagic = DiskImageUtils.readInt( diskImage, 0 );
-
- // check if disk image's magic bytes can be found
- if ( diskImageMagic == DiskImageQcow2.QCOW2_MAGIC ) {
- isQcow2ImageFormat = true;
- } else {
- isQcow2ImageFormat = false;
- }
-
- return isQcow2ImageFormat;
- }
-
- @Override
- public boolean isStandalone() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
- final long qcowBackingFileOffset = DiskImageUtils.readLong( diskFile, 8 );
- final boolean qcowStandalone;
-
- // check if QCOW2 image does not refer to any backing file
- if ( qcowBackingFileOffset == 0 ) {
- qcowStandalone = true;
- } else {
- qcowStandalone = false;
- }
-
- return qcowStandalone;
- }
-
- @Override
- public boolean isCompressed() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
- final boolean qcowUseExtendedL2;
- boolean qcowCompressed = false;
-
- // check if QCOW2 image uses extended L2 tables
- // extended L2 tables are only possible in QCOW2 version 3 header format
- if ( this.getVersion().getMajor() >= Short.valueOf( "3" ) ) {
- // read incompatible feature bits
- final long qcowIncompatibleFeatures = DiskImageUtils.readLong( diskFile, 72 );
-
- // support for extended L2 tables is enabled if bit 4 is set
- qcowUseExtendedL2 = ( ( ( qcowIncompatibleFeatures & 0x000000000010 ) >>> 4 ) == 1 );
- } else {
- qcowUseExtendedL2 = false;
- }
-
- // get number of entries in L1 table
- final int qcowL1TableSize = DiskImageUtils.readInt( diskFile, 36 );
-
- // check if a valid L1 table is present
- if ( qcowL1TableSize > 0 ) {
- // QCOW2 image contains active L1 table with more than 0 entries: l1_size > 0
- // search for first L2 table and its first entry to get compression bit
-
- // get cluster bits to calculate the cluster size
- final int qcowClusterBits = DiskImageUtils.readInt( diskFile, 20 );
- final int qcowClusterSize = ( 1 << qcowClusterBits );
-
- // entries of a L1 table have always the size of 8 byte (64 bit)
- final int qcowL1TableEntrySize = 8;
-
- // entries of a L2 table have either the size of 8 or 16 byte (64 or 128 bit)
- final int qcowL2TableEntrySize = ( qcowUseExtendedL2 ) ? 16 : 8;
-
- // calculate number of L2 table entries
- final int qcowL2TableSize = qcowClusterSize / qcowL2TableEntrySize;
-
- // get offset of L1 table
- final long qcowL1TableOffset = DiskImageUtils.readLong( diskFile, 40 );
-
- // check for each L2 table referenced from an L1 table its entries
- // until a compressed cluster descriptor is found
- for ( long i = 0; i < qcowL1TableSize; i++ ) {
- // get offset of current L2 table from the current L1 table entry
- final long qcowL1TableEntryOffset = qcowL1TableOffset + ( i * qcowL1TableEntrySize );
- final long qcowL1TableEntry = DiskImageUtils.readLong( diskFile, qcowL1TableEntryOffset );
-
- // extract offset (bits 9 - 55) from L1 table entry
- final long qcowL2TableOffset = ( qcowL1TableEntry & 0x00fffffffffffe00L );
-
- if ( qcowL2TableOffset == 0 ) {
- // L2 table and all clusters described by this L2 table are unallocated
- continue;
- }
-
- // get each L2 table entry and check if it is a compressed cluster descriptor
- for ( long j = 0; j < qcowL2TableSize; j++ ) {
- // get current L2 table entry
- final long qcowL2TableEntryOffset = qcowL2TableOffset + ( j * qcowL2TableEntrySize );
- final long qcowL2TableEntry = DiskImageUtils.readLong( diskFile, qcowL2TableEntryOffset );
-
- // extract cluster type (standard or compressed) (bit 62)
- boolean qcowClusterCompressed = ( ( ( qcowL2TableEntry & 0x4000000000000000L ) >>> 62 ) == 1 );
-
- // check if QCOW2 disk image contains at least one compressed cluster descriptor
- if ( qcowClusterCompressed ) {
- qcowCompressed = true;
- break;
- }
- }
-
- // terminate if one compressed cluster descriptor is already found
- if ( qcowCompressed ) {
- break;
- }
- }
- } else {
- // QCOW2 image does not contain an active L1 table with any entry: l1_size = 0
- qcowCompressed = false;
- }
-
- return qcowCompressed;
- }
-
- @Override
- public boolean isSnapshot() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
- final int qcowNumSnapshots = DiskImageUtils.readInt( diskFile, 56 );
- final boolean qcowSnapshot;
-
- // check if QCOW2 image contains at least one snapshot
- if ( qcowNumSnapshots == 0 ) {
- qcowSnapshot = true;
- } else {
- qcowSnapshot = false;
- }
-
- return qcowSnapshot;
- }
-
- @Override
- public Version getVersion() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
- final int qcowVersion = DiskImageUtils.readInt( diskFile, 4 );
-
- // check QCOW2 file format version
- if ( qcowVersion < 2 || qcowVersion > 3 ) {
- // QCOW2 disk image does not contain a valid QCOW2 version
- final String errorMsg = new String( "Invalid QCOW2 version in header found!" );
- throw new DiskImageException( errorMsg );
- }
-
- return new Version( Integer.valueOf( qcowVersion ).shortValue() );
- }
-
- @Override
- public String getDescription() throws DiskImageException
- {
- // QCOW2 disk image format does not support any disk description
- return null;
- }
-
- @Override
- public ImageFormat getFormat()
- {
- return ImageFormat.QCOW2;
- }
-}
diff --git a/src/main/java/org/openslx/vm/disk/DiskImageUtils.java b/src/main/java/org/openslx/vm/disk/DiskImageUtils.java
deleted file mode 100644
index ccb053f..0000000
--- a/src/main/java/org/openslx/vm/disk/DiskImageUtils.java
+++ /dev/null
@@ -1,144 +0,0 @@
-package org.openslx.vm.disk;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * Utilities to parse disk image format elements and control versions of disk images.
- *
- * @author Manuel Bentele
- * @version 1.0
- */
-public class DiskImageUtils
-{
- /**
- * Returns the size of a specified disk image file.
- *
- * @param diskImage file to a disk storing the image content.
- * @return size of the disk image file in bytes.
- *
- * @throws DiskImageException unable to obtain the size of the disk image file.
- */
- public static long getImageSize( RandomAccessFile diskImage ) throws DiskImageException
- {
- final long imageSize;
-
- try {
- imageSize = diskImage.length();
- } catch ( IOException e ) {
- throw new DiskImageException( e.getLocalizedMessage() );
- }
-
- return imageSize;
- }
-
- /**
- * Reads two bytes ({@link Short}) at a given offset
from the specified disk image
- * file.
- *
- * @param diskImage file to a disk storing the image content.
- * @param offset offset in bytes for reading the two bytes.
- * @return value of the two bytes from the disk image file as {@link Short}.
- *
- * @throws DiskImageException unable to read two bytes from the disk image file.
- */
- public static short readShort( RandomAccessFile diskImage, long offset ) throws DiskImageException
- {
- final long imageSize = DiskImageUtils.getImageSize( diskImage );
- short value = 0;
-
- if ( imageSize >= ( offset + Short.BYTES ) ) {
- try {
- diskImage.seek( offset );
- value = diskImage.readShort();
- } catch ( IOException e ) {
- throw new DiskImageException( e.getLocalizedMessage() );
- }
- }
-
- return value;
- }
-
- /**
- * Reads four bytes ({@link Integer}) at a given offset
from the specified disk
- * image file.
- *
- * @param diskImage file to a disk storing the image content.
- * @param offset offset in bytes for reading the four bytes.
- * @return value of the four bytes from the disk image file as {@link Integer}.
- *
- * @throws DiskImageException unable to read four bytes from the disk image file.
- */
- public static int readInt( RandomAccessFile diskImage, long offset ) throws DiskImageException
- {
- final long imageSize = DiskImageUtils.getImageSize( diskImage );
- int value = 0;
-
- if ( imageSize >= ( offset + Integer.BYTES ) ) {
- try {
- diskImage.seek( offset );
- value = diskImage.readInt();
- } catch ( IOException e ) {
- throw new DiskImageException( e.getLocalizedMessage() );
- }
- }
-
- return value;
- }
-
- /**
- * Reads eight bytes ({@link Long}) at a given offset
from the specified disk image
- * file.
- *
- * @param diskImage file to a disk storing the image content.
- * @param offset offset in bytes for reading the eight bytes.
- * @return value of the eight bytes from the disk image file as {@link Long}.
- *
- * @throws DiskImageException unable to read eight bytes from the disk image file.
- */
- public static long readLong( RandomAccessFile diskImage, long offset ) throws DiskImageException
- {
- final long imageSize = DiskImageUtils.getImageSize( diskImage );
- long value = 0;
-
- if ( imageSize >= ( offset + Long.BYTES ) ) {
- try {
- diskImage.seek( offset );
- value = diskImage.readLong();
- } catch ( IOException e ) {
- throw new DiskImageException( e.getLocalizedMessage() );
- }
- }
-
- return value;
- }
-
- /**
- * Reads a variable number of bytes (numBytes
) at a given offset
from the specified disk image file.
- *
- * @param diskImage file to a disk storing the image content.
- * @param offset offset in bytes for reading numBytes
bytes.
- * @param numBytes number of bytes to read at offset
.
- * @return read bytes from the disk image file as {@link String}.
- *
- * @throws DiskImageException unable to read two bytes from the disk image file.
- */
- public static String readBytesAsString( RandomAccessFile diskImage, long offset, int numBytes )
- throws DiskImageException
- {
- final long imageSize = DiskImageUtils.getImageSize( diskImage );
- byte values[] = {};
-
- if ( imageSize >= ( offset + numBytes ) ) {
- try {
- diskImage.seek( offset );
- values = new byte[ numBytes ];
- diskImage.readFully( values );
- } catch ( IOException e ) {
- throw new DiskImageException( e.getLocalizedMessage() );
- }
- }
-
- return new String( values );
- }
-}
diff --git a/src/main/java/org/openslx/vm/disk/DiskImageVdi.java b/src/main/java/org/openslx/vm/disk/DiskImageVdi.java
deleted file mode 100644
index 37e45c1..0000000
--- a/src/main/java/org/openslx/vm/disk/DiskImageVdi.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package org.openslx.vm.disk;
-
-import java.io.RandomAccessFile;
-
-import org.openslx.virtualization.Version;
-
-/**
- * VDI disk image for virtual machines.
- *
- * @author Manuel Bentele
- * @version 1.0
- */
-public class DiskImageVdi extends DiskImage
-{
- /**
- * Big endian representation of the little endian VDI magic bytes (signature).
- */
- private static final int VDI_MAGIC = 0x7f10dabe;
-
- /**
- * Creates a new VDI disk image from an existing VDI image file.
- *
- * @param diskImage file to a VDI disk storing the image content.
- */
- DiskImageVdi( RandomAccessFile diskImage )
- {
- super( diskImage );
- }
-
- /**
- * Probe specified file with unknown format to be a VDI disk image file.
- *
- * @param diskImage file with unknown format that should be probed.
- * @return state whether file is a VDI disk image or not.
- *
- * @throws DiskImageException cannot probe specified file with unknown format.
- */
- public static boolean probe( RandomAccessFile diskImage ) throws DiskImageException
- {
- final boolean isVdiImageFormat;
-
- // goto the beginning of the disk image to read the magic bytes
- // skip first 64 bytes (opening tag)
- final int diskImageMagic = DiskImageUtils.readInt( diskImage, 64 );
-
- // check if disk image's magic bytes can be found
- if ( diskImageMagic == DiskImageVdi.VDI_MAGIC ) {
- isVdiImageFormat = true;
- } else {
- isVdiImageFormat = false;
- }
-
- return isVdiImageFormat;
- }
-
- @Override
- public boolean isStandalone() throws DiskImageException
- {
- // VDI does not seem to support split VDI files, so VDI files are always standalone
- return true;
- }
-
- @Override
- public boolean isCompressed() throws DiskImageException
- {
- // compression is done by sparsifying the disk files, there is no flag for it
- return false;
- }
-
- @Override
- public boolean isSnapshot() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
-
- // if parent UUID is set, the VDI file is a snapshot
- final String parentUuid = DiskImageUtils.readBytesAsString( diskFile, 440, 16 );
- final String zeroUuid = new String( new byte[ 16 ] );
-
- return !zeroUuid.equals( parentUuid );
- }
-
- @Override
- public Version getVersion() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
-
- final short vdiVersionMajor = Short.reverseBytes( DiskImageUtils.readShort( diskFile, 68 ) );
- final short vdiVersionMinor = Short.reverseBytes( DiskImageUtils.readShort( diskFile, 70 ) );
-
- return new Version( vdiVersionMajor, vdiVersionMinor );
- }
-
- @Override
- public String getDescription() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
- return DiskImageUtils.readBytesAsString( diskFile, 84, 256 );
- }
-
- @Override
- public ImageFormat getFormat()
- {
- return ImageFormat.VDI;
- }
-}
diff --git a/src/main/java/org/openslx/vm/disk/DiskImageVmdk.java b/src/main/java/org/openslx/vm/disk/DiskImageVmdk.java
deleted file mode 100644
index 75a2bac..0000000
--- a/src/main/java/org/openslx/vm/disk/DiskImageVmdk.java
+++ /dev/null
@@ -1,281 +0,0 @@
-package org.openslx.vm.disk;
-
-import java.io.RandomAccessFile;
-
-import org.openslx.util.Util;
-import org.openslx.virtualization.configuration.VirtualizationConfigurationVmwareFileFormat;
-import org.openslx.virtualization.Version;
-import org.openslx.virtualization.configuration.VirtualizationConfigurationException;
-
-/**
- * VMDK (sparse extent) disk image for virtual machines.
- *
- * @author Manuel Bentele
- * @version 1.0
- */
-public class DiskImageVmdk extends DiskImage
-{
- /**
- * Big endian representation of the little endian magic bytes KDMV
.
- */
- private static final int VMDK_MAGIC = 0x4b444d56;
-
- /**
- * Size of a VMDK disk image data cluster in bytes.
- */
- private static final int VMDK_SECTOR_SIZE = 512;
-
- /**
- * Default hardware version of a VMDK disk image.
- */
- private static final int VMDK_DEFAULT_HW_VERSION = 10;
-
- /**
- * Stores disk configuration if VMDK disk image contains an embedded descriptor file.
- */
- private final VirtualizationConfigurationVmwareFileFormat vmdkConfig;
-
- /**
- * Creates a new VMDK disk image from an existing VMDK image file.
- *
- * @param diskImage file to a VMDK disk storing the image content.
- *
- * @throws DiskImageException parsing of the VMDK's embedded descriptor file failed.
- */
- DiskImageVmdk( RandomAccessFile diskImage ) throws DiskImageException
- {
- super( diskImage );
-
- this.vmdkConfig = this.parseVmdkConfig();
- }
-
- /**
- * Probe specified file with unknown format to be a VMDK disk image file.
- *
- * @param diskImage file with unknown format that should be probed.
- * @return state whether file is a VMDK disk image or not.
- *
- * @throws DiskImageException cannot probe specified file with unknown format.
- */
- public static boolean probe( RandomAccessFile diskImage ) throws DiskImageException
- {
- final boolean isVmdkImageFormat;
-
- // goto the beginning of the disk image to read the magic bytes
- final int diskImageMagic = DiskImageUtils.readInt( diskImage, 0 );
-
- // check if disk image's magic bytes can be found
- if ( diskImageMagic == DiskImageVmdk.VMDK_MAGIC ) {
- isVmdkImageFormat = true;
- } else {
- isVmdkImageFormat = false;
- }
-
- return isVmdkImageFormat;
- }
-
- /**
- * Returns the creation type from the VMDK's embedded descriptor file.
- *
- * @return creation type from the VMDK's embedded descriptor file.
- */
- private String getCreationType()
- {
- final VirtualizationConfigurationVmwareFileFormat vmdkConfig = this.getVmdkConfig();
- final String vmdkCreationType;
-
- if ( vmdkConfig == null ) {
- // VMDK disk image does not contain any descriptor file
- // assume that the file is not stand alone
- vmdkCreationType = null;
- } else {
- // VMDK disk image contains a descriptor file
- // get creation type from the content of the descriptor file
- vmdkCreationType = this.vmdkConfig.get( "createType" );
- }
-
- return vmdkCreationType;
- }
-
- /**
- * Parse the configuration of the VMDK's embedded descriptor file.
- *
- * @return parsed configuration of the VMDK's embedded descriptor file.
- *
- * @throws DiskImageException parsing of the VMDK's embedded descriptor file failed.
- */
- protected VirtualizationConfigurationVmwareFileFormat parseVmdkConfig() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
- final VirtualizationConfigurationVmwareFileFormat vmdkConfig;
-
- // get offset and size of descriptor file embedded into the VMDK disk image
- final long vmdkDescriptorSectorOffset = Long.reverseBytes( DiskImageUtils.readLong( diskFile, 28 ) );
- final long vmdkDescriptorSectorSize = Long.reverseBytes( DiskImageUtils.readLong( diskFile, 36 ) );
-
- if ( vmdkDescriptorSectorOffset > 0 ) {
- // get content of descriptor file embedded into the VMDK disk image
- final long vmdkDescriptorOffset = vmdkDescriptorSectorOffset * DiskImageVmdk.VMDK_SECTOR_SIZE;
- final long vmdkDescriptorSizeMax = vmdkDescriptorSectorSize * DiskImageVmdk.VMDK_SECTOR_SIZE;
- final String descriptorStr = DiskImageUtils.readBytesAsString( diskFile, vmdkDescriptorOffset,
- Long.valueOf( vmdkDescriptorSizeMax ).intValue() );
-
- // get final length of the content within the sectors to be able to trim all 'zero' characters
- final int vmdkDescriptorSize = descriptorStr.indexOf( 0 );
-
- // if final length of the content is invalid, throw an exception
- if ( vmdkDescriptorSize > vmdkDescriptorSizeMax || vmdkDescriptorSize < 0 ) {
- final String errorMsg = new String( "Embedded descriptor size in VMDK disk image is invalid!" );
- throw new DiskImageException( errorMsg );
- }
-
- // trim all 'zero' characters at the end of the descriptor content to avoid errors during parsing
- final String configStr = descriptorStr.substring( 0, vmdkDescriptorSize );
-
- // create configuration instance from content of the descriptor file
- try {
- vmdkConfig = new VirtualizationConfigurationVmwareFileFormat( configStr.getBytes(), vmdkDescriptorSize );
- } catch ( VirtualizationConfigurationException e ) {
- throw new DiskImageException( e.getLocalizedMessage() );
- }
- } else {
- // there is no descriptor file embedded into the VMDK disk image
- vmdkConfig = null;
- }
-
- return vmdkConfig;
- }
-
- /**
- * Returns parsed configuration of the VMDK's embedded descriptor file.
- *
- * @return parsed configuration of the VMDK's embedded descriptor file.
- */
- protected VirtualizationConfigurationVmwareFileFormat getVmdkConfig()
- {
- return this.vmdkConfig;
- }
-
- /**
- * Returns the hardware version from the VMDK's embedded descriptor file.
- *
- * If the VMDK's embedded descriptor file does not contain any hardware version configuration
- * entry, the default hardware version (see {@link #VMDK_DEFAULT_HW_VERSION}) is returned.
- *
- * @return hardware version from the VMDK's embedded descriptor file.
- *
- * @throws DiskImageException unable to obtain the VMDK's hardware version of the disk image
- * format.
- */
- public Version getHwVersion() throws DiskImageException
- {
- final VirtualizationConfigurationVmwareFileFormat vmdkConfig = this.getVmdkConfig();
- final Version hwVersion;
-
- if ( vmdkConfig != null ) {
- // VMDK image contains a hardware version, so return parsed hardware version
- // if hardware version cannot be parsed, return default hardware version
- final String hwVersionStr = vmdkConfig.get( "ddb.virtualHWVersion" );
-
- final int hwVersionMajor = Util.parseInt( hwVersionStr, DiskImageVmdk.VMDK_DEFAULT_HW_VERSION );
- hwVersion = new Version( Integer.valueOf( hwVersionMajor ).shortValue() );
- } else {
- // VMDK image does not contain any hardware version, so return default hardware version
- final int hwVersionMajor = DiskImageVmdk.VMDK_DEFAULT_HW_VERSION;
- hwVersion = new Version( Integer.valueOf( hwVersionMajor ).shortValue() );
- }
-
- return hwVersion;
- }
-
- @Override
- public boolean isStandalone() throws DiskImageException
- {
- final String vmdkCreationType = this.getCreationType();
- final boolean vmdkStandalone;
-
- if ( vmdkCreationType != null ) {
- // creation type is defined, so check if VMDK disk image is a snapshot
- if ( this.isSnapshot() ) {
- // VMDK disk image is a snapshot and not stand alone
- vmdkStandalone = false;
- } else {
- // VMDK disk image is not a snapshot
- // determine stand alone disk image property
- vmdkStandalone = vmdkCreationType.equalsIgnoreCase( "streamOptimized" ) ||
- vmdkCreationType.equalsIgnoreCase( "monolithicSparse" );
- }
- } else {
- // creation type is not defined
- // assume that the file is not stand alone
- vmdkStandalone = false;
- }
-
- return vmdkStandalone;
- }
-
- @Override
- public boolean isCompressed() throws DiskImageException
- {
- final String vmdkCreationType = this.getCreationType();
- final boolean vmdkCompressed;
-
- if ( vmdkCreationType != null && vmdkCreationType.equalsIgnoreCase( "streamOptimized" ) ) {
- // creation type is defined, and VMDK disk image is compressed
- vmdkCompressed = true;
- } else {
- // creation type for compression is not defined
- // assume that the file is not compressed
- vmdkCompressed = false;
- }
-
- return vmdkCompressed;
- }
-
- @Override
- public boolean isSnapshot() throws DiskImageException
- {
- final VirtualizationConfigurationVmwareFileFormat vmdkConfig = this.getVmdkConfig();
- final boolean vmdkSnapshot;
-
- if ( vmdkConfig == null ) {
- // VMDK disk image does not contain any descriptor file
- // assume that the file is not a snapshot
- vmdkSnapshot = false;
- } else {
- // get parent CID to determine snapshot disk image property
- final String parentCid = vmdkConfig.get( "parentCID" );
-
- if ( parentCid != null && !parentCid.equalsIgnoreCase( "ffffffff" ) ) {
- // link to parent content identifier is defined, so VMDK disk image is a snapshot
- vmdkSnapshot = true;
- } else {
- // link to parent content identifier is not defined, so VMDK disk image is not a snapshot
- vmdkSnapshot = false;
- }
- }
-
- return vmdkSnapshot;
- }
-
- @Override
- public Version getVersion() throws DiskImageException
- {
- final RandomAccessFile diskFile = this.getDiskImage();
- final int vmdkVersion = Integer.reverseBytes( DiskImageUtils.readInt( diskFile, 4 ) );
-
- return new Version( Integer.valueOf( vmdkVersion ).shortValue() );
- }
-
- @Override
- public String getDescription() throws DiskImageException
- {
- return null;
- }
-
- @Override
- public ImageFormat getFormat()
- {
- return ImageFormat.VMDK;
- }
-}
diff --git a/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java
index 1cc7841..fa2ed13 100644
--- a/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java
+++ b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java
@@ -40,9 +40,9 @@ import org.openslx.virtualization.configuration.VirtualizationConfiguration.Ethe
import org.openslx.virtualization.configuration.VirtualizationConfiguration.SoundCardType;
import org.openslx.virtualization.configuration.VirtualizationConfiguration.UsbSpeed;
import org.openslx.virtualization.configuration.logic.ConfigurationLogicTestUtils;
-import org.openslx.vm.disk.DiskImage;
-import org.openslx.vm.disk.DiskImageTestResources;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
+import org.openslx.virtualization.disk.DiskImage;
+import org.openslx.virtualization.disk.DiskImageTestResources;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
public class VirtualizationConfigurationQemuTest
{
diff --git a/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBoxTest.java b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBoxTest.java
index 597fffb..1689007 100644
--- a/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBoxTest.java
+++ b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBoxTest.java
@@ -20,7 +20,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
public class VirtualizationConfigurationVirtualBoxTest
{
diff --git a/src/test/java/org/openslx/virtualization/configuration/logic/ConfigurationLogicDozModServerToDozModClientTest.java b/src/test/java/org/openslx/virtualization/configuration/logic/ConfigurationLogicDozModServerToDozModClientTest.java
index 96180ed..cb5cbb3 100644
--- a/src/test/java/org/openslx/virtualization/configuration/logic/ConfigurationLogicDozModServerToDozModClientTest.java
+++ b/src/test/java/org/openslx/virtualization/configuration/logic/ConfigurationLogicDozModServerToDozModClientTest.java
@@ -15,7 +15,7 @@ import org.openslx.libvirt.xml.LibvirtXmlTestResources;
import org.openslx.virtualization.configuration.VirtualizationConfiguration;
import org.openslx.virtualization.configuration.data.ConfigurationDataDozModServerToDozModClient;
import org.openslx.virtualization.configuration.transformation.TransformationException;
-import org.openslx.vm.disk.DiskImageTestResources;
+import org.openslx.virtualization.disk.DiskImageTestResources;
public class ConfigurationLogicDozModServerToDozModClientTest
{
diff --git a/src/test/java/org/openslx/virtualization/disk/DiskImageQcow2Test.java b/src/test/java/org/openslx/virtualization/disk/DiskImageQcow2Test.java
new file mode 100644
index 0000000..c6a294c
--- /dev/null
+++ b/src/test/java/org/openslx/virtualization/disk/DiskImageQcow2Test.java
@@ -0,0 +1,221 @@
+package org.openslx.virtualization.disk;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.virtualization.Version;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
+
+public class DiskImageQcow2Test
+{
+ @Test
+ @DisplayName( "Test detection of default QCOW2 disk image" )
+ public void testQcow2DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of compressed, 16384 byte cluster QCOW2 disk image with extended L2 tables" )
+ public void testQcow2DetectionL2Compressed16384DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-16384_cp-on_l2-on.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( true, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of compressed, 16384 byte cluster QCOW2 disk image without extended L2 tables" )
+ public void testQcow2DetectionNonL2Compressed16384DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-16384_cp-on_l2-off.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( true, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of non-compressed, 16384 byte cluster QCOW2 disk image with extended L2 tables" )
+ public void testQcow2DetectionL2NonCompressed16384DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-16384_cp-off_l2-on.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of non-compressed, 16384 byte cluster QCOW2 disk image without extended L2 tables" )
+ public void testQcow2DetectionNonL2NonCompressed16384DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-16384_cp-off_l2-off.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of compressed, 65536 byte cluster QCOW2 disk image with extended L2 tables" )
+ public void testQcow2DetectionL2Compressed65536DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-65536_cp-on_l2-on.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( true, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of compressed, 65536 byte cluster QCOW2 disk image without extended L2 tables" )
+ public void testQcow2DetectionNonL2Compressed65536DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-65536_cp-on_l2-off.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( true, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of non-compressed, 65536 byte cluster QCOW2 disk image with extended L2 tables" )
+ public void testQcow2DetectionL2NonCompressed65536DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-65536_cp-off_l2-on.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of non-compressed, 65536 byte cluster QCOW2 disk image without extended L2 tables" )
+ public void testQcow2DetectionNonL2NonCompressed65536DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-65536_cp-off_l2-off.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of compressed, 2097152 byte cluster QCOW2 disk image with extended L2 tables" )
+ public void testQcow2DetectionL2Compressed2097152DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-2097152_cp-on_l2-on.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( true, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of compressed, 2097152 byte cluster QCOW2 disk image without extended L2 tables" )
+ public void testQcow2DetectionNonL2Compressed2097152DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-2097152_cp-on_l2-off.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( true, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of non-compressed, 2097152 byte cluster QCOW2 disk image with extended L2 tables" )
+ public void testQcow2DetectionL2NonCompressed2097152DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-2097152_cp-off_l2-on.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of non-compressed, 2097152 byte cluster QCOW2 disk image without extended L2 tables" )
+ public void testQcow2DetectionNonL2NonCompressed2097152DiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage
+ .newInstance( DiskImageTestResources.getDiskFile( "image_cs-2097152_cp-off_l2-off.qcow2" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+
+ assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+ }
+}
diff --git a/src/test/java/org/openslx/virtualization/disk/DiskImageTest.java b/src/test/java/org/openslx/virtualization/disk/DiskImageTest.java
new file mode 100644
index 0000000..9293a90
--- /dev/null
+++ b/src/test/java/org/openslx/virtualization/disk/DiskImageTest.java
@@ -0,0 +1,19 @@
+package org.openslx.virtualization.disk;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class DiskImageTest
+{
+ @Test
+ @DisplayName( "Test of invalid disk image" )
+ public void testInvalidDiskImage() throws IOException
+ {
+ Assertions.assertThrows( DiskImageException.class, () -> {
+ DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default.invalid" ) );
+ } );
+ }
+}
diff --git a/src/test/java/org/openslx/virtualization/disk/DiskImageTestResources.java b/src/test/java/org/openslx/virtualization/disk/DiskImageTestResources.java
new file mode 100644
index 0000000..ab97bbd
--- /dev/null
+++ b/src/test/java/org/openslx/virtualization/disk/DiskImageTestResources.java
@@ -0,0 +1,16 @@
+package org.openslx.virtualization.disk;
+
+import java.io.File;
+import java.net.URL;
+
+public class DiskImageTestResources
+{
+ private static final String DISK_PREFIX_PATH = File.separator + "disk";
+
+ public static File getDiskFile( String diskFileName )
+ {
+ String diskPath = DiskImageTestResources.DISK_PREFIX_PATH + File.separator + diskFileName;
+ URL disk = DiskImageTestResources.class.getResource( diskPath );
+ return new File( disk.getFile() );
+ }
+}
diff --git a/src/test/java/org/openslx/virtualization/disk/DiskImageVdiTest.java b/src/test/java/org/openslx/virtualization/disk/DiskImageVdiTest.java
new file mode 100644
index 0000000..06307fa
--- /dev/null
+++ b/src/test/java/org/openslx/virtualization/disk/DiskImageVdiTest.java
@@ -0,0 +1,44 @@
+package org.openslx.virtualization.disk;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.virtualization.Version;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
+
+public class DiskImageVdiTest
+{
+ @Test
+ @DisplayName( "Test detection of default VDI disk image" )
+ public void testVdiDiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default.vdi" ) );
+ final Version imageVersion = new Version( Short.valueOf( "1" ), Short.valueOf( "1" ) );
+
+ assertEquals( ImageFormat.VDI.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNotNull( image.getDescription() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of VDI disk image snapshot" )
+ public void testVdiDiskImageSnapshot() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default_snapshot.vdi" ) );
+ final Version imageVersion = new Version( Short.valueOf( "1" ), Short.valueOf( "1" ) );
+
+ assertEquals( ImageFormat.VDI.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( true, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNotNull( image.getDescription() );
+ }
+}
diff --git a/src/test/java/org/openslx/virtualization/disk/DiskImageVmdkTest.java b/src/test/java/org/openslx/virtualization/disk/DiskImageVmdkTest.java
new file mode 100644
index 0000000..5b3cccf
--- /dev/null
+++ b/src/test/java/org/openslx/virtualization/disk/DiskImageVmdkTest.java
@@ -0,0 +1,111 @@
+package org.openslx.virtualization.disk;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.virtualization.Version;
+import org.openslx.virtualization.disk.DiskImage.ImageFormat;
+
+public class DiskImageVmdkTest
+{
+ @Test
+ @DisplayName( "Test detection of default VMDK disk image" )
+ public void testVmdkDiskImage() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default.vmdk" ) );
+ final Version imageVersion = new Version( Short.valueOf( "1" ) );
+ final Version imageHwVersion = new Version( Short.valueOf( "18" ) );
+
+ assertEquals( ImageFormat.VMDK.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+
+ // test special features of the VMDK disk image format
+ final DiskImageVmdk vmdkImage = DiskImageVmdk.class.cast( image );
+ assertEquals( imageHwVersion, vmdkImage.getHwVersion() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of VMDK disk image (type 0: single growable virtual disk)" )
+ public void testVmdkDiskImageType0() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t0.vmdk" ) );
+ final Version imageVersion = new Version( Short.valueOf( "1" ) );
+ final Version imageHwVersion = new Version( Short.valueOf( "18" ) );
+
+ assertEquals( ImageFormat.VMDK.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( false, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+
+ // test special features of the VMDK disk image format
+ final DiskImageVmdk vmdkImage = DiskImageVmdk.class.cast( image );
+ assertEquals( imageHwVersion, vmdkImage.getHwVersion() );
+ }
+
+ @Test
+ @DisplayName( "Test detection of VMDK disk image (type 1: growable virtual disk split into multiple files)" )
+ public void testVmdkDiskImageType1() throws DiskImageException, IOException
+ {
+ Assertions.assertThrows( DiskImageException.class, () -> {
+ DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t1.vmdk" ) );
+ } );
+ }
+
+ @Test
+ @DisplayName( "Test detection of VMDK disk image (type 2: preallocated virtual disk)" )
+ public void testVmdkDiskImageType2() throws DiskImageException, IOException
+ {
+ Assertions.assertThrows( DiskImageException.class, () -> {
+ DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t2.vmdk" ) );
+ } );
+ }
+
+ @Test
+ @DisplayName( "Test detection of VMDK disk image (type 3: preallocated virtual disk split into multiple files)" )
+ public void testVmdkDiskImageType3() throws DiskImageException, IOException
+ {
+ Assertions.assertThrows( DiskImageException.class, () -> {
+ DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t3.vmdk" ) );
+ } );
+ }
+
+ @Test
+ @DisplayName( "Test detection of VMDK disk image (type 4: preallocated ESX-type virtual disk)" )
+ public void testVmdkDiskImageType4() throws DiskImageException, IOException
+ {
+ Assertions.assertThrows( DiskImageException.class, () -> {
+ DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t4.vmdk" ) );
+ } );
+ }
+
+ @Test
+ @DisplayName( "Test detection of VMDK disk image (type 5: compressed disk optimized for streaming)" )
+ public void testVmdkDiskImageType5() throws DiskImageException, IOException
+ {
+ final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t5.vmdk" ) );
+ final Version imageVersion = new Version( Short.valueOf( "3" ) );
+ final Version imageHwVersion = new Version( Short.valueOf( "18" ) );
+
+ assertEquals( ImageFormat.VMDK.toString(), image.getFormat().toString() );
+ assertEquals( true, image.isStandalone() );
+ assertEquals( false, image.isSnapshot() );
+ assertEquals( true, image.isCompressed() );
+ assertEquals( imageVersion, image.getVersion() );
+ assertNull( image.getDescription() );
+
+ // test special features of the VMDK disk image format
+ final DiskImageVmdk vmdkImage = DiskImageVmdk.class.cast( image );
+ assertEquals( imageHwVersion, vmdkImage.getHwVersion() );
+ }
+}
diff --git a/src/test/java/org/openslx/vm/disk/DiskImageQcow2Test.java b/src/test/java/org/openslx/vm/disk/DiskImageQcow2Test.java
deleted file mode 100644
index 7804d7d..0000000
--- a/src/test/java/org/openslx/vm/disk/DiskImageQcow2Test.java
+++ /dev/null
@@ -1,221 +0,0 @@
-package org.openslx.vm.disk;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-
-import java.io.IOException;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
-
-public class DiskImageQcow2Test
-{
- @Test
- @DisplayName( "Test detection of default QCOW2 disk image" )
- public void testQcow2DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of compressed, 16384 byte cluster QCOW2 disk image with extended L2 tables" )
- public void testQcow2DetectionL2Compressed16384DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-16384_cp-on_l2-on.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( true, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of compressed, 16384 byte cluster QCOW2 disk image without extended L2 tables" )
- public void testQcow2DetectionNonL2Compressed16384DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-16384_cp-on_l2-off.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( true, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of non-compressed, 16384 byte cluster QCOW2 disk image with extended L2 tables" )
- public void testQcow2DetectionL2NonCompressed16384DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-16384_cp-off_l2-on.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of non-compressed, 16384 byte cluster QCOW2 disk image without extended L2 tables" )
- public void testQcow2DetectionNonL2NonCompressed16384DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-16384_cp-off_l2-off.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of compressed, 65536 byte cluster QCOW2 disk image with extended L2 tables" )
- public void testQcow2DetectionL2Compressed65536DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-65536_cp-on_l2-on.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( true, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of compressed, 65536 byte cluster QCOW2 disk image without extended L2 tables" )
- public void testQcow2DetectionNonL2Compressed65536DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-65536_cp-on_l2-off.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( true, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of non-compressed, 65536 byte cluster QCOW2 disk image with extended L2 tables" )
- public void testQcow2DetectionL2NonCompressed65536DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-65536_cp-off_l2-on.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of non-compressed, 65536 byte cluster QCOW2 disk image without extended L2 tables" )
- public void testQcow2DetectionNonL2NonCompressed65536DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-65536_cp-off_l2-off.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of compressed, 2097152 byte cluster QCOW2 disk image with extended L2 tables" )
- public void testQcow2DetectionL2Compressed2097152DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-2097152_cp-on_l2-on.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( true, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of compressed, 2097152 byte cluster QCOW2 disk image without extended L2 tables" )
- public void testQcow2DetectionNonL2Compressed2097152DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-2097152_cp-on_l2-off.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( true, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of non-compressed, 2097152 byte cluster QCOW2 disk image with extended L2 tables" )
- public void testQcow2DetectionL2NonCompressed2097152DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-2097152_cp-off_l2-on.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of non-compressed, 2097152 byte cluster QCOW2 disk image without extended L2 tables" )
- public void testQcow2DetectionNonL2NonCompressed2097152DiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage
- .newInstance( DiskImageTestResources.getDiskFile( "image_cs-2097152_cp-off_l2-off.qcow2" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
-
- assertEquals( ImageFormat.QCOW2.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
- }
-}
diff --git a/src/test/java/org/openslx/vm/disk/DiskImageTest.java b/src/test/java/org/openslx/vm/disk/DiskImageTest.java
deleted file mode 100644
index 2572c58..0000000
--- a/src/test/java/org/openslx/vm/disk/DiskImageTest.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.openslx.vm.disk;
-
-import java.io.IOException;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-
-public class DiskImageTest
-{
- @Test
- @DisplayName( "Test of invalid disk image" )
- public void testInvalidDiskImage() throws IOException
- {
- Assertions.assertThrows( DiskImageException.class, () -> {
- DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default.invalid" ) );
- } );
- }
-}
diff --git a/src/test/java/org/openslx/vm/disk/DiskImageTestResources.java b/src/test/java/org/openslx/vm/disk/DiskImageTestResources.java
deleted file mode 100644
index 2ec2e05..0000000
--- a/src/test/java/org/openslx/vm/disk/DiskImageTestResources.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.openslx.vm.disk;
-
-import java.io.File;
-import java.net.URL;
-
-public class DiskImageTestResources
-{
- private static final String DISK_PREFIX_PATH = File.separator + "disk";
-
- public static File getDiskFile( String diskFileName )
- {
- String diskPath = DiskImageTestResources.DISK_PREFIX_PATH + File.separator + diskFileName;
- URL disk = DiskImageTestResources.class.getResource( diskPath );
- return new File( disk.getFile() );
- }
-}
diff --git a/src/test/java/org/openslx/vm/disk/DiskImageVdiTest.java b/src/test/java/org/openslx/vm/disk/DiskImageVdiTest.java
deleted file mode 100644
index 85112cc..0000000
--- a/src/test/java/org/openslx/vm/disk/DiskImageVdiTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.openslx.vm.disk;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-import java.io.IOException;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
-
-public class DiskImageVdiTest
-{
- @Test
- @DisplayName( "Test detection of default VDI disk image" )
- public void testVdiDiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default.vdi" ) );
- final Version imageVersion = new Version( Short.valueOf( "1" ), Short.valueOf( "1" ) );
-
- assertEquals( ImageFormat.VDI.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNotNull( image.getDescription() );
- }
-
- @Test
- @DisplayName( "Test detection of VDI disk image snapshot" )
- public void testVdiDiskImageSnapshot() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default_snapshot.vdi" ) );
- final Version imageVersion = new Version( Short.valueOf( "1" ), Short.valueOf( "1" ) );
-
- assertEquals( ImageFormat.VDI.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( true, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNotNull( image.getDescription() );
- }
-}
diff --git a/src/test/java/org/openslx/vm/disk/DiskImageVmdkTest.java b/src/test/java/org/openslx/vm/disk/DiskImageVmdkTest.java
deleted file mode 100644
index 4c8be82..0000000
--- a/src/test/java/org/openslx/vm/disk/DiskImageVmdkTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.openslx.vm.disk;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-
-import java.io.IOException;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-import org.openslx.virtualization.Version;
-import org.openslx.vm.disk.DiskImage.ImageFormat;
-
-public class DiskImageVmdkTest
-{
- @Test
- @DisplayName( "Test detection of default VMDK disk image" )
- public void testVmdkDiskImage() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image-default.vmdk" ) );
- final Version imageVersion = new Version( Short.valueOf( "1" ) );
- final Version imageHwVersion = new Version( Short.valueOf( "18" ) );
-
- assertEquals( ImageFormat.VMDK.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
-
- // test special features of the VMDK disk image format
- final DiskImageVmdk vmdkImage = DiskImageVmdk.class.cast( image );
- assertEquals( imageHwVersion, vmdkImage.getHwVersion() );
- }
-
- @Test
- @DisplayName( "Test detection of VMDK disk image (type 0: single growable virtual disk)" )
- public void testVmdkDiskImageType0() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t0.vmdk" ) );
- final Version imageVersion = new Version( Short.valueOf( "1" ) );
- final Version imageHwVersion = new Version( Short.valueOf( "18" ) );
-
- assertEquals( ImageFormat.VMDK.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( false, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
-
- // test special features of the VMDK disk image format
- final DiskImageVmdk vmdkImage = DiskImageVmdk.class.cast( image );
- assertEquals( imageHwVersion, vmdkImage.getHwVersion() );
- }
-
- @Test
- @DisplayName( "Test detection of VMDK disk image (type 1: growable virtual disk split into multiple files)" )
- public void testVmdkDiskImageType1() throws DiskImageException, IOException
- {
- Assertions.assertThrows( DiskImageException.class, () -> {
- DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t1.vmdk" ) );
- } );
- }
-
- @Test
- @DisplayName( "Test detection of VMDK disk image (type 2: preallocated virtual disk)" )
- public void testVmdkDiskImageType2() throws DiskImageException, IOException
- {
- Assertions.assertThrows( DiskImageException.class, () -> {
- DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t2.vmdk" ) );
- } );
- }
-
- @Test
- @DisplayName( "Test detection of VMDK disk image (type 3: preallocated virtual disk split into multiple files)" )
- public void testVmdkDiskImageType3() throws DiskImageException, IOException
- {
- Assertions.assertThrows( DiskImageException.class, () -> {
- DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t3.vmdk" ) );
- } );
- }
-
- @Test
- @DisplayName( "Test detection of VMDK disk image (type 4: preallocated ESX-type virtual disk)" )
- public void testVmdkDiskImageType4() throws DiskImageException, IOException
- {
- Assertions.assertThrows( DiskImageException.class, () -> {
- DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t4.vmdk" ) );
- } );
- }
-
- @Test
- @DisplayName( "Test detection of VMDK disk image (type 5: compressed disk optimized for streaming)" )
- public void testVmdkDiskImageType5() throws DiskImageException, IOException
- {
- final DiskImage image = DiskImage.newInstance( DiskImageTestResources.getDiskFile( "image_t5.vmdk" ) );
- final Version imageVersion = new Version( Short.valueOf( "3" ) );
- final Version imageHwVersion = new Version( Short.valueOf( "18" ) );
-
- assertEquals( ImageFormat.VMDK.toString(), image.getFormat().toString() );
- assertEquals( true, image.isStandalone() );
- assertEquals( false, image.isSnapshot() );
- assertEquals( true, image.isCompressed() );
- assertEquals( imageVersion, image.getVersion() );
- assertNull( image.getDescription() );
-
- // test special features of the VMDK disk image format
- final DiskImageVmdk vmdkImage = DiskImageVmdk.class.cast( image );
- assertEquals( imageHwVersion, vmdkImage.getHwVersion() );
- }
-}
--
cgit v1.2.3-55-g7522