[libvirt] [test-API][PATCH] Add dir volume wipe cases
by Wayne Sun
* add dir volume wipe and wipe pattern cases
* wipe case compare wiped volume with zero volume file with same
capacity
* wipe pattern cases support algorithms in:
zero|nnsa|dod|bsi|gutmann|schneier|pfitzner7|pfitzner33|random,
Besides zero, other algorithms are patterns supported by scrub,
some algorithm might fail due to scrub version.
* the check method in wipe pattern case for each algorithm is the
same, only to make sure digest before and after wipe is
different.
Signed-off-by: Wayne Sun <gsun(a)redhat.com>
---
cases/storage_dir_vol_wipe.conf | 132 ++++++++++++++++++++++++++++++++
repos/storage/dir_vol_wipe.py | 136 +++++++++++++++++++++++++++++++++
repos/storage/dir_vol_wipe_pattern.py | 123 +++++++++++++++++++++++++++++
3 files changed, 391 insertions(+), 0 deletions(-)
create mode 100644 cases/storage_dir_vol_wipe.conf
create mode 100644 repos/storage/dir_vol_wipe.py
create mode 100644 repos/storage/dir_vol_wipe_pattern.py
diff --git a/cases/storage_dir_vol_wipe.conf b/cases/storage_dir_vol_wipe.conf
new file mode 100644
index 0000000..aa39415
--- /dev/null
+++ b/cases/storage_dir_vol_wipe.conf
@@ -0,0 +1,132 @@
+storage:create_dir_pool
+ poolname
+ $defaultpoolname
+
+storage:dir_vol_wipe
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 2M
+ volformat
+ raw
+clean
+
+storage:dir_vol_wipe
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 50M
+ volformat
+ qcow2
+clean
+
+storage:dir_vol_wipe
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 30M
+ volformat
+ qed
+clean
+
+storage:dir_vol_wipe_pattern
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 2M
+ volformat
+ raw
+ algorithm
+ zero
+clean
+
+storage:dir_vol_wipe_pattern
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 50M
+ volformat
+ qcow2
+ algorithm
+ nnsa
+clean
+
+storage:dir_vol_wipe_pattern
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 30M
+ volformat
+ qed
+ algorithm
+ pfitzner7
+clean
+
+storage:dir_vol_wipe_pattern
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 1K
+ volformat
+ raw
+ algorithm
+ random
+clean
+
+storage:dir_vol_wipe_pattern
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 1K
+ volformat
+ raw
+ algorithm
+ dod
+clean
+
+storage:dir_vol_wipe_pattern
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 1K
+ volformat
+ raw
+ algorithm
+ bsi
+clean
+
+storage:dir_vol_wipe_pattern
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 1K
+ volformat
+ raw
+ algorithm
+ gutmann
+clean
+
+
+storage:destroy_pool
+ poolname
+ $defaultpoolname
diff --git a/repos/storage/dir_vol_wipe.py b/repos/storage/dir_vol_wipe.py
new file mode 100644
index 0000000..c020b43
--- /dev/null
+++ b/repos/storage/dir_vol_wipe.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+# volume wipe testing
+
+import os
+import string
+from xml.dom import minidom
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('poolname', 'volname', 'volformat', 'capacity',)
+optional_params = {'xml' : 'xmls/dir_volume.xml',
+ }
+
+def get_pool_path(poolobj):
+ """ get pool xml description
+ """
+ poolxml = poolobj.XMLDesc(0)
+
+ logger.debug("the xml description of pool is %s" % poolxml)
+
+ doc = minidom.parseString(poolxml)
+ path_element = doc.getElementsByTagName('path')[0]
+ textnode = path_element.childNodes[0]
+ path_value = textnode.data
+
+ return path_value
+
+def write_file(path, capacity):
+ """write test data to file
+ """
+ logger.info("write %s data into file %s" % (capacity, path))
+ out = utils.get_capacity_suffix_size(capacity)
+ f = open(path, 'w')
+ datastr = ''.join(string.lowercase + string.uppercase
+ + string.digits + '.' + '\n')
+ repeat = out['capacity_byte'] / 64
+ data = ''.join(repeat * datastr)
+ f.write(data)
+ f.close()
+
+def dir_vol_wipe(params):
+ """test volume download and check"""
+
+ global logger
+ logger = params['logger']
+ poolname = params['poolname']
+ volname = params['volname']
+ volformat = params['volformat']
+ capacity = params['capacity']
+ xmlstr = params['xml']
+
+ logger.info("the poolname is %s, volname is %s, volformat is %s" %
+ (poolname, volname, volformat))
+
+ conn = sharedmod.libvirtobj['conn']
+ try:
+ poolobj = conn.storagePoolLookupByName(poolname)
+ path_value = get_pool_path(poolobj)
+ volume_path = path_value + "/" + volname
+
+ xmlstr = xmlstr.replace('VOLPATH', volume_path)
+ xmlstr = xmlstr.replace('SUFFIX', capacity[-1])
+ xmlstr = xmlstr.replace('CAP', capacity[:-1])
+ logger.debug("volume xml:\n%s" % xmlstr)
+
+ logger.info("create %s %s volume" % (volname, volformat))
+ vol = poolobj.createXML(xmlstr, 0)
+
+ write_file(volume_path, capacity)
+
+ poolobj.refresh(0)
+
+ origdigest = utils.digest(volume_path, 0, 0)
+ logger.debug("the md5 hex digest of data read from %s is: %s" %
+ (volume_path, origdigest))
+
+ test_path = path_value + "/" + "vol_test"
+ out = utils.get_capacity_suffix_size(capacity)
+ count = out['capacity_byte'] / 1024
+ logger.info("write %s zero to test volume %s" % (capacity, test_path))
+ cmd = "dd if=/dev/zero of=%s bs=1024 count=%s" % (test_path, count)
+ utils.exec_cmd(cmd, shell=True)
+ cmpdigest = utils.digest(test_path, 0, 0)
+ logger.debug("the compare volume digest is: %s" % cmpdigest)
+
+ logger.info("wipe volume %s" % volume_path)
+ vol.wipe(0)
+
+ newdigest = utils.digest(volume_path, 0, 0)
+ logger.debug("the volum digest of data read from %s after wipe is: %s"
+ % (volume_path, newdigest))
+
+ logger.info("check the digest before and after wipe")
+ if newdigest == origdigest:
+ logger.error("wipe failed, digest did not change")
+ return 1
+ else:
+ logger.info("digest is different before and after wipe")
+
+ logger.info("compare the digest after wipe with digest of volume %s" %
+ test_path)
+ if not newdigest == cmpdigest:
+ logger.error("wipe failed, digest is different")
+ return 1
+ else:
+ logger.info("digest is same with zero volume %s" % test_path)
+
+ logger.info("wipe succeed")
+
+ except libvirtError, e:
+ logger.error("libvirt call failed: " + str(e))
+ return 1
+
+ return 0
+
+def dir_vol_wipe_clean(params):
+ """clean testing environment"""
+ poolname = params['poolname']
+ volname = params['volname']
+
+ conn = sharedmod.libvirtobj['conn']
+ poolobj = conn.storagePoolLookupByName(poolname)
+ path_value = get_pool_path(poolobj)
+ test_path = path_value + "/" + "vol_test"
+
+ vol = poolobj.storageVolLookupByName(volname)
+ vol.delete(0)
+
+ if os.path.exists(test_path):
+ os.unlink(test_path)
+
+ return 0
diff --git a/repos/storage/dir_vol_wipe_pattern.py b/repos/storage/dir_vol_wipe_pattern.py
new file mode 100644
index 0000000..86e3ea2
--- /dev/null
+++ b/repos/storage/dir_vol_wipe_pattern.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+# volume wipe with pattern testing, the supported algorithm are
+# zero and algorithm patterns supported by 'scrub' command which
+# are nnsa|dod|bsi|gutmann|schneier|pfitzner7|pfitzner33|random
+
+import os
+import string
+from xml.dom import minidom
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('poolname', 'volname', 'volformat', 'capacity', 'algorithm',)
+optional_params = {'xml' : 'xmls/dir_volume.xml',
+ }
+
+def get_pool_path(poolobj):
+ """ get pool xml description
+ """
+ poolxml = poolobj.XMLDesc(0)
+
+ logger.debug("the xml description of pool is %s" % poolxml)
+
+ doc = minidom.parseString(poolxml)
+ path_element = doc.getElementsByTagName('path')[0]
+ textnode = path_element.childNodes[0]
+ path_value = textnode.data
+
+ return path_value
+
+def write_file(path, capacity):
+ """write test data to file
+ """
+ logger.info("write %s data into file %s" % (capacity, path))
+ out = utils.get_capacity_suffix_size(capacity)
+ f = open(path, 'w')
+ datastr = ''.join(string.lowercase + string.uppercase
+ + string.digits + '.' + '\n')
+ repeat = out['capacity_byte'] / 64
+ data = ''.join(repeat * datastr)
+ f.write(data)
+ f.close()
+
+def dir_vol_wipe_pattern(params):
+ """test volume download and check"""
+
+ global logger
+ logger = params['logger']
+ poolname = params['poolname']
+ volname = params['volname']
+ volformat = params['volformat']
+ capacity = params['capacity']
+ algorithm = params['algorithm']
+ xmlstr = params['xml']
+
+ logger.info("the poolname is %s, volname is %s, volformat is %s" %
+ (poolname, volname, volformat))
+
+ logger.info("the wipe algorithm given is %s" % algorithm)
+ alg_str = 'libvirt.VIR_STORAGE_VOL_WIPE_ALG_%s' % algorithm.upper()
+ alg_val = eval(alg_str)
+ logger.info("the correspond algorithm value is %s" % alg_val)
+
+ conn = sharedmod.libvirtobj['conn']
+ try:
+ poolobj = conn.storagePoolLookupByName(poolname)
+ path_value = get_pool_path(poolobj)
+ volume_path = path_value + "/" + volname
+
+ xmlstr = xmlstr.replace('VOLPATH', volume_path)
+ xmlstr = xmlstr.replace('SUFFIX', capacity[-1])
+ xmlstr = xmlstr.replace('CAP', capacity[:-1])
+ logger.debug("volume xml:\n%s" % xmlstr)
+
+ logger.info("create %s %s volume" % (volname, volformat))
+ vol = poolobj.createXML(xmlstr, 0)
+
+ write_file(volume_path, capacity)
+
+ poolobj.refresh(0)
+
+ origdigest = utils.digest(volume_path, 0, 0)
+ logger.debug("the md5 hex digest of data read from %s is: %s" %
+ (volume_path, origdigest))
+
+ logger.info("wipe volume %s with algorithm value %s" %
+ (volume_path, alg_val))
+ vol.wipePattern(alg_val, 0)
+
+ newdigest = utils.digest(volume_path, 0, 0)
+ logger.debug("the volum digest of data read from %s after wipe is: %s"
+ % (volume_path, newdigest))
+
+ logger.info("check the digest before and after wipe")
+ if newdigest == origdigest:
+ logger.error("wipe with algorithm %s failed, digest is the same"
+ % algorithm)
+ return 1
+ else:
+ logger.info("digest is different before and after wipe")
+
+ logger.info("wipe with algorithm %s succeed" % algorithm)
+
+ except libvirtError, e:
+ logger.error("libvirt call failed: " + str(e))
+ return 1
+
+ return 0
+
+def dir_vol_wipe_pattern_clean(params):
+ """clean testing environment"""
+ poolname = params['poolname']
+ volname = params['volname']
+
+ conn = sharedmod.libvirtobj['conn']
+ poolobj = conn.storagePoolLookupByName(poolname)
+ vol = poolobj.storageVolLookupByName(volname)
+ vol.delete(0)
+
+ return 0
--
1.7.1
11 years, 11 months
[libvirt] [test-API][PATCH v2] Add volume upload and download cases
by Wayne Sun
The cases only cover dir volume testing.
v1:
* test download storage volumes using storage download API.
* test upload storage volumes using storage upload API.
For upload case, only raw volume format is supported, other
format will fail.
The offset and length value should be chosen from 0 and
1048576, because upload size is set as 1M.
* both case use blocking stream.
* sample conf is added.
v2:
* move digest function to utils
* rename cases with prefix 'dir_' to emphasise that they are
only for dir vol testing
Signed-off-by: Wayne Sun <gsun(a)redhat.com>
---
cases/storage_dir_vol_upload_download.conf | 127 ++++++++++++++++++++++
repos/storage/dir_vol_download.py | 131 +++++++++++++++++++++++
repos/storage/dir_vol_upload.py | 158 ++++++++++++++++++++++++++++
utils/utils.py | 24 ++++
4 files changed, 440 insertions(+), 0 deletions(-)
create mode 100644 cases/storage_dir_vol_upload_download.conf
create mode 100644 repos/storage/dir_vol_download.py
create mode 100644 repos/storage/dir_vol_upload.py
diff --git a/cases/storage_dir_vol_upload_download.conf b/cases/storage_dir_vol_upload_download.conf
new file mode 100644
index 0000000..fd22720
--- /dev/null
+++ b/cases/storage_dir_vol_upload_download.conf
@@ -0,0 +1,127 @@
+storage:create_dir_pool
+ poolname
+ $defaultpoolname
+
+storage:dir_vol_upload
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 10M
+ volformat
+ raw
+ offset
+ 0
+ length
+ 0
+clean
+
+storage:dir_vol_upload
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 10M
+ volformat
+ raw
+ offset
+ 1048576
+ length
+ 0
+clean
+
+storage:dir_vol_upload
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 10M
+ volformat
+ raw
+ offset
+ 0
+ length
+ 1048576
+clean
+
+storage:dir_vol_upload
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 10M
+ volformat
+ raw
+ offset
+ 1048576
+ length
+ 1048576
+clean
+
+storage:dir_vol_download
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 50M
+ volformat
+ raw
+ offset
+ 0
+ length
+ 0
+clean
+
+storage:dir_vol_download
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 50M
+ volformat
+ qcow2
+ offset
+ 1048576
+ length
+ 0
+clean
+
+storage:dir_vol_download
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 50M
+ volformat
+ qed
+ offset
+ 0
+ length
+ 1048576
+clean
+
+storage:dir_vol_download
+ poolname
+ $defaultpoolname
+ volname
+ $defaultvolumename
+ capacity
+ 50M
+ volformat
+ raw
+ offset
+ 1048576
+ length
+ 1048576
+clean
+
+storage:destroy_pool
+ poolname
+ $defaultpoolname
diff --git a/repos/storage/dir_vol_download.py b/repos/storage/dir_vol_download.py
new file mode 100644
index 0000000..ddf293b
--- /dev/null
+++ b/repos/storage/dir_vol_download.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+# dir storage volume download testing
+
+import os
+import string
+from xml.dom import minidom
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('poolname', 'volname', 'volformat', 'capacity', 'offset',
+ 'length',)
+optional_params = {'xml' : 'xmls/dir_volume.xml',
+ }
+
+def get_pool_path(poolobj):
+ """ get pool xml description
+ """
+ poolxml = poolobj.XMLDesc(0)
+
+ logger.debug("the xml description of pool is %s" % poolxml)
+
+ doc = minidom.parseString(poolxml)
+ path_element = doc.getElementsByTagName('path')[0]
+ textnode = path_element.childNodes[0]
+ path_value = textnode.data
+
+ return path_value
+
+def write_file(path, capacity):
+ """write test data to file
+ """
+ logger.info("write %s data into file %s" % (capacity, path))
+ out = utils.get_capacity_suffix_size(capacity)
+ f = open(path, 'w')
+ datastr = ''.join(string.lowercase + string.uppercase
+ + string.digits + '.' + '\n')
+ repeat = out['capacity_byte'] / 64
+ data = ''.join(repeat * datastr)
+ f.write(data)
+ f.close()
+
+def handler(stream, data, file_):
+ return file_.write(data)
+
+def dir_vol_download(params):
+ """test volume download and check"""
+
+ global logger
+ logger = params['logger']
+ poolname = params['poolname']
+ volname = params['volname']
+ volformat = params['volformat']
+ offset = int(params['offset'])
+ length = int(params['length'])
+ capacity = params['capacity']
+ xmlstr = params['xml']
+
+ logger.info("the poolname is %s, volname is %s, volformat is %s" %
+ (poolname, volname, volformat))
+ logger.info("download offset is: %s" % offset)
+ logger.info("the data length to download is: %s" % length)
+
+ conn = sharedmod.libvirtobj['conn']
+ try:
+ poolobj = conn.storagePoolLookupByName(poolname)
+ path_value = get_pool_path(poolobj)
+ volume_path = path_value + "/" + volname
+
+ xmlstr = xmlstr.replace('VOLPATH', volume_path)
+ xmlstr = xmlstr.replace('SUFFIX', capacity[-1])
+ xmlstr = xmlstr.replace('CAP', capacity[:-1])
+ logger.debug("volume xml:\n%s" % xmlstr)
+
+ logger.info("create %s %s volume" % (volname, volformat))
+ vol = poolobj.createXML(xmlstr, 0)
+
+ write_file(volume_path, capacity)
+ origdigest = utils.digest(volume_path, offset, length)
+ logger.debug("the md5 hex digest of data read from %s is: %s" %
+ (volume_path, origdigest))
+
+ st = conn.newStream(0)
+
+ test_path = path_value + "/" + "vol_test"
+
+ f = open(test_path, 'w')
+ logger.info("start download")
+ vol.download(st, offset, length, 0)
+ logger.info("downloaded all data")
+ st.recvAll(handler, f)
+ logger.info("finished stream")
+ st.finish()
+ f.close()
+
+ newdigest = utils.digest(test_path, 0, 0)
+ logger.debug("the md5 hex digest of data read from %s is: %s" %
+ (test_path, newdigest))
+
+ if origdigest == newdigest:
+ logger.info("file digests match, download succeed")
+ else:
+ logger.error("file digests not match, download failed")
+ return 1
+
+ except libvirtError, e:
+ logger.error("libvirt call failed: " + str(e))
+ return 1
+
+ return 0
+
+def dir_vol_download_clean(params):
+ """clean testing environment"""
+ poolname = params['poolname']
+ volname = params['volname']
+
+ conn = sharedmod.libvirtobj['conn']
+ poolobj = conn.storagePoolLookupByName(poolname)
+ path_value = get_pool_path(poolobj)
+ test_path = path_value + "/" + "vol_test"
+
+ vol = poolobj.storageVolLookupByName(volname)
+ vol.delete(0)
+
+ if os.path.exists(test_path):
+ os.unlink(test_path)
+
+ return 0
diff --git a/repos/storage/dir_vol_upload.py b/repos/storage/dir_vol_upload.py
new file mode 100644
index 0000000..78188e9
--- /dev/null
+++ b/repos/storage/dir_vol_upload.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+# dir storage volume upload testing, only raw format volume is
+# supported, other format might fail. offset and length can
+# only be chosen in 0 and 1048576.
+
+import os
+import string
+from xml.dom import minidom
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('poolname', 'volname', 'volformat', 'capacity',
+ 'offset', 'length',)
+optional_params = {'xml' : 'xmls/dir_volume.xml',
+ }
+
+def get_pool_path(poolobj):
+ """ get pool xml description
+ """
+ poolxml = poolobj.XMLDesc(0)
+
+ logger.debug("the xml description of pool is %s" % poolxml)
+
+ doc = minidom.parseString(poolxml)
+ path_element = doc.getElementsByTagName('path')[0]
+ textnode = path_element.childNodes[0]
+ path_value = textnode.data
+
+ return path_value
+
+def write_file(path):
+ """write 1M test data to file
+ """
+ logger.info("write data into file %s" % path)
+ f = open(path, 'w')
+ datastr = ''.join(string.lowercase + string.uppercase
+ + string.digits + '.' + '\n')
+ data = ''.join(16384 * datastr)
+ f.write(data)
+ f.close()
+
+def handler(stream, data, file_):
+ return file_.read(data)
+
+def dir_vol_upload(params):
+ """test volume download and check"""
+
+ global logger
+ logger = params['logger']
+ poolname = params['poolname']
+ volname = params['volname']
+ volformat = params['volformat']
+ offset = int(params['offset'])
+ length = int(params['length'])
+ capacity = params['capacity']
+ xmlstr = params['xml']
+
+ logger.info("the poolname is %s, volname is %s, volformat is %s" %
+ (poolname, volname, volformat))
+ logger.info("upload offset is: %s" % offset)
+ logger.info("the data length to upload is: %s" % length)
+
+ conn = sharedmod.libvirtobj['conn']
+ try:
+ poolobj = conn.storagePoolLookupByName(poolname)
+ path_value = get_pool_path(poolobj)
+ volume_path = path_value + "/" + volname
+
+ xmlstr = xmlstr.replace('VOLPATH', volume_path)
+ xmlstr = xmlstr.replace('SUFFIX', capacity[-1])
+ xmlstr = xmlstr.replace('CAP', capacity[:-1])
+ logger.debug("volume xml:\n%s" % xmlstr)
+
+ logger.info("create %s %s volume" % (volname, volformat))
+ vol = poolobj.createXML(xmlstr, 0)
+
+ test_path = path_value + "/" + "vol_test"
+ write_file(test_path)
+ olddigest = utils.digest(test_path, 0, 0)
+ logger.debug("the old file digest is: %s" % olddigest)
+
+ if offset:
+ origdigestpre = utils.digest(volume_path, 0, offset)
+ else:
+ origdigestpre = ''
+ logger.debug("the original pre region digest is: %s" % origdigestpre)
+
+ origdigestpost = utils.digest(volume_path, offset + 1024 * 1024, 0)
+ logger.debug("the original post region digest is: %s" % origdigestpost)
+
+ st = conn.newStream(0)
+
+ f = open(test_path, 'r')
+ logger.info("start upload")
+ vol.upload(st, offset, length, 0)
+ logger.info("sent all data")
+ st.sendAll(handler, f)
+ logger.info("finished stream")
+ st.finish()
+ f.close()
+
+ newdigest = utils.digest(volume_path, offset, 1024 * 1024)
+ logger.debug("the new file digest is: %s" % olddigest)
+
+ if offset:
+ newdigestpre = utils.digest(volume_path, 0, offset)
+ else:
+ newdigestpre = ''
+ logger.debug("the new pre region digest is: %s" % origdigestpre)
+
+ newdigestpost = utils.digest(volume_path, offset + 1024 * 1024, 0)
+ logger.debug("the new post region digest is: %s" % origdigestpost)
+
+ if newdigestpre == origdigestpre:
+ logger.info("file pre region digests match")
+ else:
+ logger.error("file pre region digests not match")
+ return 1
+
+ if olddigest == newdigest:
+ logger.info("file digests match")
+ else:
+ logger.error("file digests not match")
+ return 1
+
+ if newdigestpost == origdigestpost:
+ logger.info("file post region digests match")
+ else:
+ logger.error("file post region digests not match")
+ return 1
+
+ except libvirtError, e:
+ logger.error("libvirt call failed: " + str(e))
+ return 1
+
+ return 0
+
+def dir_vol_upload_clean(params):
+ """clean testing environment"""
+ poolname = params['poolname']
+ volname = params['volname']
+
+ conn = sharedmod.libvirtobj['conn']
+ poolobj = conn.storagePoolLookupByName(poolname)
+ path_value = get_pool_path(poolobj)
+ test_path = path_value + "/" + "vol_test"
+
+ vol = poolobj.storageVolLookupByName(volname)
+ vol.delete(0)
+
+ if os.path.exists(test_path):
+ os.unlink(test_path)
+
+ return 0
diff --git a/utils/utils.py b/utils/utils.py
index 1ed673a..d3b0dc1 100644
--- a/utils/utils.py
+++ b/utils/utils.py
@@ -29,6 +29,7 @@ import struct
import pexpect
import string
import subprocess
+import hashlib
import libvirt
from xml.dom import minidom
from urlparse import urlparse
@@ -725,6 +726,29 @@ def param_to_tuple(paramlist, length):
else:
return False
+def digest(path, offset, length):
+ """read data from file with length bytes, begin at offset
+ and return md5 hexdigest
+ """
+ f = open(path, 'r')
+ f.seek(offset)
+ m = hashlib.md5()
+ done = 0
+
+ while True:
+ want = 1024
+ if length and length - done < want:
+ want = length - done
+ outstr = f.read(want)
+ got = len(outstr)
+ if got == 0:
+ break
+ done += got
+ m.update(outstr)
+
+ f.close()
+ return m.hexdigest()
+
def run_wget_app(hostname, username, password, file_url, logger):
"""Simple test for wget app on specified host"""
cmd_line = "wget -P /tmp %s -o /tmp/wget.log" % (file_url)
--
1.7.1
11 years, 11 months
[libvirt] [PATCH 0/2] Add virsh commands to modify cpu node and model node of a domain XML
by Ken ICHIKAWA
From: Ken ICHIKAWA <ichikawa.ken(a)jp.fujitsu.com>
This patchset adds two virsh commands, "confcpu" and "confcpu-model".
"confcpu" allows to modify 'mode' attirbute and 'match' attribute of
a cpu node of a domain XML.
"confcpu-model" allows to modify cpu model, 'fallback' attribute and
'vendor_id' attribute of a model node of a domain XML.
By using these commands, we can easily change cpu mode, model and etc. by
hand or shellscript without editing XML.
Ken ICHIKAWA (2):
virsh: Add a new command "confcpu"
virsh: Add a new command "confcpu-model"
tools/virsh-domain.c | 411 +++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 51 +++++++
2 files changed, 462 insertions(+)
--
1.7.11.7
11 years, 11 months
[libvirt] [PATCH 5/5] virsh: Command to define new domain using OVA package.
by Ata E Husain Bohra
This patch provides virsh commands to support defining
new domain using an OVA package.
---
tools/virsh-domain.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index f3da1d5..5218d12 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -5594,11 +5594,25 @@ static const vshCmdInfo info_define[] = {
{NULL, NULL}
};
+static const vshCmdInfo info_define_ova[] = {
+ {"help", N_("define (but don't start) a domain from an OVA package")},
+ {"desc", N_("Define a domain.")},
+ {NULL, NULL}
+};
+
static const vshCmdOptDef opts_define[] = {
{"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML domain description")},
{NULL, 0, 0, NULL}
};
+static const vshCmdOptDef opts_define_ova[] = {
+ {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
+ N_("ova package file")},
+ {"pool", VSH_OT_STRING, VSH_OFLAG_REQ_OPT,
+ N_("storage pool to define new domain")},
+ {NULL, 0, 0, NULL}
+};
+
static bool
cmdDefine(vshControl *ctl, const vshCmd *cmd)
{
@@ -5627,6 +5641,35 @@ cmdDefine(vshControl *ctl, const vshCmd *cmd)
return ret;
}
+static bool
+cmdDefineOVA(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom;
+ const char *file = NULL;
+ const char *pool = NULL;
+ bool ret = true;
+
+ if (vshCommandOptString(cmd, "file", &file) <= 0)
+ return false;
+
+ if (vshCommandOptString(cmd, "pool", &pool) <= 0)
+ return false;
+
+ dom = virDomainDefineOVA(ctl->conn, file, pool);
+ VIR_FREE(file);
+ VIR_FREE(pool);
+
+ if (dom != NULL) {
+ vshPrint(ctl, _("Domain %s defined from %s\n"),
+ virDomainGetName(dom), file);
+ virDomainFree(dom);
+ } else {
+ vshError(ctl, _("Failed to define domain from %s"), file);
+ ret = false;
+ }
+ return ret;
+}
+
/*
* "destroy" command
*/
@@ -8515,6 +8558,7 @@ const vshCmdDef domManagementCmds[] = {
{"cpu-stats", cmdCPUStats, opts_cpu_stats, info_cpu_stats, 0},
{"create", cmdCreate, opts_create, info_create, 0},
{"define", cmdDefine, opts_define, info_define, 0},
+ {"define-ova", cmdDefineOVA, opts_define_ova, info_define_ova, 0},
{"desc", cmdDesc, opts_desc, info_desc, 0},
{"destroy", cmdDestroy, opts_destroy, info_destroy, 0},
{"detach-device", cmdDetachDevice, opts_detach_device,
--
1.7.9.5
11 years, 11 months
[libvirt] [PATCH 4/5] ESX: Driver support to define new domain using an OVA pacakge
by Ata E Husain Bohra
This patch provides implementation support to define new domain
using given OVA package for an ESXi server.
As per vSphere API documentation, the OVA installation consists of
following steps:
1. Run OVF descriptor against hypervisor to check if it can be
deployed.
2. Obtain ImportSpec object from hypervisor defining new domain's
specifications such as: virtual hrdware detials, networks etc.
3. Create virtual machine entity on the hypervisor.
4. Upload virtual disk contained inside OVA package using lease
obtained from step 3.
---
src/esx/esx_driver.c | 573 ++++++++++++++++++++++++++-
src/esx/esx_vi_generator.input | 856 +++++++++++++++++++++++++++++++++++++++-
src/esx/esx_vi_generator.py | 13 +-
src/esx/esx_vi_types.c | 13 +-
4 files changed, 1430 insertions(+), 25 deletions(-)
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 1366c81..d4f4ce4 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -5,6 +5,7 @@
* Copyright (C) 2010-2012 Red Hat, Inc.
* Copyright (C) 2009-2012 Matthias Bolte <matthias.bolte(a)googlemail.com>
* Copyright (C) 2009 Maximilian Wilhelm <max(a)rfc2324.org>
+ * Copyright (C) 2013 Ata E Husain Bohra <ata.husain(a)hotmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@
#include "viralloc.h"
#include "virlog.h"
#include "viruuid.h"
+#include "virfile.h"
#include "vmx.h"
#include "virtypedparam.h"
#include "esx_driver.h"
@@ -46,10 +48,16 @@
#include "esx_vi_methods.h"
#include "esx_util.h"
#include "viruri.h"
+#include "virova.h"
#define VIR_FROM_THIS VIR_FROM_ESX
+
static int esxDomainGetMaxVcpus(virDomainPtr domain);
+static int esxDomainUploadDisks(virConnectPtr conn,
+ esxVI_ManagedObjectReference *nfcLease,
+ esxVI_OvfCreateImportSpecResult *importResult,
+ virOVAPtr ova);
typedef struct _esxVMX_Data esxVMX_Data;
@@ -59,7 +67,6 @@ struct _esxVMX_Data {
};
-
static void
esxFreePrivate(esxPrivate **priv)
{
@@ -3304,6 +3311,569 @@ esxDomainDefineXML(virConnectPtr conn, const char *xml)
static int
+esxDomainUploadDisks(virConnectPtr conn,
+ esxVI_ManagedObjectReference *nfcLease,
+ esxVI_OvfCreateImportSpecResult *importResult,
+ virOVAPtr ova)
+{
+ int result = -1;
+ esxPrivate* priv = conn->privateData;
+ esxVI_Context *ctx = priv->primary;
+ esxVI_String *propertyNameInfo = NULL;
+ esxVI_DynamicProperty *dynamicProperty = NULL;
+ esxVI_ObjectContent *infoObject = NULL;
+ esxVI_HttpNfcLeaseInfo *httpNfcInfo = NULL;
+ esxVI_HttpNfcLeaseDeviceUrl *deviceUrl = NULL;
+ esxVI_FileData *fileData = NULL;
+ esxVI_CURL *curl = NULL;
+ virBuffer buffer = VIR_BUFFER_INITIALIZER;
+ virOVADiskListPtr listDisk = NULL;
+ bool ready = false;
+ char *uploadUrl = NULL;
+ char *fileExtension = NULL;
+ off_t bytesToSend = 0;
+ int numAttempts = 0;
+ char cl_string[64] = {'\0'};
+ int fd = -1;
+
+ if (!ova || !ova->fHandle) {
+ goto cleanup;
+ }
+
+ /**
+ * obtain file handle for OVA file, it is better to re-open
+ * file while uploading given disk. Cleanup for esxVI_FileData and
+ * virFreeOVA remains simple and clean this way
+ */
+ fd = fileno(ova->fHandle);
+ if (fd <= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Invalid fielno for OVA file"));
+ goto cleanup;
+ }
+
+ if (esxVI_String_AppendValueListToList(&propertyNameInfo,
+ "info\0state\0error\0") < 0) {
+ return -1;
+ }
+
+ if (esxVI_CURL_Alloc(&curl) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /**
+ * CURL headers for streaming vmdk are different from normal
+ * execution headers, open a dedicated curl->handle to upload
+ * VMDKs
+ */
+ curl->handle = curl_easy_init();
+ if (!curl->handle) {
+ fprintf(stderr, "curl init failed");
+ goto cleanup;
+ }
+
+ /**
+ * vSphere API recommends wait till ESX sets the status to
+ * "ready" before initiating disk transfer. Wait for max
+ * 10 seconds before giving up!
+ *
+ * TODO May be convert it to WaitForUpdate call */
+ for (ready = false, numAttempts = 0;
+ ready != true && numAttempts < 10; ++numAttempts) {
+ esxVI_ObjectContent_Free(&infoObject);
+
+ if (esxVI_LookupObjectContentByType(ctx, nfcLease,
+ "HttpNfcLease", propertyNameInfo,
+ &infoObject, esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ for (dynamicProperty = infoObject->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "state")) {
+ if (STREQ(dynamicProperty->val->value, "initializing")) {
+ /* check after sometime */
+ sleep(1);
+ } else {
+ ready = true;
+ }
+ } else if (STREQ(dynamicProperty->name, "error")) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ dynamicProperty->val->value);
+ goto cleanup;
+ }
+ }
+ }
+
+ if (!ready) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("ESX server not ready for disk upload"));
+ goto cleanup;
+ }
+
+ /**
+ * Better to retrieve "info" object again once the ESX server
+ * is "ready"
+ */
+ esxVI_String_Free(&propertyNameInfo);
+ esxVI_ObjectContent_Free(&infoObject);
+ if (esxVI_String_AppendValueListToList(
+ &propertyNameInfo, "info\0") < 0 ||
+ esxVI_LookupObjectContentByType(
+ ctx, nfcLease, "HttpNfcLease", propertyNameInfo,
+ &infoObject, esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+ for (dynamicProperty = infoObject->propSet; dynamicProperty != NULL;
+ dynamicProperty = dynamicProperty->_next) {
+ if (STREQ(dynamicProperty->name, "info")) {
+ if (esxVI_HttpNfcLeaseInfo_CastFromAnyType(
+ dynamicProperty->val, &httpNfcInfo) < 0) {
+ goto cleanup;
+ }
+ }
+ }
+
+ bytesToSend = ova->totalSize;
+ for (listDisk = ova->head; listDisk != NULL; listDisk = listDisk->next) {
+ fileExtension = strrchr(listDisk->data->name, '.');
+ if (!fileExtension || STRNEQ(fileExtension, ".vmdk")) {
+ /* not a VMDK */
+ continue ;
+ }
+
+ /* iterate over deviceUri and upload VMDK files from OVA */
+ for (deviceUrl = httpNfcInfo->deviceUrl;
+ deviceUrl != NULL; deviceUrl = deviceUrl->_next) {
+ virOVADiskListPtr candidate = NULL;
+ esxVI_OvfFileItem *fileItem = NULL;
+ int position = -1;
+ char *ptr_char = NULL;
+
+ /* ESXi HttpLeaseInfo object when returned have "url"(s) to be
+ * used to upload VMDK files. The format of the url is
+ * https://\\*\\/<session-id>/<vmdk-file-name>
+ * Replaces the "\\*" with approriate server IP address.
+ */
+
+ VIR_FREE(uploadUrl);
+ virBufferFreeAndReset(&buffer);
+
+ if (!deviceUrl->url) {
+ goto cleanup;
+ }
+
+ position = strcspn(deviceUrl->url, "*");
+ if (position <= 0) {
+ goto cleanup;
+ }
+
+ virBufferAdd(&buffer, deviceUrl->url, position);
+
+ ptr_char = strchr(deviceUrl->url, '*');
+ if (ptr_char == NULL) {
+ goto cleanup;
+ }
+
+ virBufferStrcat(&buffer, ctx->ipAddress, NULL);
+ virBufferStrcat(&buffer, ptr_char + 1, NULL);
+ uploadUrl = virBufferContentAndReset(&buffer);
+
+ /* iterate virOVA struct to find relevant file details */
+ for (fileItem = importResult->fileItem;
+ fileItem != NULL; fileItem = fileItem->_next) {
+ if (STREQ(deviceUrl->importKey, fileItem->deviceId)) {
+ break;
+ }
+ }
+
+ if (!fileItem || !fileItem->path) {
+ goto cleanup;
+ }
+
+ candidate = ova->head;
+ for (; candidate != NULL; candidate = candidate->next) {
+ if (STREQ(candidate->data->name, fileItem->path)) {
+
+ esxVI_FileData_Free(&fileData);
+ if (esxVI_FileData_Alloc(&fileData) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ fileData->fHandle = VIR_FDOPEN(fd, "r");
+ if (!fileData->fHandle) {
+ goto cleanup;
+ }
+
+ /* Seek the file to the proper offset */
+ if (fseeko(fileData->fHandle, candidate->data->offset,
+ SEEK_SET) < 0) {
+ goto cleanup;
+ }
+
+ fileData->ctx = ctx;
+ fileData->lease = nfcLease;
+ fileData->cur_size = candidate->data->size;
+ fileData->time_elapsed = time(NULL);
+ fileData->total_size = bytesToSend;
+ fileData->type = OVA_DISK;
+
+ if (curl->headers) {
+ curl_slist_free_all(curl->headers);
+ }
+
+ /**
+ * Prepare the header to reflect the vmware-vdisk
+ * stream with proper size sever should expect
+ */
+ curl->headers = curl_slist_append(curl->headers,
+ "Connection: Keep-Alive");
+ curl->headers = curl_slist_append(curl->headers,
+ "Content-Type: application/x-vnd.vmware-streamVmdk");
+
+ memset(cl_string, '\0', sizeof(cl_string));
+ snprintf(cl_string, sizeof(cl_string),
+ "Content-Length: %ld", fileData->cur_size);
+ curl->headers = curl_slist_append(curl->headers, cl_string);
+
+ if (curl->headers == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Could not build CURL header list"));
+ goto cleanup;
+ }
+
+ curl_easy_setopt(
+ curl->handle, CURLOPT_HTTPHEADER , curl->headers);
+ curl_easy_setopt(curl->handle, CURLOPT_SSL_VERIFYPEER, false);
+ curl_easy_setopt(curl->handle, CURLOPT_SSL_VERIFYHOST, false);
+
+
+ if (esxVI_CURL_FileUpload(curl, uploadUrl,
+ fileData) < 0) {
+ goto cleanup;
+ }
+
+ bytesToSend -= candidate->data->size;
+ }
+ }
+ }
+ }
+
+ result = 0;
+
+cleanup:
+
+ esxVI_String_Free(&propertyNameInfo);
+ esxVI_ObjectContent_Free(&infoObject);
+ esxVI_HttpNfcLeaseInfo_Free(&httpNfcInfo);
+ esxVI_FileData_Free(&fileData);
+ esxVI_CURL_Free(&curl);
+ virBufferFreeAndReset(&buffer);
+ VIR_FREE(uploadUrl);
+
+ return result;
+
+}
+
+
+
+static virDomainPtr
+esxDomainDefineOVA(virConnectPtr conn, const char *ovaPath,
+ const char *datastoreName)
+{
+ virDomainPtr domain = NULL;
+ virOVAPtr ova = NULL;
+ esxPrivate* priv = conn->interfacePrivateData;
+ esxVI_Context *ctx = priv->primary;
+ esxVI_OvfParseDescriptorParams *pdp = NULL;
+ esxVI_OvfParseDescriptorResult *pdResult = NULL;
+ esxVI_OvfCreateImportSpecParams *cisp = NULL;
+ esxVI_ObjectContent *datastore = NULL;
+ esxVI_OvfCreateImportSpecResult *importResult = NULL;
+ esxVI_ManagedObjectReference *nfcLease = NULL;
+ esxVI_ManagedObjectReference *ovfManager = NULL;
+ char *ovfDescriptor = NULL;
+ char *escapedOvfDescriptor = NULL;
+ char *domainName = NULL;
+ struct curl_slist *headers = NULL;
+ const struct curl_slist *old_headers = NULL;
+
+ if (esxVI_EnsureSession(priv->primary) < 0 ||
+ virParseOVA(ovaPath, &ova) < 0) {
+ goto cleanup;
+ }
+
+ /**
+ * FIXME: vSphere API v2.5 does expose all relevant information
+ * needed by ESXi servers suporting vSphere API version 4.0
+ * or above. As per API version 4.0, the connection header
+ * or execution CURL header should include:
+ * "SOAPACTION: urn:vim25"
+ * header field, otherwise, ServiceContent object is not
+ * fully populated and miss references to MoBs such as:
+ * ovfManager. Also, this namespace is necessary to expose
+ * API methods such as: ParseDescriptor, CreateImportSpec
+ * and ImportVApp.
+ *
+ * But, adding this header item in esxVI_XXX initial functions has
+ * various bad affects:
+ * 1. Ordering of other MoB deserialization is affected that breaks
+ * existing code (this one is big risk)
+ * 2. Namespace add extra fields that may cause warning messages
+ * (this one is benign though)
+ *
+ * To avoid breaking existing API calls, modify CURL headers in this
+ * routine to include "SOAPACTION" field.
+ */
+ if (ctx->service->ovfManager == NULL) {
+
+ headers = curl_slist_append(headers,
+ "Content-Type: text/xml; charset=UTF-8");
+ headers = curl_slist_append(headers, "Expect:");
+ headers = curl_slist_append(headers,
+ "SOAPAction: \"urn:vim25\"");
+ if (headers == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Could not build CURL header list"));
+ goto cleanup;
+ }
+
+ old_headers = ctx->curl->headers;
+ curl_easy_setopt(ctx->curl->handle, CURLOPT_HTTPHEADER , headers);
+
+ if (esxVI_ManagedObjectReference_Alloc(&ovfManager) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ovfManager->_next = NULL;
+ ovfManager->_type = esxVI_Type_ManagedObjectReference;
+ ovfManager->type = strdup("OvfManager");
+ ovfManager->value = strdup("ha-ovf-manager");
+ }
+
+ /**
+ * OVA installation is a multi step process:
+ *
+ * Step 1: ParseDescriptor:
+ * run OVF descriptor by hypervisor to see if it is deployable.
+ */
+ if (esxVI_OvfParseDescriptorParams_Alloc(&pdp) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ pdp->locale = strdup("en-US");
+ pdp->deploymentOption = strdup("");
+
+ if (virGetOVFDescriptor(ova, &ovfDescriptor) < 0 ||
+ ovfDescriptor == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing OVF descriptor"));
+ goto cleanup;
+ };
+
+ escapedOvfDescriptor = esxUtil_EscapeForXml(ovfDescriptor);
+ if (escapedOvfDescriptor == NULL) {
+ goto cleanup;
+ }
+
+ if (ctx->service->ovfManager) {
+ if (esxVI_ParseDescriptor(ctx, ctx->service->ovfManager,
+ escapedOvfDescriptor, pdp, &pdResult) < 0) {
+ goto cleanup;
+ }
+ } else {
+ if (esxVI_ParseDescriptor(ctx, ovfManager, escapedOvfDescriptor,
+ pdp, &pdResult) < 0) {
+ goto cleanup;
+ }
+ }
+
+ if (pdResult == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("ParseDescriptor: NULL return value"));
+ goto cleanup;
+ } else if (pdResult->error) {
+ esxVI_LocalizedMethodFault *pFault = NULL;
+
+ for (pFault = pdResult->error;
+ pFault != NULL;
+ pFault = pFault->_next) {
+ if (pFault->localizedMessage) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ pFault->localizedMessage);
+ }
+ }
+
+ goto cleanup;
+ }
+
+ /*
+ * Step 2: InstallvAPP:
+ * create virtual machine entity on the hypervisor.
+ */
+ if (esxVI_OvfCreateImportSpecParams_Alloc(&cisp) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ domainName = virGetOVFDomainName(ovfDescriptor);
+ if (domainName == NULL) {
+ goto cleanup;
+ }
+
+ cisp->locale = strdup("en-US");
+ cisp->deploymentOption = strdup("");
+ cisp->entityName = strdup(domainName);
+
+ if (esxVI_ManagedObjectReference_DeepCopy(
+ &cisp->hostSystem, priv->host->hostSystem->_reference) < 0 ||
+ esxVI_LookupDatastoreByName(ctx, datastoreName, NULL, &datastore,
+ esxVI_Occurrence_RequiredItem) < 0) {
+ goto cleanup;
+ }
+
+
+ cisp->ipAllocationPolicy = strdup("fixedPolicy");
+ cisp->ipProtocol = strdup("IPv4");
+ cisp->diskProvisioning = strdup("thick");
+
+ if (ctx->service->ovfManager) {
+ if (esxVI_CreateImportSpec(
+ ctx, ctx->service->ovfManager, escapedOvfDescriptor,
+ priv->primary->computeResource->resourcePool,
+ datastore->obj, cisp, &importResult) < 0) {
+ goto cleanup;
+ }
+ } else {
+ if (esxVI_CreateImportSpec(
+ ctx, ovfManager, escapedOvfDescriptor,
+ priv->primary->computeResource->resourcePool,
+ datastore->obj, cisp, &importResult) < 0) {
+ goto cleanup;
+ }
+ }
+
+ if (importResult == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("CreateImportSpec returned NULL."));
+ goto cleanup;
+ } else {
+ if (!importResult->error) {
+ if (importResult->warning) {
+ esxVI_LocalizedMethodFault *pWarn= NULL;
+ for (pWarn = importResult->warning;
+ pWarn != NULL;
+ pWarn = pWarn->_next) {
+ if (pWarn->localizedMessage) {
+ VIR_WARN("%s", pWarn->localizedMessage);
+ }
+ }
+ }
+ } else {
+ esxVI_LocalizedMethodFault *pFault = NULL;
+
+ for (pFault = importResult->error;
+ pFault != NULL;
+ pFault = pFault->_next) {
+ if (pFault->localizedMessage) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ pFault->localizedMessage);
+ }
+ }
+
+ goto cleanup;
+ }
+ }
+
+ if (!importResult->importSpec) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("InstallVApp : ImportSpec is NULL"));
+ goto cleanup;
+ }
+
+ /* Step 3: ImportVApp: this will create the VApp entity on the
+ * ESXi box.
+ */
+ if (esxVI_ImportVApp(ctx,
+ priv->primary->computeResource->resourcePool,
+ importResult->importSpec,
+ priv->primary->datacenter->vmFolder,
+ priv->host->hostSystem->_reference,
+ &nfcLease) < 0) {
+ goto cleanup;
+ }
+
+ if (nfcLease == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("ImportVApp: lease NULL."));
+ goto cleanup;
+ }
+
+ /*
+ * Step 3: Transfer VMDKs:
+ * if VM creation is a success, ESX provides the lease object
+ * with URL to upload vmdks to the ESX server.
+ */
+
+ if (esxDomainUploadDisks(conn, nfcLease, importResult, ova) < 0) {
+ goto abort;
+ }
+
+ /* Done: installation */
+ if (esxVI_HttpNfcLeaseComplete(ctx, nfcLease) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("ImportVApp: VMDK upload complete error"));
+ goto abort;
+ }
+
+ domain = esxDomainLookupByName(conn, domainName);
+
+ cleanup:
+
+ esxVI_OvfParseDescriptorParams_Free(&pdp);
+ esxVI_OvfParseDescriptorResult_Free(&pdResult);
+ esxVI_OvfCreateImportSpecParams_Free(&cisp);
+ esxVI_OvfCreateImportSpecResult_Free(&importResult);
+ esxVI_ObjectContent_Free(&datastore);
+ esxVI_ManagedObjectReference_Free(&nfcLease);
+ esxVI_ManagedObjectReference_Free(&ovfManager);
+ VIR_FREE(ovfDescriptor);
+ VIR_FREE(escapedOvfDescriptor);
+ VIR_FREE(domainName);
+ virFreeOVA(ova);
+
+ if (old_headers) {
+ curl_easy_setopt(ctx->curl->handle, CURLOPT_HTTPHEADER , old_headers);
+ }
+
+ if (headers) {
+ curl_slist_free_all(headers);
+ }
+
+ return domain;
+
+ abort:
+
+ /* Abort the Lease */
+ if (nfcLease != NULL) {
+ /**
+ * ESXi will clean up the lease objects when the timeout expires
+ * ignore if this calls fails.
+ */
+ esxVI_HttpNfcLeaseAbort(ctx, nfcLease);
+ }
+
+ goto cleanup;
+
+}
+
+
+static int
esxDomainUndefineFlags(virDomainPtr domain,
unsigned int flags)
{
@@ -5284,6 +5854,7 @@ static virDriver esxDriver = {
.domainCreate = esxDomainCreate, /* 0.7.0 */
.domainCreateWithFlags = esxDomainCreateWithFlags, /* 0.8.2 */
.domainDefineXML = esxDomainDefineXML, /* 0.7.2 */
+ .domainDefineOVA = esxDomainDefineOVA, /* 1.0.2 */
.domainUndefine = esxDomainUndefine, /* 0.7.1 */
.domainUndefineFlags = esxDomainUndefineFlags, /* 0.9.4 */
.domainGetAutostart = esxDomainGetAutostart, /* 0.9.0 */
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index eec135e..5f0df45 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -51,10 +51,17 @@
# Enumerations
#
+enum ArrayUpdateOperation
+ add
+ edit
+ remove
+end
+
+
enum AutoStartWaitHeartbeatSetting
- yes
- no
- systemDefault
+ yes
+ no
+ systemDefault
end
@@ -66,6 +73,14 @@ enum FibreChannelPortType
end
+enum HttpNfcLeaseState
+ initializing
+ ready
+ done
+ error
+end
+
+
enum ManagedEntityStatus
gray
green
@@ -122,6 +137,27 @@ enum TaskInfoState
end
+enum VirtualDeviceConfigSpecFileOperation
+ create
+ destroy
+ replace
+end
+
+
+enum VirtualDeviceConfigSpecOperation
+ add
+ edit
+ remove
+end
+
+
+enum VirtualSCSISharing
+ noSharing
+ physicalSharing
+ virtualSharing
+end
+
+
enum VirtualMachineMovePriority
lowPriority
highPriority
@@ -136,6 +172,17 @@ enum VirtualMachinePowerState
end
+enum VirtualMachineToolsStatus
+ toolsNotInstalled
+ toolsNotRunning
+ toolsOk
+ toolsOld
+end
+
+enum vStorageSupport
+ vStorageUnknown
+end
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Objects
#
@@ -158,6 +205,12 @@ object AboutInfo
end
+object ArrayUpdateSpec
+ ArrayUpdateOperation operation r
+ AnyType removeKey o
+end
+
+
object AutoStartDefaults
Boolean enabled o
Int startDelay o
@@ -184,6 +237,26 @@ object ChoiceOption extends OptionType
end
+object ClusterDasVmConfigSpec extends ArrayUpdateSpec
+ ClusterDasVmConfigInfo info i
+end
+
+
+object ClusterDpmHostConfigSpec extends ArrayUpdateSpec
+ ClusterDpmHostConfigInfo info i
+end
+
+
+object ClusterRuleSpec extends ArrayUpdateSpec
+ ClusterRuleInfo info i
+end
+
+
+object ClusterDrsVmConfigSpec extends ArrayUpdateSpec
+ ClusterDrsVmConfigInfo info i
+end
+
+
object DatastoreHostMount
ManagedObjectReference key r
HostMountInfo mountInfo r
@@ -740,6 +813,64 @@ object HostVmfsVolume extends HostFileSystemVolume
end
+object HttpNfcLease
+ LocalizedMethodFault error o
+ HttpNfcLeaseInfo info o
+ Int initializeProgress r
+ HttpNfcLeaseState state r
+end
+
+
+object HttpNfcLeaseDatastoreLeaseInfo
+ String datastoreKey r
+ HttpNfcLeaseHostInfo hosts rl
+end
+
+
+object HttpNfcLeaseDeviceUrl
+ String datastoreKey o
+ Boolean disk o
+ Long fileSize o
+ String importKey r
+ String key r
+ String sslThumbprint r
+ String targetId o
+ String url r
+end
+
+
+object HttpNfcLeaseHostInfo
+ String sslThumbprint r
+ String url r
+end
+
+
+object HttpNfcLeaseInfo
+ HttpNfcLeaseDeviceUrl deviceUrl ol
+ ManagedObjectReference entity r
+ HttpNfcLeaseDatastoreLeaseInfo hostMap ol
+ ManagedObjectReference lease r
+ Int leaseTimeout r
+ Long totalDiskCapacityInKB r
+end
+
+
+
+object HttpNfcLeaseManifestEntry
+ Long capacity o
+ Boolean disk r
+ String key r
+ Long populatedSize o
+ String sha1 r
+ Long size r
+end
+
+
+object ImportSpec
+ VAppEntityConfigInfo entityConfig o
+end
+
+
object IsoImageFileInfo extends FileInfo
end
@@ -754,6 +885,12 @@ object KeyAnyValue
end
+object KeyValue
+ String key r
+ String value r
+end
+
+
object LocalDatastoreInfo extends DatastoreInfo
String path o
end
@@ -792,6 +929,11 @@ object ObjectUpdate
end
+object OptionDef extends ElementDescription
+ OptionType optionType r
+end
+
+
object OptionType
Boolean valueIsReadonly o
end
@@ -803,6 +945,97 @@ object OptionValue
end
+object OvfCreateImportSpecParams extends OvfManagerCommonParams
+ String entityName r
+ ManagedObjectReference hostSystem o
+ OvfNetworkMapping networkMapping ol
+ String ipAllocationPolicy o
+ String ipProtocol o
+ String diskProvisioning o
+ KeyValue propertyMapping ol
+ OvfResourceMap resourceMapping ol
+
+end
+
+
+object OvfCreateImportSpecResult
+ LocalizedMethodFault error ol
+ OvfFileItem fileItem ol
+ VirtualMachineImportSpec importSpec o
+ LocalizedMethodFault warning ol
+end
+
+
+object OvfDeploymentOption
+ String description r
+ String key r
+ String label r
+end
+
+
+object OvfFileItem
+ Long chunkSize o
+ Int cimType r
+ String compressionMethod o
+ Boolean create r
+ String deviceId r
+ String path r
+ Long size o
+end
+
+
+object OvfManagerCommonParams
+ String locale r
+ String deploymentOption r
+ KeyValue msgBundle ol
+end
+
+
+object OvfNetworkInfo
+ String description r
+ String name r
+end
+
+
+object OvfNetworkMapping
+ String name r
+ ManagedObjectReference network r
+end
+
+
+object OvfParseDescriptorParams extends OvfManagerCommonParams
+end
+
+
+object OvfParseDescriptorResult
+ String annotation o
+ Long approximateDownloadSize o
+ Long approximateFlatDeploymentSize o
+ Long approximateSparseDeploymentSize o
+ String defaultDeploymentOption r
+ String defaultEntityName r
+ OvfDeploymentOption deploymentOption ol
+ KeyValue entityName ol
+ LocalizedMethodFault error ol
+ String eula ol
+ String ipAllocationScheme ol
+ String ipProtocols ol
+ OvfNetworkInfo network ol
+ VAppProductInfo productInfo o
+ VAppPropertyInfo property ol
+ Boolean virtualApp r
+ LocalizedMethodFault warning ol
+end
+
+
+object OvfResourceMap
+ ManagedObjectReference datastore o
+ ManagedObjectReference parent o
+ ResourceConfigSpec resourceSpec o
+ String source r
+end
+
+
object PerfCounterInfo
Int key r
ElementDescription nameInfo r
@@ -911,6 +1144,15 @@ object PropertySpec
end
+object ResourceConfigSpec
+ String changeVersion o
+ ResourceAllocationInfo cpuAllocation r
+ ManagedObjectReference entity o
+ DateTime lastModified o
+ ResourceAllocationInfo memoryAllocation r
+end
+
+
object ResourceAllocationInfo
Long reservation o
Boolean expandableReservation o
@@ -1017,6 +1259,18 @@ object SharesInfo
end
+object StorageIOAllocationInfo
+ Long limit o
+ SharesInfo shares o
+end
+
+
+object StringOption extends OptionType
+ String defaultValue r
+ String validCharacters o
+end
+
+
object TaskInfo
String key r
ManagedObjectReference task r
@@ -1051,6 +1305,19 @@ object TemplateConfigFileQuery extends VmConfigFileQuery
end
+object ToolsConfigInfo
+ Boolean afterPowerOn o
+ Boolean afterResume o
+ Boolean beforeGuestStandby o
+ Boolean beforeGuestShutdown o
+ Boolean beforeGuestReboot o
+ String pendingCustomization o
+ Boolean syncTimeWithHost o
+ String toolsUpgradePolicy o
+ Int toolsVersion o
+end
+
+
object TraversalSpec extends SelectionSpec
String type r
String path r
@@ -1073,6 +1340,175 @@ object UserSession
DateTime lastActiveTime r
String locale r
String messageLocale r
+ Boolean extensionSession o
+end
+
+
+object VAppConfigSpec extends VmConfigSpec
+ String annotation o
+ VAppEntityConfigInfo entityConfig ol
+end
+
+object VAppEntityConfigInfo
+ Boolean destroyWithParent o
+ ManagedObjectReference key o
+ String startAction o
+ Int startDelay o
+ Int startOrder o
+ String stopAction o
+ Int stopDelay o
+ String tag o
+ Boolean waitingForGuest o
+end
+
+
+object VAppIPAssignmentInfo
+ String ipAllocationPolicy o
+ String ipProtocol o
+ String supportedAllocationScheme ol
+ String supportedIpProtocol ol
+end
+
+
+object VAppOvfSectionInfo
+ Boolean atEnvelopeLevel o
+ String contents o
+ Int key o
+ String namespace o
+ String type o
+end
+
+
+object VAppOvfSectionSpec extends ArrayUpdateSpec
+ VAppOvfSectionInfo info o
+end
+
+
+object VAppProductInfo
+ String appUrl o
+ String classId o
+ String fullVersion o
+ String instanceId o
+ Int key r
+ String name o
+ String productUrl o
+ String vendor o
+ String vendorUrl o
+ String version o
+end
+
+
+object VAppProductSpec extends ArrayUpdateSpec
+ VAppProductInfo info o
+end
+
+
+object VAppPropertyInfo
+ String category o
+ String classId o
+ String defaultValue o
+ String description o
+ String id o
+ Int key r
+ String label o
+ String type o
+ Boolean userConfigurable o
+ String value o
+end
+
+
+object VAppPropertySpec extends ArrayUpdateSpec
+ VAppPropertyInfo info o
+end
+
+
+object VirtualDevice
+ Int key r
+ Description deviceInfo o
+ VirtualDeviceBackingInfo backing o
+ VirtualDeviceConnectInfo connectable o
+ Int controllerKey o
+ Int unitNumber o
+end
+
+
+object VirtualDeviceBackingInfo
+end
+
+
+object VirtualDeviceConnectInfo
+ Boolean startConnected r
+ Boolean allowGuestControl r
+ Boolean connected r
+ String status o
+end
+
+
+object VirtualCdrom extends VirtualDevice
+end
+
+
+object VirtualController extends VirtualDevice
+ Int busNumber r
+ Int device ol
+end
+
+
+object VirtualIDEController extends VirtualController
+end
+
+
+object VirtualPCIController extends VirtualController
+end
+
+
+object VirtualPS2Controller extends VirtualController
+end
+
+
+object VirtualSCSIController extends VirtualController
+ Boolean hotAddRemove o
+ Int scsiCtlrUnitNumber o
+ VirtualSCSISharing sharedBus r
+end
+
+
+object ParaVirtualSCSIController extends VirtualSCSIController
+end
+
+
+object VirtualBusLogicController extends VirtualSCSIController
+end
+
+
+object VirtualLsiLogicController extends VirtualSCSIController
+end
+
+
+object VirtualLsiLogicSASController extends VirtualSCSIController
+end
+
+
+object VirtualSIOController extends VirtualController
+end
+
+
+object VirtualUSBController extends VirtualController
+ Boolean autoConnectDevices o
+ Boolean ehciEnabled o
+end
+
+
+object VirtualDeviceConfigSpec
+ VirtualDeviceConfigSpecOperation operation o
+ VirtualDeviceConfigSpecFileOperation fileOperation o
+ VirtualDevice device r
+end
+
+
+object VirtualDisk extends VirtualDevice
+ Long capacityInKB r
+ SharesInfo shares o
end
@@ -1082,6 +1518,283 @@ object VirtualDiskSpec
end
+object VirtualEthernetCard extends VirtualDevice
+ String addressType o
+ String macAddress o
+ Boolean wakeOnLanEnabled o
+end
+
+
+object VirtualE1000 extends VirtualEthernetCard
+end
+
+
+object VirtualPCNet32 extends VirtualEthernetCard
+end
+
+
+object VirtualVmxnet extends VirtualEthernetCard
+end
+
+
+object VirtualVmxnet2 extends VirtualVmxnet
+end
+
+
+object VirtualVmxnet3 extends VirtualVmxnet
+end
+
+
+object VirtualFloppy extends VirtualDevice
+end
+
+
+object VirtualKeyboard extends VirtualDevice
+end
+
+
+object VirtualMachineCpuIdInfoSpec
+ HostCpuIdInfo info o
+end
+
+
+object VirtualMachineVideoCard extends VirtualDevice
+ Boolean enable3DSupport o
+ Int numDisplays o
+ Boolean useAutoDetect o
+ Long videoRamSizeInKB o
+end
+
+
+object VirtualMachineVMCIDevice extends VirtualDevice
+ Boolean allowUnrestrictedCommunication o
+ Long id o
+end
+
+
+object VirtualMachineVMIROM extends VirtualDevice
+end
+
+
+object VirtualParallelPort extends VirtualDevice
+end
+
+
+object VirtualPCIPassthrough extends VirtualDevice
+end
+
+
+object VirtualPointingDevice extends VirtualDevice
+end
+
+
+object VirtualSCSIPassthrough extends VirtualDevice
+end
+
+
+object VirtualSerialPort extends VirtualDevice
+ Boolean yieldOnPoll r
+end
+
+object VirtualSoundCard extends VirtualDevice
+end
+
+object VirtualUSB extends VirtualDevice
+ Boolean connected r
+end
+
+
+object VirtualDeviceBackingInfo
+end
+
+
+object VirtualDeviceDeviceBackingInfo extends VirtualDeviceBackingInfo
+ String deviceName r
+ Boolean useAutoDetect o
+end
+
+
+object VirtualCdromAtapiBackingInfo extends VirtualDeviceDeviceBackingInfo
+end
+
+
+object VirtualCdromPassthroughBackingInfo extends VirtualDeviceDeviceBackingInfo
+ Boolean exclusive r
+end
+
+
+object VirtualDiskRawDiskVer2BackingInfo extends VirtualDeviceDeviceBackingInfo
+ String changeId o
+ String descriptorFileName r
+ String uuid o
+end
+
+
+object VirtualDiskPartitionedRawDiskVer2BackingInfo extends VirtualDiskRawDiskVer2BackingInfo
+ Int partition rl
+end
+
+
+object VirtualEthernetCardLegacyNetworkBackingInfo extends VirtualDeviceDeviceBackingInfo
+end
+
+
+object VirtualEthernetCardNetworkBackingInfo extends VirtualDeviceDeviceBackingInfo
+ Boolean inPassthroughMode o
+ ManagedObjectReference network o
+end
+
+
+object VirtualFloppyDeviceBackingInfo extends VirtualDeviceDeviceBackingInfo
+end
+
+
+object VirtualParallelPortDeviceBackingInfo extends VirtualDeviceDeviceBackingInfo
+end
+
+
+object VirtualPCIPassthroughDeviceBackingInfo extends VirtualDeviceDeviceBackingInfo
+ String deviceId r
+ String id r
+ String systemId r
+ Int vendorId r
+end
+
+
+object VirtualPointingDeviceDeviceBackingInfo extends VirtualDeviceDeviceBackingInfo
+ String hostPointingDevice r
+end
+
+
+object VirtualSCSIPassthroughDeviceBackingInfo extends VirtualDeviceDeviceBackingInfo
+end
+
+
+object VirtualSerialPortDeviceBackingInfo extends VirtualDeviceDeviceBackingInfo
+end
+
+
+object VirtualSoundCardDeviceBackingInfo extends VirtualDeviceDeviceBackingInfo
+end
+
+
+object VirtualUSBUSBBackingInfo extends VirtualDeviceDeviceBackingInfo
+end
+
+
+object VirtualDeviceFileBackingInfo extends VirtualDeviceBackingInfo
+ String fileName r
+ ManagedObjectReference datastore o
+end
+
+
+object VirtualCdromIsoBackingInfo extends VirtualDeviceFileBackingInfo
+end
+
+
+object VirtualDiskFlatVer1BackingInfo extends VirtualDeviceFileBackingInfo
+ String contentId o
+ String diskMode r
+ VirtualDiskFlatVer1BackingInfo parent o
+ Boolean split o
+ Boolean writeThrough o
+end
+
+
+object VirtualDiskFlatVer2BackingInfo extends VirtualDeviceFileBackingInfo
+ String changeId o
+ String contentId o
+ String diskMode r
+ VirtualDiskFlatVer2BackingInfo parent o
+ Boolean split o
+ Boolean thinProvisioned o
+ Boolean eagerlyScrub o
+ String uuid o
+ Boolean writeThrough o
+end
+
+
+object VirtualDiskRawDiskMappingVer1BackingInfo extends VirtualDeviceFileBackingInfo
+ String changeId o
+ String compatibilityMode o
+ String contentId o
+ String deviceName o
+ String diskMode o
+ String lunUuid o
+ VirtualDiskRawDiskMappingVer1BackingInfo parent o
+ String uuid o
+end
+
+
+object VirtualDiskSparseVer1BackingInfo extends VirtualDeviceFileBackingInfo
+ String contentId o
+ String diskMode r
+ VirtualDiskSparseVer1BackingInfo parent o
+ Long spaceUsedInKB o
+ Boolean split o
+ Boolean writeThrough o
+end
+
+
+object VirtualDiskSparseVer2BackingInfo extends VirtualDeviceFileBackingInfo
+ String changeId o
+ String contentId o
+ String diskMode r
+ VirtualDiskSparseVer2BackingInfo parent o
+ Long spaceUsedInKB o
+ Boolean split o
+ String uuid o
+ Boolean writeThrough o
+end
+
+
+object VirtualFloppyImageBackingInfo extends VirtualDeviceFileBackingInfo
+end
+
+
+object VirtualParallelPortFileBackingInfo extends VirtualDeviceFileBackingInfo
+end
+
+
+object VirtualSerialPortFileBackingInfo extends VirtualDeviceFileBackingInfo
+end
+
+
+object VirtualDevicePipeBackingInfo extends VirtualDeviceBackingInfo
+ String pipeName r
+end
+
+
+object VirtualSerialPortPipeBackingInfo extends VirtualDevicePipeBackingInfo
+ String endpoint r
+ Boolean noRxLoss o
+end
+
+
+object VirtualDeviceRemoteDeviceBackingInfo extends VirtualDeviceBackingInfo
+ String deviceName r
+ Boolean useAutoDetect o
+end
+
+
+object VirtualCdromRemoteAtapiBackingInfo extends VirtualDeviceRemoteDeviceBackingInfo
+end
+
+
+object VirtualCdromRemotePassthroughBackingInfo extends VirtualDeviceRemoteDeviceBackingInfo
+ Boolean exclusive r
+end
+
+
+object VirtualFloppyRemoteDeviceBackingInfo extends VirtualDeviceRemoteDeviceBackingInfo
+end
+
+
+object VirtualMachineAffinityInfo
+ Int affinitySet ol
+end
+
+
object VirtualMachineConfigSpec
String changeVersion o
String name o
@@ -1100,33 +1813,93 @@ object VirtualMachineConfigSpec
String guestId o
String alternateGuestName o
String annotation o
- VirtualMachineFileInfo files i
- ToolsConfigInfo tools i
- VirtualMachineFlagInfo flags i
- VirtualMachineConsolePreferences consolePreferences i
- VirtualMachineDefaultPowerOpInfo powerOpInfo i
+ VirtualMachineFileInfo files o
+ ToolsConfigInfo tools o
+ VirtualMachineFlagInfo flags o
+ VirtualMachineConsolePreferences consolePreferences o
+ VirtualMachineDefaultPowerOpInfo powerOpInfo o
Int numCPUs o
+ Int numCoresPerSocket o
Long memoryMB o
Boolean memoryHotAddEnabled o
Boolean cpuHotAddEnabled o
Boolean cpuHotRemoveEnabled o
- VirtualDeviceConfigSpec deviceChange i
+ VirtualDeviceConfigSpec deviceChange ol
ResourceAllocationInfo cpuAllocation o
ResourceAllocationInfo memoryAllocation o
- VirtualMachineAffinityInfo cpuAffinity i
- VirtualMachineAffinityInfo memoryAffinity i
- VirtualMachineNetworkShaperInfo networkShaper i
- VirtualMachineCpuIdInfoSpec cpuFeatureMask i
- OptionValue extraConfig i
+ VirtualMachineAffinityInfo cpuAffinity o
+ VirtualMachineAffinityInfo memoryAffinity o
+ VirtualMachineNetworkShaperInfo networkShaper o
+ VirtualMachineCpuIdInfoSpec cpuFeatureMask o
+ OptionValue extraConfig ol
String swapPlacement o
- VirtualMachineBootOptions bootOptions i
- VmConfigSpec vAppConfig i
+ VirtualMachineBootOptions bootOptions o
+ VmConfigSpec vAppConfig o
FaultToleranceConfigInfo ftInfo i
Boolean vAppConfigRemoved o
Boolean vAssertsEnabled o
Boolean changeTrackingEnabled o
end
+object VirtualMachineDefaultPowerOpInfo
+ String defaultPowerOffType o
+ String defaultResetType o
+ String defaultSuspendType o
+ String powerOffType o
+ String resetType o
+ String standbyAction o
+ String suspendType o
+end
+
+object VirtualMachineConsolePreferences
+ Boolean closeOnPowerOffOrSuspend o
+ Boolean enterFullScreenOnPowerOn o
+ Boolean powerOnWhenOpened o
+end
+
+object VirtualMachineFileInfo
+ String logDrirectory o
+ String snapshotDirectory o
+ String suspendDirectory o
+ String vmPathName o
+end
+
+
+object VirtualMachineNetworkShaperInfo
+ Long averageBps o
+ Long burstSize o
+ Boolean enabled o
+ Long peakBps o
+end
+
+object VirtualMachineFlagInfo
+ Boolean disableAcceleration o
+ Boolean diskUuidEnabled o
+ Boolean enableLogging o
+ String htSharing o
+ String monitorType o
+ Boolean recordReplayEnabled o
+ Boolean runWithDebugInfo o
+ Boolean snapshotDisabled o
+ Boolean snapshotLocked o
+ String snapshotPowerOffBehavior o
+ Boolean useToe o
+ String virtualExecUsage o
+ String virtualMmuUsage o
+end
+
+object VirtualMachineBootOptions
+ Long bootDelay o
+ Long bootRetryDelay o
+ Boolean bootRetryEnabled o
+ Boolean enterBIOSSetup o
+end
+
+object VirtualMachineImportSpec extends ImportSpec
+ VirtualMachineConfigSpec configSpec r
+ ManagedObjectReference resPoolEntity o
+end
+
object VirtualMachineQuestionInfo
String id r
@@ -1172,6 +1945,18 @@ object VmConfigFileQueryFlags
end
+object VmConfigSpec
+ Boolean installBootRequired o
+ Int installBootStopDelay o
+ String eula ol
+ VAppIPAssignmentInfo ipAssignment o
+ String ovfEnviornmentTransport ol
+ VAppOvfSectionSpec ovfSection ol
+ VAppProductSpec product ol
+ VAppPropertySpec property ol
+end
+
+
object VmDiskFileInfo extends FileInfo
String diskType o
Long capacityKb o
@@ -1310,6 +2095,15 @@ method CopyVirtualDisk_Task returns ManagedObjectReference r
end
+method CreateImportSpec returns OvfCreateImportSpecResult r
+ ManagedObjectReference _this r
+ String ovfDescriptor r
+ ManagedObjectReference resourcePool r
+ ManagedObjectReference datastore r
+ OvfCreateImportSpecParams cisp r
+end
+
+
method CreateFilter returns ManagedObjectReference r
ManagedObjectReference _this:propertyCollector r
PropertyFilterSpec spec r
@@ -1363,12 +2157,35 @@ method FindByUuid returns ManagedObjectReference o
end
+method HttpNfcLeaseAbort
+ ManagedObjectReference _this r
+end
+
+
+method HttpNfcLeaseComplete
+ ManagedObjectReference _this r
+end
+
+
+method HttpNfcLeaseGetManifest returns HttpNfcLeaseManifestEntry rl
+ ManagedObjectReference _this r
+end
+
+
method HttpNfcLeaseProgress
ManagedObjectReference _this r
Int percent r
end
+method ImportVApp returns ManagedObjectReference r
+ ManagedObjectReference _this r
+ VirtualMachineImportSpec spec r
+ ManagedObjectReference folder o
+ ManagedObjectReference host o
+end
+
+
method Login returns UserSession r
ManagedObjectReference _this:sessionManager r
String userName r
@@ -1404,6 +2221,13 @@ method PowerOffVM_Task returns ManagedObjectReference r
end
+method ParseDescriptor returns OvfParseDescriptorResult r
+ ManagedObjectReference _this r
+ String ovfDescriptor r
+ OvfParseDescriptorParams pdp r
+end
+
+
method PowerOnVM_Task returns ManagedObjectReference r
ManagedObjectReference _this r
ManagedObjectReference host o
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index af4e7e8..19f4ffe 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -1284,7 +1284,6 @@ class ManagedObject(Type):
return source
-
class Enum(Type):
FEATURE__ANY_TYPE = (1 << 1)
FEATURE__SERIALIZE = (1 << 2)
@@ -1518,7 +1517,8 @@ predefined_objects = ["AnyType",
additional_enum_features = { "ManagedEntityStatus" : Enum.FEATURE__ANY_TYPE,
"TaskInfoState" : Enum.FEATURE__ANY_TYPE,
- "VirtualMachinePowerState" : Enum.FEATURE__ANY_TYPE }
+ "VirtualMachinePowerState" : Enum.FEATURE__ANY_TYPE,
+ "VirtualMachineToolsStatus" : Enum.FEATURE__ANY_TYPE }
additional_object_features = { "AutoStartDefaults" : Object.FEATURE__ANY_TYPE,
"AutoStartPowerInfo" : Object.FEATURE__ANY_TYPE,
@@ -1527,6 +1527,7 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN
Object.FEATURE__ANY_TYPE,
"DatastoreInfo" : Object.FEATURE__ANY_TYPE |
Object.FEATURE__DYNAMIC_CAST,
+ "DynamicProperty" : Object.FEATURE__LIST,
"HostConfigManager" : Object.FEATURE__ANY_TYPE,
"HostCpuIdInfo" : Object.FEATURE__LIST |
Object.FEATURE__ANY_TYPE,
@@ -1552,8 +1553,12 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN
"HostVirtualSwitch" : Object.FEATURE__DEEP_COPY |
Object.FEATURE__LIST |
Object.FEATURE__ANY_TYPE,
+ "HttpNfcLeaseInfo" : Object.FEATURE__ANY_TYPE,
"ManagedObjectReference" : Object.FEATURE__ANY_TYPE,
"ObjectContent" : Object.FEATURE__DEEP_COPY,
+ "OptionDef" : Object.FEATURE__LIST,
+ "OptionValue" : Object.FEATURE__ANY_TYPE |
+ Object.FEATURE__LIST,
"PhysicalNic" : Object.FEATURE__DEEP_COPY |
Object.FEATURE__LIST |
Object.FEATURE__ANY_TYPE,
@@ -1567,9 +1572,13 @@ additional_object_features = { "AutoStartDefaults" : Object.FEATURE__AN
"TaskInfo" : Object.FEATURE__LIST |
Object.FEATURE__ANY_TYPE,
"UserSession" : Object.FEATURE__ANY_TYPE,
+ "VirtualDeviceConfigSpec" : Object.FEATURE__LIST,
+ "VirtualMachineImportSpec" : Object.FEATURE__DYNAMIC_CAST,
"VirtualMachineQuestionInfo" : Object.FEATURE__ANY_TYPE,
"VirtualMachineSnapshotTree" : Object.FEATURE__DEEP_COPY |
Object.FEATURE__ANY_TYPE,
+ "VirtualDevice" : Object.FEATURE__ANY_TYPE |
+ Object.FEATURE__LIST,
"VmEventArgument" : Object.FEATURE__DESERIALIZE }
removed_object_features = {}
diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c
index d1f91ff..c1c314c 100644
--- a/src/esx/esx_vi_types.c
+++ b/src/esx/esx_vi_types.c
@@ -720,14 +720,15 @@ esxVI_GetActualObjectType(xmlNodePtr node, esxVI_Type baseType,
BAD_CAST "http://www.w3.org/2001/XMLSchema-instance");
if (type == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("%s is missing 'type' property"),
- esxVI_Type_ToString(baseType));
- return -1;
+ /**
+ * Few ESX objects are nasty and doesn't contain any 'type' value,
+ * for instance: VmConfigSpec; set the value to baseType and proceed
+ */
+ *actualType = baseType;
+ } else {
+ *actualType = esxVI_Type_FromString(type);
}
- *actualType = esxVI_Type_FromString(type);
-
if (*actualType == esxVI_Type_Undefined || *actualType == esxVI_Type_Other) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unknown value '%s' for %s 'type' property"),
--
1.7.9.5
11 years, 11 months
[libvirt] [PATCH 3/5] ESX: CURL routine to allow file upload to the server
by Ata E Husain Bohra
Currently esx_vi.c supports file upload/download to the server
but only for string based contents. This patch extends the support
to upload file contents by opening file and sending data in chunks
using CURL POST operation.
This patch also servers as fundemental block for OVA installations
to create new domain. This patch introduces a structure to maintain
metadata information about the file being uploaded, it defines an
enum to allow user to set the "file type". For instance: OVA
disk(s) while uploading needs to refresh "lease timeout" by reporting
upload progress, the file type allow us to perform specific operations
to be performed per file upload if needed.
---
src/esx/esx_vi.c | 147 +++++++++++++++++++++++++++++++++++++++-
src/esx/esx_vi.h | 35 +++++++++-
src/esx/esx_vi_generator.input | 6 ++
3 files changed, 186 insertions(+), 2 deletions(-)
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index 99c1eb1..a49ab7e 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2010-2012 Red Hat, Inc.
* Copyright (C) 2009-2012 Matthias Bolte <matthias.bolte(a)googlemail.com>
+ * Copyright (C) 2013 Ata E Husain Bohra <ata.husain(a)hotmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,6 +34,7 @@
#include "viruuid.h"
#include "vmx.h"
#include "virxml.h"
+#include "virfile.h"
#include "esx_vi.h"
#include "esx_vi_methods.h"
#include "esx_util.h"
@@ -115,6 +117,22 @@ ESX_VI__TEMPLATE__FREE(CURL,
virMutexDestroy(&item->lock);
})
+
+/* esxVI_FileData_Alloc */
+ESX_VI__TEMPLATE__ALLOC(FileData)
+
+
+/* esxVI_FileData_Free */
+ESX_VI__TEMPLATE__FREE(FileData,
+{
+ if (item->fHandle) {
+ if (VIR_FCLOSE(item->fHandle) < 0) {
+ VIR_FORCE_FCLOSE(item->fHandle);
+ }
+ }
+})
+
+
static size_t
esxVI_CURL_ReadString(char *data, size_t size, size_t nmemb, void *userdata)
{
@@ -167,6 +185,85 @@ esxVI_CURL_WriteBuffer(char *data, size_t size, size_t nmemb, void *userdata)
return 0;
}
+/* 1 minute timeout to report upload status */
+#define UPLOAD_STATUS_TIMEOUT 30
+
+static size_t
+esxVI_CURL_ReadFile(void *data, size_t size, size_t nmemb, void *userdata)
+{
+ int result = -1;
+ size_t readsize = -1;
+ esxVI_FileData *fileData = (esxVI_FileData *) userdata;
+ esxVI_Int *percentage = NULL;
+ time_t cur_time = 0;
+ int elapsed = 0;
+
+ if ((fileData == NULL) ||
+ (fileData->fHandle == NULL)) {
+ return readsize;
+ }
+
+ if (fileData->cur_size == 0) {
+ readsize = 0;
+ } else {
+ if ((size*nmemb) > fileData->cur_size) {
+ readsize = fread(data, 1, fileData->cur_size,
+ (FILE*) fileData->fHandle);
+ } else {
+ readsize = fread(data, size, nmemb, (FILE*)fileData->fHandle);
+ }
+
+ fileData->cur_size -= readsize;
+ }
+
+ if (fileData->type == OVA_DISK) {
+ cur_time = time(NULL);
+ elapsed = cur_time - fileData->time_elapsed;
+
+ if (elapsed < UPLOAD_STATUS_TIMEOUT) {
+ /* no need to update upload progress */
+ result = 0;
+ goto cleanup;
+ }
+
+ if (fileData->ctx == NULL ||
+ fileData->lease == NULL) {
+ /* inability to extend lease may timeout the connection.
+ * Abort the transfer!
+ */
+ goto cleanup;
+ }
+
+ /**
+ * to extend the timeout we have to report upload progress
+ * to the server.
+ */
+ if (esxVI_Int_Alloc(&percentage) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ percentage->value =
+ ((fileData->total_size - fileData->cur_size) * 100)/fileData->total_size;
+
+ esxVI_HttpNfcLeaseProgress(
+ fileData->ctx, fileData->lease, percentage);
+
+
+ fileData->time_elapsed = time(NULL);
+ }
+
+ result = 0;
+
+cleanup:
+
+ esxVI_Int_Free(&percentage);
+
+ return result < 0 ? -1 : readsize;
+
+}
+
+
#define ESX_VI__CURL__ENABLE_DEBUG_OUTPUT 0
#if ESX_VI__CURL__ENABLE_DEBUG_OUTPUT
@@ -480,6 +577,55 @@ esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content)
return 0;
}
+int esxVI_CURL_FileUpload(esxVI_CURL *curl, const char *url,
+ esxVI_FileData *fileData)
+{
+ /*
+ * FIXME: VMDK upload does not work well as it stops the transfer
+ * after sending metadata. However, this method is used to upload
+ * OVA disk, given parsing OVA we extract the exact file offset
+ * to initiate the transfer.
+ */
+
+ int result = -1;
+ int responseCode = 0;
+
+ if (fileData == NULL || fileData->fHandle == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
+ goto cleanup;
+ }
+
+ virMutexLock(&curl->lock);
+
+ curl_easy_setopt(curl->handle, CURLOPT_POST, 1L);
+ curl_easy_setopt(curl->handle, CURLOPT_URL, url);
+ curl_easy_setopt(curl->handle, CURLOPT_READDATA, fileData);
+ curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE,
+ (curl_off_t) fileData->cur_size);
+ curl_easy_setopt(curl->handle, CURLOPT_READFUNCTION,
+ esxVI_CURL_ReadFile);
+
+ responseCode = esxVI_CURL_Perform(curl, url);
+
+ virMutexUnlock(&curl->lock);
+
+ if (responseCode < 0) {
+ goto cleanup;
+ } else if (responseCode != 200 && responseCode != 201) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("HTTP response code %d for upload to '%s'"),
+ responseCode, url);
+ goto cleanup;
+ }
+
+ result = 0;
+
+cleanup:
+
+ return result;
+
+}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@ -5213,5 +5359,4 @@ esxVI_LookupManagedObjectHelper(esxVI_Context *ctx,
}
-
#include "esx_vi.generated.c"
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index 3eaeb38..324f931 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -1,9 +1,9 @@
-
/*
* esx_vi.h: client for the VMware VI API 2.5 to manage ESX hosts
*
* Copyright (C) 2011 Red Hat, Inc.
* Copyright (C) 2009-2012 Matthias Bolte <matthias.bolte(a)googlemail.com>
+ * Copyright (C) 2013 Ata E Husain Bohra <ata.husain(a)hotmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -75,6 +75,7 @@
typedef enum _esxVI_APIVersion esxVI_APIVersion;
typedef enum _esxVI_ProductVersion esxVI_ProductVersion;
typedef enum _esxVI_Occurrence esxVI_Occurrence;
+typedef enum _esxVI_UploadFileType esxVI_UploadFileType;
typedef struct _esxVI_ParsedHostCpuIdInfo esxVI_ParsedHostCpuIdInfo;
typedef struct _esxVI_CURL esxVI_CURL;
typedef struct _esxVI_SharedCURL esxVI_SharedCURL;
@@ -84,6 +85,7 @@ typedef struct _esxVI_Response esxVI_Response;
typedef struct _esxVI_Enumeration esxVI_Enumeration;
typedef struct _esxVI_EnumerationValue esxVI_EnumerationValue;
typedef struct _esxVI_List esxVI_List;
+typedef struct _esxVI_FileData esxVI_FileData;
@@ -167,6 +169,37 @@ int esxVI_CURL_Download(esxVI_CURL *curl, const char *url, char **content,
unsigned long long offset, unsigned long long *length);
int esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content);
+/* Upload Files to ESX server */
+
+/**
+ * Based on file, upload may be requied to do extra work.
+ * For instance: OVA file upload need to report upload transfer
+ * progress to extend Upload Lease
+ */
+enum _esxVI_UploadFileType {
+ VMDK,
+ OVA_DISK,
+ OTHERS
+};
+
+struct _esxVI_FileData
+{
+ FILE *fHandle;
+ off_t cur_size; /* file size of the current file */
+ off_t total_size; /* total size of all files */
+ esxVI_UploadFileType type; /* type of file to upload */
+ /**
+ * below parameteres are mandatory only for OVA disk upload
+ */
+ esxVI_Context *ctx;
+ esxVI_ManagedObjectReference *lease;
+ time_t time_elapsed; /* time since upload started */
+};
+
+int esxVI_FileData_Alloc(esxVI_FileData **fileData);
+void esxVI_FileData_Free(esxVI_FileData **fileData);
+int esxVI_CURL_FileUpload(esxVI_CURL *curl, const char *url,
+ esxVI_FileData *fileData);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
diff --git a/src/esx/esx_vi_generator.input b/src/esx/esx_vi_generator.input
index 22c114e..eec135e 100644
--- a/src/esx/esx_vi_generator.input
+++ b/src/esx/esx_vi_generator.input
@@ -1363,6 +1363,12 @@ method FindByUuid returns ManagedObjectReference o
end
+method HttpNfcLeaseProgress
+ ManagedObjectReference _this r
+ Int percent r
+end
+
+
method Login returns UserSession r
ManagedObjectReference _this:sessionManager r
String userName r
--
1.7.9.5
11 years, 11 months
[libvirt] [PATCH 2/5] Parsing and file handling operations for an OVA file
by Ata E Husain Bohra
The set of routines provides parsing and file handling
operation for a given OVA package, the extracted information
contains:
1. OVF descriptor (xml descriptor contained in the package)
2. List of virtual disk and related details (file name, size and
offset)
Parsing results are stored in a structure virOVA, one of the
members of this structure is head of linked list (single pointed)
which stores file details for all OVA contained files (such as:
OVF descriptor(s), virtual disk, metaconf files etc.).
---
po/POTFILES.in | 1 +
src/Makefile.am | 1 +
src/util/virova.c | 463 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/util/virova.h | 68 ++++++++
4 files changed, 533 insertions(+)
create mode 100644 src/util/virova.c
create mode 100644 src/util/virova.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 95619f9..580a035 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -182,6 +182,7 @@ src/util/viruri.c
src/util/virusb.c
src/util/virutil.c
src/util/virxml.c
+src/util/virova.c
src/vbox/vbox_MSCOMGlue.c
src/vbox/vbox_XPCOMCGlue.c
src/vbox/vbox_driver.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 955973e..2c20433 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -116,6 +116,7 @@ UTIL_SOURCES = \
util/virutil.c util/virutil.h \
util/viruuid.c util/viruuid.h \
util/virxml.c util/virxml.h \
+ util/virova.c util/virova.h \
$(NULL)
diff --git a/src/util/virova.c b/src/util/virova.c
new file mode 100644
index 0000000..23709e0
--- /dev/null
+++ b/src/util/virova.c
@@ -0,0 +1,463 @@
+/*
+ * virova.c: OVA file handling/parsing
+ *
+ * Copyright (C) 2013 Ata E Husain Bohra <ata.husain(a)hotmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+#include "internal.h"
+
+#include <string.h>
+#include <sys/stat.h>
+#include <libxml/parser.h>
+#include <libxml/xpathInternals.h>
+
+#include "virova.h"
+#include "virfile.h"
+#include "virerror.h"
+#include "viralloc.h"
+#include "virbuffer.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+#define XMLCHAR_CAST(VALUE) (const char *)(VALUE)
+
+/**
+ * OVA file is a tar file, the details of header/metadata are:
+ *
+ * ---------------- OVA/TAR Header--------------------------------------
+ *___________________________________________________________________
+ *| Field | Field | Field |
+ *| Offset| Size | |
+ *|_______|_______|__________________________________________________|
+ *| 0 | 100 |File name |
+ *| 100 | 8 |File mode |
+ *| 108 | 8 |Owner's numeric user ID |
+ *| 116 | 8 |Group's numeric user ID |
+ *| 124 | 12 |File size in bytes |
+ *| 136 | 12 |Last modification time in numeric Unix time format|
+ *| 148 | 8 |Checksum for header block |
+ *| 156 | 1 |Link indicator (file type) |
+ *| 157 | 100 |Name of linked file |
+ *| 257 | 6 |TAR magic |
+ *| 263 | 2 |Version |
+ *|_______|_______|__________________________________________________|
+ */
+
+#define FILE_NAME_LENGTH 100
+#define FILE_SIZE_LENGTH 12
+#define HEADER_SIZE 512
+#define VERSION_LENGTH 2
+#define MAGIC_LENGTH 6
+
+static const char *MAGIC_STRING = "ustar";
+static const char *GNU_VERSION = " ";
+
+static const int START_OFFSET = 0L;
+static const int FILE_SIZE_OFFSET = 24L;
+static const int MAGIC_OFFSET = 257;
+static const int VERSION_OFFSET = 263L;
+static const int HEADER_END_OFFSET = 377L;
+static const char LARGE_FILE_OCTET = '\200';
+
+static int validateOVAMagic(FILE *fHandle);
+
+
+/**
+ * validateOVAMagic: verify OVA magix string
+ *
+ * @fHandle: FILE*
+ *
+ * validate if given OVA package contains a valid TAR magic string.
+ */
+int
+validateOVAMagic(FILE *fHandle)
+{
+ int result = -1;
+ char magic[MAGIC_LENGTH+1] = {'\0'};
+ char version[VERSION_LENGTH+1] = {'\0'};
+ size_t bytesRead = 0;
+
+ if (fseeko(fHandle, MAGIC_OFFSET, SEEK_SET) < 0) {
+ virReportSystemError(errno, "%s", _("Seek error: OVA magic string"));
+ goto cleanup;
+ }
+
+ bytesRead = fread(magic, 1, MAGIC_LENGTH, fHandle);
+ if (bytesRead != MAGIC_LENGTH) {
+ virReportSystemError(errno, "%s", _("Unable to read magic string"));
+ goto cleanup;
+ }
+
+ if (STRNEQLEN(magic, MAGIC_STRING, MAGIC_LENGTH-1)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Invalid magic string"));
+ goto cleanup;
+ }
+
+ /* FIXME: Version string can be found at offset 263 in the header.
+ * Two supported tar version packages are:
+ * 1. POSIX_VERSION: version string is "00"
+ * 2. GNU_VERSION: version string is " "
+ *
+ * Current parsing support is valid ONLY for GNU VERSION format
+ */
+ if (fseeko(fHandle, VERSION_OFFSET, SEEK_SET) < 0) {
+ virReportSystemError(errno, "%s", _("Seek error: version string"));
+ goto cleanup;
+ }
+
+ bytesRead = fread(version, 1, VERSION_LENGTH, fHandle);
+ if (bytesRead != VERSION_LENGTH) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Error reading version string"));
+ goto cleanup;
+ }
+
+ if (STRNEQLEN(version, GNU_VERSION, VERSION_LENGTH-1)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Only GNU VERSION OVA packages are supported"));
+ goto cleanup;
+ }
+
+ result = 0;
+
+cleanup:
+
+ /* ignore seek error */
+ fseeko(fHandle, START_OFFSET, SEEK_SET);
+
+ return result;
+
+}
+
+
+
+/**
+ * virParseOva
+ *
+ * @ovaPath: string containing full path of OVA file.
+ *
+ * Function open OVA package and populates virOVA struct
+ */
+int
+virParseOVA(const char *ovaPath, virOVAPtr *ret)
+{
+ int result = -1;
+ virOVAPtr ova = NULL;
+ virOVADiskListPtr listItr = NULL;
+ char fileSizeBuff[FILE_SIZE_LENGTH+1] = {'\0'};
+ size_t bytesRead = 0;
+ off_t adjust = 0;
+ struct stat buff;
+
+ if (VIR_ALLOC(ova) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ova->fHandle = fopen(ovaPath, "r");
+ if (ova->fHandle == NULL) {
+ virReportSystemError(errno, "%s", _("Unable to open file"));
+ goto cleanup;
+ }
+
+ if (fstat(fileno(ova->fHandle), &buff) < 0) {
+ virReportSystemError(errno, "%s", _("File stat error"));
+ goto cleanup;
+ }
+
+ ova->totalSize = buff.st_size;
+
+ /* seek to the stating of the package */
+ if (fseeko(ova->fHandle, START_OFFSET, SEEK_SET) < 0) {
+ virReportSystemError(errno, "%s", _("File seek error"));
+ goto cleanup;
+ }
+
+ /* verify OVA magic string is valid. */
+ if (validateOVAMagic(ova->fHandle) < 0) {
+ goto cleanup;
+ }
+
+ /* extract details */
+ while (1) {
+ virOVADiskList *diskList = NULL;
+
+ if (VIR_ALLOC(diskList) < 0 ||
+ VIR_ALLOC(diskList->data)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ memset(diskList->data->name, '\0', FILE_NAME_LENGTH+1);
+ diskList->data->offset = 0;
+ diskList->data->size = 0;
+ diskList->next = NULL;
+
+ memset(fileSizeBuff, '\0', FILE_SIZE_LENGTH+1);
+
+ /* extract file name */
+ bytesRead = fread(diskList->data->name, 1, FILE_NAME_LENGTH,
+ ova->fHandle);
+ if (bytesRead <= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Invalid file name"));
+ goto cleanup;
+ }
+
+ if (diskList->data->name[0] == '\0') {
+ /* package parsing is done */
+ VIR_FREE(diskList->data);
+ VIR_FREE(diskList);
+ break;
+ }
+
+ /* extract file size */
+ if (fseeko(ova->fHandle, FILE_SIZE_OFFSET, SEEK_CUR) < 0) {
+ virReportSystemError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("File seek error"));
+ goto cleanup;
+ }
+
+ bytesRead = fread(fileSizeBuff, 1, FILE_SIZE_LENGTH, ova->fHandle);
+ if (bytesRead <= 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Invalid file length"));
+ goto cleanup;
+ }
+
+ /**
+ * if file size exceeds 8 G, then file size has to be obtained
+ * by reading 11 bytes of which first byte will be '\200'
+ */
+ if (fileSizeBuff[0] == LARGE_FILE_OCTET) {
+ const int byteSize = 4;
+ int i = 0;
+
+ for (i = 0; i < 8; ++i) {
+ uint8_t c = 0;
+ c = fileSizeBuff[byteSize + i];
+ diskList->data->size = (diskList->data->size << 8) | c;
+ }
+ } else {
+ sscanf(fileSizeBuff, "%lo", &diskList->data->size);
+ }
+
+ /* set the file content offset */
+ if (fseeko(ova->fHandle, HEADER_END_OFFSET, SEEK_CUR) < 0) {
+ virReportSystemError(errno, "%s", _("Seek error"));
+ VIR_FREE(diskList->data);
+ VIR_FREE(diskList);
+ goto cleanup;
+ }
+
+ diskList->data->offset = ftello(ova->fHandle) - 1;
+ if (diskList->data->offset < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Invalid file offset"));
+ VIR_FREE(diskList->data);
+ VIR_FREE(diskList);
+ goto cleanup;
+ }
+
+ /* adjust seek head to header size boundary */
+ adjust = diskList->data->size;
+ if (diskList->data->size % HEADER_SIZE) {
+ adjust = (adjust/HEADER_SIZE + 1) * HEADER_SIZE;
+ }
+
+ if (fseeko(ova->fHandle, adjust - 1, SEEK_CUR) < 0) {
+ virReportSystemError(errno, "%s", _("Seek error"));
+ goto cleanup;
+ }
+
+ if (!ova->head) {
+ ova->head = diskList;
+ listItr = ova->head;
+ } else {
+ listItr->next = diskList;
+ listItr = listItr->next;
+ }
+ }
+
+ *ret = ova;
+ result = 0;
+
+cleanup:
+
+ if (result < 0) {
+ virFreeOVA(ova);
+ }
+
+ return result;
+
+}
+
+
+/**
+ * virGetOVFDescriptor
+ *
+ * @ova: virOVAPtr
+ *
+ * Returns OVF descriptor string.
+ */
+
+int
+virGetOVFDescriptor(virOVAPtr ova, char **ret)
+{
+ int result = -1;
+ virOVADiskListPtr candidate = NULL;
+ char *fileExtension = NULL;
+ size_t bytesRead = 0;
+
+ if (ova == NULL || ret == NULL) {
+ goto cleanup;
+ }
+
+ /**
+ * TODO: OVA may have multiple OVF descriptors,
+ * for now consider deploying only one OVF at once
+ */
+ for (candidate = ova->head; candidate != NULL;
+ candidate = candidate->next) {
+ if (!candidate->data) {
+ goto cleanup;
+ }
+ fileExtension = strrchr(candidate->data->name, '.');
+ if (fileExtension && STREQ(fileExtension, ".ovf")) {
+ break;
+ }
+ }
+
+ if (!candidate) {
+ /**
+ * OVA may have multiple OVF descriptor, leave error handling
+ * to the caller
+ */
+ goto cleanup;
+ }
+
+ if (fseeko(ova->fHandle, candidate->data->offset, SEEK_SET) < 0) {
+ virReportSystemError(errno, "%s", _("File seek error"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(*ret, candidate->data->size+1) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ bytesRead = fread(*ret, 1, candidate->data->size, ova->fHandle);
+ if (bytesRead != candidate->data->size) {
+ virReportSystemError(errno, "%s", _("File read error"));
+ goto cleanup;
+ }
+
+ result = 0;
+
+cleanup:
+
+ return result;
+
+}
+
+
+
+/**
+ * virGetOVFDomainName
+ *
+ * Extract domain name from a OVF file
+ */
+char *
+virGetOVFDomainName(const char *ovf)
+{
+ char *domainName = NULL;
+ xmlNode *root_element = NULL;
+ xmlNode *curNode = NULL;
+ xmlNode *section = NULL;
+ xmlNode *element = NULL;
+ xmlDoc *doc = xmlReadMemory(ovf, strlen(ovf), NULL, NULL, 0);
+
+ if (!doc) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Error reading OVF xml"));
+ goto cleanup;
+ }
+
+ root_element = xmlDocGetRootElement(doc);
+ for (curNode = root_element; curNode != NULL; curNode = curNode->next) {
+ if (STRCASENEQ(XMLCHAR_CAST(curNode->name), "envelope")) {
+ /* not the OVF root element */
+ continue;
+ }
+
+ for (section = curNode->children; section; section = section->next) {
+ if (STRCASENEQ(XMLCHAR_CAST(section->name), "virtualsystem")) {
+ /* wait for VirtualSystem section */
+ continue;
+ }
+
+ for (element = section->children; element ; element = element->next) {
+ if (STRCASENEQ(XMLCHAR_CAST(element->name), "name")) {
+ continue;
+ }
+
+ domainName = strdup(XMLCHAR_CAST(xmlNodeGetContent(element)));
+ }
+ }
+ }
+
+cleanup:
+
+ xmlFreeDoc(doc);
+
+ return domainName;
+
+}
+
+
+
+/**
+ * virFreeOVA: free OVA structure members
+ */
+void virFreeOVA(virOVAPtr ova)
+{
+ struct _virOVADiskList *list = NULL;
+
+ if (ova == NULL) {
+ /* nothing to free */
+ return ;
+ }
+
+ if (VIR_FCLOSE(ova->fHandle) < 0) {
+ VIR_FORCE_FCLOSE(ova->fHandle);
+ }
+
+ /* iterate over linked list and free */
+ while (ova->head != NULL) {
+ list = ova->head;
+ ova->head = ova->head->next;
+
+ VIR_FREE(list->data);
+ VIR_FREE(list);
+ }
+
+ VIR_FREE(ova);
+
+}
diff --git a/src/util/virova.h b/src/util/virova.h
new file mode 100644
index 0000000..df74e0f
--- /dev/null
+++ b/src/util/virova.h
@@ -0,0 +1,68 @@
+/*
+ * virova.h: OVA file handling/parsing
+ *
+ * Copyright (C) 2013 Ata E Husain Bohra <ata.husain(a)hotmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_OVA_H_
+# define __VIR_OVA_H_
+
+# include <fcntl.h>
+# include <stdio.h>
+
+typedef struct _virOVADiskList virOVADiskList;
+typedef struct _virOVADiskFile virOVADiskFile;
+typedef struct _virOVA virOVA;
+
+/* opaque management of OVA file details */
+struct _virOVADiskFile {
+ char name[101]; /* TAR header file name limit */
+ off_t size; /* virtual disk file size */
+ off_t offset; /* virtual disk file offset */
+};
+
+typedef virOVADiskFile *virOVADiskFilePtr;
+
+/* opaque type to maintain OVA files as single pointer linked list */
+struct _virOVADiskList {
+ struct _virOVADiskList *next;
+ virOVADiskFilePtr data;
+};
+
+typedef virOVADiskList *virOVADiskListPtr;
+
+/**
+ * parse OVA and populate the containing file details (OVA desc, vDisk etc.)
+ */
+struct _virOVA {
+ FILE* fHandle; /* file handle for OVA file */
+ virOVADiskListPtr head; /* virtual disk single linked list */
+ off_t totalSize; /* total size of OVA package */
+};
+
+typedef virOVA *virOVAPtr;
+
+int virParseOVA(const char *ovaPath, virOVAPtr *ret);
+
+int virGetOVFDescriptor(virOVAPtr ova, char **ret);
+
+char *virGetOVFDomainName(const char *ovf);
+
+void virFreeOVA(virOVAPtr ova);
+
+#endif /* __VIR_OVA_H_ */
--
1.7.9.5
11 years, 11 months
[libvirt] [PATCH 0/5] Add support to define new domain using an OVA package.
by Ata E Husain Bohra
This patch aims to extend libvirt functionality to define new
domain using a given OVA package. The patch consist of multiple
commits divided mainly into two categories:
Infrastructure support:
-----------------------
Patch 1,2 and 5 lays the foundation work including:
1. Libvirt Public API support.
2. OVA file handling and parsing operations.
3. virsh command.
ESX specific implementation:
---------------------------
Patch 3 and 4 adds implementation support to define new domain
for a ESX hypervisor.
NOTE:
-----
During development of this patch, I have fixed two issues with
exisiting ESX hypervisor driver, they are posted as seperate
reviews:
1. https://www.redhat.com/archives/libvir-list/2012-December/msg01377.html
2. https://www.redhat.com/archives/libvir-list/2013-January/msg00007.html
Above patches are necessary for proper functioning of the proposed feature.
Ata E Husain Bohra (5):
Public API to allow defining new domain using OVA file
Parsing and file handling operations for an OVA file
ESX: CURL routine to allow file upload to the server
ESX: Driver support to define new domain using an OVA pacakge
virsh: Command to define new domain using OVA package.
include/libvirt/libvirt.h.in | 3 +
po/POTFILES.in | 1 +
src/Makefile.am | 1 +
src/driver.h | 5 +
src/esx/esx_driver.c | 573 +++++++++++++++++++++++++-
src/esx/esx_vi.c | 147 ++++++-
src/esx/esx_vi.h | 35 +-
src/esx/esx_vi_generator.input | 862 +++++++++++++++++++++++++++++++++++++++-
src/esx/esx_vi_generator.py | 13 +-
src/esx/esx_vi_types.c | 13 +-
src/libvirt.c | 58 +++
src/libvirt_public.syms | 5 +
src/util/virova.c | 463 +++++++++++++++++++++
src/util/virova.h | 68 ++++
tools/virsh-domain.c | 44 ++
15 files changed, 2264 insertions(+), 27 deletions(-)
create mode 100644 src/util/virova.c
create mode 100644 src/util/virova.h
--
1.7.9.5
11 years, 11 months
[libvirt] [PATCH] Install virtlockd.{socket, service} non executable
by Guido Günther
since they're not scripts but systemd service files.
---
src/Makefile.am | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index f7a9b91..0cfc1ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1687,9 +1687,9 @@ DISTCLEANFILES += virtlockd.service virtlockd.socket
install-systemd: virtlockd.service virtlockd.socket install-sysconfig
$(MKDIR_P) $(DESTDIR)$(SYSTEMD_UNIT_DIR)
- $(INSTALL_SCRIPT) virtlockd.service \
+ $(INSTALL_DATA) virtlockd.service \
$(DESTDIR)$(SYSTEMD_UNIT_DIR)/
- $(INSTALL_SCRIPT) virtlockd.socket \
+ $(INSTALL_DATA) virtlockd.socket \
$(DESTDIR)$(SYSTEMD_UNIT_DIR)/
uninstall-systemd: uninstall-sysconfig
--
1.7.10.4
11 years, 11 months
[libvirt] [PATCH 0/4] Fix segfault while redefining snapshots and allow redefinition of external snapshots
by Peter Krempa
This series fixes two issues while redefining snapshots:
1) Segfault when disk alignment of the new snapshot failed (patch 3)
2) Failure to redefine external snapshots. A check was missing to align disks for external snapshots. (patch 4)
Peter Krempa (4):
snapshot: conf: Make virDomainSnapshotIsExternal more reusable
snapshot: qemu: Separate logic blocks with newlines
snapshot: qemu: Fix segfault and vanishing snapshots when redefining
snapshot: qemu: Allow redefinition of external snapshots
src/conf/snapshot_conf.c | 14 ++++++++----
src/conf/snapshot_conf.h | 1 +
src/libvirt_private.syms | 1 +
src/qemu/qemu_driver.c | 57 +++++++++++++++++++++++++++++++++++-------------
4 files changed, 54 insertions(+), 19 deletions(-)
--
1.8.0.2
11 years, 11 months