Linux Archive

Linux Archive (http://www.linux-archive.org/)
-   Fedora/Linux Management Tools (http://www.linux-archive.org/fedora-linux-management-tools/)
-   -   virt-inst Package an image for VMware distribution (http://www.linux-archive.org/fedora-linux-management-tools/98270-virt-inst-package-image-vmware-distribution.html)

Joey Boggs 05-30-2008 07:43 PM

virt-inst Package an image for VMware distribution
 
These patches were originally written by David Lutterkort and I've
tweaked the conversion process a little bit to work out some staging issues


virt-pack will tar all the files for the image into a tarball. The name
and toplevel directory are derived from the name and version of the
image descriptor. Scratch disks are omitted, since they can be rebuilt
when the image is deployed.


A VMware format configuration file is produced with vmdk descriptors
pointing at the disk images rather than converting the raw images. For
scratch disks, sparse VMDK files are generated, since VMWare has no
notion of scratch disks. The generated VMX
file is very conservative, so that it's widely usable, but there are
many things that could be improved in it if we had more information
about the image (one example: are vmware-tools installed ?)


The image.xml file must contain two new elements: version and release

<name version="1" release="1">example-image</name>

Example running:

[jboggs@localhost RHX_Sugar]$ sudo ./virt-pack i1.xml
Checking /home/jboggs/RHX_Sugar/rhx_sugar.img
Writing /home/jboggs/RHX_Sugar/../example-image-1.tgz
example-image-1/
example-image-1/i1.xml
example-image-1/rhx_sugar.vmdk
example-image-1/rhx_sugar.img
example-image-1/example-image.vmx


When completed you will have an virtual instance capable of being run
under VMWare or virt-image. Prior to conversion the image must contain
VMWare disk controller drivers enabling it to boot, otherwise will
result in a kernel panic: no init found.


version.patch
abspath.patch
filename.patch
drives.patch
package.patch
_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Cole Robinson 06-06-2008 05:39 PM

virt-inst Package an image for VMware distribution
 
Joey Boggs wrote:
> These patches were originally written by David Lutterkort and I've
> tweaked the conversion process a little bit to work out some staging issues
>
> virt-pack will tar all the files for the image into a tarball. The name
> and toplevel directory are derived from the name and version of the
> image descriptor. Scratch disks are omitted, since they can be rebuilt
> when the image is deployed.
>

Hi Joey,

I committed all the patches except the actual virt-pack command, since they
were separate and straight forward.

...

> +import os, sys, string
> +from optparse import OptionParser, OptionValueError
> +import subprocess
> +import logging
> +import libxml2
> +import urlgrabber.progress as progress
> +
> +import virtinst
> +import virtinst.ImageParser
> +import virtinst.CapabilitiesParser
> +import virtinst.cli as cli
> +import virtinst.util as util
> +import virtinst.UnWare
> +
> +import tempfile
> +
> +import gettext
> +import locale
> +
> +locale.setlocale(locale.LC_ALL, ')
> +gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
> +gettext.install(virtinst.gettext_app, virtinst.gettext_dir)
> +
> +class PackageException(Exception):
> + def __init__(self, msg):
> + Exception.__init__(self, msg)
> +
> +class Package:
> +
> + def __init__(self, image):
> + self.image = image
> + if image.name is None or image.version is None:
> + raise PackageException(
> + _("The image name and version must be present"))
> + self.vername = "%s-%s" % (image.name, image.version)
> + self.tmpdir = tempfile.mkdtemp(dir="/var/tmp", prefix="virt-pack")
> + self.stagedir = os.path.join(self.tmpdir, self.vername)
> + self.files = []
> +
> + def add_image_files(self):
> + cwd = os.getcwd()
> + img = self.image
> + self.files.append(os.path.basename(img.filename))
> + try:
> + os.chdir(img.base)
> + for d in img.storage.keys():
> + disk = img.storage[d]
> + if disk.use == disk.USE_SCRATCH:
> + if disk.size is None:
> + raise PackageException(_("Scratch disk %s does not have a size attribute") % disk.id)
> + else:
> + if not os.path.exists(disk.file):
> + raise PackageException(_("Disk file %s could not be found") % disk.id)
> + self.files.append(disk.file)
> + finally:
> + os.chdir(cwd)

Why change directories here? Seems like it could all be avoided if the
above check is changed to: os.path.exists(os.path.join(img.base, disk.file))

> +
> + def make_vmx_files(self):
> + img = virtinst.UnWare.Image(self.image)
> + files = img.make(self.image.base)
> + self.files.extend(files)
> +
> + def pack(self, outdir):
> + outfile = os.path.join(outdir, self.vername + ".tgz")
> + for f in set(self.files):
> + dir = os.path.join(self.stagedir, os.path.dirname(f))
> + if not os.path.exists(dir):
> + os.makedirs(dir)
> + os.symlink(os.path.join(self.image.base, f),
> + os.path.join(self.stagedir, f))
> + print "Writing %s" % outfile
> + cmd = "tar chzv -C %s -f %s %s" % (self.tmpdir,
> + outfile,
> + os.path.basename(self.vername))
> + util.system(cmd)
> + return outfile
> +
> +### Option parsing
> +def parse_args():
> + parser = OptionParser()
> + parser.set_usage("%prog [options] image.xml")
> +
> + parser.add_option("-o", "--output", type="string", dest="output",
> + action="callback", callback=cli.check_before_store,
> + help=_("Directory in which packaged file will be put"))
> + parser.add_option("-d", "--debug", action="store_true", dest="debug",
> + help=_("Print debugging information"))
> +
> + (options,args) = parser.parse_args()
> + if len(args) < 1:
> + parser.error(_("You need to provide an image XML descriptor"))
> + options.image = args[0]
> +
> + return options
> +
> +def main():
> + options = parse_args()
> +
> +
> + cli.setupLogging("virt-pack", options.debug)
> +
> + image = virtinst.ImageParser.parse_file(os.path.abspath(op tions.image))
> +
> + if image.name is None or image.version is None:
> + print >> sys.stderr, _("The image descriptor must contain name and version")
> + valid = False
> +
> + if options.output is None:
> + options.output = os.path.join(image.base, "..")
> +
> + pkg = Package(image)
> + try:
> + pkg.add_image_files()
> + except PackageException, e:
> + print >> sys.stderr, "Validation failed: %s", e
> + return 1
> +
> + try:
> + pkg.make_vmx_files()
> + pkg.pack(options.output)
> + except PackageException, e:
> + print >> sys.stderr, "Packaging failed: %s" % e
> + return 1
> +

Might want to wrap the above two messages in _("...") to mark them as
translatable.

> +if __name__ == "__main__":
> + main()
> +
> diff -r 2f7a50a57c1c virtinst/UnWare.py
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/virtinst/UnWare.py Wed Dec 12 17:53:53 2007 -0800
> @@ -0,0 +1,291 @@

...

> +
> +class Disk:
> + """A disk for a VMWare(tm) virtual machine"""
> +
> + MONOLITHIC_FLAT = "monolithicFlat"
> + TWO_GB_MAX_EXTENT_SPARSE = "twoGbMaxExtentSparse"
> + # This seems only to be usable if the vmdk header is embedded in the
> + # data file, not when the descriptor is in a separate text file. Use
> + # TWO_GB_MAX_EXTENT_SPARSE instead.
> + # VMWare's(tm) documentation of VMDK seriously sucks. A lot.
> + MONOLITHIC_SPARSE = "monolithicSparse"
> +
> + IDE_HEADS = 16
> + IDE_SECTORS = 63
> +
> + def __init__(self, descriptor, extent, size, dev, format):
> + """Create a new disk. DESCRIPTOR is the name of the VMDK descriptor
> + file. EXTENT is the name of the file holding the actual data. SIZE
> + is the filesize in bytes. DEV identifies the device, for IDE (the
> + only one supported right now) it should be $bus:$master. FORMAT is
> + the format of the underlying extent, one of the formats defined in
> + virtinst.ImageParser.Disk"""
> + self.cid = 0xffffffff
> + self.createType = Disk.MONOLITHIC_FLAT
> + self.descriptor = descriptor
> + self.extent = extent
> + self.size = size
> + self.dev = dev
> + self.format = format
> +
> + def make_extent(self, base):
> + """Write the descriptor file, and create the extent as a monolithic
> + sparse extent if it does not exist yet"""
> + f = os.path.join(base, self.extent)
> + print "Checking %s" % f

We shouldn't just straight 'print' from a library, even if only one app is using it.
I suggest using logging.debug.

> + if not os.path.exists(f):
> + util.system("qemu-img create -f vmdk %s %d" % (f, self.size/1024))
> + self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
> + else:
> + qemu = os.popen("qemu-img info %s" % f, "r")
> + for l in qemu:
> + (tag, val) = l.split(":")
> + if tag == "file format" and val.strip() == "vmdk":
> + self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
> + qemu.close()
> + return self.extent
> +
> + def to_vmdk(self):
> + """Return the VMDK descriptor for this disk"""
> +
> + vmdk = """# Disk DescriptorFile
> +# Generated from libvirt
> +version=1
> +"""

Generated from libvirt? If putting anything, I guess the best thing would be 'virtinst'

> + vmdk += "CID=%08x
parentCID=ffffffff
" % self.cid
> + vmdk += "createType="%s"

" % self.createType
> + vmdk += "# Extent description
"
> + blocks = self.size/512
> + if self.createType == Disk.MONOLITHIC_FLAT:
> + vmdk += "RW %d FLAT "%s" 0
" % (blocks, os.path.basename(self.extent))
> + else: # Disk.MONOLITHIC_SPARSE
> + vmdk += "RW %d SPARSE "%s"
" % (blocks, os.path.basename(self.extent))
> +
> + vmdk += """
> +# Disk Data Base
> +ddb.virtualHWVersion = "4"
> +ddb.adapterType = "ide"
> +ddb.geometry.sectors = "%d"
> +ddb.geometry.heads = "%d"
> +ddb.geometry.cylinders = "%d"
> +""" % (Disk.IDE_SECTORS, Disk.IDE_HEADS, blocks/(Disk.IDE_SECTORS*Disk.IDE_HEADS))
> + return vmdk

This piece above is kind of a mess. My recommendation is to wrap the entire thing
in triple quotes, and just do all the variable calculation prior to the assignment.
You won't need to escape anything or manually insert newlines. Or use the same
format as used later in the file, just define a _VMDK_TEMPLATE.

The rest looks fine to me.

- Cole

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Joey Boggs 06-07-2008 12:11 AM

virt-inst Package an image for VMware distribution
 
Cole,

I'll work on those changes this weekend/next week, thanks for the comments.

Joey

Cole Robinson wrote:

Joey Boggs wrote:

These patches were originally written by David Lutterkort and I've
tweaked the conversion process a little bit to work out some staging issues


virt-pack will tar all the files for the image into a tarball. The name
and toplevel directory are derived from the name and version of the
image descriptor. Scratch disks are omitted, since they can be rebuilt
when the image is deployed.




Hi Joey,

I committed all the patches except the actual virt-pack command, since they
were separate and straight forward.

...



+import os, sys, string
+from optparse import OptionParser, OptionValueError
+import subprocess
+import logging
+import libxml2
+import urlgrabber.progress as progress
+
+import virtinst
+import virtinst.ImageParser
+import virtinst.CapabilitiesParser
+import virtinst.cli as cli
+import virtinst.util as util
+import virtinst.UnWare
+
+import tempfile
+
+import gettext
+import locale
+
+locale.setlocale(locale.LC_ALL, ')
+gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
+gettext.install(virtinst.gettext_app, virtinst.gettext_dir)
+
+class PackageException(Exception):
+ def __init__(self, msg):
+ Exception.__init__(self, msg)
+
+class Package:
+
+ def __init__(self, image):

+ self.image = image
+ if image.name is None or image.version is None:
+ raise PackageException(
+ _("The image name and version must be present"))
+ self.vername = "%s-%s" % (image.name, image.version)
+ self.tmpdir = tempfile.mkdtemp(dir="/var/tmp", prefix="virt-pack")
+ self.stagedir = os.path.join(self.tmpdir, self.vername)
+ self.files = []
+
+ def add_image_files(self):
+ cwd = os.getcwd()
+ img = self.image
+ self.files.append(os.path.basename(img.filename))
+ try:
+ os.chdir(img.base)
+ for d in img.storage.keys():
+ disk = img.storage[d]
+ if disk.use == disk.USE_SCRATCH:
+ if disk.size is None:
+ raise PackageException(_("Scratch disk %s does not have a size attribute") % disk.id)
+ else:
+ if not os.path.exists(disk.file):
+ raise PackageException(_("Disk file %s could not be found") % disk.id)
+ self.files.append(disk.file)
+ finally:
+ os.chdir(cwd)



Why change directories here? Seems like it could all be avoided if the
above check is changed to: os.path.exists(os.path.join(img.base, disk.file))



+
+ def make_vmx_files(self):
+ img = virtinst.UnWare.Image(self.image)
+ files = img.make(self.image.base)
+ self.files.extend(files)
+
+ def pack(self, outdir):
+ outfile = os.path.join(outdir, self.vername + ".tgz")
+ for f in set(self.files):
+ dir = os.path.join(self.stagedir, os.path.dirname(f))
+ if not os.path.exists(dir):
+ os.makedirs(dir)
+ os.symlink(os.path.join(self.image.base, f),
+ os.path.join(self.stagedir, f))
+ print "Writing %s" % outfile
+ cmd = "tar chzv -C %s -f %s %s" % (self.tmpdir,
+ outfile,
+ os.path.basename(self.vername))

+ util.system(cmd)
+ return outfile
+
+### Option parsing
+def parse_args():
+ parser = OptionParser()
+ parser.set_usage("%prog [options] image.xml")
+
+ parser.add_option("-o", "--output", type="string", dest="output",
+ action="callback", callback=cli.check_before_store,
+ help=_("Directory in which packaged file will be put"))
+ parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help=_("Print debugging information"))
+
+ (options,args) = parser.parse_args()
+ if len(args) < 1:
+ parser.error(_("You need to provide an image XML descriptor"))
+ options.image = args[0]
+
+ return options

+
+def main():
+ options = parse_args()
+
+
+ cli.setupLogging("virt-pack", options.debug)
+
+ image = virtinst.ImageParser.parse_file(os.path.abspath(op tions.image))
+
+ if image.name is None or image.version is None:
+ print >> sys.stderr, _("The image descriptor must contain name and version")
+ valid = False
+
+ if options.output is None:
+ options.output = os.path.join(image.base, "..")
+
+ pkg = Package(image)
+ try:
+ pkg.add_image_files()
+ except PackageException, e:
+ print >> sys.stderr, "Validation failed: %s", e
+ return 1
+
+ try:
+ pkg.make_vmx_files()
+ pkg.pack(options.output)
+ except PackageException, e:
+ print >> sys.stderr, "Packaging failed: %s" % e
+ return 1
+



Might want to wrap the above two messages in _("...") to mark them as
translatable.



+if __name__ == "__main__":
+ main()
+
diff -r 2f7a50a57c1c virtinst/UnWare.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtinst/UnWare.py Wed Dec 12 17:53:53 2007 -0800
@@ -0,0 +1,291 @@



...



+
+class Disk:
+ """A disk for a VMWare(tm) virtual machine"""
+
+ MONOLITHIC_FLAT = "monolithicFlat"
+ TWO_GB_MAX_EXTENT_SPARSE = "twoGbMaxExtentSparse"
+ # This seems only to be usable if the vmdk header is embedded in the
+ # data file, not when the descriptor is in a separate text file. Use
+ # TWO_GB_MAX_EXTENT_SPARSE instead.
+ # VMWare's(tm) documentation of VMDK seriously sucks. A lot.
+ MONOLITHIC_SPARSE = "monolithicSparse"
+
+ IDE_HEADS = 16
+ IDE_SECTORS = 63
+
+ def __init__(self, descriptor, extent, size, dev, format):

+ """Create a new disk. DESCRIPTOR is the name of the VMDK descriptor
+ file. EXTENT is the name of the file holding the actual data. SIZE
+ is the filesize in bytes. DEV identifies the device, for IDE (the
+ only one supported right now) it should be $bus:$master. FORMAT is
+ the format of the underlying extent, one of the formats defined in
+ virtinst.ImageParser.Disk"""
+ self.cid = 0xffffffff
+ self.createType = Disk.MONOLITHIC_FLAT
+ self.descriptor = descriptor
+ self.extent = extent
+ self.size = size
+ self.dev = dev
+ self.format = format
+
+ def make_extent(self, base):
+ """Write the descriptor file, and create the extent as a monolithic
+ sparse extent if it does not exist yet"""

+ f = os.path.join(base, self.extent)
+ print "Checking %s" % f



We shouldn't just straight 'print' from a library, even if only one app is using it.
I suggest using logging.debug.



+ if not os.path.exists(f):
+ util.system("qemu-img create -f vmdk %s %d" % (f, self.size/1024))
+ self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
+ else:
+ qemu = os.popen("qemu-img info %s" % f, "r")
+ for l in qemu:
+ (tag, val) = l.split(":")
+ if tag == "file format" and val.strip() == "vmdk":
+ self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
+ qemu.close()
+ return self.extent
+
+ def to_vmdk(self):

+ """Return the VMDK descriptor for this disk"""
+
+ vmdk = """# Disk DescriptorFile
+# Generated from libvirt
+version=1
+"""



Generated from libvirt? If putting anything, I guess the best thing would be 'virtinst'



+ vmdk += "CID=%08x
parentCID=ffffffff
" % self.cid
+ vmdk += "createType="%s"

" % self.createType
+ vmdk += "# Extent description
"
+ blocks = self.size/512
+ if self.createType == Disk.MONOLITHIC_FLAT:
+ vmdk += "RW %d FLAT "%s" 0
" % (blocks, os.path.basename(self.extent))
+ else: # Disk.MONOLITHIC_SPARSE
+ vmdk += "RW %d SPARSE "%s"
" % (blocks, os.path.basename(self.extent))
+
+ vmdk += """
+# Disk Data Base
+ddb.virtualHWVersion = "4"
+ddb.adapterType = "ide"
+ddb.geometry.sectors = "%d"
+ddb.geometry.heads = "%d"
+ddb.geometry.cylinders = "%d"
+""" % (Disk.IDE_SECTORS, Disk.IDE_HEADS, blocks/(Disk.IDE_SECTORS*Disk.IDE_HEADS))
+ return vmdk



This piece above is kind of a mess. My recommendation is to wrap the entire thing
in triple quotes, and just do all the variable calculation prior to the assignment.
You won't need to escape anything or manually insert newlines. Or use the same
format as used later in the file, just define a _VMDK_TEMPLATE.

The rest looks fine to me.

- Cole



_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Joey Boggs 06-09-2008 05:08 PM

virt-inst Package an image for VMware distribution
 
Updated virt-pack and Unware.py per suggestions




Cole Robinson wrote:

Joey Boggs wrote:

These patches were originally written by David Lutterkort and I've
tweaked the conversion process a little bit to work out some staging issues


virt-pack will tar all the files for the image into a tarball. The name
and toplevel directory are derived from the name and version of the
image descriptor. Scratch disks are omitted, since they can be rebuilt
when the image is deployed.




Hi Joey,

I committed all the patches except the actual virt-pack command, since they
were separate and straight forward.

...



+import os, sys, string
+from optparse import OptionParser, OptionValueError
+import subprocess
+import logging
+import libxml2
+import urlgrabber.progress as progress
+
+import virtinst
+import virtinst.ImageParser
+import virtinst.CapabilitiesParser
+import virtinst.cli as cli
+import virtinst.util as util
+import virtinst.UnWare
+
+import tempfile
+
+import gettext
+import locale
+
+locale.setlocale(locale.LC_ALL, ')
+gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
+gettext.install(virtinst.gettext_app, virtinst.gettext_dir)
+
+class PackageException(Exception):
+ def __init__(self, msg):
+ Exception.__init__(self, msg)
+
+class Package:
+
+ def __init__(self, image):

+ self.image = image
+ if image.name is None or image.version is None:
+ raise PackageException(
+ _("The image name and version must be present"))
+ self.vername = "%s-%s" % (image.name, image.version)
+ self.tmpdir = tempfile.mkdtemp(dir="/var/tmp", prefix="virt-pack")
+ self.stagedir = os.path.join(self.tmpdir, self.vername)
+ self.files = []
+
+ def add_image_files(self):
+ cwd = os.getcwd()
+ img = self.image
+ self.files.append(os.path.basename(img.filename))
+ try:
+ os.chdir(img.base)
+ for d in img.storage.keys():
+ disk = img.storage[d]
+ if disk.use == disk.USE_SCRATCH:
+ if disk.size is None:
+ raise PackageException(_("Scratch disk %s does not have a size attribute") % disk.id)
+ else:
+ if not os.path.exists(disk.file):
+ raise PackageException(_("Disk file %s could not be found") % disk.id)
+ self.files.append(disk.file)
+ finally:
+ os.chdir(cwd)



Why change directories here? Seems like it could all be avoided if the
above check is changed to: os.path.exists(os.path.join(img.base, disk.file))



+
+ def make_vmx_files(self):
+ img = virtinst.UnWare.Image(self.image)
+ files = img.make(self.image.base)
+ self.files.extend(files)
+
+ def pack(self, outdir):
+ outfile = os.path.join(outdir, self.vername + ".tgz")
+ for f in set(self.files):
+ dir = os.path.join(self.stagedir, os.path.dirname(f))
+ if not os.path.exists(dir):
+ os.makedirs(dir)
+ os.symlink(os.path.join(self.image.base, f),
+ os.path.join(self.stagedir, f))
+ print "Writing %s" % outfile
+ cmd = "tar chzv -C %s -f %s %s" % (self.tmpdir,
+ outfile,
+ os.path.basename(self.vername))

+ util.system(cmd)
+ return outfile
+
+### Option parsing
+def parse_args():
+ parser = OptionParser()
+ parser.set_usage("%prog [options] image.xml")
+
+ parser.add_option("-o", "--output", type="string", dest="output",
+ action="callback", callback=cli.check_before_store,
+ help=_("Directory in which packaged file will be put"))
+ parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help=_("Print debugging information"))
+
+ (options,args) = parser.parse_args()
+ if len(args) < 1:
+ parser.error(_("You need to provide an image XML descriptor"))
+ options.image = args[0]
+
+ return options

+
+def main():
+ options = parse_args()
+
+
+ cli.setupLogging("virt-pack", options.debug)
+
+ image = virtinst.ImageParser.parse_file(os.path.abspath(op tions.image))
+
+ if image.name is None or image.version is None:
+ print >> sys.stderr, _("The image descriptor must contain name and version")
+ valid = False
+
+ if options.output is None:
+ options.output = os.path.join(image.base, "..")
+
+ pkg = Package(image)
+ try:
+ pkg.add_image_files()
+ except PackageException, e:
+ print >> sys.stderr, "Validation failed: %s", e
+ return 1
+
+ try:
+ pkg.make_vmx_files()
+ pkg.pack(options.output)
+ except PackageException, e:
+ print >> sys.stderr, "Packaging failed: %s" % e
+ return 1
+



Might want to wrap the above two messages in _("...") to mark them as
translatable.



+if __name__ == "__main__":
+ main()
+
diff -r 2f7a50a57c1c virtinst/UnWare.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtinst/UnWare.py Wed Dec 12 17:53:53 2007 -0800
@@ -0,0 +1,291 @@



...



+
+class Disk:
+ """A disk for a VMWare(tm) virtual machine"""
+
+ MONOLITHIC_FLAT = "monolithicFlat"
+ TWO_GB_MAX_EXTENT_SPARSE = "twoGbMaxExtentSparse"
+ # This seems only to be usable if the vmdk header is embedded in the
+ # data file, not when the descriptor is in a separate text file. Use
+ # TWO_GB_MAX_EXTENT_SPARSE instead.
+ # VMWare's(tm) documentation of VMDK seriously sucks. A lot.
+ MONOLITHIC_SPARSE = "monolithicSparse"
+
+ IDE_HEADS = 16
+ IDE_SECTORS = 63
+
+ def __init__(self, descriptor, extent, size, dev, format):

+ """Create a new disk. DESCRIPTOR is the name of the VMDK descriptor
+ file. EXTENT is the name of the file holding the actual data. SIZE
+ is the filesize in bytes. DEV identifies the device, for IDE (the
+ only one supported right now) it should be $bus:$master. FORMAT is
+ the format of the underlying extent, one of the formats defined in
+ virtinst.ImageParser.Disk"""
+ self.cid = 0xffffffff
+ self.createType = Disk.MONOLITHIC_FLAT
+ self.descriptor = descriptor
+ self.extent = extent
+ self.size = size
+ self.dev = dev
+ self.format = format
+
+ def make_extent(self, base):
+ """Write the descriptor file, and create the extent as a monolithic
+ sparse extent if it does not exist yet"""

+ f = os.path.join(base, self.extent)
+ print "Checking %s" % f



We shouldn't just straight 'print' from a library, even if only one app is using it.
I suggest using logging.debug.



+ if not os.path.exists(f):
+ util.system("qemu-img create -f vmdk %s %d" % (f, self.size/1024))
+ self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
+ else:
+ qemu = os.popen("qemu-img info %s" % f, "r")
+ for l in qemu:
+ (tag, val) = l.split(":")
+ if tag == "file format" and val.strip() == "vmdk":
+ self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
+ qemu.close()
+ return self.extent
+
+ def to_vmdk(self):

+ """Return the VMDK descriptor for this disk"""
+
+ vmdk = """# Disk DescriptorFile
+# Generated from libvirt
+version=1
+"""



Generated from libvirt? If putting anything, I guess the best thing would be 'virtinst'



+ vmdk += "CID=%08x
parentCID=ffffffff
" % self.cid
+ vmdk += "createType="%s"

" % self.createType
+ vmdk += "# Extent description
"
+ blocks = self.size/512
+ if self.createType == Disk.MONOLITHIC_FLAT:
+ vmdk += "RW %d FLAT "%s" 0
" % (blocks, os.path.basename(self.extent))
+ else: # Disk.MONOLITHIC_SPARSE
+ vmdk += "RW %d SPARSE "%s"
" % (blocks, os.path.basename(self.extent))
+
+ vmdk += """
+# Disk Data Base
+ddb.virtualHWVersion = "4"
+ddb.adapterType = "ide"
+ddb.geometry.sectors = "%d"
+ddb.geometry.heads = "%d"
+ddb.geometry.cylinders = "%d"
+""" % (Disk.IDE_SECTORS, Disk.IDE_HEADS, blocks/(Disk.IDE_SECTORS*Disk.IDE_HEADS))
+ return vmdk



This piece above is kind of a mess. My recommendation is to wrap the entire thing
in triple quotes, and just do all the variable calculation prior to the assignment.
You won't need to escape anything or manually insert newlines. Or use the same
format as used later in the file, just define a _VMDK_TEMPLATE.

The rest looks fine to me.

- Cole



_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Cole Robinson 06-10-2008 06:02 PM

virt-inst Package an image for VMware distribution
 
Joey Boggs wrote:
> Updated virt-pack and Unware.py per suggestions
>

Comments inline:


> diff -Naur virtinst--devel.orig/virtinst/UnWare.py virtinst--devel/virtinst/UnWare.py
> --- virtinst--devel.orig/virtinst/UnWare.py 1969-12-31 19:00:00.000000000 -0500
> +++ virtinst--devel/virtinst/UnWare.py 2008-06-09 13:03:41.000000000 -0400
> @@ -0,0 +1,309 @@
> +#
> +# Processing of VMWare(tm) .vmx files
> +#
> +# Copyright 2007 Red Hat, Inc.
> +# David Lutterkort <dlutter@redhat.com>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> +# MA 02110-1301 USA.
> +
> +import time
> +import sys
> +import os
> +
> +import ImageParser
> +import util
> +
> +class Disk:
> + """A disk for a VMWare(tm) virtual machine"""
> +
> + MONOLITHIC_FLAT = "monolithicFlat"
> + TWO_GB_MAX_EXTENT_SPARSE = "twoGbMaxExtentSparse"
> + # This seems only to be usable if the vmdk header is embedded in the
> + # data file, not when the descriptor is in a separate text file. Use
> + # TWO_GB_MAX_EXTENT_SPARSE instead.
> + # VMWare's(tm) documentation of VMDK seriously sucks. A lot.
> + MONOLITHIC_SPARSE = "monolithicSparse"
> +
> + IDE_HEADS = 16
> + IDE_SECTORS = 63
> +
> + def __init__(self, descriptor, extent, size, dev, format):
> + """Create a new disk. DESCRIPTOR is the name of the VMDK descriptor
> + file. EXTENT is the name of the file holding the actual data. SIZE
> + is the filesize in bytes. DEV identifies the device, for IDE (the
> + only one supported right now) it should be $bus:$master. FORMAT is
> + the format of the underlying extent, one of the formats defined in
> + virtinst.ImageParser.Disk"""
> + self.cid = 0xffffffff
> + self.createType = Disk.MONOLITHIC_FLAT
> + self.descriptor = descriptor
> + self.extent = extent
> + self.size = size
> + self.dev = dev
> + self.format = format
> +
> + def make_extent(self, base):
> + """Write the descriptor file, and create the extent as a monolithic
> + sparse extent if it does not exist yet"""
> + f = os.path.join(base, self.extent)
> + print "Checking %s" % f


This print is still in place, any reason for that? My previous comment was:

> We shouldn't just straight 'print' from a library, even if only one app is using it.
> I suggest using logging.debug.


> + if not os.path.exists(f):
> + util.system("qemu-img create -f vmdk %s %d" % (f, self.size/1024))
> + self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
> + else:
> + qemu = os.popen("qemu-img info %s" % f, "r")
> + for l in qemu:
> + (tag, val) = l.split(":")
> + if tag == "file format" and val.strip() == "vmdk":
> + self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
> + qemu.close()
> + return self.extent
> +
> + def _VMDK_TEMPLATE(self):
> +
> + blocks = self.size/512
> + if self.createType == Disk.MONOLITHIC_FLAT:
> + vmdk_extent_info= "RW %d FLAT "%s" 0
" % (blocks, os.path.basename(self.extent))
> + else: # Disk.MONOLITHIC_SPARSE
> + vmdk_extent_info= "RW %d SPARSE "%s"
" % (blocks, os.path.basename(self.extent))
> +
> + dict = {
> + "SELF_CID" : self.cid,
> + "CREATE_TYPE" : self.createType,
> + "IDE_SECTORS" : Disk.IDE_SECTORS,
> + "IDE_HEADS" : Disk.IDE_HEADS,
> + "IDE_BLOCKS" : blocks,
> + "IDE_CYLINDERS" : blocks/(Disk.IDE_SECTORS*Disk.IDE_HEADS),
> + "VMDK_EXTENT_INFO" : vmdk_extent_info,
> + }
> +
> + vmdk = """# Disk DescriptorFile
> +# Generated from virtinst
> +version=1
> +
> +CID=%(SELF_CID)s
> +parentCID=ffffffff
> +createType="%(CREATE_TYPE)s"
> +
> +# Extent description
> +%(VMDK_EXTENT_INFO)s
> +
> +# Disk Data Base
> +ddb.virtualHWVersion = "4"
> +ddb.adapterType = "ide"
> +ddb.geometry.sectors = "%(IDE_SECTORS)s"
> +ddb.geometry.heads = "%(IDE_HEADS)s"
> +ddb.geometry.cylinders = "%(IDE_CYLINDERS)s"
> +"""
> + vmdk = vmdk % dict
> + return vmdk


Not that there are any adverse effects with the current code, but
'dict' is actually used in python referring to the actual
dictionary type. So it might be good to use a different variable
name here (and there is an example below as well.)


> +
> +
> + def to_vmx(self):
> + """Return the fragment for the VMX file for this disk"""
> +
> + vmx = ""
> + dict = {
> + "dev" : self.dev,
> + "disk_filename" : self.descriptor
> + }
> + if self.format == ImageParser.Disk.FORMAT_ISO:
> + vmx = _VMX_ISO_TEMPLATE % dict
> + else: # FORMAT_RAW
> + vmx = _VMX_IDE_TEMPLATE % dict
> + return vmx
> +
> +class Image:
> + """Represent an image for generation of a VMWare(tm) description"""
> +
> + def __init__(self, image = None):
> + if image is not None:
> + self._init_from_image(image)
> +
> + def _init_from_image(self, image):
> + domain = image.domain
> + boot = domain.boots[0]
> +
> + self.base = image.base
> + self.name = image.name
> + self.descr = image.descr
> + self.label = image.label
> + self.vcpu = domain.vcpu
> + self.memory = domain.memory
> + self.interface = domain.interface
> +
> + self.disks = []
> + for d in boot.drives:
> + disk = d.disk
> + descriptor = sub_ext(disk.file, ".vmdk")
> + if disk.size is None:
> + f = os.path.join(image.base, disk.file)
> + size = os.stat(f).st_size
> + else:
> + size = long(disk.size) * 1024L * 1024L
> + ide_count = len(self.disks)
> + dev = "%d:%d" % (ide_count / 2, ide_count % 2)
> + self.disks.append(Disk(descriptor, disk.file, size, dev,
> + disk.format))
> +
> + def make(self, base):
> + """Write the descriptor file and all the disk descriptors"""
> + files = []
> + out = open(os.path.join(self.base, self.name + ".vmx"), "w")
> + out.write(self.to_vmx())
> + out.close()
> + files.append(self.name + ".vmx")
> +
> + for d in self.disks:
> + f = d.make_extent(self.base)
> + files.append(f)
> + out = open(os.path.join(base, d.descriptor), "w")
> + out.write(d._VMDK_TEMPLATE())
> + out.close()
> + files.append(d.descriptor)
> + return files
> +
> + def to_vmx(self):
> + """Return the VMX description of this image"""
> + # Strip blank spaces and EOL to prevent syntax errors in vmx file
> + self.descr = self.descr.strip()
> + self.descr = self.descr.replace("
","|")
> +
> + dict = {
> + "now": time.strftime("%Y-%m-%dT%H:%M:%S %Z", time.localtime()),
> + "progname": os.path.basename(sys.argv[0]),
> + "/image/name": self.name,
> + "/image/description": self.descr or "None",
> + "/image/label": self.label or self.name,
> + "/image/devices/vcpu" : self.vcpu,
> + "/image/devices/memory": long(self.memory)/1024
> + }
> +
> + vmx = _VMX_MAIN_TEMPLATE % dict
> + if self.interface:
> + vmx += _VMX_ETHER_TEMPLATE
> +
> + for d in self.disks:
> + vmx += d.to_vmx()
> +
> + return vmx
> +
> +def sub_ext(filename, ext):
> + return os.path.splitext(filename)[0] + ext
> +
> +_VMX_MAIN_TEMPLATE = """
> +#!/usr/bin/vmplayer
> +
> +# Generated %(now)s by %(progname)s
> +# http://virt-manager.et.redhat.com/
> +
> +# This is a Workstation 5 or 5.5 config file
> +# It can be used with Player
> +config.version = "8"
> +virtualHW.version = "4"
> +
> +# Selected operating system for your virtual machine
> +guestOS = "other"
> +
> +# displayName is your own name for the virtual machine
> +displayName = "%(/image/name)s"
> +
> +# These fields are free text description fields
> +annotation = "%(/image/description)s"
> +guestinfo.vmware.product.long = "%(/image/label)s"
> +guestinfo.vmware.product.url = "http://virt-manager.et.redhat.com/"
> +guestinfo.vmware.product.class = "virtual machine"
> +
> +# Number of virtual CPUs. Your virtual machine will not
> +# work if this number is higher than the number of your physical CPUs
> +numvcpus = "%(/image/devices/vcpu)s"
> +
> +# Memory size and other memory settings
> +memsize = "%(/image/devices/memory)d"
> +MemAllowAutoScaleDown = "FALSE"
> +MemTrimRate = "-1"
> +
> +# Unique ID for the virtual machine will be created
> +uuid.action = "create"
> +
> +## For appliances where tools are installed already, this should really
> +## be false, but we don't have that ionfo in the metadata
> +# Remind to install VMware Tools
> +# This setting has no effect in VMware Player
> +tools.remindInstall = "TRUE"
> +
> +# Startup hints interfers with automatic startup of a virtual machine
> +# This setting has no effect in VMware Player
> +hints.hideAll = "TRUE"
> +
> +# Enable time synchronization between computer
> +# and virtual machine
> +tools.syncTime = "TRUE"
> +
> +# First serial port, physical COM1 is not available
> +serial0.present = "FALSE"
> +
> +# Optional second serial port, physical COM2 is not available
> +serial1.present = "FALSE"
> +
> +# First parallell port, physical LPT1 is not available
> +parallel0.present = "FALSE"
> +
> +# Logging
> +# This config activates logging, and keeps last log
> +logging = "TRUE"
> +log.fileName = "%(/image/name)s.log"
> +log.append = "TRUE"
> +log.keepOld = "3"
> +
> +# These settings decides interaction between your
> +# computer and the virtual machine
> +isolation.tools.hgfs.disable = "FALSE"
> +isolation.tools.dnd.disable = "FALSE"
> +isolation.tools.copy.enable = "TRUE"
> +isolation.tools.paste.enabled = "TRUE"
> +
> +# Settings for physical floppy drive
> +floppy0.present = "FALSE"
> +"""
> +
> +_VMX_ETHER_TEMPLATE = """
> +## if /image/devices/interface is present:
> +# First network interface card
> +ethernet0.present = "TRUE"
> +ethernet0.connectionType = "nat"
> +ethernet0.addressType = "generated"
> +ethernet0.generatedAddressOffset = "0"
> +ethernet0.autoDetect = "TRUE"
> +"""
> +
> +_VMX_ISO_TEMPLATE = """
> +# CDROM drive
> +ide%(dev)s.present = "TRUE"
> +ide%(dev)s.deviceType = "cdrom-raw"
> +ide%(dev)s.startConnected = "TRUE"
> +ide%(dev)s.fileName = "%(disk_filename)s"
> +ide%(dev)s.autodetect = "TRUE"
> +"""
> +
> +_VMX_IDE_TEMPLATE = """
> +# IDE disk
> +ide%(dev)s.present = "TRUE"
> +ide%(dev)s.fileName = "%(disk_filename)s"
> +ide%(dev)s.mode = "persistent"
> +ide%(dev)s.startConnected = "TRUE"
> +ide%(dev)s.writeThrough = "TRUE"
> +"""
> diff -Naur virtinst--devel.orig/virt-pack virtinst--devel/virt-pack
> --- virtinst--devel.orig/virt-pack 1969-12-31 19:00:00.000000000 -0500
> +++ virtinst--devel/virt-pack 2008-06-09 13:03:30.000000000 -0400
> @@ -0,0 +1,146 @@
> +#!/usr/bin/python -tt
> +#
> +# Package and unpackage images for distribution
> +#
> +# Copyright 2007 Red Hat, Inc.
> +# David Lutterkort <dlutter@redhat.com>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> +# MA 02110-1301 USA.
> +
> +import os, sys, string
> +from optparse import OptionParser, OptionValueError
> +import subprocess
> +import logging
> +import libxml2
> +import urlgrabber.progress as progress
> +
> +import virtinst
> +import virtinst.ImageParser
> +import virtinst.CapabilitiesParser
> +import virtinst.cli as cli
> +import virtinst.util as util
> +import virtinst.UnWare
> +
> +import tempfile
> +
> +import gettext
> +import locale
> +
> +locale.setlocale(locale.LC_ALL, ')
> +gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
> +gettext.install(virtinst.gettext_app, virtinst.gettext_dir)
> +
> +class PackageException(Exception):
> + def __init__(self, msg):
> + Exception.__init__(self, msg)
> +
> +class Package:
> +
> + def __init__(self, image):
> + self.image = image
> + if image.name is None or image.version is None:
> + raise PackageException(
> + _("The image name and version must be present"))
> + self.vername = "%s-%s" % (image.name, image.version)
> + self.tmpdir = tempfile.mkdtemp(dir="/var/tmp", prefix="virt-pack")
> + self.stagedir = os.path.join(self.tmpdir, self.vername)
> + self.files = []
> +
> + def add_image_files(self):
> + cwd = os.getcwd()
> + img = self.image
> + self.files.append(os.path.basename(img.filename))
> + try:
> + os.chdir(img.base)
> + for d in img.storage.keys():
> + disk = img.storage[d]
> + if disk.use == disk.USE_SCRATCH:
> + if disk.size is None:
> + raise PackageException(_("Scratch disk %s does not have a size attribute") % disk.id)
> + else:
> + if not os.path.exists(disk.file):
> + raise PackageException(_("Disk file %s could not be found") % disk.id)
> + self.files.append(disk.file)
> + finally:
> + os.chdir(cwd)
> +


Is there any reason for this to still be here that I'm missing? My previous
comment was:

> Why change directories here? Seems like it could all be avoided if the
> above check is changed to: os.path.exists(os.path.join(img.base, disk.file))


> + def make_vmx_files(self):
> + img = virtinst.UnWare.Image(self.image)
> + files = img.make(self.image.base)
> + self.files.extend(files)
> +
> + def pack(self, outdir):
> + outfile = os.path.join(outdir, self.vername + ".tgz")
> + for f in set(self.files):
> + dir = os.path.join(self.stagedir, os.path.dirname(f))
> + if not os.path.exists(dir):
> + os.makedirs(dir)
> + # cwd = os.getcwd()
> + os.symlink(os.path.join(self.image.base, f),
> + os.path.join(self.stagedir, f))
> + print "Writing %s" % outfile
> + cmd = "tar chzv -C %s -f %s %s" % (self.tmpdir,
> + outfile,
> + os.path.basename(self.vername))
> + util.system(cmd)
> + return outfile


I missed this above message first time around: might want to also wrap
"Writing %s" to make it translatable.


> +
> +### Option parsing
> +def parse_args():
> + parser = OptionParser()
> + parser.set_usage("%prog [options] image.xml")
> +
> + parser.add_option("-o", "--output", type="string", dest="output",
> + action="callback", callback=cli.check_before_store,
> + help=_("Directory in which packaged file will be put"))
> + parser.add_option("-d", "--debug", action="store_true", dest="debug",
> + help=_("Print debugging information"))
> +
> + (options,args) = parser.parse_args()
> + if len(args) < 1:
> + parser.error(_("You need to provide an image XML descriptor"))
> + options.image = args[0]
> +
> + return options
> +
> +def main():
> + options = parse_args()
> + cli.setupLogging("virt-pack", options.debug)
> + image = virtinst.ImageParser.parse_file(os.path.abspath(op tions.image))
> + if image.name is None or image.version is None:
> + print >> sys.stderr, _("The image descriptor must contain name and version")
> + valid = False
> +
> + if options.output is None:
> + options.output = os.path.join(image.base, "..")
> +
> + pkg = Package(image)
> + try:
> + pkg.add_image_files()
> + except PackageException, e:
> + print >> sys.stderr, _("Validation failed: %s"), e
> + return 1
> +
> + try:
> + pkg.make_vmx_files()
> + pkg.pack(options.output)
> + except PackageException, e:
> + print >> sys.stderr, _("Packaging failed: %s") % e
> + return 1
> +
> +if __name__ == "__main__":
> + main()
> +


Thanks,
Cole

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Joey Boggs 06-10-2008 06:35 PM

virt-inst Package an image for VMware distribution
 
Some of my changes hadn't saved, not sure why. I made them again and
renamed dict to vmdk_dict



Cole Robinson wrote:

Joey Boggs wrote:


Updated virt-pack and Unware.py per suggestions




Comments inline:




diff -Naur virtinst--devel.orig/virtinst/UnWare.py virtinst--devel/virtinst/UnWare.py
--- virtinst--devel.orig/virtinst/UnWare.py 1969-12-31 19:00:00.000000000 -0500
+++ virtinst--devel/virtinst/UnWare.py 2008-06-09 13:03:41.000000000 -0400
@@ -0,0 +1,309 @@
+#
+# Processing of VMWare(tm) .vmx files
+#
+# Copyright 2007 Red Hat, Inc.
+# David Lutterkort <dlutter@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+
+import time
+import sys
+import os
+
+import ImageParser
+import util
+
+class Disk:
+ """A disk for a VMWare(tm) virtual machine"""
+
+ MONOLITHIC_FLAT = "monolithicFlat"
+ TWO_GB_MAX_EXTENT_SPARSE = "twoGbMaxExtentSparse"
+ # This seems only to be usable if the vmdk header is embedded in the
+ # data file, not when the descriptor is in a separate text file. Use
+ # TWO_GB_MAX_EXTENT_SPARSE instead.
+ # VMWare's(tm) documentation of VMDK seriously sucks. A lot.
+ MONOLITHIC_SPARSE = "monolithicSparse"
+
+ IDE_HEADS = 16
+ IDE_SECTORS = 63
+
+ def __init__(self, descriptor, extent, size, dev, format):

+ """Create a new disk. DESCRIPTOR is the name of the VMDK descriptor
+ file. EXTENT is the name of the file holding the actual data. SIZE
+ is the filesize in bytes. DEV identifies the device, for IDE (the
+ only one supported right now) it should be $bus:$master. FORMAT is
+ the format of the underlying extent, one of the formats defined in
+ virtinst.ImageParser.Disk"""
+ self.cid = 0xffffffff
+ self.createType = Disk.MONOLITHIC_FLAT
+ self.descriptor = descriptor
+ self.extent = extent
+ self.size = size
+ self.dev = dev
+ self.format = format
+
+ def make_extent(self, base):
+ """Write the descriptor file, and create the extent as a monolithic
+ sparse extent if it does not exist yet"""

+ f = os.path.join(base, self.extent)
+ print "Checking %s" % f




This print is still in place, any reason for that? My previous comment was:



We shouldn't just straight 'print' from a library, even if only one app is using it.
I suggest using logging.debug.






+ if not os.path.exists(f):
+ util.system("qemu-img create -f vmdk %s %d" % (f, self.size/1024))
+ self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
+ else:
+ qemu = os.popen("qemu-img info %s" % f, "r")
+ for l in qemu:
+ (tag, val) = l.split(":")
+ if tag == "file format" and val.strip() == "vmdk":
+ self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
+ qemu.close()
+ return self.extent
+
+ def _VMDK_TEMPLATE(self):

+
+ blocks = self.size/512
+ if self.createType == Disk.MONOLITHIC_FLAT:
+ vmdk_extent_info= "RW %d FLAT "%s" 0
" % (blocks, os.path.basename(self.extent))
+ else: # Disk.MONOLITHIC_SPARSE
+ vmdk_extent_info= "RW %d SPARSE "%s"
" % (blocks, os.path.basename(self.extent))
+
+ dict = {
+ "SELF_CID" : self.cid,
+ "CREATE_TYPE" : self.createType,
+ "IDE_SECTORS" : Disk.IDE_SECTORS,
+ "IDE_HEADS" : Disk.IDE_HEADS,
+ "IDE_BLOCKS" : blocks,
+ "IDE_CYLINDERS" : blocks/(Disk.IDE_SECTORS*Disk.IDE_HEADS),
+ "VMDK_EXTENT_INFO" : vmdk_extent_info,
+ }
+
+ vmdk = """# Disk DescriptorFile

+# Generated from virtinst
+version=1
+
+CID=%(SELF_CID)s
+parentCID=ffffffff
+createType="%(CREATE_TYPE)s"
+
+# Extent description
+%(VMDK_EXTENT_INFO)s
+
+# Disk Data Base
+ddb.virtualHWVersion = "4"
+ddb.adapterType = "ide"
+ddb.geometry.sectors = "%(IDE_SECTORS)s"
+ddb.geometry.heads = "%(IDE_HEADS)s"
+ddb.geometry.cylinders = "%(IDE_CYLINDERS)s"
+"""
+ vmdk = vmdk % dict

+ return vmdk




Not that there are any adverse effects with the current code, but
'dict' is actually used in python referring to the actual
dictionary type. So it might be good to use a different variable
name here (and there is an example below as well.)




+
+
+ def to_vmx(self):
+ """Return the fragment for the VMX file for this disk"""
+
+ vmx = ""
+ dict = {
+ "dev" : self.dev,
+ "disk_filename" : self.descriptor
+ }
+ if self.format == ImageParser.Disk.FORMAT_ISO:
+ vmx = _VMX_ISO_TEMPLATE % dict
+ else: # FORMAT_RAW
+ vmx = _VMX_IDE_TEMPLATE % dict
+ return vmx
+
+class Image:

+ """Represent an image for generation of a VMWare(tm) description"""
+
+ def __init__(self, image = None):
+ if image is not None:
+ self._init_from_image(image)
+
+ def _init_from_image(self, image):
+ domain = image.domain
+ boot = domain.boots[0]
+
+ self.base = image.base
+ self.name = image.name
+ self.descr = image.descr
+ self.label = image.label
+ self.vcpu = domain.vcpu
+ self.memory = domain.memory
+ self.interface = domain.interface
+
+ self.disks = []
+ for d in boot.drives:
+ disk = d.disk
+ descriptor = sub_ext(disk.file, ".vmdk")
+ if disk.size is None:
+ f = os.path.join(image.base, disk.file)
+ size = os.stat(f).st_size
+ else:
+ size = long(disk.size) * 1024L * 1024L
+ ide_count = len(self.disks)
+ dev = "%d:%d" % (ide_count / 2, ide_count % 2)
+ self.disks.append(Disk(descriptor, disk.file, size, dev,
+ disk.format))

+
+ def make(self, base):
+ """Write the descriptor file and all the disk descriptors"""
+ files = []
+ out = open(os.path.join(self.base, self.name + ".vmx"), "w")
+ out.write(self.to_vmx())
+ out.close()
+ files.append(self.name + ".vmx")
+
+ for d in self.disks:
+ f = d.make_extent(self.base)
+ files.append(f)
+ out = open(os.path.join(base, d.descriptor), "w")
+ out.write(d._VMDK_TEMPLATE())
+ out.close()
+ files.append(d.descriptor)
+ return files
+
+ def to_vmx(self):
+ """Return the VMX description of this image"""
+ # Strip blank spaces and EOL to prevent syntax errors in vmx file
+ self.descr = self.descr.strip()
+ self.descr = self.descr.replace("
","|")
+
+ dict = {
+ "now": time.strftime("%Y-%m-%dT%H:%M:%S %Z", time.localtime()),
+ "progname": os.path.basename(sys.argv[0]),
+ "/image/name": self.name,
+ "/image/description": self.descr or "None",
+ "/image/label": self.label or self.name,
+ "/image/devices/vcpu" : self.vcpu,
+ "/image/devices/memory": long(self.memory)/1024
+ }
+
+ vmx = _VMX_MAIN_TEMPLATE % dict
+ if self.interface:
+ vmx += _VMX_ETHER_TEMPLATE
+
+ for d in self.disks:
+ vmx += d.to_vmx()
+
+ return vmx
+
+def sub_ext(filename, ext):

+ return os.path.splitext(filename)[0] + ext
+
+_VMX_MAIN_TEMPLATE = """
+#!/usr/bin/vmplayer
+
+# Generated %(now)s by %(progname)s
+# http://virt-manager.et.redhat.com/
+
+# This is a Workstation 5 or 5.5 config file
+# It can be used with Player
+config.version = "8"
+virtualHW.version = "4"
+
+# Selected operating system for your virtual machine
+guestOS = "other"
+
+# displayName is your own name for the virtual machine
+displayName = "%(/image/name)s"
+
+# These fields are free text description fields
+annotation = "%(/image/description)s"
+guestinfo.vmware.product.long = "%(/image/label)s"
+guestinfo.vmware.product.url = "http://virt-manager.et.redhat.com/"
+guestinfo.vmware.product.class = "virtual machine"
+
+# Number of virtual CPUs. Your virtual machine will not
+# work if this number is higher than the number of your physical CPUs
+numvcpus = "%(/image/devices/vcpu)s"
+
+# Memory size and other memory settings
+memsize = "%(/image/devices/memory)d"
+MemAllowAutoScaleDown = "FALSE"
+MemTrimRate = "-1"
+
+# Unique ID for the virtual machine will be created
+uuid.action = "create"
+
+## For appliances where tools are installed already, this should really
+## be false, but we don't have that ionfo in the metadata
+# Remind to install VMware Tools
+# This setting has no effect in VMware Player
+tools.remindInstall = "TRUE"
+
+# Startup hints interfers with automatic startup of a virtual machine
+# This setting has no effect in VMware Player
+hints.hideAll = "TRUE"
+
+# Enable time synchronization between computer
+# and virtual machine
+tools.syncTime = "TRUE"
+
+# First serial port, physical COM1 is not available
+serial0.present = "FALSE"
+
+# Optional second serial port, physical COM2 is not available
+serial1.present = "FALSE"
+
+# First parallell port, physical LPT1 is not available
+parallel0.present = "FALSE"
+
+# Logging
+# This config activates logging, and keeps last log
+logging = "TRUE"
+log.fileName = "%(/image/name)s.log"
+log.append = "TRUE"
+log.keepOld = "3"
+
+# These settings decides interaction between your
+# computer and the virtual machine
+isolation.tools.hgfs.disable = "FALSE"
+isolation.tools.dnd.disable = "FALSE"
+isolation.tools.copy.enable = "TRUE"
+isolation.tools.paste.enabled = "TRUE"
+
+# Settings for physical floppy drive
+floppy0.present = "FALSE"
+"""
+
+_VMX_ETHER_TEMPLATE = """
+## if /image/devices/interface is present:
+# First network interface card
+ethernet0.present = "TRUE"
+ethernet0.connectionType = "nat"
+ethernet0.addressType = "generated"
+ethernet0.generatedAddressOffset = "0"
+ethernet0.autoDetect = "TRUE"
+"""
+
+_VMX_ISO_TEMPLATE = """
+# CDROM drive
+ide%(dev)s.present = "TRUE"
+ide%(dev)s.deviceType = "cdrom-raw"
+ide%(dev)s.startConnected = "TRUE"
+ide%(dev)s.fileName = "%(disk_filename)s"
+ide%(dev)s.autodetect = "TRUE"
+"""
+
+_VMX_IDE_TEMPLATE = """
+# IDE disk
+ide%(dev)s.present = "TRUE"
+ide%(dev)s.fileName = "%(disk_filename)s"
+ide%(dev)s.mode = "persistent"
+ide%(dev)s.startConnected = "TRUE"
+ide%(dev)s.writeThrough = "TRUE"
+"""
diff -Naur virtinst--devel.orig/virt-pack virtinst--devel/virt-pack
--- virtinst--devel.orig/virt-pack 1969-12-31 19:00:00.000000000 -0500
+++ virtinst--devel/virt-pack 2008-06-09 13:03:30.000000000 -0400
@@ -0,0 +1,146 @@
+#!/usr/bin/python -tt
+#
+# Package and unpackage images for distribution
+#
+# Copyright 2007 Red Hat, Inc.
+# David Lutterkort <dlutter@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+
+import os, sys, string
+from optparse import OptionParser, OptionValueError
+import subprocess
+import logging
+import libxml2
+import urlgrabber.progress as progress
+
+import virtinst
+import virtinst.ImageParser
+import virtinst.CapabilitiesParser
+import virtinst.cli as cli
+import virtinst.util as util
+import virtinst.UnWare
+
+import tempfile
+
+import gettext
+import locale
+
+locale.setlocale(locale.LC_ALL, ')
+gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
+gettext.install(virtinst.gettext_app, virtinst.gettext_dir)
+
+class PackageException(Exception):
+ def __init__(self, msg):
+ Exception.__init__(self, msg)
+
+class Package:
+
+ def __init__(self, image):

+ self.image = image
+ if image.name is None or image.version is None:
+ raise PackageException(
+ _("The image name and version must be present"))
+ self.vername = "%s-%s" % (image.name, image.version)
+ self.tmpdir = tempfile.mkdtemp(dir="/var/tmp", prefix="virt-pack")
+ self.stagedir = os.path.join(self.tmpdir, self.vername)
+ self.files = []
+
+ def add_image_files(self):
+ cwd = os.getcwd()
+ img = self.image
+ self.files.append(os.path.basename(img.filename))
+ try:
+ os.chdir(img.base)
+ for d in img.storage.keys():
+ disk = img.storage[d]
+ if disk.use == disk.USE_SCRATCH:
+ if disk.size is None:
+ raise PackageException(_("Scratch disk %s does not have a size attribute") % disk.id)
+ else:
+ if not os.path.exists(disk.file):
+ raise PackageException(_("Disk file %s could not be found") % disk.id)
+ self.files.append(disk.file)
+ finally:
+ os.chdir(cwd)
+




Is there any reason for this to still be here that I'm missing? My previous
comment was:



Why change directories here? Seems like it could all be avoided if the
above check is changed to: os.path.exists(os.path.join(img.base, disk.file))






+ def make_vmx_files(self):
+ img = virtinst.UnWare.Image(self.image)
+ files = img.make(self.image.base)
+ self.files.extend(files)
+
+ def pack(self, outdir):
+ outfile = os.path.join(outdir, self.vername + ".tgz")
+ for f in set(self.files):
+ dir = os.path.join(self.stagedir, os.path.dirname(f))
+ if not os.path.exists(dir):
+ os.makedirs(dir)
+ # cwd = os.getcwd()
+ os.symlink(os.path.join(self.image.base, f),
+ os.path.join(self.stagedir, f))

+ print "Writing %s" % outfile
+ cmd = "tar chzv -C %s -f %s %s" % (self.tmpdir,
+ outfile,
+ os.path.basename(self.vername))

+ util.system(cmd)
+ return outfile




I missed this above message first time around: might want to also wrap
"Writing %s" to make it translatable.




+
+### Option parsing
+def parse_args():
+ parser = OptionParser()
+ parser.set_usage("%prog [options] image.xml")
+
+ parser.add_option("-o", "--output", type="string", dest="output",
+ action="callback", callback=cli.check_before_store,
+ help=_("Directory in which packaged file will be put"))
+ parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help=_("Print debugging information"))
+
+ (options,args) = parser.parse_args()
+ if len(args) < 1:
+ parser.error(_("You need to provide an image XML descriptor"))
+ options.image = args[0]
+
+ return options

+
+def main():
+ options = parse_args()
+ cli.setupLogging("virt-pack", options.debug)
+ image = virtinst.ImageParser.parse_file(os.path.abspath(op tions.image))
+ if image.name is None or image.version is None:
+ print >> sys.stderr, _("The image descriptor must contain name and version")
+ valid = False
+
+ if options.output is None:
+ options.output = os.path.join(image.base, "..")
+
+ pkg = Package(image)
+ try:
+ pkg.add_image_files()
+ except PackageException, e:
+ print >> sys.stderr, _("Validation failed: %s"), e
+ return 1
+
+ try:
+ pkg.make_vmx_files()
+ pkg.pack(options.output)
+ except PackageException, e:
+ print >> sys.stderr, _("Packaging failed: %s") % e
+ return 1
+
+if __name__ == "__main__":
+ main()
+




Thanks,
Cole



_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Joey Boggs 06-10-2008 07:31 PM

virt-inst Package an image for VMware distribution
 
Made more updates based on comments.



Cole Robinson wrote:

Joey Boggs wrote:


Updated virt-pack and Unware.py per suggestions




Comments inline:




diff -Naur virtinst--devel.orig/virtinst/UnWare.py virtinst--devel/virtinst/UnWare.py
--- virtinst--devel.orig/virtinst/UnWare.py 1969-12-31 19:00:00.000000000 -0500
+++ virtinst--devel/virtinst/UnWare.py 2008-06-09 13:03:41.000000000 -0400
@@ -0,0 +1,309 @@
+#
+# Processing of VMWare(tm) .vmx files
+#
+# Copyright 2007 Red Hat, Inc.
+# David Lutterkort <dlutter@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+
+import time
+import sys
+import os
+
+import ImageParser
+import util
+
+class Disk:
+ """A disk for a VMWare(tm) virtual machine"""
+
+ MONOLITHIC_FLAT = "monolithicFlat"
+ TWO_GB_MAX_EXTENT_SPARSE = "twoGbMaxExtentSparse"
+ # This seems only to be usable if the vmdk header is embedded in the
+ # data file, not when the descriptor is in a separate text file. Use
+ # TWO_GB_MAX_EXTENT_SPARSE instead.
+ # VMWare's(tm) documentation of VMDK seriously sucks. A lot.
+ MONOLITHIC_SPARSE = "monolithicSparse"
+
+ IDE_HEADS = 16
+ IDE_SECTORS = 63
+
+ def __init__(self, descriptor, extent, size, dev, format):

+ """Create a new disk. DESCRIPTOR is the name of the VMDK descriptor
+ file. EXTENT is the name of the file holding the actual data. SIZE
+ is the filesize in bytes. DEV identifies the device, for IDE (the
+ only one supported right now) it should be $bus:$master. FORMAT is
+ the format of the underlying extent, one of the formats defined in
+ virtinst.ImageParser.Disk"""
+ self.cid = 0xffffffff
+ self.createType = Disk.MONOLITHIC_FLAT
+ self.descriptor = descriptor
+ self.extent = extent
+ self.size = size
+ self.dev = dev
+ self.format = format
+
+ def make_extent(self, base):
+ """Write the descriptor file, and create the extent as a monolithic
+ sparse extent if it does not exist yet"""

+ f = os.path.join(base, self.extent)
+ print "Checking %s" % f




This print is still in place, any reason for that? My previous comment was:



We shouldn't just straight 'print' from a library, even if only one app is using it.
I suggest using logging.debug.






+ if not os.path.exists(f):
+ util.system("qemu-img create -f vmdk %s %d" % (f, self.size/1024))
+ self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
+ else:
+ qemu = os.popen("qemu-img info %s" % f, "r")
+ for l in qemu:
+ (tag, val) = l.split(":")
+ if tag == "file format" and val.strip() == "vmdk":
+ self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
+ qemu.close()
+ return self.extent
+
+ def _VMDK_TEMPLATE(self):

+
+ blocks = self.size/512
+ if self.createType == Disk.MONOLITHIC_FLAT:
+ vmdk_extent_info= "RW %d FLAT "%s" 0
" % (blocks, os.path.basename(self.extent))
+ else: # Disk.MONOLITHIC_SPARSE
+ vmdk_extent_info= "RW %d SPARSE "%s"
" % (blocks, os.path.basename(self.extent))
+
+ dict = {
+ "SELF_CID" : self.cid,
+ "CREATE_TYPE" : self.createType,
+ "IDE_SECTORS" : Disk.IDE_SECTORS,
+ "IDE_HEADS" : Disk.IDE_HEADS,
+ "IDE_BLOCKS" : blocks,
+ "IDE_CYLINDERS" : blocks/(Disk.IDE_SECTORS*Disk.IDE_HEADS),
+ "VMDK_EXTENT_INFO" : vmdk_extent_info,
+ }
+
+ vmdk = """# Disk DescriptorFile

+# Generated from virtinst
+version=1
+
+CID=%(SELF_CID)s
+parentCID=ffffffff
+createType="%(CREATE_TYPE)s"
+
+# Extent description
+%(VMDK_EXTENT_INFO)s
+
+# Disk Data Base
+ddb.virtualHWVersion = "4"
+ddb.adapterType = "ide"
+ddb.geometry.sectors = "%(IDE_SECTORS)s"
+ddb.geometry.heads = "%(IDE_HEADS)s"
+ddb.geometry.cylinders = "%(IDE_CYLINDERS)s"
+"""
+ vmdk = vmdk % dict

+ return vmdk




Not that there are any adverse effects with the current code, but
'dict' is actually used in python referring to the actual
dictionary type. So it might be good to use a different variable
name here (and there is an example below as well.)




+
+
+ def to_vmx(self):
+ """Return the fragment for the VMX file for this disk"""
+
+ vmx = ""
+ dict = {
+ "dev" : self.dev,
+ "disk_filename" : self.descriptor
+ }
+ if self.format == ImageParser.Disk.FORMAT_ISO:
+ vmx = _VMX_ISO_TEMPLATE % dict
+ else: # FORMAT_RAW
+ vmx = _VMX_IDE_TEMPLATE % dict
+ return vmx
+
+class Image:

+ """Represent an image for generation of a VMWare(tm) description"""
+
+ def __init__(self, image = None):
+ if image is not None:
+ self._init_from_image(image)
+
+ def _init_from_image(self, image):
+ domain = image.domain
+ boot = domain.boots[0]
+
+ self.base = image.base
+ self.name = image.name
+ self.descr = image.descr
+ self.label = image.label
+ self.vcpu = domain.vcpu
+ self.memory = domain.memory
+ self.interface = domain.interface
+
+ self.disks = []
+ for d in boot.drives:
+ disk = d.disk
+ descriptor = sub_ext(disk.file, ".vmdk")
+ if disk.size is None:
+ f = os.path.join(image.base, disk.file)
+ size = os.stat(f).st_size
+ else:
+ size = long(disk.size) * 1024L * 1024L
+ ide_count = len(self.disks)
+ dev = "%d:%d" % (ide_count / 2, ide_count % 2)
+ self.disks.append(Disk(descriptor, disk.file, size, dev,
+ disk.format))

+
+ def make(self, base):
+ """Write the descriptor file and all the disk descriptors"""
+ files = []
+ out = open(os.path.join(self.base, self.name + ".vmx"), "w")
+ out.write(self.to_vmx())
+ out.close()
+ files.append(self.name + ".vmx")
+
+ for d in self.disks:
+ f = d.make_extent(self.base)
+ files.append(f)
+ out = open(os.path.join(base, d.descriptor), "w")
+ out.write(d._VMDK_TEMPLATE())
+ out.close()
+ files.append(d.descriptor)
+ return files
+
+ def to_vmx(self):
+ """Return the VMX description of this image"""
+ # Strip blank spaces and EOL to prevent syntax errors in vmx file
+ self.descr = self.descr.strip()
+ self.descr = self.descr.replace("
","|")
+
+ dict = {
+ "now": time.strftime("%Y-%m-%dT%H:%M:%S %Z", time.localtime()),
+ "progname": os.path.basename(sys.argv[0]),
+ "/image/name": self.name,
+ "/image/description": self.descr or "None",
+ "/image/label": self.label or self.name,
+ "/image/devices/vcpu" : self.vcpu,
+ "/image/devices/memory": long(self.memory)/1024
+ }
+
+ vmx = _VMX_MAIN_TEMPLATE % dict
+ if self.interface:
+ vmx += _VMX_ETHER_TEMPLATE
+
+ for d in self.disks:
+ vmx += d.to_vmx()
+
+ return vmx
+
+def sub_ext(filename, ext):

+ return os.path.splitext(filename)[0] + ext
+
+_VMX_MAIN_TEMPLATE = """
+#!/usr/bin/vmplayer
+
+# Generated %(now)s by %(progname)s
+# http://virt-manager.et.redhat.com/
+
+# This is a Workstation 5 or 5.5 config file
+# It can be used with Player
+config.version = "8"
+virtualHW.version = "4"
+
+# Selected operating system for your virtual machine
+guestOS = "other"
+
+# displayName is your own name for the virtual machine
+displayName = "%(/image/name)s"
+
+# These fields are free text description fields
+annotation = "%(/image/description)s"
+guestinfo.vmware.product.long = "%(/image/label)s"
+guestinfo.vmware.product.url = "http://virt-manager.et.redhat.com/"
+guestinfo.vmware.product.class = "virtual machine"
+
+# Number of virtual CPUs. Your virtual machine will not
+# work if this number is higher than the number of your physical CPUs
+numvcpus = "%(/image/devices/vcpu)s"
+
+# Memory size and other memory settings
+memsize = "%(/image/devices/memory)d"
+MemAllowAutoScaleDown = "FALSE"
+MemTrimRate = "-1"
+
+# Unique ID for the virtual machine will be created
+uuid.action = "create"
+
+## For appliances where tools are installed already, this should really
+## be false, but we don't have that ionfo in the metadata
+# Remind to install VMware Tools
+# This setting has no effect in VMware Player
+tools.remindInstall = "TRUE"
+
+# Startup hints interfers with automatic startup of a virtual machine
+# This setting has no effect in VMware Player
+hints.hideAll = "TRUE"
+
+# Enable time synchronization between computer
+# and virtual machine
+tools.syncTime = "TRUE"
+
+# First serial port, physical COM1 is not available
+serial0.present = "FALSE"
+
+# Optional second serial port, physical COM2 is not available
+serial1.present = "FALSE"
+
+# First parallell port, physical LPT1 is not available
+parallel0.present = "FALSE"
+
+# Logging
+# This config activates logging, and keeps last log
+logging = "TRUE"
+log.fileName = "%(/image/name)s.log"
+log.append = "TRUE"
+log.keepOld = "3"
+
+# These settings decides interaction between your
+# computer and the virtual machine
+isolation.tools.hgfs.disable = "FALSE"
+isolation.tools.dnd.disable = "FALSE"
+isolation.tools.copy.enable = "TRUE"
+isolation.tools.paste.enabled = "TRUE"
+
+# Settings for physical floppy drive
+floppy0.present = "FALSE"
+"""
+
+_VMX_ETHER_TEMPLATE = """
+## if /image/devices/interface is present:
+# First network interface card
+ethernet0.present = "TRUE"
+ethernet0.connectionType = "nat"
+ethernet0.addressType = "generated"
+ethernet0.generatedAddressOffset = "0"
+ethernet0.autoDetect = "TRUE"
+"""
+
+_VMX_ISO_TEMPLATE = """
+# CDROM drive
+ide%(dev)s.present = "TRUE"
+ide%(dev)s.deviceType = "cdrom-raw"
+ide%(dev)s.startConnected = "TRUE"
+ide%(dev)s.fileName = "%(disk_filename)s"
+ide%(dev)s.autodetect = "TRUE"
+"""
+
+_VMX_IDE_TEMPLATE = """
+# IDE disk
+ide%(dev)s.present = "TRUE"
+ide%(dev)s.fileName = "%(disk_filename)s"
+ide%(dev)s.mode = "persistent"
+ide%(dev)s.startConnected = "TRUE"
+ide%(dev)s.writeThrough = "TRUE"
+"""
diff -Naur virtinst--devel.orig/virt-pack virtinst--devel/virt-pack
--- virtinst--devel.orig/virt-pack 1969-12-31 19:00:00.000000000 -0500
+++ virtinst--devel/virt-pack 2008-06-09 13:03:30.000000000 -0400
@@ -0,0 +1,146 @@
+#!/usr/bin/python -tt
+#
+# Package and unpackage images for distribution
+#
+# Copyright 2007 Red Hat, Inc.
+# David Lutterkort <dlutter@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+
+import os, sys, string
+from optparse import OptionParser, OptionValueError
+import subprocess
+import logging
+import libxml2
+import urlgrabber.progress as progress
+
+import virtinst
+import virtinst.ImageParser
+import virtinst.CapabilitiesParser
+import virtinst.cli as cli
+import virtinst.util as util
+import virtinst.UnWare
+
+import tempfile
+
+import gettext
+import locale
+
+locale.setlocale(locale.LC_ALL, ')
+gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
+gettext.install(virtinst.gettext_app, virtinst.gettext_dir)
+
+class PackageException(Exception):
+ def __init__(self, msg):
+ Exception.__init__(self, msg)
+
+class Package:
+
+ def __init__(self, image):

+ self.image = image
+ if image.name is None or image.version is None:
+ raise PackageException(
+ _("The image name and version must be present"))
+ self.vername = "%s-%s" % (image.name, image.version)
+ self.tmpdir = tempfile.mkdtemp(dir="/var/tmp", prefix="virt-pack")
+ self.stagedir = os.path.join(self.tmpdir, self.vername)
+ self.files = []
+
+ def add_image_files(self):
+ cwd = os.getcwd()
+ img = self.image
+ self.files.append(os.path.basename(img.filename))
+ try:
+ os.chdir(img.base)
+ for d in img.storage.keys():
+ disk = img.storage[d]
+ if disk.use == disk.USE_SCRATCH:
+ if disk.size is None:
+ raise PackageException(_("Scratch disk %s does not have a size attribute") % disk.id)
+ else:
+ if not os.path.exists(disk.file):
+ raise PackageException(_("Disk file %s could not be found") % disk.id)
+ self.files.append(disk.file)
+ finally:
+ os.chdir(cwd)
+




Is there any reason for this to still be here that I'm missing? My previous
comment was:



Why change directories here? Seems like it could all be avoided if the
above check is changed to: os.path.exists(os.path.join(img.base, disk.file))






+ def make_vmx_files(self):
+ img = virtinst.UnWare.Image(self.image)
+ files = img.make(self.image.base)
+ self.files.extend(files)
+
+ def pack(self, outdir):
+ outfile = os.path.join(outdir, self.vername + ".tgz")
+ for f in set(self.files):
+ dir = os.path.join(self.stagedir, os.path.dirname(f))
+ if not os.path.exists(dir):
+ os.makedirs(dir)
+ # cwd = os.getcwd()
+ os.symlink(os.path.join(self.image.base, f),
+ os.path.join(self.stagedir, f))

+ print "Writing %s" % outfile
+ cmd = "tar chzv -C %s -f %s %s" % (self.tmpdir,
+ outfile,
+ os.path.basename(self.vername))

+ util.system(cmd)
+ return outfile




I missed this above message first time around: might want to also wrap
"Writing %s" to make it translatable.




+
+### Option parsing
+def parse_args():
+ parser = OptionParser()
+ parser.set_usage("%prog [options] image.xml")
+
+ parser.add_option("-o", "--output", type="string", dest="output",
+ action="callback", callback=cli.check_before_store,
+ help=_("Directory in which packaged file will be put"))
+ parser.add_option("-d", "--debug", action="store_true", dest="debug",
+ help=_("Print debugging information"))
+
+ (options,args) = parser.parse_args()
+ if len(args) < 1:
+ parser.error(_("You need to provide an image XML descriptor"))
+ options.image = args[0]
+
+ return options

+
+def main():
+ options = parse_args()
+ cli.setupLogging("virt-pack", options.debug)
+ image = virtinst.ImageParser.parse_file(os.path.abspath(op tions.image))
+ if image.name is None or image.version is None:
+ print >> sys.stderr, _("The image descriptor must contain name and version")
+ valid = False
+
+ if options.output is None:
+ options.output = os.path.join(image.base, "..")
+
+ pkg = Package(image)
+ try:
+ pkg.add_image_files()
+ except PackageException, e:
+ print >> sys.stderr, _("Validation failed: %s"), e
+ return 1
+
+ try:
+ pkg.make_vmx_files()
+ pkg.pack(options.output)
+ except PackageException, e:
+ print >> sys.stderr, _("Packaging failed: %s") % e
+ return 1
+
+if __name__ == "__main__":
+ main()
+




Thanks,
Cole



_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Cole Robinson 06-13-2008 08:36 PM

virt-inst Package an image for VMware distribution
 
Joey Boggs wrote:
> Made more updates based on comments.
>

This version looks good to me. If Dan is fine with it as well i'll commit it.

Thanks,
Cole


> diff -Naur virtinst--devel.orig/virtinst/UnWare.py virtinst--devel/virtinst/UnWare.py
> --- virtinst--devel.orig/virtinst/UnWare.py 1969-12-31 19:00:00.000000000 -0500
> +++ virtinst--devel/virtinst/UnWare.py 2008-06-10 15:22:17.000000000 -0400
> @@ -0,0 +1,309 @@
> +#
> +# Processing of VMWare(tm) .vmx files
> +#
> +# Copyright 2007 Red Hat, Inc.
> +# David Lutterkort <dlutter@redhat.com>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> +# MA 02110-1301 USA.
> +
> +import time
> +import sys
> +import os
> +import logging
> +import ImageParser
> +import util
> +
> +class Disk:
> + """A disk for a VMWare(tm) virtual machine"""
> +
> + MONOLITHIC_FLAT = "monolithicFlat"
> + TWO_GB_MAX_EXTENT_SPARSE = "twoGbMaxExtentSparse"
> + # This seems only to be usable if the vmdk header is embedded in the
> + # data file, not when the descriptor is in a separate text file. Use
> + # TWO_GB_MAX_EXTENT_SPARSE instead.
> + # VMWare's(tm) documentation of VMDK seriously sucks. A lot.
> + MONOLITHIC_SPARSE = "monolithicSparse"
> +
> + IDE_HEADS = 16
> + IDE_SECTORS = 63
> +
> + def __init__(self, descriptor, extent, size, dev, format):
> + """Create a new disk. DESCRIPTOR is the name of the VMDK descriptor
> + file. EXTENT is the name of the file holding the actual data. SIZE
> + is the filesize in bytes. DEV identifies the device, for IDE (the
> + only one supported right now) it should be $bus:$master. FORMAT is
> + the format of the underlying extent, one of the formats defined in
> + virtinst.ImageParser.Disk"""
> + self.cid = 0xffffffff
> + self.createType = Disk.MONOLITHIC_FLAT
> + self.descriptor = descriptor
> + self.extent = extent
> + self.size = size
> + self.dev = dev
> + self.format = format
> +
> + def make_extent(self, base):
> + """Write the descriptor file, and create the extent as a monolithic
> + sparse extent if it does not exist yet"""
> + f = os.path.join(base, self.extent)
> + logging.debug("Checking %s" % f)
> + if not os.path.exists(f):
> + util.system("qemu-img create -f vmdk %s %d" % (f, self.size/1024))
> + self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
> + else:
> + qemu = os.popen("qemu-img info %s" % f, "r")
> + for l in qemu:
> + (tag, val) = l.split(":")
> + if tag == "file format" and val.strip() == "vmdk":
> + self.createType = Disk.TWO_GB_MAX_EXTENT_SPARSE
> + qemu.close()
> + return self.extent
> +
> + def _VMDK_TEMPLATE(self):
> +
> + blocks = self.size/512
> + if self.createType == Disk.MONOLITHIC_FLAT:
> + vmdk_extent_info= "RW %d FLAT "%s" 0
" % (blocks, os.path.basename(self.extent))
> + else: # Disk.MONOLITHIC_SPARSE
> + vmdk_extent_info= "RW %d SPARSE "%s"
" % (blocks, os.path.basename(self.extent))
> +
> + vmdk_dict = {
> + "SELF_CID" : self.cid,
> + "CREATE_TYPE" : self.createType,
> + "IDE_SECTORS" : Disk.IDE_SECTORS,
> + "IDE_HEADS" : Disk.IDE_HEADS,
> + "IDE_BLOCKS" : blocks,
> + "IDE_CYLINDERS" : blocks/(Disk.IDE_SECTORS*Disk.IDE_HEADS),
> + "VMDK_EXTENT_INFO" : vmdk_extent_info,
> + }
> +
> + vmdk = """# Disk DescriptorFile
> +# Generated from virtinst
> +version=1
> +
> +CID=%(SELF_CID)s
> +parentCID=ffffffff
> +createType="%(CREATE_TYPE)s"
> +
> +# Extent description
> +%(VMDK_EXTENT_INFO)s
> +
> +# Disk Data Base
> +ddb.virtualHWVersion = "4"
> +ddb.adapterType = "ide"
> +ddb.geometry.sectors = "%(IDE_SECTORS)s"
> +ddb.geometry.heads = "%(IDE_HEADS)s"
> +ddb.geometry.cylinders = "%(IDE_CYLINDERS)s"
> +"""
> + vmdk = vmdk % vmdk_dict
> + return vmdk
> +
> +
> + def to_vmx(self):
> + """Return the fragment for the VMX file for this disk"""
> +
> + vmx = ""
> + vmx_dict = {
> + "dev" : self.dev,
> + "disk_filename" : self.descriptor
> + }
> + if self.format == ImageParser.Disk.FORMAT_ISO:
> + vmx = _VMX_ISO_TEMPLATE % vmx_dict
> + else: # FORMAT_RAW
> + vmx = _VMX_IDE_TEMPLATE % vmx_dict
> + return vmx
> +
> +class Image:
> + """Represent an image for generation of a VMWare(tm) description"""
> +
> + def __init__(self, image = None):
> + if image is not None:
> + self._init_from_image(image)
> +
> + def _init_from_image(self, image):
> + domain = image.domain
> + boot = domain.boots[0]
> +
> + self.base = image.base
> + self.name = image.name
> + self.descr = image.descr
> + self.label = image.label
> + self.vcpu = domain.vcpu
> + self.memory = domain.memory
> + self.interface = domain.interface
> +
> + self.disks = []
> + for d in boot.drives:
> + disk = d.disk
> + descriptor = sub_ext(disk.file, ".vmdk")
> + if disk.size is None:
> + f = os.path.join(image.base, disk.file)
> + size = os.stat(f).st_size
> + else:
> + size = long(disk.size) * 1024L * 1024L
> + ide_count = len(self.disks)
> + dev = "%d:%d" % (ide_count / 2, ide_count % 2)
> + self.disks.append(Disk(descriptor, disk.file, size, dev,
> + disk.format))
> +
> + def make(self, base):
> + """Write the descriptor file and all the disk descriptors"""
> + files = []
> + out = open(os.path.join(self.base, self.name + ".vmx"), "w")
> + out.write(self.to_vmx())
> + out.close()
> + files.append(self.name + ".vmx")
> +
> + for d in self.disks:
> + f = d.make_extent(self.base)
> + files.append(f)
> + out = open(os.path.join(base, d.descriptor), "w")
> + out.write(d._VMDK_TEMPLATE())
> + out.close()
> + files.append(d.descriptor)
> + return files
> +
> + def to_vmx(self):
> + """Return the VMX description of this image"""
> + # Strip blank spaces and EOL to prevent syntax errors in vmx file
> + self.descr = self.descr.strip()
> + self.descr = self.descr.replace("
","|")
> +
> + dict = {
> + "now": time.strftime("%Y-%m-%dT%H:%M:%S %Z", time.localtime()),
> + "progname": os.path.basename(sys.argv[0]),
> + "/image/name": self.name,
> + "/image/description": self.descr or "None",
> + "/image/label": self.label or self.name,
> + "/image/devices/vcpu" : self.vcpu,
> + "/image/devices/memory": long(self.memory)/1024
> + }
> +
> + vmx = _VMX_MAIN_TEMPLATE % dict
> + if self.interface:
> + vmx += _VMX_ETHER_TEMPLATE
> +
> + for d in self.disks:
> + vmx += d.to_vmx()
> +
> + return vmx
> +
> +def sub_ext(filename, ext):
> + return os.path.splitext(filename)[0] + ext
> +
> +_VMX_MAIN_TEMPLATE = """
> +#!/usr/bin/vmplayer
> +
> +# Generated %(now)s by %(progname)s
> +# http://virt-manager.et.redhat.com/
> +
> +# This is a Workstation 5 or 5.5 config file
> +# It can be used with Player
> +config.version = "8"
> +virtualHW.version = "4"
> +
> +# Selected operating system for your virtual machine
> +guestOS = "other"
> +
> +# displayName is your own name for the virtual machine
> +displayName = "%(/image/name)s"
> +
> +# These fields are free text description fields
> +annotation = "%(/image/description)s"
> +guestinfo.vmware.product.long = "%(/image/label)s"
> +guestinfo.vmware.product.url = "http://virt-manager.et.redhat.com/"
> +guestinfo.vmware.product.class = "virtual machine"
> +
> +# Number of virtual CPUs. Your virtual machine will not
> +# work if this number is higher than the number of your physical CPUs
> +numvcpus = "%(/image/devices/vcpu)s"
> +
> +# Memory size and other memory settings
> +memsize = "%(/image/devices/memory)d"
> +MemAllowAutoScaleDown = "FALSE"
> +MemTrimRate = "-1"
> +
> +# Unique ID for the virtual machine will be created
> +uuid.action = "create"
> +
> +## For appliances where tools are installed already, this should really
> +## be false, but we don't have that ionfo in the metadata
> +# Remind to install VMware Tools
> +# This setting has no effect in VMware Player
> +tools.remindInstall = "TRUE"
> +
> +# Startup hints interfers with automatic startup of a virtual machine
> +# This setting has no effect in VMware Player
> +hints.hideAll = "TRUE"
> +
> +# Enable time synchronization between computer
> +# and virtual machine
> +tools.syncTime = "TRUE"
> +
> +# First serial port, physical COM1 is not available
> +serial0.present = "FALSE"
> +
> +# Optional second serial port, physical COM2 is not available
> +serial1.present = "FALSE"
> +
> +# First parallell port, physical LPT1 is not available
> +parallel0.present = "FALSE"
> +
> +# Logging
> +# This config activates logging, and keeps last log
> +logging = "TRUE"
> +log.fileName = "%(/image/name)s.log"
> +log.append = "TRUE"
> +log.keepOld = "3"
> +
> +# These settings decides interaction between your
> +# computer and the virtual machine
> +isolation.tools.hgfs.disable = "FALSE"
> +isolation.tools.dnd.disable = "FALSE"
> +isolation.tools.copy.enable = "TRUE"
> +isolation.tools.paste.enabled = "TRUE"
> +
> +# Settings for physical floppy drive
> +floppy0.present = "FALSE"
> +"""
> +
> +_VMX_ETHER_TEMPLATE = """
> +## if /image/devices/interface is present:
> +# First network interface card
> +ethernet0.present = "TRUE"
> +ethernet0.connectionType = "nat"
> +ethernet0.addressType = "generated"
> +ethernet0.generatedAddressOffset = "0"
> +ethernet0.autoDetect = "TRUE"
> +"""
> +
> +_VMX_ISO_TEMPLATE = """
> +# CDROM drive
> +ide%(dev)s.present = "TRUE"
> +ide%(dev)s.deviceType = "cdrom-raw"
> +ide%(dev)s.startConnected = "TRUE"
> +ide%(dev)s.fileName = "%(disk_filename)s"
> +ide%(dev)s.autodetect = "TRUE"
> +"""
> +
> +_VMX_IDE_TEMPLATE = """
> +# IDE disk
> +ide%(dev)s.present = "TRUE"
> +ide%(dev)s.fileName = "%(disk_filename)s"
> +ide%(dev)s.mode = "persistent"
> +ide%(dev)s.startConnected = "TRUE"
> +ide%(dev)s.writeThrough = "TRUE"
> +"""
> diff -Naur virtinst--devel.orig/virt-pack virtinst--devel/virt-pack
> --- virtinst--devel.orig/virt-pack 1969-12-31 19:00:00.000000000 -0500
> +++ virtinst--devel/virt-pack 2008-06-10 15:28:36.000000000 -0400
> @@ -0,0 +1,143 @@
> +#!/usr/bin/python -tt
> +#
> +# Package and unpackage images for distribution
> +#
> +# Copyright 2007 Red Hat, Inc.
> +# David Lutterkort <dlutter@redhat.com>
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> +# MA 02110-1301 USA.
> +
> +import os, sys, string
> +from optparse import OptionParser, OptionValueError
> +import subprocess
> +import logging
> +import libxml2
> +import urlgrabber.progress as progress
> +
> +import virtinst
> +import virtinst.ImageParser
> +import virtinst.CapabilitiesParser
> +import virtinst.cli as cli
> +import virtinst.util as util
> +import virtinst.UnWare
> +
> +import tempfile
> +
> +import gettext
> +import locale
> +
> +locale.setlocale(locale.LC_ALL, ')
> +gettext.bindtextdomain(virtinst.gettext_app, virtinst.gettext_dir)
> +gettext.install(virtinst.gettext_app, virtinst.gettext_dir)
> +
> +class PackageException(Exception):
> + def __init__(self, msg):
> + Exception.__init__(self, msg)
> +
> +class Package:
> +
> + def __init__(self, image):
> + self.image = image
> + if image.name is None or image.version is None:
> + raise PackageException(
> + _("The image name and version must be present"))
> + self.vername = "%s-%s" % (image.name, image.version)
> + self.tmpdir = tempfile.mkdtemp(dir="/var/tmp", prefix="virt-pack")
> + self.stagedir = os.path.join(self.tmpdir, self.vername)
> + self.files = []
> +
> + def add_image_files(self):
> + cwd = os.getcwd()
> + img = self.image
> + self.files.append(os.path.basename(img.filename))
> + os.chdir(img.base)
> + for d in img.storage.keys():
> + disk = img.storage[d]
> + if disk.use == disk.USE_SCRATCH:
> + if disk.size is None:
> + raise PackageException(_("Scratch disk %s does not have a size attribute") % disk.id)
> + else:
> + if not os.path.exists(disk.file):
> + raise PackageException(_("Disk file %s could not be found") % disk.id)
> + self.files.append(disk.file)
> + os.path.exists(os.path.join(img.base, disk.file))
> +
> + def make_vmx_files(self):
> + img = virtinst.UnWare.Image(self.image)
> + files = img.make(self.image.base)
> + self.files.extend(files)
> +
> + def pack(self, outdir):
> + outfile = os.path.join(outdir, self.vername + ".tgz")
> + for f in set(self.files):
> + dir = os.path.join(self.stagedir, os.path.dirname(f))
> + if not os.path.exists(dir):
> + os.makedirs(dir)
> + os.symlink(os.path.join(self.image.base, f),
> + os.path.join(self.stagedir, f))
> + print _("Writing %s") % outfile
> + cmd = "tar chzv -C %s -f %s %s" % (self.tmpdir,
> + outfile,
> + os.path.basename(self.vername))
> + util.system(cmd)
> + return outfile
> +
> +### Option parsing
> +def parse_args():
> + parser = OptionParser()
> + parser.set_usage("%prog [options] image.xml")
> +
> + parser.add_option("-o", "--output", type="string", dest="output",
> + action="callback", callback=cli.check_before_store,
> + help=_("Directory in which packaged file will be put"))
> + parser.add_option("-d", "--debug", action="store_true", dest="debug",
> + help=_("Print debugging information"))
> +
> + (options,args) = parser.parse_args()
> + if len(args) < 1:
> + parser.error(_("You need to provide an image XML descriptor"))
> + options.image = args[0]
> +
> + return options
> +
> +def main():
> + options = parse_args()
> + cli.setupLogging("virt-pack", options.debug)
> + image = virtinst.ImageParser.parse_file(os.path.abspath(op tions.image))
> + if image.name is None or image.version is None:
> + print >> sys.stderr, _("The image descriptor must contain name and version")
> + valid = False
> +
> + if options.output is None:
> + options.output = os.path.join(image.base, "..")
> +
> + pkg = Package(image)
> + try:
> + pkg.add_image_files()
> + except PackageException, e:
> + print >> sys.stderr, _("Validation failed: %s"), e
> + return 1
> +
> + try:
> + pkg.make_vmx_files()
> + pkg.pack(options.output)
> + except PackageException, e:
> + print >> sys.stderr, _("Packaging failed: %s") % e
> + return 1
> +
> +if __name__ == "__main__":
> + main()
> +



_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

"Daniel P. Berrange" 06-13-2008 08:44 PM

virt-inst Package an image for VMware distribution
 
On Fri, Jun 13, 2008 at 04:36:28PM -0400, Cole Robinson wrote:
> Joey Boggs wrote:
> > Made more updates based on comments.
> >
>
> This version looks good to me. If Dan is fine with it as well i'll commit it.

Yes, this looks ok to me. Though I'd like to see a man page written
in POD format too....

Regards,
Daniel.
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools

Joey Boggs 06-16-2008 08:30 PM

virt-inst Package an image for VMware distribution
 
attached virt-pack documentation in pod format. If it's missing anything
please let me know.


Daniel P. Berrange wrote:

On Fri, Jun 13, 2008 at 04:36:28PM -0400, Cole Robinson wrote:


Joey Boggs wrote:


Made more updates based on comments.



This version looks good to me. If Dan is fine with it as well i'll commit it.



Yes, this looks ok to me. Though I'd like to see a man page written
in POD format too....

Regards,
Daniel.



_______________________________________________
et-mgmt-tools mailing list
et-mgmt-tools@redhat.com
https://www.redhat.com/mailman/listinfo/et-mgmt-tools


All times are GMT. The time now is 10:07 PM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.