[libvirt] RFC: Exposing backing chains in <domain> XML
by Eric Blake
tl;dr:
I am working on a series of patches to expose backing chain information
in <domain> XML. Comments are welcome, to make sure my XML design is on
the right track.
Purpose
=======
Among other things, this will help us support Peter's proposal of
enhancing the block-pull and block-commit actions to specify a
destination by relative depth in the backing chain (where "vda[0]"
represents the active image, "vda[1]" represents the backing file of the
active image, and so on).
It will also help debug situations where libvirt and qemu disagree on
what constitutes a backing chain, and therefore causes sVirt labeling
discrepancies or prohibits block-pull/block-commit actions. For
example, given the chain "base <- mid <- top", if top forgot the
backing_fmt attribute, and /etc/libvirt/qemu.conf
allow_disk_format_probing=0 (which it is by default for security
resasons), libvirt treats 'mid' as a raw file and refuses to acknowledge
that 'base' is part of the chain, while qemu would happily treat mid as
qcow2 and therefore use 'base' if permissions allow it to. I have
helped debug this scenario several times on IRC or in bugzilla reports.
This feature is being driven in part by
https://bugzilla.redhat.com/show_bug.cgi?id=1069407
Existing design
===============
Note that libvirt can already expose backing file details (but only one
layer; it is not recursive) when using virStorageVolGetXMLDesc(); for
example:
# virsh vol-dumpxml --pool gluster img3
<volume type='network'>
<name>img3</name>
<key>vol1/img3</key>
...
<target>
<path>gluster://localhost/vol1/img3</path>
<format type='qcow2'/>
...
</target>
<backingStore>
<path>gluster://localhost/vol1/img2</path>
<format type='qcow2'/>
<permissions>
<mode>00</mode>
<owner>0</owner>
<group>0</group>
</permissions>
</backingStore>
</volume>
In the current volume representation, if a <backingStore> element is
present, it gives the <path> to the backing file. But this
representation is a bit limited: it is rather hard-coded to the
assumption that there is only one backing file, and does not do a good
job when the backing image is not in the same storage pool as the volume
it is describing. Some of the enhancements I'm proposing for <domain>
should also be applied to the information output by <volume> XML, which
means I have to be careful that the design I'm proposing will mesh well
with the storage xml to maximize code reuse.
The volume approach is a bit painful to users trying to track the
backing chain of a disk tied to a <domain> because it necessitates
creating a storage pool and making multiple calls to follow the chain,
so we need to expose the backing chain directly in the <disk> element of
a domain, and recursively show the entire chain. Furthermore, there are
some formats that require multiple resources: for example, both qemu
2.0's new quorum driver and HyperV VHDX images can have multiple backing
files, and where these files can in turn have more backing images.
Thus, any proper representation of disk resources needs to show a full
tree of relationships. Thankfully, circular references in backing files
would form an invalid image (all known virtual disk image formats
require a DAG of relationships).
With existing API, we still have not fully implemented 'virsh
snapshot-delete' of external snapshots. So our current advice is for
people to manually use qemu-img to alter backing chains, then update
libvirt to match. Once libvirt starts tracking backing chains, it
becomes all the more important to provide two new actions in libvirt: we
need a validation mode (check that what is recorded on disk matches what
is recorded in XML and flag an error if they differ) and a correction
mode (ignore what is recorded in XML and regenerate it to match what is
actually on disk).
Proposal
========
For each <disk> of a domain, I will be adding a new <backingStore>
element. The element is optional on input, which allows libvirt to
continue to understand input from older versions, but will always be
present on output, to show what libvirt is tracking as the backing chain.
For a file with no backing store (including raw file format), the usage
is simple:
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='/path/to/somewhere'/>
<backingStore/>
<target dev='vda' bus='virtio'/>
</disk>
The new explicit <backingStore/> makes it clear that there is no backing
chain.
A backing chain of 3 files (base <- mid <- top) in the local file system:
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/top.qcow2'/>
<backingStore type='file'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/mid.qcow2'/>
<backingStore type='file'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/base.qcow2'/>
<backingStore/>
</backingStore>
</backingStore>
<target dev='vda' bus='virtio'/>
</disk>
Note that this is intentionally nested, so that for file formats that
support more than one backing resource, it can list parallel
<backingStore> as siblings to describe those related resources (thus
leaving the door open to expose a qemu quorum as a <disk type='quorum'>
with no direct <source> but instead with three <backingStore> sibling
elements for each member of the quorum, and where each member of the
quorum can further have its own backing chain).
Design wise, the <backingStore> element is either completely empty
(end-of-chain), or has a mandatory type='...' attribute that mirrors the
same type attribute of a <disk>. Then, within the backingStore element,
there is a <source> or other appropriate sub-elements similar to what
<disk> already uses for describing a single host resource. So, for an
example, here would be the output for a 2-element chain on gluster:
<disk type='network' device='disk'>
<driver name='qemu' type='qcow2'/>
<source protocol='gluster' name='vol1/img2'>
<host name='red'/>
</source>
<backingStore type='network'>
<driver name='qemu' type='qcow2'/>
<source protocol='gluster' name='vol1/img1'>
<host name='red'/>
</source>
<backingStore/>
</backingStore>
<target dev='vdb' bus='virtio'/>
</disk>
Or again, but this time using volume references to a storage pool
(assuming 'glusterVol1' is the storage pool wrapping gluster://red/vol1):
<disk type='volume' device='disk'>
<driver name='qemu' type='qcow2'/>
<source pool='glusterVol1' volume='img2'/>
<backingStore type='volume'>
<driver name='qemu' type='qcow2'/>
<source pool='glusterVol1' volume='img1'/>
<backingStore/>
</backingStore>
<target dev='vdb' bus='virtio'/>
</disk>
As can be seen, this design heavily reuses existing <disk type='...'>
handling, which should make it easier to reuse blocks of code both in
libvirt to handle the backing chains, and in clients when processing
backing chains to hand to libvirt up front or in inspecting the dumpxml
results. Management apps like vdsm that use transient domains should
start supplying <backingStore> elements to fully describe chains.
Implementation
==============
The following APIs will be affected:
defining domain XML (whether via define for persistent domains, or
create for transient domains): parse the new element. If the element is
already present, default to trusting the backing chain in that element
instead of reading from the disk files. If the element is absent, read
the disk files and populate the element. It is probably also worth
adding a flag to trigger validation mode: read the disk files to ensure
they match the xml, and refuse the operation if there is a mismatch (as
for updating xml to match reality, the simplest is to edit the XML and
delete the <backingStore> element then try the define again, so I don't
see the need for a flag for that action).
I may also need to figure out if it is worth tainting a domain any time
where libvirt detects that the XML backing chain vs. the disk file read
backing chain have diverged.
Note that defining domain XML includes loading from saved state or from
incoming migration.
dumping domain XML: always output the new element, by default without
consulting disk files. By tracking the chain in memory ever since the
guest is defined, it should already be available for output. I'm
debating whether we need a flag (similar to virsh dumpxml --update-cpu)
that can force libvirt to re-read the disk files at the time of the dump
and regenerate the chain to match reality of any changes made behind
libvirt's back.
creating external snapshots: the <domainsnapshot> XMl will continue to
be the picture of the domain prior to the creation of the snapshot (but
this picture will now include any <backingStore> elements already
present in the chain), but after the snapshot is taken, the <domain> XML
will also be modified to record the updated chain (the old disk source
is now the <backingStore> of the new disk source).
deleting external snapshots is not yet implemented, but the
implementation will have to shrink the backingStore chain to match reality.
block-pull (block-rebase in pull mode), block-commit: at the completion
of the pull, the <backingStore> needs to be updated to reflect the new
shorter state of the chain
block-copy (block-rebase in copy mode): the operation starts out by
creating a mirror, but during the first phase, the mirror is not usable
as an accurate copy of what the guest sees. Right now we fudge by
saying that block copy can only be done on transient domains; but even
with that, we still track a <mirror> element in the <disk> XML to track
that a block copy is underway (so that the operation survives a libvirtd
restart). The <mirror> element will now need to be taught a
<backingStore>, particularly if the user passes in a pre-existing file
to be reused as the copy destination. Then, when the second phase is
complete and the mirroring is ended, the <disk> will need another update
to select which side of the backing chain is now in force
virsh domblklist: should be taught a new flag to show the backing chain
in a tree format, since the command already exists to extract <disk>
information from a domain into a nicer human format
sVirt security labeling: right now, we are read the disk files to both
label and remove labels on a backing chain - obviously, once the chain
is tracked natively as part of the <disk>, we should be labeling without
having to read disk files
storage volumes - investigate how much of the backing chain code can be
reused in enhancing storage volume xml output
anything else you can think of in the code base that will be impacted?
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
11 years
[libvirt] [java] [PATCH 1/2] GetNodeCpuStat binding
by Pasquale.phate867@gmail.com
From: Pasquale Di Rienzo <phate867(a)gmail.com>
-Added the getNodeCpuStat binding to Libvirt class
-Added virNodeCPUStats and CPUStat classes to support this binding
-Added the method getCPUStats to Connect class
---
AUTHORS | 1 +
src/main/java/org/libvirt/CPUStat.java | 57 ++++++++++++++++++++++
src/main/java/org/libvirt/Connect.java | 53 ++++++++++++++++++++
src/main/java/org/libvirt/jna/Libvirt.java | 5 ++
src/main/java/org/libvirt/jna/virNodeCPUStats.java | 19 ++++++++
5 files changed, 135 insertions(+)
create mode 100644 src/main/java/org/libvirt/CPUStat.java
create mode 100644 src/main/java/org/libvirt/jna/virNodeCPUStats.java
diff --git a/AUTHORS b/AUTHORS
index 07809bf..77139e5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -16,3 +16,4 @@ Andrea Sansottera <andrea.sansottera(a)gmail.com>
Stefan Majer <stefan.majer(a)gmail.com>
Wido den Hollander <wido(a)widodh.nl>
Eric Blake <eblake(a)redhat.com>
+Pasquale Di Rienzo <phate867(a)gmail.com>
diff --git a/src/main/java/org/libvirt/CPUStat.java b/src/main/java/org/libvirt/CPUStat.java
new file mode 100644
index 0000000..527049c
--- /dev/null
+++ b/src/main/java/org/libvirt/CPUStat.java
@@ -0,0 +1,57 @@
+package org.libvirt;
+
+import java.nio.charset.Charset;
+import org.libvirt.jna.virNodeCPUStats;
+import org.libvirt.jna.virTypedParameter;
+
+/**
+ * This class holds a cpu time.
+ * The tag attribute is a string of either "kernel","user","idle","iowait"
+ * while the value attribute is the actual time value
+ * @author Pasquale Di Rienzo
+ *
+ */
+public class CPUStat {
+ public String tag;
+ public long value;
+
+ private String createStringFromBytes(byte[] b){
+ Charset ch = Charset.forName("UTF-8");
+ int i = 0;
+ while ((i<b.length) && (b[i]!=0))
+ i++;
+
+ return new String(b,0,i,ch);
+ }
+
+ public CPUStat(virNodeCPUStats stat){
+ tag = createStringFromBytes(stat.field);
+ value = stat.value.longValue();
+ }
+
+ public CPUStat(virTypedParameter stat){
+ tag = createStringFromBytes(stat.field);
+ value = stat.value.l;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public long getValue() {
+ return value;
+ }
+
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ public void setValue(long val) {
+ this.value = val;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("tag:%s%nval:%d%n", tag, value);
+ }
+}
diff --git a/src/main/java/org/libvirt/Connect.java b/src/main/java/org/libvirt/Connect.java
index fedc60e..d8a4ce2 100644
--- a/src/main/java/org/libvirt/Connect.java
+++ b/src/main/java/org/libvirt/Connect.java
@@ -2,6 +2,8 @@ package org.libvirt;
import java.util.UUID;
+import org.libvirt.CPUStat;
+import org.libvirt.LibvirtException;
import org.libvirt.jna.ConnectionPointer;
import org.libvirt.jna.DevicePointer;
import org.libvirt.jna.DomainPointer;
@@ -14,6 +16,7 @@ import org.libvirt.jna.StoragePoolPointer;
import org.libvirt.jna.StorageVolPointer;
import org.libvirt.jna.StreamPointer;
import org.libvirt.jna.virConnectAuth;
+import org.libvirt.jna.virNodeCPUStats;
import org.libvirt.jna.virNodeInfo;
import static org.libvirt.Library.libvirt;
@@ -23,6 +26,7 @@ import static org.libvirt.ErrorHandler.processErrorIfZero;
import com.sun.jna.Memory;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
+import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.LongByReference;
/**
@@ -207,6 +211,55 @@ public class Connect {
}
return processError(success);
}
+
+ /**
+ * This function returns statistics about the cpu, that is the time
+ * each cpu is spending in kernel time, user time, io time and idle time.
+ * Each CPUStat object refers to a particular time.
+ *
+ * Note that not all these stats are granted to be retrieved.
+ *
+ * @param the number of the cpu you want to retrieve stats from.
+ * passing -1 will make this function retrieve a mean value
+ * from all cpus the system has.
+ *
+ * @param some flags
+ * @return a cpustat object for each cpu
+ * @throws LibvirtException
+ */
+ public CPUStat[] getCPUStats(int cpuNumber,long flags) throws LibvirtException{
+ CPUStat[] stats = null;
+
+ IntByReference nParams = new IntByReference();
+
+ //according to libvirt reference you call this function once passing
+ //null as param paramether to get the actual stats (kernel,user,io,idle) number into the
+ //nParams reference. Generally this number would be 4, but some systems
+ //may not give all 4 times, so it is always good to call it.
+ int result = libvirt.virNodeGetCPUStats(
+ VCP, cpuNumber, null, nParams, flags);
+
+ processError(result);
+
+ if(result == 0){//dunno if this check is actually needed
+
+ //this time we create an array to fit the number of paramethers
+ virNodeCPUStats[] params = new virNodeCPUStats[nParams.getValue()];
+ //and we pass it to the function
+ result = libvirt.virNodeGetCPUStats(VCP, cpuNumber , params, nParams, flags);
+ processError(result);
+
+ //finally we parse the result in an user friendly class which does
+ //not expose libvirt's internal paramethers
+ if(result >= 0){
+ stats = new CPUStat[params.length];
+ for(int i=0;i<params.length;i++)
+ stats[i] = new CPUStat(params[i]);
+ }
+ }
+
+ return stats;
+ }
/**
* Compares the given CPU description with the host CPU
diff --git a/src/main/java/org/libvirt/jna/Libvirt.java b/src/main/java/org/libvirt/jna/Libvirt.java
index 0e4c9fc..658299f 100644
--- a/src/main/java/org/libvirt/jna/Libvirt.java
+++ b/src/main/java/org/libvirt/jna/Libvirt.java
@@ -1,5 +1,8 @@
package org.libvirt.jna;
+import org.libvirt.jna.ConnectionPointer;
+import org.libvirt.jna.virNodeCPUStats;
+
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
@@ -267,6 +270,8 @@ public interface Libvirt extends Library {
int virNetworkUndefine(NetworkPointer virConnectPtr);
// Node functions
+ int virNodeGetCPUStats(ConnectionPointer virConnectPtr, int cpuNum,
+ virNodeCPUStats[] stats,IntByReference nparams, long flags);
int virNodeGetInfo(ConnectionPointer virConnectPtr, virNodeInfo virNodeInfo);
int virNodeGetCellsFreeMemory(ConnectionPointer virConnectPtr, LongByReference freeMems, int startCell,
int maxCells);
diff --git a/src/main/java/org/libvirt/jna/virNodeCPUStats.java b/src/main/java/org/libvirt/jna/virNodeCPUStats.java
new file mode 100644
index 0000000..a8f2dca
--- /dev/null
+++ b/src/main/java/org/libvirt/jna/virNodeCPUStats.java
@@ -0,0 +1,19 @@
+package org.libvirt.jna;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.sun.jna.NativeLong;
+import com.sun.jna.Structure;
+
+public class virNodeCPUStats extends Structure{
+ public byte[] field = new byte[80];
+ public NativeLong value ;
+
+ private static final List fields = Arrays.asList( "field", "value");
+
+ @Override
+ protected List getFieldOrder() {
+ return fields;
+ }
+}
--
1.8.3.2
11 years
[libvirt] [PATCH] nodeinfo: Make sure we always reset errno before calling readdir
by Natanael Copa
We must always reset errno to 0 even if we do 'continue'.
This fixes runtime with musl libc which will set errno on sscanf.
Signed-off-by: Natanael Copa <ncopa(a)alpinelinux.org>
---
src/nodeinfo.c | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 53ba716..8d3214e 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -452,8 +452,7 @@ virNodeParseNode(const char *node,
/* enumerate sockets in the node */
CPU_ZERO(&sock_map);
- errno = 0;
- while ((cpudirent = readdir(cpudir))) {
+ for (errno = 0; (cpudirent = readdir(cpudir)); errno = 0) {
if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
continue;
@@ -470,8 +469,6 @@ virNodeParseNode(const char *node,
if (sock > sock_max)
sock_max = sock;
-
- errno = 0;
}
if (errno) {
@@ -490,8 +487,7 @@ virNodeParseNode(const char *node,
/* iterate over all CPU's in the node */
rewinddir(cpudir);
- errno = 0;
- while ((cpudirent = readdir(cpudir))) {
+ for (errno = 0; (cpudirent = readdir(cpudir)); errno = 0) {
if (sscanf(cpudirent->d_name, "cpu%u", &cpu) != 1)
continue;
@@ -530,8 +526,6 @@ virNodeParseNode(const char *node,
if (siblings > *threads)
*threads = siblings;
-
- errno = 0;
}
if (errno) {
@@ -672,8 +666,7 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
goto fallback;
}
- errno = 0;
- while ((nodedirent = readdir(nodedir))) {
+ for (errno = 0; (nodedirent = readdir(nodedir)); errno = 0) {
if (sscanf(nodedirent->d_name, "node%u", &node) != 1)
continue;
@@ -699,8 +692,6 @@ int linuxNodeInfoCPUPopulate(FILE *cpuinfo,
if (threads > nodeinfo->threads)
nodeinfo->threads = threads;
-
- errno = 0;
}
if (errno) {
--
1.9.1
11 years
[libvirt] [PATCH tck] 202-numa-set-parameters.t: use AFFECT_CONFIG when changing nodeset
by Mike Latimer
The 202-numa-set-parameters.t test sets NUMA_NODESET using AFFECT_LIVE on a
running domain, destroys and starts the domain, then verifies the NUMA_NODESET
setting. As AFFECT_LIVE does not write the setting to the domain xml file,
the new nodeset setting is lost when the domain is destroyed and the test
fails.
This patch adds AFFECT_CONFIG to set_numa_parameters, so both the live
environment and the xml file are updated with the new setting. An additional
test was also added, before the domain is destroyed, to ensure the nodeset
change is seen on the live domain.
---
scripts/domain/202-numa-set-parameters.t | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/scripts/domain/202-numa-set-parameters.t b/scripts/domain/202-numa-set-parameters.t
index 886a979..f5ed871 100644
--- a/scripts/domain/202-numa-set-parameters.t
+++ b/scripts/domain/202-numa-set-parameters.t
@@ -28,7 +28,7 @@ after the API call to set NUMA parameters for a domain.
use strict;
use warnings;
-use Test::More tests => 12;
+use Test::More tests => 13;
use Sys::Virt::TCK;
use Test::Exception;
@@ -57,8 +57,12 @@ my %params = (
Sys::Virt::Domain::NUMA_NODESET => '0',
);
-diag "Set numa parameters, affects live config";
-lives_ok(sub {$dom->set_numa_parameters(\%params, Sys::Virt::Domain::AFFECT_LIVE)}, "set_numa_parameters");
+diag "Set numa parameters, affects live and config";
+lives_ok(sub {$dom->set_numa_parameters(\%params, Sys::Virt::Domain::AFFECT_LIVE | Sys::Virt::Domain::AFFECT_CONFIG)}, "set_numa_parameters");
+
+diag "Get numa parameters";
+my $params = $dom->get_numa_parameters(Sys::Virt::Domain::AFFECT_LIVE);
+ok($params->{Sys::Virt::Domain::NUMA_NODESET} eq '0', 'Check nodeset');
diag "Destroy the domain";
$dom->destroy;
@@ -68,7 +72,7 @@ $dom->create;
ok($dom->get_id > 0, "running domain with ID > 0");
diag "Get numa parameters";
-my $params = $dom->get_numa_parameters(Sys::Virt::Domain::AFFECT_LIVE);
+$params = $dom->get_numa_parameters(Sys::Virt::Domain::AFFECT_LIVE);
ok($params->{Sys::Virt::Domain::NUMA_NODESET} eq '0', 'Check nodeset');
diag "Destroy the domain";
--
1.8.4.5
11 years
[libvirt] [PATCH tck] 220-no-ip-spoofing.t: Don't use a static netmask
by Mike Latimer
For environments not using a /24 netmask, this test can end up in a hung
state. This patch reads the netmask from the nic and uses it later when
ip addresses are changed and restored.
---
scripts/nwfilter/220-no-ip-spoofing.t | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/scripts/nwfilter/220-no-ip-spoofing.t b/scripts/nwfilter/220-no-ip-spoofing.t
index 5e8e0d7..3a0213d 100644
--- a/scripts/nwfilter/220-no-ip-spoofing.t
+++ b/scripts/nwfilter/220-no-ip-spoofing.t
@@ -79,19 +79,20 @@ $ssh->login("root", $tck->root_password());
diag "preparing ip spoof";
my $cmdfile = <<EOF;
echo "DEV=`ip link | head -3 | tail -1 | awk '{print \\\$2}' | sed -e 's/://'`
+MASK=`ip addr show \\\$DEV | grep 'inet ' | awk '{print \\\$2}' | sed -e 's/.*\\///;q'`
/sbin/ip addr show \\\$DEV
/sbin/ip link set \\\$DEV down
/sbin/ip addr flush dev \\\$DEV
-/sbin/ip addr add 192.168.122.183/24 dev \\\$DEV
+/sbin/ip addr add 192.168.122.183/\\\$MASK dev \\\$DEV
/sbin/ip link set \\\$DEV up
/sbin/ip addr show \\\$DEV
/bin/sleep 1
/bin/ping -c 1 192.168.122.1
/sbin/ip link set \\\$DEV down
/sbin/ip addr flush dev \\\$DEV
-/sbin/ip addr add ${guestip}/24 dev \\\$DEV
+/sbin/ip addr add ${guestip}/\\\$MASK dev \\\$DEV
/sbin/ip link set \\\$DEV up
-/sbin/ip link \\\$DEV" > /test.sh
+/sbin/ip addr show \\\$DEV" > /test.sh
EOF
diag $cmdfile;
my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile);
--
1.8.4.5
11 years
[libvirt] [PATCH tck] 210-no-mac-spoofing.t: Catch network is unreachable error
by Mike Latimer
Some environments (openSUSE 13.1) can report the network is unreachable during
this test. Trap that condition as well.
---
scripts/nwfilter/210-no-mac-spoofing.t | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/nwfilter/210-no-mac-spoofing.t b/scripts/nwfilter/210-no-mac-spoofing.t
index d7c57e6..7e80216 100644
--- a/scripts/nwfilter/210-no-mac-spoofing.t
+++ b/scripts/nwfilter/210-no-mac-spoofing.t
@@ -92,7 +92,7 @@ echo "DEV=`ip link | head -3 | tail -1 | awk '{print \\\$2}' | sed -e 's/://'`
/sbin/ip link set \\\$DEV address ${macfalse}
/sbin/ip link set \\\$DEV up
/sbin/ip addr show dev \\\$DEV
-/bin/ping -c 10 ${gateway}
+/bin/ping -c 10 ${gateway} 2>&1
/sbin/ip link set \\\$DEV down
/sbin/ip link set \\\$DEV address ${mac}
/sbin/ip link set \\\$DEV up
@@ -119,7 +119,7 @@ diag $exit;
diag $stdout;
diag $stderr;
diag $exit;
-ok($stdout =~ "100% packet loss", "packet loss expected");
+ok($stdout =~ /100% packet loss|Network is unreachable/, "packet loss expected");
shutdown_vm_gracefully($dom);
--
1.8.4.5
11 years
[libvirt] [PATCH tck] 110-static-relabel-yes.t: Only 5 tests in 110-static-relabel
by Mike Latimer
Trivial, but there are only 5 tests in 110-static-relabel-yes.t.
---
scripts/selinux/110-static-relabel-yes.t | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/selinux/110-static-relabel-yes.t b/scripts/selinux/110-static-relabel-yes.t
index f558cc9..76781ca 100644
--- a/scripts/selinux/110-static-relabel-yes.t
+++ b/scripts/selinux/110-static-relabel-yes.t
@@ -28,7 +28,7 @@ and files can be relabelled
use strict;
use warnings;
-use Test::More tests => 6;
+use Test::More tests => 5;
use Sys::Virt::TCK;
use Sys::Virt::TCK::SELinux;
--
1.8.4.5
11 years
[libvirt] [PATCH tck] 300-vsitype.t: Skip after $tck is defined
by Mike Latimer
With $tck added to the skip conditional, the entire codeblock has to be
after $tck is defined. Also, $tck->cleanup should be added to the skip
conditions.
---
scripts/nwfilter/300-vsitype.t | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/scripts/nwfilter/300-vsitype.t b/scripts/nwfilter/300-vsitype.t
index 1de67d1..430618f 100644
--- a/scripts/nwfilter/300-vsitype.t
+++ b/scripts/nwfilter/300-vsitype.t
@@ -28,14 +28,6 @@ use warnings;
use Test::More;
-if ( ! -e '/usr/sbin/lldptool' ) {
- eval "use Test::More skip_all => \"lldptool is not available\";";
-} elsif (!$tck->get_host_network_device()) {
- eval "use Test::More skip_all => \"no host net device configured\";";
-} else {
- eval "use Test::More tests => 4";
-}
-
use Sys::Virt::TCK;
use Sys::Virt::TCK::NetworkHelpers;
use Test::Exception;
@@ -49,6 +41,16 @@ END {
$tck->cleanup if $tck;
}
+if ( ! -e '/usr/sbin/lldptool' ) {
+ $tck->cleanup if $tck;
+ eval "use Test::More skip_all => \"lldptool is not available\";";
+} elsif (!$tck->get_host_network_device()) {
+ $tck->cleanup if $tck;
+ eval "use Test::More skip_all => \"no host net device configured\";";
+} else {
+ eval "use Test::More tests => 4";
+}
+
# create first domain and start it
my $xml = $tck->generic_domain(name => "tck", fullos => 1,
netmode => "vepa")->as_xml();
--
1.8.4.5
11 years
[libvirt] [java] [PATCH] GetNodeCpuStat binding
by phate867@gmail.com
From: Pasquale Di Rienzo <phate867(a)gmail.com>
-Added the getNodeCpuStat binding to Libvirt class
-Added virNodeCPUStats and CPUStat classes to support this binding
-Added the method getCPUStats to Connect class
---
AUTHORS | 1 +
src/main/java/org/libvirt/CPUStat.java | 57 ++++++++++++++++++++++
src/main/java/org/libvirt/Connect.java | 53 ++++++++++++++++++++
src/main/java/org/libvirt/jna/Libvirt.java | 5 ++
src/main/java/org/libvirt/jna/virNodeCPUStats.java | 19 ++++++++
5 files changed, 135 insertions(+)
create mode 100644 src/main/java/org/libvirt/CPUStat.java
create mode 100644 src/main/java/org/libvirt/jna/virNodeCPUStats.java
diff --git a/AUTHORS b/AUTHORS
index 07809bf..77139e5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -16,3 +16,4 @@ Andrea Sansottera <andrea.sansottera(a)gmail.com>
Stefan Majer <stefan.majer(a)gmail.com>
Wido den Hollander <wido(a)widodh.nl>
Eric Blake <eblake(a)redhat.com>
+Pasquale Di Rienzo <phate867(a)gmail.com>
diff --git a/src/main/java/org/libvirt/CPUStat.java b/src/main/java/org/libvirt/CPUStat.java
new file mode 100644
index 0000000..527049c
--- /dev/null
+++ b/src/main/java/org/libvirt/CPUStat.java
@@ -0,0 +1,57 @@
+package org.libvirt;
+
+import java.nio.charset.Charset;
+import org.libvirt.jna.virNodeCPUStats;
+import org.libvirt.jna.virTypedParameter;
+
+/**
+ * This class holds a cpu time.
+ * The tag attribute is a string of either "kernel","user","idle","iowait"
+ * while the value attribute is the actual time value
+ * @author Pasquale Di Rienzo
+ *
+ */
+public class CPUStat {
+ public String tag;
+ public long value;
+
+ private String createStringFromBytes(byte[] b){
+ Charset ch = Charset.forName("UTF-8");
+ int i = 0;
+ while ((i<b.length) && (b[i]!=0))
+ i++;
+
+ return new String(b,0,i,ch);
+ }
+
+ public CPUStat(virNodeCPUStats stat){
+ tag = createStringFromBytes(stat.field);
+ value = stat.value.longValue();
+ }
+
+ public CPUStat(virTypedParameter stat){
+ tag = createStringFromBytes(stat.field);
+ value = stat.value.l;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public long getValue() {
+ return value;
+ }
+
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ public void setValue(long val) {
+ this.value = val;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("tag:%s%nval:%d%n", tag, value);
+ }
+}
diff --git a/src/main/java/org/libvirt/Connect.java b/src/main/java/org/libvirt/Connect.java
index fedc60e..d8a4ce2 100644
--- a/src/main/java/org/libvirt/Connect.java
+++ b/src/main/java/org/libvirt/Connect.java
@@ -2,6 +2,8 @@ package org.libvirt;
import java.util.UUID;
+import org.libvirt.CPUStat;
+import org.libvirt.LibvirtException;
import org.libvirt.jna.ConnectionPointer;
import org.libvirt.jna.DevicePointer;
import org.libvirt.jna.DomainPointer;
@@ -14,6 +16,7 @@ import org.libvirt.jna.StoragePoolPointer;
import org.libvirt.jna.StorageVolPointer;
import org.libvirt.jna.StreamPointer;
import org.libvirt.jna.virConnectAuth;
+import org.libvirt.jna.virNodeCPUStats;
import org.libvirt.jna.virNodeInfo;
import static org.libvirt.Library.libvirt;
@@ -23,6 +26,7 @@ import static org.libvirt.ErrorHandler.processErrorIfZero;
import com.sun.jna.Memory;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
+import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.LongByReference;
/**
@@ -207,6 +211,55 @@ public class Connect {
}
return processError(success);
}
+
+ /**
+ * This function returns statistics about the cpu, that is the time
+ * each cpu is spending in kernel time, user time, io time and idle time.
+ * Each CPUStat object refers to a particular time.
+ *
+ * Note that not all these stats are granted to be retrieved.
+ *
+ * @param the number of the cpu you want to retrieve stats from.
+ * passing -1 will make this function retrieve a mean value
+ * from all cpus the system has.
+ *
+ * @param some flags
+ * @return a cpustat object for each cpu
+ * @throws LibvirtException
+ */
+ public CPUStat[] getCPUStats(int cpuNumber,long flags) throws LibvirtException{
+ CPUStat[] stats = null;
+
+ IntByReference nParams = new IntByReference();
+
+ //according to libvirt reference you call this function once passing
+ //null as param paramether to get the actual stats (kernel,user,io,idle) number into the
+ //nParams reference. Generally this number would be 4, but some systems
+ //may not give all 4 times, so it is always good to call it.
+ int result = libvirt.virNodeGetCPUStats(
+ VCP, cpuNumber, null, nParams, flags);
+
+ processError(result);
+
+ if(result == 0){//dunno if this check is actually needed
+
+ //this time we create an array to fit the number of paramethers
+ virNodeCPUStats[] params = new virNodeCPUStats[nParams.getValue()];
+ //and we pass it to the function
+ result = libvirt.virNodeGetCPUStats(VCP, cpuNumber , params, nParams, flags);
+ processError(result);
+
+ //finally we parse the result in an user friendly class which does
+ //not expose libvirt's internal paramethers
+ if(result >= 0){
+ stats = new CPUStat[params.length];
+ for(int i=0;i<params.length;i++)
+ stats[i] = new CPUStat(params[i]);
+ }
+ }
+
+ return stats;
+ }
/**
* Compares the given CPU description with the host CPU
diff --git a/src/main/java/org/libvirt/jna/Libvirt.java b/src/main/java/org/libvirt/jna/Libvirt.java
index 0e4c9fc..658299f 100644
--- a/src/main/java/org/libvirt/jna/Libvirt.java
+++ b/src/main/java/org/libvirt/jna/Libvirt.java
@@ -1,5 +1,8 @@
package org.libvirt.jna;
+import org.libvirt.jna.ConnectionPointer;
+import org.libvirt.jna.virNodeCPUStats;
+
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
@@ -267,6 +270,8 @@ public interface Libvirt extends Library {
int virNetworkUndefine(NetworkPointer virConnectPtr);
// Node functions
+ int virNodeGetCPUStats(ConnectionPointer virConnectPtr, int cpuNum,
+ virNodeCPUStats[] stats,IntByReference nparams, long flags);
int virNodeGetInfo(ConnectionPointer virConnectPtr, virNodeInfo virNodeInfo);
int virNodeGetCellsFreeMemory(ConnectionPointer virConnectPtr, LongByReference freeMems, int startCell,
int maxCells);
diff --git a/src/main/java/org/libvirt/jna/virNodeCPUStats.java b/src/main/java/org/libvirt/jna/virNodeCPUStats.java
new file mode 100644
index 0000000..a8f2dca
--- /dev/null
+++ b/src/main/java/org/libvirt/jna/virNodeCPUStats.java
@@ -0,0 +1,19 @@
+package org.libvirt.jna;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.sun.jna.NativeLong;
+import com.sun.jna.Structure;
+
+public class virNodeCPUStats extends Structure{
+ public byte[] field = new byte[80];
+ public NativeLong value ;
+
+ private static final List fields = Arrays.asList( "field", "value");
+
+ @Override
+ protected List getFieldOrder() {
+ return fields;
+ }
+}
--
1.8.3.2
11 years
[libvirt] [PATCH] storage: netfs: Handle backend errors
by John Ferlan
Commit id '18642d10' caused a virt-test regression for NFS backend
storage error path checks when running the command:
'virsh find-storage-pool-sources-as netfs Unknown '
when the host did not have Gluster installed. Prior to the commit,
the test would fail with the error:
error: internal error: Child process (/usr/sbin/showmount --no-headers
--exports Unknown) unexpected exit status 1: clnt_create: RPC: Unknown host
After the commit, the error would be ignored, the call would succeed,
and an empty list of pool sources returned. This was tucked into the
commit message as an expected outcome.
When the target host does not have a GLUSTER_CLI this is a regression
over the previous release. Furthermore, even if Gluster CLI was present,
but had a failure to get devices, the API would return a failure even if
the NFS backend had found devices.
Add code to handle the error conditions.
- If NFS fails
- If there is no Gluster CLI, then jump to cleanup/failure.
- If there is a Gluster CLI, then message the NFS
failure and continue with the Gluster checks.
- If Gluster fails
- If NFS had failed, then jump to cleanup/failure.
- Message the Gluster failure and continue on.
- If only one fails, fetch and return a list of source devices
even if it's empty
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
src/storage/storage_backend.c | 14 +++++++++++++
src/storage/storage_backend.h | 1 +
src/storage/storage_backend_fs.c | 43 +++++++++++++++++++++++++++++++++++-----
3 files changed, 53 insertions(+), 5 deletions(-)
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index b56fefe..4d73902 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -1643,6 +1643,13 @@ virStorageBackendStablePath(virStoragePoolObjPtr pool,
}
#ifdef GLUSTER_CLI
+bool
+virStorageBackendHaveGlusterCLI(void)
+{
+ return true;
+}
+
+
int
virStorageBackendFindGlusterPoolSources(const char *host,
int pooltype,
@@ -1721,6 +1728,13 @@ virStorageBackendFindGlusterPoolSources(const char *host,
return ret;
}
#else /* #ifdef GLUSTER_CLI */
+bool
+virStorageBackendHaveGlusterCLI(void)
+{
+ return false;
+}
+
+
int
virStorageBackendFindGlusterPoolSources(const char *host ATTRIBUTE_UNUSED,
int pooltype ATTRIBUTE_UNUSED,
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index 4f95000..41eed97 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -87,6 +87,7 @@ int virStorageBackendFindFSImageTool(char **tool);
virStorageBackendBuildVolFrom
virStorageBackendFSImageToolTypeToFunc(int tool_type);
+bool virStorageBackendHaveGlusterCLI(void);
int virStorageBackendFindGlusterPoolSources(const char *host,
int pooltype,
virStoragePoolSourceListPtr list);
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index 4e4a7ae..f3d4a6d 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -238,9 +238,11 @@ virStorageBackendFileSystemNetFindPoolSourcesFunc(char **const groups,
}
-static void
+static int
virStorageBackendFileSystemNetFindNFSPoolSources(virNetfsDiscoverState *state)
{
+ int ret = -1;
+
/*
* # showmount --no-headers -e HOSTNAME
* /tmp *
@@ -267,9 +269,13 @@ virStorageBackendFileSystemNetFindNFSPoolSources(virNetfsDiscoverState *state)
if (virCommandRunRegex(cmd, 1, regexes, vars,
virStorageBackendFileSystemNetFindPoolSourcesFunc,
state, NULL) < 0)
- virResetLastError();
+ goto cleanup;
+ ret = 0;
+
+ cleanup:
virCommandFree(cmd);
+ return ret;
}
@@ -289,6 +295,7 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
virStoragePoolSourcePtr source = NULL;
char *ret = NULL;
size_t i;
+ bool failNFS = false;
virCheckFlags(0, NULL);
@@ -310,12 +317,38 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE
state.host = source->hosts[0].name;
- virStorageBackendFileSystemNetFindNFSPoolSources(&state);
+ if (virStorageBackendFileSystemNetFindNFSPoolSources(&state) < 0) {
+ virErrorPtr err;
+ /* If no Gluster CLI, then force error right here */
+ if (!virStorageBackendHaveGlusterCLI())
+ goto cleanup;
+
+ /* If we have a Gluster CLI, then message the error, clean it out,
+ * and move onto the Gluster code
+ */
+ err = virGetLastError();
+ VIR_ERROR(_("Failed to get NFS pool sources: '%s'"),
+ err != NULL ? err->message: _("unknown error"));
+ virResetLastError();
+ failNFS = true;
+ }
if (virStorageBackendFindGlusterPoolSources(state.host,
VIR_STORAGE_POOL_NETFS_GLUSTERFS,
- &state.list) < 0)
- goto cleanup;
+ &state.list) < 0) {
+ virErrorPtr err;
+ /* If NFS failed as well, then force the error right here */
+ if (failNFS)
+ goto cleanup;
+
+ /* Otherwise, NFS passed, so we message the Gluster error, clean
+ * it out, and generate the source list (even if it's empty)
+ */
+ err = virGetLastError();
+ VIR_ERROR(_("Failed to get Gluster pool sources: '%s'"),
+ err != NULL ? err->message: _("unknown error"));
+ virResetLastError();
+ }
if (!(ret = virStoragePoolSourceListFormat(&state.list)))
goto cleanup;
--
1.9.0
11 years