[PATCH] transparent support for pushing qcow2 images to rhev-m

Jim Meyering jim at meyering.net
Tue Dec 6 10:23:37 UTC 2011


Ian McLeod wrote:
> Below is a further revision to this patch incorporating some feedback
> from both Pete and Jim.
>
...
>  	if (rc < 0) goto err_xml;
> -	rc = xmlTextWriterWriteAttribute(writer,
> -	    BAD_CAST "ovf:volume-format", BAD_CAST "RAW");
> -	if (rc < 0) goto err_xml;
> -	rc = xmlTextWriterWriteAttribute(writer,
> -	    BAD_CAST "ovf:volume-type", BAD_CAST "Preallocated");
> -	if (rc < 0) goto err_xml;
> +	if (qcow2) {
> +		rc = xmlTextWriterWriteAttribute(writer,
> +		    BAD_CAST "ovf:volume-format", BAD_CAST "COW");
> +		if (rc < 0) goto err_xml;
> +		rc = xmlTextWriterWriteAttribute(writer,
> +		    BAD_CAST "ovf:volume-type", BAD_CAST "Sparse");
> +		if (rc < 0) goto err_xml;
> +	} else {
> +		rc = xmlTextWriterWriteAttribute(writer,
> +		    BAD_CAST "ovf:volume-format", BAD_CAST "RAW");
> +		if (rc < 0) goto err_xml;
> +		rc = xmlTextWriterWriteAttribute(writer,
> +		    BAD_CAST "ovf:volume-type", BAD_CAST "Preallocated");
> +		if (rc < 0) goto err_xml;
> +	}

Thanks.
I've added our usual ChangeLog-style commit log for you,
and made an additional change to avoid the duplication in the above:

+	char const *fmt = qcow2 ? "COW" : "RAW";
+	char const *vol_type = qcow2 ? "Sparse" : "Preallocated";
 	rc = xmlTextWriterWriteAttribute(writer,
-	    BAD_CAST "ovf:volume-format", BAD_CAST "RAW");
+	    BAD_CAST "ovf:volume-format", BAD_CAST fmt);
 	if (rc < 0) goto err_xml;
 	rc = xmlTextWriterWriteAttribute(writer,
-	    BAD_CAST "ovf:volume-type", BAD_CAST "Preallocated");
+	    BAD_CAST "ovf:volume-type", BAD_CAST vol_type);

I also moved each of the declarations in read_qcow_size "down" to
the point of first use.  That makes for more readable code (shorter
and more maintainable).


>From ab30576d6dd55efe5a7c087d6dc8dcd77967e734 Mon Sep 17 00:00:00 2001
From: Jim Meyering <meyering at redhat.com>
Date: Tue, 6 Dec 2011 11:16:16 +0100
Subject: [PATCH] rhev-m: add QCOW image support

* dc-rhev-image.c: Automatically detect and use a QCOW image.
Include <endian.h> and <inttypes.h>.
(QCOW_MAGIC, QCOW_VERSION): Define.
(struct qcow_header): Define.
(read_qcow_size): New function.
(spitovf): Add/use boolean qcow2 parameter.
(copyimage): Use read_qcow_size to determine image size and type.
* NEWS (New features): Mention it.
---
 NEWS            |    6 ++++
 dc-rhev-image.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 76 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index 83a0a95..23682d3 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,12 @@ iwhd NEWS                                                   -*- outline -*-

 * Noteworthy changes in release ?.? (????-??-??) [?]

+** New features
+
+  Add automatic qcow2 format detection to the dc-rhev-image helper
+  utility.  This change allows you to use both raw and qcow2 images to
+  create templates in a RHEV-M environment.
+

 * Noteworthy changes in release 1.1 (2011-12-01) [stable]

diff --git a/dc-rhev-image.c b/dc-rhev-image.c
index 7e9781e..bf26212 100644
--- a/dc-rhev-image.c
+++ b/dc-rhev-image.c
@@ -34,7 +34,9 @@
 #include <stdbool.h>
 #include <stdint.h>
 #include <unistd.h>
+#include <endian.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <time.h>

 #include <curl/curl.h>
@@ -63,6 +65,9 @@
 #define NFSUID 36
 #define NFSGID 36

+#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+#define QCOW_VERSION 2
+
 #ifndef MIN
 # define MIN(a,b) (((a) < (b)) ? (a) : (b))
 #endif
@@ -137,6 +142,22 @@ struct api_conn {
 	char *path;	/* "/rhevm-api" or "/rhevm-api-powershell" */
 };

+struct qcow_header {
+	uint32_t magic;
+	uint32_t version;
+	uint64_t backing_file_offset;
+	uint32_t backing_file_size;
+	uint32_t cluster_bits;
+	uint64_t size; /* in bytes */
+	uint32_t crypt_method;
+	uint32_t l1_size;
+	uint64_t l1_table_offset;
+	uint64_t refcount_table_offset;
+	uint32_t refcount_table_clusters;
+	uint32_t nb_snapshots;
+	uint64_t snapshots_offset;
+};
+
 static void Usage(void)
 {
 	fprintf(stderr, "ERROR Usage: " TAG " [" TAG ".conf]\n");
@@ -156,6 +177,36 @@ static char **env_p;
 		uri->token##_len = (len);	\
 	} while (0)

