[libvirt] [PATCH v3] xml: introduce startupPolicy for chardev device
by Seiji Aguchi
[Problem]
Currently, guest OS's messages can be logged to a local disk of host OS
by creating chadevs with options below.
-chardev file,id=charserial0,path=<log file's path> -device isa-serial,chardev=chardevserial0,id=serial0
When a hardware failure happens in the disk, qemu-kvm can't create the
chardevs. In this case, guest OS doesn't boot up.
Actually, there are users who don't desire that guest OS goes down due
to a hardware failure of a log disk only. Therefore, qemu should offer
some way to boot guest OS up even if the log disk is broken.
[Solution]
This patch supports startupPolicy for chardev.
The starupPolicy is introduced just in cases where chardev is "file"
because this patch aims for making guest OS boot up when a hardware
failure happens.
In other cases (pty, dev, pipe and unix) it is not introduced
because they don't access to hardware.
The policy works as follows.
- If the value is "optional", guestOS boots up by dropping the chardev.
- If other values are specified, guestOS fails to boot up. (the default)
Description about original startupPolicy attribute:
http://libvirt.org/git/?p=libvirt.git;a=commitdiff;h=e5a84d74a278
Signed-off-by: Seiji Aguchi <seiji.aguchi(a)hds.com>
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Change from v2
- To pass "make check", add followings.
- Add serial source optional testing.
- check if startupPolicy is NULL in virDomainChrSourceDefParseXML().
- Add xml format of startupPolicy in virDomainChrSourceDefFormat().
Patch v2 and comment from Eric Blake
- https://www.redhat.com/archives/libvir-list/2013-May/msg01814.html
- https://www.redhat.com/archives/libvir-list/2013-May/msg01943.html
---
docs/formatdomain.html.in | 16 ++++++++-
docs/schemas/domaincommon.rng | 3 ++
src/conf/domain_conf.c | 22 +++++++++++-
src/conf/domain_conf.h | 1 +
src/qemu/qemu_process.c | 25 +++++++++++++-
.../qemuxml2argv-serial-source-optional.args | 9 +++++
.../qemuxml2argv-serial-source-optional.xml | 35 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 2 +
tests/qemuxml2xmltest.c | 1 +
tests/virt-aa-helper-test | 3 ++
10 files changed, 113 insertions(+), 4 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 7601aaa..5c9d4fb 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -4281,13 +4281,27 @@ qemu-kvm -net nic,model=? /dev/null
<p>
A file is opened and all data sent to the character
device is written to the file.
+ <span class="since">Since 1.0.6</span>, it is possible to define
+ policy on what happens if the file is not accessible when
+ booting or migrating. This is done by
+ a <code>startupPolicy</code> attribute:
</p>
+ <ul>
+ <li>If the value is "mandatory" (the default), the guest fails
+ to boot or migrate if the file is not found.</li>
+ <li>If the value is "optional", a missing file is at boot or
+ migration is substituted with /dev/null, so the guest still sees
+ the device but the host no longer tracks guest data on the device.</li>
+ <li>If the value is "requisite", the file is required for
+ booting, but optional on migration.</li>
+ </ul>
+
<pre>
...
<devices>
<serial type="file">
- <source path="/var/log/vm/vm-serial.log"/>
+ <source path="/var/log/vm/vm-serial.log" startupPolicy="optional"/>
<target port="1"/>
</serial>
</devices>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 745b959..10b3365 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2817,6 +2817,9 @@
</optional>
<optional>
<attribute name="path"/>
+ <optional>
+ <ref name="startupPolicy"/>
+ </optional>
</optional>
<optional>
<attribute name="host"/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 10cb7f6..279ff9e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -6819,6 +6819,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
char *path = NULL;
char *mode = NULL;
char *protocol = NULL;
+ char *startupPolicy = NULL;
int remaining = 0;
while (cur != NULL) {
@@ -6839,6 +6840,9 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
!(flags & VIR_DOMAIN_XML_INACTIVE)))
path = virXMLPropString(cur, "path");
+ if (startupPolicy == NULL &&
+ def->type == VIR_DOMAIN_CHR_TYPE_FILE)
+ startupPolicy = virXMLPropString(cur, "startupPolicy");
break;
case VIR_DOMAIN_CHR_TYPE_UDP:
@@ -6911,6 +6915,13 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
def->data.file.path = path;
path = NULL;
+
+ if (startupPolicy) {
+ def->data.file.startupPolicy =
+ virDomainStartupPolicyTypeFromString(startupPolicy);
+ startupPolicy = NULL;
+ }
+
break;
case VIR_DOMAIN_CHR_TYPE_STDIO:
@@ -15014,8 +15025,15 @@ virDomainChrSourceDefFormat(virBufferPtr buf,
if (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
(def->data.file.path &&
!(flags & VIR_DOMAIN_XML_INACTIVE))) {
- virBufferEscapeString(buf, " <source path='%s'/>\n",
- def->data.file.path);
+ virBufferEscapeString(buf, " <source path='%s'",
+ def->data.file.path);
+
+ if (def->data.file.path && def->data.file.startupPolicy) {
+ const char *policy =
+virDomainStartupPolicyTypeToString(def->data.file.startupPolicy);
+ virBufferAsprintf(buf, " startupPolicy='%s'", policy);
+ }
+ virBufferAddLit(buf, "/>\n");
}
break;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index f265966..0899556 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1102,6 +1102,7 @@ struct _virDomainChrSourceDef {
/* no <source> for null, vc, stdio */
struct {
char *path;
+ int startupPolicy; /* enum virDomainStartupPolicy */
} file; /* pty, file, pipe, or device */
struct {
char *host;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index a46d944..35d63d5 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -2511,7 +2511,30 @@ qemuProcessPrepareChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
virReportSystemError(errno,
_("Unable to pre-create chardev file '%s'"),
dev->source.data.file.path);
- return -1;
+ if (dev->source.data.file.startupPolicy !=
+ VIR_DOMAIN_STARTUP_POLICY_OPTIONAL) {
+ return -1;
+ }
+ VIR_FREE(dev->source.data.file.path);
+ /*
+ * Change a destination to /dev/null to boot guest OS up
+ * even if a log disk is broken.
+ */
+ VIR_WARN("Switch the destination to /dev/null");
+ dev->source.data.file.path = strdup("/dev/null");
+
+ if (!(dev->source.data.file.path)) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if ((fd = open(dev->source.data.file.path,
+ O_CREAT | O_APPEND, S_IRUSR|S_IWUSR)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to pre-create chardev file '%s'"),
+ dev->source.data.file.path);
+ return -1;
+ }
}
VIR_FORCE_CLOSE(fd);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.args
new file mode 100644
index 0000000..9ffe8de
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.args
@@ -0,0 +1,9 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu \
+-S -M \
+pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/test-monitor,server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=readline \
+-no-acpi -boot c -usb -hdc /tmp/idedisk.img \
+-chardev file,id=charserial0,path=/tmp/serial.log \
+-device isa-serial,chardev=charserial0,id=serial0 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.xml
new file mode 100644
index 0000000..1aeb82a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.xml
@@ -0,0 +1,35 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='file' device='disk'>
+ <source file='/tmp/idedisk.img'/>
+ <target dev='hdc' bus='ide'/>
+ <address type='drive' controller='0' bus='0' target='0' unit='2'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <serial type='file'>
+ <source path='/tmp/serial.log' startupPolicy='optional'/>
+ <target port='0'/>
+ </serial>
+ <console type='file'>
+ <source path='/tmp/serial.log' startupPolicy='optional'/>
+ <target type='serial' port='0'/>
+ </console>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 0f96eef..588c922 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -728,6 +728,8 @@ mymain(void)
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
DO_TEST("console-compat-chardev",
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
+ DO_TEST("serial-source-optional",
+ QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
DO_TEST("channel-guestfwd",
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 77cac3f..9faca1f 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -234,6 +234,7 @@ mymain(void)
DO_TEST("console-virtio-many");
DO_TEST("channel-guestfwd");
DO_TEST("channel-virtio");
+ DO_TEST("serial-source-optional");
DO_TEST("hostdev-usb-address");
DO_TEST("hostdev-pci-address");
diff --git a/tests/virt-aa-helper-test b/tests/virt-aa-helper-test
index af91c61..7172fd6 100755
--- a/tests/virt-aa-helper-test
+++ b/tests/virt-aa-helper-test
@@ -255,6 +255,9 @@ testme "0" "disk (empty cdrom)" "-r -u $valid_uuid" "$test_xml"
sed -e "s,###UUID###,$uuid,g" -e "s,###DISK###,$disk1,g" -e "s,</devices>,<serial type='file'><source path='$tmpdir/serial.log'/><target port='0'/></serial></devices>,g" "$template_xml" > "$test_xml"
testme "0" "serial" "-r -u $valid_uuid" "$test_xml"
+sed -e "s,###UUID###,$uuid,g" -e "s,###DISK###,$disk1,g" -e "s,</devices>,<serial type='file'><source path='$tmpdir/serial.log' startupPolicy='optional'/><target port='0'/></serial></devices>,g" "$template_xml" > "$test_xml"
+testme "0" "serial" "-r -u $valid_uuid" "$test_xml"
+
sed -e "s,###UUID###,$uuid,g" -e "s,###DISK###,$disk1,g" -e "s,</devices>,<serial type='pty'><target port='0'/></serial></devices>,g" "$template_xml" > "$test_xml"
testme "0" "serial (pty)" "-r -u $valid_uuid" "$test_xml"
-- 1.7.1
11 years, 9 months
[libvirt] [PATCH] libxl: unref DomainObjPrivate on error path
by Jim Fehlig
There is a potential leak of a newly created libxlDomainObjPrivate
when subsequent allocation of the object's chrdev field fails.
Unref the object on such an error so that it is properly disposed.
---
src/libxl/libxl_driver.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index ddd7943..f09ad61 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -454,8 +454,10 @@ libxlDomainObjPrivateAlloc(void)
if (!(priv = virObjectLockableNew(libxlDomainObjPrivateClass)))
return NULL;
- if (!(priv->devs = virChrdevAlloc()))
+ if (!(priv->devs = virChrdevAlloc())) {
+ virObjectUnref(priv);
return NULL;
+ }
return priv;
}
--
1.8.1.4
11 years, 9 months
[libvirt] [PATCH] virsh-domain: Fix memleak in cmdUndefine with storage
by Peter Krempa
When undefining a domain with storage when the volume isn't managed by
libvirt the name and path strings weren't freed properly.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=996050
---
tools/virsh-domain.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 8cafce4..57065e4 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -3048,6 +3048,8 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
for (i = 0; i < nvolumes; i++) {
ctxt->node = vol_nodes[i];
+ VIR_FREE(source);
+ VIR_FREE(target);
/* get volume source and target paths */
if (!(target = virXPathString("string(./target/@dev)", ctxt)))
@@ -3090,6 +3092,8 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
}
vlist[nvols].source = source;
vlist[nvols].target = target;
+ source = NULL;
+ target = NULL;
nvols++;
}
@@ -3189,6 +3193,8 @@ out:
}
cleanup:
+ VIR_FREE(source);
+ VIR_FREE(target);
for (i = 0; i < nvols; i++) {
VIR_FREE(vlist[i].source);
VIR_FREE(vlist[i].target);
--
1.8.3.2
11 years, 9 months
[libvirt] Error while adding volume through virsh
by varun bhatnagar
Hi,
I was trying to add volume...I got one xml snippet and I modified it
according to my node configuration:
< volume>
<name>testNode/cluster.vmdk </name>
<allocation>0 </allocation>
<capacity unit='G'>2<capacity>
</volume>
Now when I executed "virsh vol-create datastore1 /local/new_volume.xml" one
error message came saying:
"Error: Failed to create volume from /local/new_volume.xml"
Error: internal error: Creation of raw volumes is not supported"
Can anyone tell me what is going wrong here?
Regards,
Varun
11 years, 9 months
[libvirt] [PATCH] Fix qemuProcessReadLog with non-zero offset
by Ján Tomko
This restores the error message when QMP probing is not used.
https://bugzilla.redhat.com/show_bug.cgi?id=991334
---
src/qemu/qemu_process.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 0dccac3..31de759 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1435,18 +1435,17 @@ qemuProcessReadLog(int fd, char *buf, int buflen, int off)
ssize_t bytes;
char *eol;
- buf[0] = '\0';
-
while (off < buflen - 1) {
bytes = saferead(fd, buf + off, buflen - off - 1);
if (bytes < 0)
return -1;
- else if (bytes == 0)
- break;
off += bytes;
buf[off] = '\0';
+ if (bytes == 0)
+ break;
+
/* Filter out debug messages from intermediate libvirt process */
while ((eol = strchr(filter_next, '\n'))) {
*eol = '\0';
--
1.8.1.5
11 years, 9 months
[libvirt] [PATCH] Update polkit examples to use 'lookup' method
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
Feedback from the polkit developers indicates that the
"_detail_XXXX" attributes are a private implementation
detail. Our examples should be recommending use of the
"action.lookup('XXX')" method instead.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
docs/aclpolkit.html.in | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/docs/aclpolkit.html.in b/docs/aclpolkit.html.in
index 3f0689e..1a09139 100644
--- a/docs/aclpolkit.html.in
+++ b/docs/aclpolkit.html.in
@@ -344,10 +344,8 @@
dealing with local clients connected via the UNIX socket).
On the <code>action</code> object, the permission name is
accessible via the <code>id</code> attribute, while the
- object identifying attributes are exposed via a set of
- attributes with the naming convention <code>_detail_[attrname]</code>.
- For example, the 'domain_name' attribute would be exposed via
- a property <code>_detail_domain_name</code>.
+ object identifying attributes are exposed via the
+ <code>lookup</code> method.
</p>
<h3><a name="exconnect">Example: restricting ability to connect to drivers</a></h3>
@@ -359,7 +357,7 @@
use the <code>QEMU</code> driver and not the Xen or LXC
drivers which are also available in libvirtd.
To achieve this we need to write a rule which checks
- whether the <code>_detail_connect_driver</code> attribute
+ whether the <code>connect_driver</code> attribute
is <code>QEMU</code>, and match on an action
name of <code>org.libvirt.api.connect.getattr</code>. Using
the javascript rules format, this ends up written as
@@ -369,7 +367,7 @@
polkit.addRule(function(action, subject) {
if (action.id == "org.libvirt.api.connect.getattr" &&
subject.user == "berrange") {
- if (action._detail_connect_driver == 'QEMU') {
+ if (action.lookup("connect_driver") == 'QEMU') {
return polkit.Result.YES;
} else {
return polkit.Result.NO;
@@ -386,8 +384,8 @@ polkit.addRule(function(action, subject) {
full read-write mode. The goal is to only allow them to
see the domain called <code>demo</code> on the LXC driver.
To achieve this we need to write a rule which checks
- whether the <code>_detail_connect_driver</code> attribute
- is <code>LXC</code> and the <code>_detail_domain_name</code>
+ whether the <code>connect_driver</code> attribute
+ is <code>LXC</code> and the <code>domain_name</code>
attribute is <code>demo</code>, and match on a action
name of <code>org.libvirt.api.domain.getattr</code>. Using
the javascript rules format, this ends up written as
@@ -397,8 +395,8 @@ polkit.addRule(function(action, subject) {
polkit.addRule(function(action, subject) {
if (action.id == "org.libvirt.api.domain.getattr" &&
subject.user == "berrange") {
- if (action._detail_connect_driver == 'LXC' &&
- action._detail_domain_name == 'demo') {
+ if (action.lookup("connect_driver") == 'LXC' &&
+ action.lookup("domain_name") == 'demo') {
return polkit.Result.YES;
} else {
return polkit.Result.NO;
--
1.8.1.4
11 years, 9 months
[libvirt] Refactored previous patch into 5 patches
by Dan Walsh
[sandbox PATCH 1/5] Add virt-sandbox -s inherit, to execute the
[sandbox PATCH 2/5] Unit files only exist in Systemd Containers.
[sandbox PATCH 3/5] -S is not supported by virt-sandbox
[sandbox PATCH 4/5] Fix SEE ALSO lines to be multi-line
[sandbox PATCH 5/5] virt-sandbox needs to mention LIBVIRT_DEFAULT_URI
11 years, 9 months
[libvirt] Updated patch for virt-sandbox -s inherit
by Dan Walsh
> -s static,label=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Well running "virt-sandbox -s inherit" would run as unconfined_t for most users.
I the future we need to add a check to libvirt to ask SELinux if it is ok for a user to transiton to the label, rather then just to do it.
Imagine a confined admin which is allowed to generate containers, he should
only be allowed to generate containers with processes labels that he can
transition into, not that libvirt can transition into.
[sandbox PATCH 1/2] Add virt-sandbox -s inherit, to execute the
[sandbox PATCH 2/2] Unit files only exist in Systemd Containers.
11 years, 9 months
[libvirt] [PATCH] modify the subtitle of usb node
by Xuesong Zhang
---
docs/formatnode.html.in | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/formatnode.html.in b/docs/formatnode.html.in
index 5f57a5a..b424c96 100644
--- a/docs/formatnode.html.in
+++ b/docs/formatnode.html.in
@@ -136,11 +136,11 @@
<dl>
<dt><code>number</code></dt>
<dd>The device number.</dd>
- <dt><code>number</code></dt>
+ <dt><code>class</code></dt>
<dd>The device class.</dd>
- <dt><code>number</code></dt>
+ <dt><code>subclass</code></dt>
<dd>The device subclass.</dd>
- <dt><code>number</code></dt>
+ <dt><code>protocol</code></dt>
<dd>The device protocol.</dd>
<dt><code>description</code></dt>
<dd>If present, a description of the device.</dd>
--
1.7.11.7
11 years, 9 months
[libvirt] [test-API][PATCH] Add display of cases result to log.xml
by Hongming Zhang
The original log.xml only display the testrun result, the patch add
display of case result to log.xml.
modified: src/generator.py
-Perserver case result list and pass it to log_generator class.
modified: src/log.xsl
-Read from xml and display case result
modified: src/log_generator.py
-Create case result xml and add it to log.xml
---
src/generator.py | 5 +++--
src/log.xsl | 23 ++++++++++++++++++++---
src/log_generator.py | 16 ++++++++++++++--
3 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/src/generator.py b/src/generator.py
index 0cdc9de..208fa7b 100644
--- a/src/generator.py
+++ b/src/generator.py
@@ -87,7 +87,6 @@ class FuncGen(object):
env_logger = envlog.env_log()
casenumber = len(self.case_name_list)
start_time = time.strftime("%Y-%m-%d %H:%M:%S")
-
env_logger.info("Checking Testing Environment... ")
envck = env_inspect.EnvInspect(self.env, env_logger)
@@ -103,6 +102,7 @@ class FuncGen(object):
# retflag: [pass, fail, skip]
retflag = [0, 0, 0]
+ case_retlist = []
for i in range(casenumber):
clean_flag = False
@@ -165,7 +165,7 @@ class FuncGen(object):
retflag[2] += 1
self.fmt.print_end(mod_case, ret, env_logger)
-
+ case_retlist.append(ret)
# close hypervisor connection
envck.close_hypervisor_connection()
end_time = time.strftime("%Y-%m-%d %H:%M:%S")
@@ -179,6 +179,7 @@ class FuncGen(object):
self.log_xml_parser.add_test_summary(self.testrunid,
self.testid,
result,
+ case_retlist,
start_time,
end_time,
self.logfile)
diff --git a/src/log.xsl b/src/log.xsl
index 577a0a5..0ca6afe 100644
--- a/src/log.xsl
+++ b/src/log.xsl
@@ -119,9 +119,10 @@
<tr>
<th width="5%">No.</th>
<th width="5%">Result</th>
- <th width="12%">Start</th>
- <th width="12%">End</th>
- <th width="66%">Test Procedure</th>
+ <th width="10%">Start</th>
+ <th width="10%">End</th>
+ <th width="65%">Test Procedure</th>
+ <th width="5%">Case Result</th>
</tr>
</thead>
<tbody>
@@ -164,6 +165,22 @@
</xsl:for-each>
</table>
</td>
+ <td>
+ <table class="pro" cellspacing="1" cellspan="0" >
+ <xsl:for-each select="caseresult/case">
+ <tr>
+ <td>
+ <xsl:if test="self::node()[text()='FAIL']">
+ <tr class="fail"><xsl:value-of select="current()"/></tr>
+ </xsl:if>
+ <xsl:if test="self::node()[text()='PASS']">
+ <tr class="pass"><xsl:value-of select="current()"/></tr>
+ </xsl:if>
+ </td>
+ </tr>
+ </xsl:for-each>
+ </table>
+ </td>
</tr>
</xsl:for-each>
</tbody>
diff --git a/src/log_generator.py b/src/log_generator.py
index be483d6..de18654 100644
--- a/src/log_generator.py
+++ b/src/log_generator.py
@@ -93,7 +93,7 @@ class LogGenerator(object):
self. __write_to_file(xmldoc, self.logxml)
- def add_test_summary(self, testrunid, testid, result,
+ def add_test_summary(self, testrunid, testid, result, case_retlist,
start_time, end_time, path):
""" add a test summary xml block into log xml file """
xmldoc = minidom.parse(self.logxml)
@@ -101,6 +101,8 @@ class LogGenerator(object):
resulttext = self.doc.createTextNode(result)
testresult.appendChild(resulttext)
+ caseresult = self.doc.createElement('caseresult')
+
teststarttime = self.doc.createElement('start_time')
starttimetext = self.doc.createTextNode(start_time)
teststarttime.appendChild(starttimetext)
@@ -126,10 +128,20 @@ class LogGenerator(object):
test.childNodes.insert(0, testendtime)
test.childNodes.insert(0, teststarttime)
test.childNodes.insert(0, testresult)
+ test.childNodes.insert(0, caseresult)
+ for ret in reversed(case_retlist):
+ retstr = ''
+ if ret == 0:
+ retstr = 'PASS'
+ else:
+ retstr = 'FAIL'
+ itemresult = self.doc.createElement('case')
+ caseresulttext = self.doc.createTextNode(retstr)
+ itemresult.appendChild(caseresulttext)
+ caseresult.childNodes.insert(0,itemresult)
self. __write_to_file(xmldoc, self.logxml)
-
def add_testrun_summary(self, testrunid, passnum, failnum, totalnum,
start_time, end_time):
""" add a testrun summary xml block into log xml file """
--
1.7.1
11 years, 9 months