+/*
+ * return size of virtual disk inside qcow2 file
+ * return 0 if file is not qcow2
+ */
+static uint64_t
+read_qcow_size(const char *image_file)
+{
+	FILE *fp = fopen(image_file, "r");
+	if (!fp) {
+		fprintf(stderr,
+		    "ERROR unable to open %s for qcow2 analysis: %s\n",
+		    image_file, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	struct qcow_header header;
+	size_t n_read = fread(&header, sizeof(header), 1, fp);
+	fclose(fp);
+
+	if (n_read != 1) {
+		return 0;
+	}
+
+	if (be32toh(header.magic) == QCOW_MAGIC &&
+	    be32toh(header.version) == QCOW_VERSION)
+		return be64toh(header.size);
+	else
+		return 0;
+}
+
 static struct http_uri *huri_parse(struct http_uri *uri, const char *uri_text)
 {
 	const char *p, *temp;
@@ -1377,7 +1428,8 @@ static void gen_uuids(struct id_pack *idp)
 }

 static void spitovf(const struct config *cfg, const struct stor_dom *sd,
-    const char *poolid, const struct id_pack *idp, off_t vol_size)
+    const char *poolid, const struct id_pack *idp, off_t vol_size,
+    bool qcow2)
 {
 	time_t now;
 	struct tm now_tm;
@@ -1523,11 +1575,13 @@ static void spitovf(const struct config *cfg, const struct stor_dom *sd,
 	    BAD_CAST "ovf:format",
 	    BAD_CAST "http://www.vmware.com/technical-resources/interfaces/vmdk_access.html");
 	if (rc < 0) goto err_xml;
+	char const *fmt = qcow2 ? "COW" : "RAW";
+	char const *vol_type = qcow2 ? "Sparse" : "Preallocated";
 	rc = xmlTextWriterWriteAttribute(writer,
-	    BAD_CAST "ovf:volume-format", BAD_CAST "RAW");
+	    BAD_CAST "ovf:volume-format", BAD_CAST fmt);
 	if (rc < 0) goto err_xml;
 	rc = xmlTextWriterWriteAttribute(writer,
-	    BAD_CAST "ovf:volume-type", BAD_CAST "Preallocated");
+	    BAD_CAST "ovf:volume-type", BAD_CAST vol_type);
 	if (rc < 0) goto err_xml;
 	rc = xmlTextWriterWriteAttribute(writer,
 	    BAD_CAST "ovf:disk-interface", BAD_CAST "VirtIO");
@@ -1896,12 +1950,17 @@ static void copyimage(const struct config *cfg, const struct id_pack *idp,
 	/* No error processing here, it exits on error. */
 	copy_file_preserving(imgsrc, imgdst);

-	if (stat(imgdst, &statb) < 0) {
-		fprintf(stderr, "ERROR failed to stat %s: %s\n",
-		    imgdst, strerror(errno));
-		exit(EXIT_FAILURE);
+	uint64_t qcow_size = read_qcow_size(imgsrc);
+	if (qcow_size) {
+		vol_size = qcow_size;
+	} else {
+		if (stat(imgdst, &statb) < 0) {
+			fprintf(stderr, "ERROR failed to stat %s: %s\n",
+			    imgdst, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+		vol_size = statb.st_size;
 	}
-	vol_size = statb.st_size;

 	rc = asprintf(&imgmeta, "%s.meta", imgdst);
 	if (rc < 0)
@@ -1918,7 +1977,8 @@ static void copyimage(const struct config *cfg, const struct id_pack *idp,
 	fprintf(fp, "VOLTYPE=LEAF\n");
 	fprintf(fp, "CTIME=%llu\n", (long long)now);
 	/* saved template has FORMAT=COW */
-	fprintf(fp, "FORMAT=RAW\n");
+	char const *fmt = qcow_size ? "COW" : "RAW";
+	fprintf(fp, "FORMAT=%s\n", fmt);
 	fprintf(fp, "IMAGE=%s\n", idp->image);
 	fprintf(fp, "DISKTYPE=1\n");
 	fprintf(fp, "PUUID=%s\n", NULID);
@@ -1935,7 +1995,7 @@ static void copyimage(const struct config *cfg, const struct id_pack *idp,
 		exit(EXIT_FAILURE);
 	}

-	spitovf(cfg, sd, poolid, idp, vol_size);
+	spitovf(cfg, sd, poolid, idp, vol_size, qcow_size != 0);

 	free(imgmeta);
 	free(imgdst);
--
1.7.8


More information about the iwhd-devel mailing list