From xiawenc at linux.vnet.ibm.com Fri Dec 7 06:12:56 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Fri, 07 Dec 2012 14:12:56 +0800 Subject: [Libvirt-cim] [RFC] libvirt-cim0.6.2 release plan In-Reply-To: <396a03d14542c9fb6bb68e7a2d723c80d9fafbf4.1353324056.git.jdenemar@redhat.com> References: <396a03d14542c9fb6bb68e7a2d723c80d9fafbf4.1353324056.git.jdenemar@redhat.com> Message-ID: <50C188E8.5040105@linux.vnet.ibm.com> Hi, Danial Currently upstream libvirt-cim have some bug not fixed, and some patch for them not merged yet. I think 0.6.1 is not stable enough and we should release 0.6.2 with all patch merged as a stable release, so any user later could use yum upgrade to get it. I want to know your opinion, if you agree I'll resort and sent the patches again, including libvirt-cim and libcmpiutils. -- Best Regards Wenchao Xia From veillard at redhat.com Thu Dec 13 08:51:05 2012 From: veillard at redhat.com (Daniel Veillard) Date: Thu, 13 Dec 2012 16:51:05 +0800 Subject: [Libvirt-cim] [RFC] libvirt-cim0.6.2 release plan In-Reply-To: <50C188E8.5040105@linux.vnet.ibm.com> References: <396a03d14542c9fb6bb68e7a2d723c80d9fafbf4.1353324056.git.jdenemar@redhat.com> <50C188E8.5040105@linux.vnet.ibm.com> Message-ID: <20121213085105.GE4786@redhat.com> On Fri, Dec 07, 2012 at 02:12:56PM +0800, Wenchao Xia wrote: > Hi, Danial Hi Wenchao, > Currently upstream libvirt-cim have some bug not fixed, and some > patch for them not merged yet. I think 0.6.1 is not stable enough > and we should release 0.6.2 with all patch merged as a stable > release, so any user later could use yum upgrade to get it. > I want to know your opinion, if you agree I'll resort and > sent the patches again, including libvirt-cim and libcmpiutils. Okay I was in vacations and very busy so didn't looked much at libvirt-cim lately, making a new release is probably a good idea, yes send again the patches which were not reviewed and applied :-) Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard at redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/ From xiawenc at linux.vnet.ibm.com Mon Dec 17 09:31:04 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 17:31:04 +0800 Subject: [Libvirt-cim] [PATCH V2 1/2] libcmpiutil: fix potential debug print crash Message-ID: <1355736665-21321-1-git-send-email-xiawenc@linux.vnet.ibm.com> v2: Rebased. Signed-off-by: Wenchao Xia --- std_indication.c | 14 ++++++++++++-- 1 files changed, 12 insertions(+), 2 deletions(-) diff --git a/std_indication.c b/std_indication.c index f9dbea4..21df1f5 100644 --- a/std_indication.c +++ b/std_indication.c @@ -141,7 +141,12 @@ static CMPIStatus raise(struct std_indication_ctx *ctx, enabled = is_ind_enabled(ctx, ind_name, &s); if (s.rc != CMPI_RC_OK) { - CU_DEBUG("Problem checking enabled: '%s'", CMGetCharPtr(s.msg)); + if (s.msg != NULL) { + CU_DEBUG("Problem checking enabled: '%s'", + CMGetCharPtr(s.msg)); + } else { + CU_DEBUG("Problem checking enabled, msg is NULL"); + } goto out; } @@ -176,7 +181,12 @@ CMPIStatus stdi_deliver(const CMPIBroker *broker, enabled = is_ind_enabled(args->_ctx, ind_name, &s); if (s.rc != CMPI_RC_OK) { - CU_DEBUG("Problem checking enabled: '%s'", CMGetCharPtr(s.msg)); + if (s.msg != NULL) { + CU_DEBUG("Problem checking enabled: '%s'", + CMGetCharPtr(s.msg)); + } else { + CU_DEBUG("Problem checking enabled, msg is NULL"); + } goto out; } -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 09:31:05 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 17:31:05 +0800 Subject: [Libvirt-cim] [PATCH V2 2/2] libcmpiutil: add time and thread info in debug log In-Reply-To: <1355736665-21321-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355736665-21321-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355736665-21321-2-git-send-email-xiawenc@linux.vnet.ibm.com> On server we need these information to debug eaiser. v2: format adjusted. Signed-off-by: Wenchao Xia --- debug_util.c | 18 +++++++++++++++++- 1 files changed, 17 insertions(+), 1 deletions(-) diff --git a/debug_util.c b/debug_util.c index 2912fb6..0820b9f 100644 --- a/debug_util.c +++ b/debug_util.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include "libcmpiutil.h" @@ -32,6 +35,15 @@ static FILE *log = NULL; void debug_print(char *fmt, ...) { char *log_file = NULL; + pthread_t id = pthread_self(); + struct timeval tv; + struct timezone tz; + gettimeofday(&tv, &tz); + time_t timep; + struct tm *p; + time(&timep); + p=localtime(&timep); + va_list ap; va_start(ap, fmt); @@ -49,8 +61,12 @@ void debug_print(char *fmt, ...) log_init = 1; } - if (log != NULL) + if (log != NULL) { + fprintf(log, "[%d-%02d-%02d %02d:%02d:%02d.%06d] [%ld]: ", + (1900+p->tm_year), (1+p->tm_mon), p->tm_mday, p->tm_hour, + p->tm_min, p->tm_sec, (int)tv.tv_usec, id); vfprintf(log, fmt, ap); + } va_end(ap); } -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:08 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:08 +0800 Subject: [Libvirt-cim] [PATCH V2 00/11] bug fix and enhancement patch rebase for 6.2 Message-ID: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> These are the patches rebased which fix bugs reported for 6.1 or potential problem. Last patch is an enhancement for migration usage. Each patch is stand alone can can be applied independendly. Wenchao Xia (11): remove script for bridge network do not deregister virt classes in yum upgrade CSI, fix debug print crash CSI, add lock to protect shared data DevicePool, fix debug print crash DevicePool, reimplement get_diskpool_config with libvirt RASDIndication, fix debug print crash device parsing, add debug print CSI Discard libvirt event by default VSSD, fix a error report issue in VSSD enum provide a hack to borrow non-root ssh keys in migration libvirt-cim.spec.in | 12 +- libxkutil/device_parsing.c | 11 +- libxkutil/xmlgen.c | 9 +- src/Virt_ComputerSystem.c | 46 ++- src/Virt_ComputerSystemIndication.c | 581 +++++++++++++++++++- src/Virt_DevicePool.c | 43 ++- src/Virt_ResourceAllocationSettingDataIndication.c | 6 +- src/Virt_VSMigrationService.c | 96 +++- src/Virt_VSSD.c | 72 ++- src/Virt_VirtualSystemManagementService.c | 36 ++- 10 files changed, 859 insertions(+), 53 deletions(-) From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:10 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:10 +0800 Subject: [Libvirt-cim] [PATCH V2 02/11] do not deregister virt classes in yum upgrade In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-3-git-send-email-xiawenc@linux.vnet.ibm.com> Now yum upgrade will deregister the virt classes, make libvirt-cim not workable. This patch fixed it from now on. v2: Rebased. Signed-off-by: Wenchao Xia --- libvirt-cim.spec.in | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in index d78eee7..3def978 100644 --- a/libvirt-cim.spec.in +++ b/libvirt-cim.spec.in @@ -104,18 +104,22 @@ rm -fr $RPM_BUILD_ROOT -r %{CIMV2_REG} -m %{CIMV2_MOF} -v >/dev/null 2>&1 || true %preun -%{_datadir}/%{name}/provider-register.sh -d -t pegasus \ +#Deregister only in uninstall, do nothing in upgrade. +if [ "$1" = "0" ]; then + echo "Deleting registered classes in libvirt-cim..." + %{_datadir}/%{name}/provider-register.sh -d -t pegasus \ -n @CIM_VIRT_NS@ \ -r %{REGISTRATION} -m %{SCHEMA} >/dev/null 2>&1 || true -%{_datadir}/%{name}/provider-register.sh -d -t pegasus \ + %{_datadir}/%{name}/provider-register.sh -d -t pegasus \ -n root/interop \ -r %{INTEROP_REG} -m %{INTEROP_MOF} >/dev/null 2>&1 || true -%{_datadir}/%{name}/provider-register.sh -d -t pegasus \ + %{_datadir}/%{name}/provider-register.sh -d -t pegasus \ -n root/PG_InterOp \ -r %{PGINTEROP_REG} -m %{PGINTEROP_MOF} >/dev/null 2>&1 || true -%{_datadir}/%{name}/provider-register.sh -d -t pegasus \ + %{_datadir}/%{name}/provider-register.sh -d -t pegasus \ -n root/cimv2 \ -r %{CIMV2_REG} -m %{CIMV2_MOF} >/dev/null 2>&1 || true +fi %postun -p /sbin/ldconfig -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:13 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:13 +0800 Subject: [Libvirt-cim] [PATCH V2 05/11] DevicePool, fix debug print crash In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-6-git-send-email-xiawenc@linux.vnet.ibm.com> v2: Rebased. Signed-off-by: Wenchao Xia --- src/Virt_DevicePool.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index 202e509..79dc108 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -710,7 +710,7 @@ static bool mempool_set_consumed(CMPIInstance *inst, virConnectPtr conn) dom = virDomainLookupByID(conn, domain_ids[i]); if (dom == NULL) { - CU_DEBUG("Cannot connect to domain %n: excluding", + CU_DEBUG("Cannot connect to domain %d: excluding", domain_ids[i]); continue; } -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:16 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:16 +0800 Subject: [Libvirt-cim] [PATCH V2 08/11] device parsing, add debug print In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-9-git-send-email-xiawenc@linux.vnet.ibm.com> Sometime libvirt will fail in these API when there are low level error, what we saw is libvirt can't got xml for some domain. This patch add debug log when met this error, so in future we can know where is wrong better. v2: Rebased. Signed-off-by: Wenchao Xia --- libxkutil/device_parsing.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index ceb4552..2841662 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -1251,12 +1251,19 @@ int get_dominfo(virDomainPtr dom, struct domain **dominfo) xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); - if (xml == NULL) + if (xml == NULL) { + CU_DEBUG("Failed to get dom xml with libvirt API."); return 0; + } ret = get_dominfo_from_xml(xml, dominfo); - if (virDomainGetAutostart(dom, &start) != 0) + if (ret != 1) { + CU_DEBUG("Failed to translate xml into struct domain"); + } + if (virDomainGetAutostart(dom, &start) != 0) { + CU_DEBUG("Failed to get dom autostart with libvirt API."); return 0; + } (*dominfo)->autostrt = start; -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:09 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:09 +0800 Subject: [Libvirt-cim] [PATCH V2 01/11] remove script for bridge network In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-2-git-send-email-xiawenc@linux.vnet.ibm.com> libvirt0.9.10 will report error if bridge network was defined with script. This is the fix for it, otherwise VM start would fail. v2: rebased. Signed-off-by: Wenchao Xia --- libxkutil/xmlgen.c | 9 +-------- 1 files changed, 1 insertions(+), 8 deletions(-) diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 2dcd0d2..31619d8 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -269,18 +269,11 @@ static const char *set_net_source(xmlNodePtr nic, return NULL; } - +/* libvirt 0.9.10 report error if script is set with brdige */ static const char *bridge_net_to_xml(xmlNodePtr nic, struct net_device *dev) { - const char *script = "vif-bridge"; - xmlNodePtr tmp; const char *msg = NULL; - tmp = xmlNewChild(nic, NULL, BAD_CAST "script", NULL); - if (tmp == NULL) - return XML_ERROR; - xmlNewProp(tmp, BAD_CAST "path", BAD_CAST script); - msg = set_net_source(nic, dev, "bridge"); return msg; -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:12 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:12 +0800 Subject: [Libvirt-cim] [PATCH V2 04/11] CSI, add lock to protect shared data In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-5-git-send-email-xiawenc@linux.vnet.ibm.com> This patch added lock on shared data without which may trigger incorrect data operation. Global lock is used so speed may be slowed down, it can be improved in the future. Original code have a small chance to free thread->args in child thread just after main thread malloc it, for that thread->id is set to zero allowing main thread to enter that code. v2: Rebased. Signed-off-by: Wenchao Xia --- src/Virt_ComputerSystemIndication.c | 39 ++++++++++++++++++++++++++++++++-- 1 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index b1b9fa0..3159ca0 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -174,9 +174,11 @@ static void csi_free_thread_data(void *data) if (data == NULL) return; + pthread_mutex_lock(&lifecycle_mutex); list_free(thread->dom_list); thread->dom_list = NULL; stdi_free_ind_args(&thread->args); + pthread_mutex_unlock(&lifecycle_mutex); } void set_source_inst_props(const CMPIBroker *broker, @@ -490,6 +492,8 @@ static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) return s.rc; } +/* following function will protect global data with lifecycle_mutex. + TODO: improve it with seperate lock later. */ static void csi_domain_event_cb(virConnectPtr conn, virDomainPtr dom, int event, @@ -502,10 +506,13 @@ static void csi_domain_event_cb(virConnectPtr conn, char *prefix = class_prefix_name(thread->args->classname); CMPIStatus s = {CMPI_RC_OK, NULL}; + pthread_mutex_lock(&lifecycle_mutex); if (lifecycle_enabled == false || thread->active_filters <= 0) { CU_DEBUG("%s indications deactivated, return", prefix); + pthread_mutex_unlock(&lifecycle_mutex); return; } + pthread_mutex_unlock(&lifecycle_mutex); CU_DEBUG("Event: Domain %s(%d) event: %d detail: %d\n", virDomainGetName(dom), virDomainGetID(dom), event, detail); @@ -537,7 +544,9 @@ static void csi_domain_event_cb(virConnectPtr conn, if (cs_event != CS_CREATED) { char uuid[VIR_UUID_STRING_BUFLEN] = {0}; virDomainGetUUIDString(dom, &uuid[0]); + pthread_mutex_lock(&lifecycle_mutex); dom_xml = list_find(thread->dom_list, uuid); + pthread_mutex_unlock(&lifecycle_mutex); } if (dom_xml == NULL) { @@ -545,12 +554,16 @@ static void csi_domain_event_cb(virConnectPtr conn, goto end; } + pthread_mutex_lock(&lifecycle_mutex); async_ind(thread->args, cs_event, dom_xml, prefix); + pthread_mutex_unlock(&lifecycle_mutex); /* Update the domain list accordingly */ if (event == VIR_DOMAIN_EVENT_DEFINED) { if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) { + pthread_mutex_lock(&lifecycle_mutex); csi_thread_dom_list_append(thread, dom_xml); + pthread_mutex_unlock(&lifecycle_mutex); } else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) { free(dom_xml->name); free(dom_xml->xml); @@ -558,7 +571,9 @@ static void csi_domain_event_cb(virConnectPtr conn, } } else if (event == VIR_DOMAIN_EVENT_DEFINED && detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { + pthread_mutex_lock(&lifecycle_mutex); list_remove(thread->dom_list, dom_xml); + pthread_mutex_unlock(&lifecycle_mutex); } end: @@ -579,10 +594,12 @@ static CMPI_THREAD_RETURN lifecycle_thread(void *params) if (prefix == NULL) goto init_out; + pthread_mutex_lock(&lifecycle_mutex); conn = connect_by_classname(_BROKER, args->classname, &s); if (conn == NULL) { CU_DEBUG("Unable to start lifecycle thread: " "Failed to connect (cn: %s)", args->classname); + pthread_mutex_unlock(&lifecycle_mutex); goto conn_out; } @@ -594,33 +611,47 @@ static CMPI_THREAD_RETURN lifecycle_thread(void *params) if (cb_id == -1) { CU_DEBUG("Failed to register domain event watch for '%s'", - args->classname) + args->classname); + pthread_mutex_unlock(&lifecycle_mutex); goto cb_out; } CBAttachThread(_BROKER, args->context); /* Get currently defined domains */ - if (update_domain_list(conn, thread) != CMPI_RC_OK) + if (update_domain_list(conn, thread) != CMPI_RC_OK) { + pthread_mutex_unlock(&lifecycle_mutex); goto end; + } + pthread_mutex_unlock(&lifecycle_mutex); CU_DEBUG("Entering CSI event loop (%s)", prefix); - while (thread->active_filters > 0) { + while (1) { + pthread_mutex_lock(&lifecycle_mutex); + if (thread->active_filters <= 0) { + pthread_mutex_unlock(&lifecycle_mutex); + break; + } + pthread_mutex_unlock(&lifecycle_mutex); if (virEventRunDefaultImpl() < 0) { virErrorPtr err = virGetLastError(); CU_DEBUG("Failed to run event loop: %s\n", err && err->message ? err->message : "Unknown error"); } + usleep(1); } CU_DEBUG("Exiting CSI event loop (%s)", prefix); + pthread_mutex_lock(&lifecycle_mutex); CBDetachThread(_BROKER, args->context); + pthread_mutex_unlock(&lifecycle_mutex); end: virConnectDomainEventDeregisterAny(conn, cb_id); cb_out: + pthread_mutex_lock(&lifecycle_mutex); thread->id = 0; thread->active_filters = 0; @@ -628,6 +659,8 @@ static CMPI_THREAD_RETURN lifecycle_thread(void *params) if (thread->args != NULL) stdi_free_ind_args(&thread->args); + pthread_mutex_unlock(&lifecycle_mutex); + conn_out: virConnectClose(conn); -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:15 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:15 +0800 Subject: [Libvirt-cim] [PATCH V2 07/11] RASDIndication, fix debug print crash In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-8-git-send-email-xiawenc@linux.vnet.ibm.com> v2: Rebased. Signed-off-by: Wenchao Xia --- src/Virt_ResourceAllocationSettingDataIndication.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/src/Virt_ResourceAllocationSettingDataIndication.c b/src/Virt_ResourceAllocationSettingDataIndication.c index a386132..93fb563 100644 --- a/src/Virt_ResourceAllocationSettingDataIndication.c +++ b/src/Virt_ResourceAllocationSettingDataIndication.c @@ -122,7 +122,11 @@ static CMPIStatus raise_indication(const CMPIBroker *broker, if (s.rc == CMPI_RC_OK) { CU_DEBUG("Indication delivered"); } else { - CU_DEBUG("Not delivered: %s", CMGetCharPtr(s.msg)); + if (s.msg == NULL) { + CU_DEBUG("Not delivered: msg is NULL."); + } else { + CU_DEBUG("Not delivered: %s", CMGetCharPtr(s.msg)); + } } out: -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:17 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:17 +0800 Subject: [Libvirt-cim] [PATCH V2 09/11] CSI Discard libvirt event by default In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-10-git-send-email-xiawenc@linux.vnet.ibm.com> From cimtest, Calling to virEventRegisterDefaultImpl() of libvirt API, resulting random fail in cases, which seems most likely tog-pegasus's internal data is damaged. The root cause may be: 1 libvirt event API have a bug, we called it from thread A and then do other things in thread B, maybe it did not handle this well. 2 tog-pegasus have confilict with libvirt's event. 3 Potential requirement in libvirt event API or tog-pegasus's thread, which is not document so we used them in a wrong way. To me, most possible is that tog-pegasus tries to manage all threads resulting the error. This patch bring back libvirt-cim's own old event implemention, which is by default used now. CSI from libvirt can still be activated with a macro. This patch also have changed some buglike code of old libvirt-cim's event implemention. Tested with cimtest on following Env, no more strange error found: RH6.3 libvirt-0.9.10-21.el6.x86_64 tog-pegasus-2.11.0-3.el6.x86_64 v2: Rebased. minor change for getting current vm status code in CSI child thread. Comment out the debug print in CSI child thread. Signed-off-by: Wenchao Xia --- src/Virt_ComputerSystem.c | 46 +++- src/Virt_ComputerSystemIndication.c | 540 ++++++++++++++++++++++++++++- src/Virt_VirtualSystemManagementService.c | 36 ++- 3 files changed, 616 insertions(+), 6 deletions(-) diff --git a/src/Virt_ComputerSystem.c b/src/Virt_ComputerSystem.c index e6c7e55..adef85e 100644 --- a/src/Virt_ComputerSystem.c +++ b/src/Virt_ComputerSystem.c @@ -45,8 +45,45 @@ #include "Virt_HostSystem.h" #include "Virt_VirtualSystemSnapshotService.h" +#include "config.h" + const static CMPIBroker *_BROKER; +#ifndef USE_LIBVIRT_EVENT +static bool trigger_mod_indication(const CMPIContext *context, + CMPIInstance *prev_inst, + const CMPIObjectPath *ref) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + const char *ind_name = "ComputerSystemModifiedIndication"; + CMPIInstance *ind = NULL; + char *type = NULL; + + CU_DEBUG("Preparing ComputerSystem indication"); + + ind = get_typed_instance(_BROKER, + CLASSNAME(ref), + ind_name, + NAMESPACE(ref)); + if (ind == NULL) { + CU_DEBUG("Failed to create ind '%s'", ind_name); + goto out; + } + + CU_DEBUG("Setting PreviousInstance"); + CMSetProperty(ind, "PreviousInstance", + (CMPIValue *)&prev_inst, CMPI_instance); + + type = get_typed_class(CLASSNAME(ref), ind_name); + + s = stdi_raise_indication(_BROKER, context, type, NAMESPACE(ref), ind); + + out: + free(type); + return s.rc == CMPI_RC_OK; +} +#endif + /* Set the "Name" property of an instance from a domain */ static int set_name_from_dom(virDomainPtr dom, CMPIInstance *instance) { @@ -1256,8 +1293,15 @@ static CMPIStatus state_change(CMPIMethodMI *self, s = __state_change(name, state, reference); - if (s.rc == CMPI_RC_OK) + if (s.rc == CMPI_RC_OK) { +#ifndef USE_LIBVIRT_EVENT + bool ind_rc= trigger_mod_indication(context, prev_inst, + reference); + if (!ind_rc) + CU_DEBUG("Unable to trigger indication"); +#endif rc = 0; + } out: CMReturnData(results, &rc, CMPI_uint32); diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index 3159ca0..6b5cdd4 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -48,6 +48,8 @@ #include "Virt_ComputerSystemIndication.h" #include "Virt_HostSystem.h" +#define WAIT_TIME 60 +#define FAIL_WAIT_TIME 2 #define CSI_NUM_PLATFORMS 3 enum CSI_PLATFORMS { @@ -80,6 +82,7 @@ struct _csi_thread_data_t { }; static const CMPIBroker *_BROKER; +static pthread_cond_t lifecycle_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER; static bool lifecycle_enabled = false; static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; @@ -580,6 +583,376 @@ static void csi_domain_event_cb(virConnectPtr conn, free(prefix); } +/* libvirt-cim's private CSI implement */ +struct dom_xml { + char uuid[VIR_UUID_STRING_BUFLEN]; + char *xml; + enum {DOM_OFFLINE, + DOM_ONLINE, + DOM_PAUSED, + DOM_CRASHED, + DOM_GONE, + } state; +}; + +static void free_dom_xml (struct dom_xml dom) +{ + free(dom.xml); + dom.xml = NULL; +} + +static char *sys_name_from_xml(char *xml) +{ + char *tmp = NULL; + char *name = NULL; + int rc; + + tmp = strstr(xml, ""); + if (tmp == NULL) + goto out; + + rc = sscanf(tmp, "%a[^<]s", &name); + if (rc != 1) + name = NULL; + + out: + return name; +} + +static int dom_state(virDomainPtr dom) +{ + virDomainInfo info; + int ret; + + ret = virDomainGetInfo(dom, &info); + if (ret != 0) + return DOM_GONE; + + switch (info.state) { + case VIR_DOMAIN_NOSTATE: + case VIR_DOMAIN_RUNNING: + case VIR_DOMAIN_BLOCKED: + return DOM_ONLINE; + + case VIR_DOMAIN_PAUSED: + return DOM_PAUSED; + + case VIR_DOMAIN_SHUTOFF: + return DOM_OFFLINE; + + case VIR_DOMAIN_CRASHED: + return DOM_CRASHED; + + default: + return DOM_GONE; + }; +} + +static CMPIStatus doms_to_xml(struct dom_xml **dom_xml_list, + virDomainPtr *dom_ptr_list, + int dom_ptr_count) +{ + int i; + int rc; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + if (dom_ptr_count <= 0) { + *dom_xml_list = NULL; + return s; + } + *dom_xml_list = calloc(dom_ptr_count, sizeof(struct dom_xml)); + for (i = 0; i < dom_ptr_count; i++) { + rc = virDomainGetUUIDString(dom_ptr_list[i], + (*dom_xml_list)[i].uuid); + if (rc == -1) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to get UUID"); + /* If any domain fails, we fail. */ + break; + } + + (*dom_xml_list)[i].xml = virDomainGetXMLDesc(dom_ptr_list[i], + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); + if ((*dom_xml_list)[i].xml == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to get xml desc"); + break; + } + + (*dom_xml_list)[i].state = dom_state(dom_ptr_list[i]); + } + + return s; +} + +static bool dom_changed(struct dom_xml prev_dom, + struct dom_xml *cur_xml, + int cur_count) +{ + int i; + bool ret = false; + + for (i = 0; i < cur_count; i++) { + if (strcmp(cur_xml[i].uuid, prev_dom.uuid) != 0) + continue; + + if (strcmp(cur_xml[i].xml, prev_dom.xml) != 0) { + CU_DEBUG("Domain config changed"); + ret = true; + } + + if (prev_dom.state != cur_xml[i].state) { + CU_DEBUG("Domain state changed"); + ret = true; + } + + break; + } + + return ret; +} + +static bool wait_for_event(int wait_time) +{ + struct timespec timeout; + int ret; + + + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += wait_time; + + ret = pthread_cond_timedwait(&lifecycle_cond, + &lifecycle_mutex, + &timeout); + + return true; +} + +static bool dom_in_list(char *uuid, int count, struct dom_xml *list) +{ + int i; + + for (i = 0; i < count; i++) { + if (STREQ(uuid, list[i].uuid)) + return true; + } + + return false; +} + +static bool async_ind_native(CMPIContext *context, + int ind_type, + struct dom_xml prev_dom, + char *prefix, + struct ind_args *args) +{ + bool rc = false; + char *name = NULL; + char *cn = NULL; + CMPIObjectPath *op; + CMPIInstance *prev_inst; + CMPIInstance *affected_inst; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + CU_DEBUG("Entering native indication diliv with type %d.", ind_type) + if (!lifecycle_enabled) { + CU_DEBUG("CSI not enabled, skipping indication delivery"); + return false; + } + + name = sys_name_from_xml(prev_dom.xml); + CU_DEBUG("Name for system: '%s'", name); + if (name == NULL) { + rc = false; + goto out; + } + + cn = get_typed_class(prefix, "ComputerSystem"); + + op = CMNewObjectPath(_BROKER, args->ns, cn, &s); + if ((s.rc != CMPI_RC_OK) || CMIsNullObject(op)) { + CU_DEBUG("op error"); + goto out; + } + + if (ind_type == CS_CREATED || ind_type == CS_MODIFIED) { + s = get_domain_by_name(_BROKER, op, name, &affected_inst); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("domain by name error"); + goto out; + } + } else if (ind_type == CS_DELETED) { + rc = create_deleted_guest_inst(prev_dom.xml, + args->ns, + prefix, + &affected_inst); + if (!rc) { + CU_DEBUG("Could not recreate guest instance"); + goto out; + } + } else { + CU_DEBUG("Unrecognized indication type"); + goto out; + } + + /* FIXME: We are unable to get the previous CS instance after it has + been modified. Consider keeping track of the previous + state in the place we keep track of the requested state */ + prev_inst = affected_inst; + + CMSetProperty(affected_inst, "Name", + (CMPIValue *)name, CMPI_chars); + CMSetProperty(affected_inst, "UUID", + (CMPIValue *)prev_dom.uuid, CMPI_chars); + + rc = _do_indication(_BROKER, context, prev_inst, affected_inst, + ind_type, prefix, args); + + out: + free(cn); + free(name); + return rc; +} + +static CMPI_THREAD_RETURN lifecycle_thread_native(void *params) +{ + CU_DEBUG("Entering libvirtc-cim native CSI thread."); + csi_thread_data_t *thread = (csi_thread_data_t *) params; + struct ind_args *args = thread->args; + CMPIContext *context = args->context; + char *prefix = class_prefix_name(args->classname); + virConnectPtr conn; + CMPIStatus s; + int retry_time = FAIL_WAIT_TIME; + + struct dom_xml *cur_xml = NULL; + struct dom_xml *prev_xml = NULL; + int prev_count = 0; + int cur_count = 0; + virDomainPtr *tmp_list = NULL; + int CBAttached = 0; + + if (prefix == NULL) + goto init_out; + + pthread_mutex_lock(&lifecycle_mutex); + conn = connect_by_classname(_BROKER, args->classname, &s); + if (conn == NULL) { + CU_DEBUG("Unable to start lifecycle thread: " + "Failed to connect (cn: %s)", args->classname); + pthread_mutex_unlock(&lifecycle_mutex); + goto conn_out; + } + + CBAttachThread(_BROKER, args->context); + CBAttached = 1; + prev_count = get_domain_list(conn, &tmp_list); + s = doms_to_xml(&prev_xml, tmp_list, prev_count); + free_domain_list(tmp_list, prev_count); + free(tmp_list); + if (s.rc != CMPI_RC_OK) + CU_DEBUG("doms_to_xml failed. Attempting to continue."); + + CU_DEBUG("Entering libvirt-cim native CSI event loop (%s)", prefix); + + int i; + while (1) { + if (thread->active_filters <= 0) { + break; + } + + bool res; + bool failure = false; + + cur_count = get_domain_list(conn, &tmp_list); + s = doms_to_xml(&cur_xml, tmp_list, cur_count); + free_domain_list(tmp_list, cur_count); + free(tmp_list); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("doms_to_xml failed. retry in %d seconds", + retry_time); + failure = true; + goto fail; + } + + /* CU_DEBUG("cur_count %d, prev_count %d.", + cur_count, prev_count); */ + for (i = 0; i < cur_count; i++) { + res = dom_in_list(cur_xml[i].uuid, prev_count, prev_xml); + if (!res) { + async_ind_native(context, CS_CREATED, + cur_xml[i], prefix, args); + } + + } + + for (i = 0; i < prev_count; i++) { + res = dom_in_list(prev_xml[i].uuid, cur_count, cur_xml); + if (!res) { + async_ind_native(context, CS_DELETED, + prev_xml[i], prefix, args); + } + } + + for (i = 0; i < prev_count; i++) { + res = dom_changed(prev_xml[i], cur_xml, cur_count); + if (res) { + async_ind_native(context, CS_MODIFIED, + prev_xml[i], prefix, args); + } + free_dom_xml(prev_xml[i]); + } + + fail: + if (failure) { + wait_for_event(FAIL_WAIT_TIME); + } else { + free(prev_xml); + prev_xml = cur_xml; + cur_xml = NULL; + prev_count = cur_count; + cur_count = 0; + wait_for_event(WAIT_TIME); + } + } + + CU_DEBUG("Exiting libvirt-cim native CSI event loop (%s)", prefix); + + if (prev_xml != NULL) { + for (i = 0; i < prev_count; i++) { + free_dom_xml(prev_xml[i]); + } + free(prev_xml); + prev_xml = NULL; + } + + pthread_mutex_unlock(&lifecycle_mutex); + + virConnectClose(conn); + + conn_out: + free(prefix); + + init_out: + pthread_mutex_lock(&lifecycle_mutex); + thread->id = 0; + thread->active_filters = 0; + + /* it seems tog-pegasus try kill this thread after detached, use this + flag to delay detach as much as possible. */ + if (CBAttached > 0) { + CBDetachThread(_BROKER, args->context); + } + if (thread->args != NULL) + stdi_free_ind_args(&thread->args); + + pthread_mutex_unlock(&lifecycle_mutex); + + return (CMPI_THREAD_RETURN) 0; +} + static CMPI_THREAD_RETURN lifecycle_thread(void *params) { csi_thread_data_t *thread = (csi_thread_data_t *) params; @@ -696,13 +1069,24 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, csi_thread_data_t *thread = NULL; static int events_registered = 0; +#ifndef USE_LIBVIRT_EVENT + int use_libvirt_event = 0; +#else + int use_libvirt_event = 1; +#endif + CU_DEBUG("ActivateFilter for %s", CLASSNAME(op)); pthread_mutex_lock(&lifecycle_mutex); - if (events_registered == 0) { - events_registered = 1; - virEventRegisterDefaultImpl(); + if (use_libvirt_event == 1) { + if (events_registered == 0) { + events_registered = 1; + CU_DEBUG("Registering libvirt event."); + virEventRegisterDefaultImpl(); + } + } else { + CU_DEBUG("Using libvirt-cim's event implemention."); } _ctx = (struct std_indication_ctx *)mi->hdl; @@ -753,7 +1137,20 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, args->_ctx = _ctx; thread->args = args; - thread->id = _BROKER->xft->newThread(lifecycle_thread, thread, 0); + + if (use_libvirt_event == 0) { + thread->id = _BROKER->xft->newThread( + lifecycle_thread_native, + thread, 0); + } else { + thread->id = _BROKER->xft->newThread(lifecycle_thread, + thread, 0); + } + + if (thread->id <= 0) { + CU_DEBUG("Error, failed to create new thread."); + error = true; + } out: if (error == true) { @@ -791,6 +1188,10 @@ static CMPIStatus DeActivateFilter(CMPIIndicationMI* mi, csi_thread_data[platform].active_filters -= 1; pthread_mutex_unlock(&lifecycle_mutex); +#ifndef USE_LIBVIRT_EVENT + pthread_cond_signal(&lifecycle_cond); +#endif + out: return s; } @@ -817,6 +1218,7 @@ static _EI_RTYPE DisableIndications(CMPIIndicationMI* mi, _EI_RET(); } + DECLARE_FILTER(xen_created, "Xen_ComputerSystemCreatedIndication"); DECLARE_FILTER(xen_deleted, "Xen_ComputerSystemDeletedIndication"); DECLARE_FILTER(xen_modified, "Xen_ComputerSystemModifiedIndication"); @@ -840,7 +1242,137 @@ static struct std_ind_filter *filters[] = { NULL, }; +#ifndef USE_LIBVIRT_EVENT +static CMPIStatus trigger_indication(const CMPIContext *context) +{ + CU_DEBUG("triggered"); + pthread_cond_signal(&lifecycle_cond); + return(CMPIStatus){CMPI_RC_OK, NULL}; +} + +static CMPIInstance *get_prev_inst(const CMPIBroker *broker, + const CMPIInstance *ind, + CMPIStatus *s) +{ + CMPIData data; + CMPIInstance *prev_inst = NULL; + + data = CMGetProperty(ind, "PreviousInstance", s); + if (s->rc != CMPI_RC_OK || CMIsNullValue(data)) { + cu_statusf(broker, s, + CMPI_RC_ERR_NO_SUCH_PROPERTY, + "Unable to get PreviousInstance of the indication"); + goto out; + } + + if (data.type != CMPI_instance) { + cu_statusf(broker, s, + CMPI_RC_ERR_TYPE_MISMATCH, + "Indication SourceInstance is of unexpected type"); + goto out; + } + + prev_inst = data.value.inst; + + out: + return prev_inst; +} + +static CMPIStatus raise_indication(const CMPIBroker *broker, + const CMPIContext *ctx, + const CMPIObjectPath *ref, + const CMPIInstance *ind) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *prev_inst; + CMPIInstance *src_inst; + CMPIObjectPath *_ref = NULL; + struct std_indication_ctx *_ctx = NULL; + struct ind_args *args = NULL; + char *prefix = NULL; + bool rc; + + if (!lifecycle_enabled) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "CSI not enabled, skipping indication delivery"); + goto out; + } + + prev_inst = get_prev_inst(broker, ind, &s); + if (s.rc != CMPI_RC_OK || CMIsNullObject(prev_inst)) + goto out; + + _ref = CMGetObjectPath(prev_inst, &s); + if (s.rc != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to get a reference to the guest"); + goto out; + } + + /* FIXME: This is a Pegasus work around. Pegsus loses the namespace + when an ObjectPath is pulled from an instance */ + if (STREQ(NAMESPACE(_ref), "")) + CMSetNameSpace(_ref, "root/virt"); + + s = get_domain_by_ref(broker, _ref, &src_inst); + if (s.rc != CMPI_RC_OK || CMIsNullObject(src_inst)) + goto out; + + _ctx = malloc(sizeof(struct std_indication_ctx)); + if (_ctx == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to allocate indication context"); + goto out; + } + + _ctx->brkr = broker; + _ctx->handler = NULL; + _ctx->filters = filters; + _ctx->enabled = lifecycle_enabled; + + args = malloc(sizeof(struct ind_args)); + if (args == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to allocate ind_args"); + goto out; + } + + args->ns = strdup(NAMESPACE(_ref)); + args->classname = strdup(CLASSNAME(_ref)); + args->_ctx = _ctx; + + prefix = class_prefix_name(args->classname); + + rc = _do_indication(broker, ctx, prev_inst, src_inst, + CS_MODIFIED, prefix, args); + + if (!rc) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Unable to generate indication"); + } + + out: + if (args != NULL) + stdi_free_ind_args(&args); + + if (_ctx != NULL) + free(_ctx); + + free(prefix); + return s; +} +#endif + static struct std_indication_handler csi = { +#ifndef USE_LIBVIRT_EVENT + .raise_fn = raise_indication, + .trigger_fn = trigger_indication, +#endif .activate_fn = ActivateFilter, .deactivate_fn = DeActivateFilter, .enable_fn = EnableIndications, diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 10adf8b..059b852 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -107,6 +107,24 @@ enum ResourceAction { RESOURCE_MOD, }; +#ifndef USE_LIBVIRT_EVENT +static bool trigger_indication(const CMPIContext *context, + const char *base_type, + const CMPIObjectPath *ref) +{ + char *type; + CMPIStatus s; + + type = get_typed_class(CLASSNAME(ref), base_type); + + s = stdi_trigger_indication(_BROKER, context, type, NAMESPACE(ref)); + + free(type); + + return s.rc == CMPI_RC_OK; +} +#endif + #if LIBVIR_VERSION_NUMBER < 9000 /* Network QoS support */ static CMPIStatus add_qos_for_mac(const uint64_t qos, @@ -2166,6 +2184,11 @@ static CMPIStatus define_system(CMPIMethodMI *self, CMAddArg(argsout, "ResultingSystem", &result, CMPI_ref); } +#ifndef USE_LIBVIRT_EVENT + trigger_indication(context, + "ComputerSystemCreatedIndication", + reference); +#endif out: if (s.rc == CMPI_RC_OK) rc = CIM_SVPC_RETURN_COMPLETED; @@ -2268,6 +2291,11 @@ error: NULL, reference, &list); +#ifndef USE_LIBVIRT_EVENT + trigger_indication(context, + "ComputerSystemDeletedIndication", + reference); +#endif } virDomainFree(dom); @@ -2349,8 +2377,14 @@ static CMPIStatus update_system_settings(const CMPIContext *context, connect_and_create(xml, ref, &s); } - if (s.rc == CMPI_RC_OK) + if (s.rc == CMPI_RC_OK) { set_autostart(vssd, ref, dom); +#ifndef USE_LIBVIRT_EVENT + trigger_indication(context, + "ComputerSystemModifiedIndication", + ref); +#endif + } out: free(xml); -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:18 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:18 +0800 Subject: [Libvirt-cim] [PATCH V2 10/11] VSSD, fix a error report issue in VSSD enum In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-11-git-send-email-xiawenc@linux.vnet.ibm.com> If user delete a VS and enum VSSD at the sametime, it may have chance to report error, but actually it succeed just with some VS not found. Root cause is race condition between libvirt API for get domain's name&count and the API for get domain's xml. This Patch fixed it. It will continue if found one VS is missing in enum. v2: Rebased and better document. Signed-off-by: Wenchao Xia --- src/Virt_VSSD.c | 72 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/Virt_VSSD.c b/src/Virt_VSSD.c index 499b157..bbf45e8 100644 --- a/src/Virt_VSSD.c +++ b/src/Virt_VSSD.c @@ -36,6 +36,8 @@ #include "Virt_VSSD.h" +#define VSSD_ERROR_RECOVERABLE (2) + const static CMPIBroker *_BROKER; static CMPIStatus _set_fv_prop(const CMPIBroker *broker, @@ -181,8 +183,19 @@ static int instance_from_dom(const CMPIBroker *broker, struct domain *dominfo = NULL; ret = get_dominfo(dom, &dominfo); - if (!ret) + if (!ret) { + int active = virDomainIsActive(dom); + if (active < 0) { + /* ret > 1 indicate that it is recoverable */ + CU_DEBUG("Failed to get dominfo, " + "it may not present now."); + ret = VSSD_ERROR_RECOVERABLE; + } else { + CU_DEBUG("Failed to get dominfo, " + "libvirt level error."); + } goto out; + } op = CMGetObjectPath(inst, NULL); pfx = class_prefix_name(CLASSNAME(op)); @@ -246,6 +259,8 @@ static int instance_from_dom(const CMPIBroker *broker, s = _set_fv_prop(broker, dominfo, inst); if (s.rc != CMPI_RC_OK) { ret = 0; + CU_DEBUG("Failed to set full virtual prop for %d dom.", + dominfo->type); goto out; } } @@ -260,6 +275,7 @@ static int instance_from_dom(const CMPIBroker *broker, if (asprintf(&vsid, "%s:%s", pfx, dominfo->name) == -1) { ret = 0; + CU_DEBUG("Failed in asprintf vsid."); goto out; } @@ -278,7 +294,8 @@ static CMPIInstance *_get_vssd(const CMPIBroker *broker, const CMPIObjectPath *reference, virConnectPtr conn, virDomainPtr dom, - CMPIStatus *s) + CMPIStatus *s, + int *error_below) { CMPIInstance *inst = NULL; @@ -294,10 +311,18 @@ static CMPIInstance *_get_vssd(const CMPIBroker *broker, goto out; } - if (instance_from_dom(broker, dom, inst) != 1) { - cu_statusf(broker, s, - CMPI_RC_ERR_FAILED, - "Unable to get VSSD instance from Domain"); + *error_below = instance_from_dom(broker, dom, inst); + if (*error_below != 1) { + if (*error_below == VSSD_ERROR_RECOVERABLE) { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to get VSSD instance from Domain, " + "Domain may not exist at this moment."); + } else { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to get VSSD instance from Domain"); + } } out: @@ -312,6 +337,7 @@ static CMPIStatus return_enum_vssd(const CMPIObjectPath *reference, virDomainPtr *list; int count; int i; + int error_below; CMPIStatus s = {CMPI_RC_OK, NULL}; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); @@ -327,14 +353,33 @@ static CMPIStatus return_enum_vssd(const CMPIObjectPath *reference, } else if (count == 0) goto out; + int fail_count = 0; for (i = 0; i < count; i++) { CMPIInstance *inst = NULL; - - inst = _get_vssd(_BROKER, reference, conn, list[i], &s); - + + inst = _get_vssd(_BROKER, reference, conn, list[i], + &s, &error_below); + virDomainFree(list[i]); - if (inst == NULL) - continue; + + if ((inst == NULL) || (s.rc != CMPI_RC_OK)) { + fail_count++; + CU_DEBUG("VSSD got %d fail instance, total %d," + " error %d.", + fail_count, count, error_below); + if (error_below == VSSD_ERROR_RECOVERABLE) { + cu_statusf(_BROKER, &s, + CMPI_RC_OK, + "%d/%d VSSD not got," + " some VS may not exist now", + fail_count, count); + CU_DEBUG("Continue to next VSSD for enum."); + continue; + } else { + CU_DEBUG("Met unrecoverable error."); + break; + } + } if (names_only) cu_return_instance_name(results, inst); @@ -358,7 +403,8 @@ CMPIStatus get_vssd_by_name(const CMPIBroker *broker, virDomainPtr dom; CMPIStatus s = {CMPI_RC_OK, NULL}; CMPIInstance *inst = NULL; - + int error_below; + conn = connect_by_classname(broker, CLASSNAME(reference), &s); if (conn == NULL) { cu_statusf(broker, &s, @@ -377,7 +423,7 @@ CMPIStatus get_vssd_by_name(const CMPIBroker *broker, goto out; } - inst = _get_vssd(broker, reference, conn, dom, &s); + inst = _get_vssd(broker, reference, conn, dom, &s, &error_below); virDomainFree(dom); -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:14 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:14 +0800 Subject: [Libvirt-cim] [PATCH V2 06/11] DevicePool, reimplement get_diskpool_config with libvirt In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-7-git-send-email-xiawenc@linux.vnet.ibm.com> Original implemetion may return pools with NULL name if some pool disappear between two libvirt pool API call. And caller of this function consider number = 0 as error only but it original return negative value when error before. This patch fix it. V2: Use for instead of while in clean up. Treat zero pool returned from libvirt as normal instead of error. Rebased. Signed-off-by: Wenchao Xia --- src/Virt_DevicePool.c | 41 +++++++++++++++++++++++++++++++---------- 1 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index 79dc108..3d75bf4 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -117,52 +117,73 @@ int get_disk_pool(virStoragePoolPtr poolptr, struct virt_pool **pool) return ret; } +/* This function returns the real number of pools, no negative value should be + returned, if error happens it returns zero, otherwise return at least 1. */ static int get_diskpool_config(virConnectPtr conn, struct tmp_disk_pool **_pools) { - int count = 0; + int count = 0, realcount = 0; int i; char ** names = NULL; struct tmp_disk_pool *pools = NULL; + int have_err = 0; count = virConnectNumOfStoragePools(conn); - if (count <= 0) + if (count < 0) { + have_err = 1; goto out; + } else if (count == 0) { + goto out; + } names = calloc(count, sizeof(char *)); if (names == NULL) { CU_DEBUG("Failed to alloc space for %i pool names", count); count = 0; + have_err = 1; goto out; } - if (virConnectListStoragePools(conn, names, count) == -1) { + realcount = virConnectListStoragePools(conn, names, count); + if (realcount == -1) { CU_DEBUG("Failed to get storage pools"); - count = 0; + realcount = 0; + have_err = 1; + goto out; + } + if (realcount == 0) { + CU_DEBUG("zero pools got, but prelist is %d.", count); goto out; } - pools = calloc(count, sizeof(*pools)); + pools = calloc(realcount, sizeof(*pools)); if (pools == NULL) { - CU_DEBUG("Failed to alloc space for %i pool structs", count); + CU_DEBUG("Failed to alloc space for %i pool structs", realcount); + realcount = 0; + have_err = 1; goto out; } - for (i = 0; i < count; i++) { + for (i = 0; i < realcount; i++) { pools[i].tag = strdup(names[i]); pools[i].primordial = false; + i++; } out: - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { free(names[i]); + i++; + } free(names); - get_disk_parent(&pools, &count); + if (have_err == 0) { + get_disk_parent(&pools, &realcount); + } *_pools = pools; - return count; + return realcount; } static bool diskpool_set_capacity(virConnectPtr conn, -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:19 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:19 +0800 Subject: [Libvirt-cim] [PATCH V2 11/11] provide a hack to borrow non-root ssh keys in migration In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-12-git-send-email-xiawenc@linux.vnet.ibm.com> This patch allow libvirt-cim to use non-root's ssh key in migration to avoid exposing root's ssh login on server. In some case server are forbidden to expose or provide any root ssh login, and still use ssh encryption between two migration nodes with key of special account created for virtual machine management. This patch provide it. The patch added three additonal paremeters in vs migration and migratable method, they are DestinationHostParams, SSH_Key_Src, SSH_Key_Dest. DestinationHostParams is the addtional string which would be appended after the uri if it was set, so with this parameter user could add additional parameter in libvirt remote uri, such as "?keyfile=/tmp/tempkey.rsa". Because libvirt woulkd ignore the private key file parameter, if the key's directory was not owned by the user, and libvirt-cim runs as root, so SSH_Key_Src and SSH_Key_Dest were provided to allow a copying of keyfile to a directory that owned by root, at runtime. if SSH_Key_Src and SSH_Key_Dest were set, libvirt-cim would run shell command "cp -f [SSH_Key_Src] [SSH_Key_Dest]". Typically cim client with authority to do a migration, could specify these three additonal parameters with ssh migration method set, as DestinationHostParams="?keyfile=/root/temp_migration_key.rsa" SSH_Key_Src="/home/VController/.ssh/id_rsa" SSH_Key_Dest="/root/temp_migration_key.rsa" then, the migration would complete with VController's key pairs, instead of root's, avoided turning on root's ssh logins. Test was done when SELinux was shutdown. V2: Rebased and Better documentation. Signed-off-by: Wenchao Xia --- src/Virt_VSMigrationService.c | 96 +++++++++++++++++++++++++++++++++++++++-- 1 files changed, 92 insertions(+), 4 deletions(-) diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c index 76e3d25..b03450c 100644 --- a/src/Virt_VSMigrationService.c +++ b/src/Virt_VSMigrationService.c @@ -150,6 +150,7 @@ static CMPIStatus get_migration_uri(CMPIInstance *msd, static char *dest_uri(const char *cn, const char *dest, + const char *dest_params, uint16_t transport) { const char *prefix; @@ -157,6 +158,7 @@ static char *dest_uri(const char *cn, const char *param = ""; char *uri = NULL; int rc; + int param_labeled = 0; if (STARTS_WITH(cn, "Xen")) prefix = "xen"; @@ -197,16 +199,75 @@ static char *dest_uri(const char *cn, goto out; } - if (!STREQC(param, "")) + if (!STREQC(param, "")) { rc = asprintf(&uri, "%s/%s", uri, param); + param_labeled = 1; + } - if (rc == -1) + if (rc == -1) { uri = NULL; + goto out; + } + if (dest_params) { + if (param_labeled == 0) { + rc = asprintf(&uri, "%s?%s", uri, dest_params); + } else { + rc = asprintf(&uri, "%s%s", uri, dest_params); + } + if (rc == -1) { + uri = NULL; + goto out; + } + } out: return uri; } +/* libvirt need private key specified must be placed in a directory owned by + root, because libvirt-cim now runs as root. So here the key would be copied, + up layer need to delete that key after migration. This method could allow + libvirt-cim borrow a non-root ssh private key, instead of using root's private + key, avoid security risk. */ +static int ssh_key_cp(const char *src, const char *dest) +{ + char *cmd = NULL; + int rc; + int ret = 0; + FILE *stream = NULL; + char buf[256]; + + rc = asprintf(&cmd, "cp -f %s %s", src, dest); + if (rc == -1) { + cmd = NULL; + ret = -1; + goto out; + } + + CU_DEBUG("excuting system cmd [%s].", cmd); + stream = popen(cmd, "r"); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + ret = -2; + goto out; + } + usleep(10000); + + buf[255] = 0; + while (fgets(buf, sizeof(buf), stream) != NULL) { + CU_DEBUG("Exception got: %s.", buf); + ret = -3; + goto out; + } + + out: + if (stream != NULL) { + pclose(stream); + } + free(cmd); + return ret; +} + static CMPIStatus get_msd_values(const CMPIObjectPath *ref, const char *destination, const CMPIArgs *argsin, @@ -217,6 +278,14 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref, CMPIInstance *msd; uint16_t uri_type; char *uri = NULL; + const char *dest_params = NULL; + const char *ssh_hack_src = NULL; + const char *ssh_hack_dest = NULL; + int ret; + + cu_get_str_arg(argsin, "DestinationHostParams", &dest_params); + cu_get_str_arg(argsin, "SSH_Key_Src", &ssh_hack_src); + cu_get_str_arg(argsin, "SSH_Key_Dest", &ssh_hack_dest); s = get_msd(ref, argsin, &msd); if (s.rc != CMPI_RC_OK) @@ -230,7 +299,7 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref, if (s.rc != CMPI_RC_OK) goto out; - uri = dest_uri(CLASSNAME(ref), destination, uri_type); + uri = dest_uri(CLASSNAME(ref), destination, dest_params, uri_type); if (uri == NULL) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -238,6 +307,19 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref, goto out; } + if ((ssh_hack_src) && (ssh_hack_dest)) { + CU_DEBUG("hacking ssh keys src %s, dest %s.", + ssh_hack_src, ssh_hack_dest); + ret = ssh_key_cp(ssh_hack_src, ssh_hack_dest); + if (ret < 0) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to copy ssh key files"); + goto out; + } + } + + CU_DEBUG("Migrate tring to connect remote host with uri %s.", uri); *conn = virConnectOpen(uri); if (*conn == NULL) { CU_DEBUG("Failed to connect to remote host (%s)", uri); @@ -1537,7 +1619,7 @@ static CMPIStatus migrate_vs_host(CMPIMethodMI *self, const char *dhost = NULL; CMPIObjectPath *system; const char *name = NULL; - + cu_get_str_arg(argsin, "DestinationHost", &dhost); cu_get_ref_arg(argsin, "ComputerSystem", &system); @@ -1608,6 +1690,9 @@ static struct method_handler vsimth = { .handler = vs_migratable_host, .args = {{"ComputerSystem", CMPI_ref, false}, {"DestinationHost", CMPI_string, false}, + {"DestinationHostParams", CMPI_string, true}, + {"SSH_Key_Src", CMPI_string, true}, + {"SSH_Key_Dest", CMPI_string, true}, {"MigrationSettingData", CMPI_instance, true}, {"NewSystemSettingData", CMPI_instance, true}, {"NewResourceSettingData", CMPI_instanceA, true}, @@ -1632,6 +1717,9 @@ static struct method_handler mvsth = { .handler = migrate_vs_host, .args = {{"ComputerSystem", CMPI_ref, false}, {"DestinationHost", CMPI_string, false}, + {"DestinationHostParams", CMPI_string, true}, + {"SSH_Key_Src", CMPI_string, true}, + {"SSH_Key_Dest", CMPI_string, true}, {"MigrationSettingData", CMPI_instance, true}, {"NewSystemSettingData", CMPI_instance, true}, {"NewResourceSettingData", CMPI_instanceA, true}, -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 11:10:11 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 19:10:11 +0800 Subject: [Libvirt-cim] [PATCH V2 03/11] CSI, fix debug print crash In-Reply-To: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355742619-7670-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355742619-7670-4-git-send-email-xiawenc@linux.vnet.ibm.com> v2: Rebased. Signed-off-by: Wenchao Xia --- src/Virt_ComputerSystemIndication.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index 2d0a94e..b1b9fa0 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -503,7 +503,7 @@ static void csi_domain_event_cb(virConnectPtr conn, CMPIStatus s = {CMPI_RC_OK, NULL}; if (lifecycle_enabled == false || thread->active_filters <= 0) { - CU_DEBUG("%s indications deactivated, return"); + CU_DEBUG("%s indications deactivated, return", prefix); return; } -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 12:16:14 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 20:16:14 +0800 Subject: [Libvirt-cim] [PATCH V3] DevicePool, reimplement get_diskpool_config with libvirt Message-ID: <1355746574-26140-1-git-send-email-xiawenc@linux.vnet.ibm.com> Original implemetion may return pools with NULL name if some pool disappear between two libvirt pool API call. And caller of this function consider number = 0 as error only but it original return negative value when error before. This patch fix it. V2: Use for instead of while in clean up. Treat zero pool returned from libvirt as normal instead of error. Rebased. v3: fix wrong i++ in for while, previous patch have this bug, it is patch 6/11, please ignore 6/11 in v2 serial. Signed-off-by: Wenchao Xia --- src/Virt_DevicePool.c | 39 +++++++++++++++++++++++++++++---------- 1 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index 79dc108..769de63 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -117,52 +117,71 @@ int get_disk_pool(virStoragePoolPtr poolptr, struct virt_pool **pool) return ret; } +/* This function returns the real number of pools, no negative value should be + returned, if error happens it returns zero, otherwise return at least 1. */ static int get_diskpool_config(virConnectPtr conn, struct tmp_disk_pool **_pools) { - int count = 0; + int count = 0, realcount = 0; int i; char ** names = NULL; struct tmp_disk_pool *pools = NULL; + int have_err = 0; count = virConnectNumOfStoragePools(conn); - if (count <= 0) + if (count < 0) { + have_err = 1; goto out; + } else if (count == 0) { + goto out; + } names = calloc(count, sizeof(char *)); if (names == NULL) { CU_DEBUG("Failed to alloc space for %i pool names", count); count = 0; + have_err = 1; goto out; } - if (virConnectListStoragePools(conn, names, count) == -1) { + realcount = virConnectListStoragePools(conn, names, count); + if (realcount == -1) { CU_DEBUG("Failed to get storage pools"); - count = 0; + realcount = 0; + have_err = 1; + goto out; + } + if (realcount == 0) { + CU_DEBUG("zero pools got, but prelist is %d.", count); goto out; } - pools = calloc(count, sizeof(*pools)); + pools = calloc(realcount, sizeof(*pools)); if (pools == NULL) { - CU_DEBUG("Failed to alloc space for %i pool structs", count); + CU_DEBUG("Failed to alloc space for %i pool structs", realcount); + realcount = 0; + have_err = 1; goto out; } - for (i = 0; i < count; i++) { + for (i = 0; i < realcount; i++) { pools[i].tag = strdup(names[i]); pools[i].primordial = false; } out: - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { free(names[i]); + } free(names); - get_disk_parent(&pools, &count); + if (have_err == 0) { + get_disk_parent(&pools, &realcount); + } *_pools = pools; - return count; + return realcount; } static bool diskpool_set_capacity(virConnectPtr conn, -- 1.7.1 From xiawenc at linux.vnet.ibm.com Mon Dec 17 13:49:51 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 17 Dec 2012 21:49:51 +0800 Subject: [Libvirt-cim] [PATCH V3] DevicePool, reimplement get_diskpool_config with libvirt In-Reply-To: <1355746574-26140-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355746574-26140-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <50CF22FF.7090405@linux.vnet.ibm.com> This version contains a bug, pls use v3 version of it at https://www.redhat.com/archives/libvirt-cim/2012-December/msg00016.html my mistake, sorry for that. > Original implemetion may return pools with NULL name if > some pool disappear between two libvirt pool API call. And > caller of this function consider number = 0 as error only > but it original return negative value when error before. > This patch fix it. > > V2: > Use for instead of while in clean up. > Treat zero pool returned from libvirt as normal instead of error. > Rebased. > > v3: > fix wrong i++ in for while, previous patch have this bug, it is patch 6/11, > please ignore 6/11 in v2 serial. > > Signed-off-by: Wenchao Xia > --- > src/Virt_DevicePool.c | 39 +++++++++++++++++++++++++++++---------- > 1 files changed, 29 insertions(+), 10 deletions(-) -- Best Regards Wenchao Xia From xiawenc at linux.vnet.ibm.com Tue Dec 18 09:14:04 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 17:14:04 +0800 Subject: [Libvirt-cim] [PATCH V3 0/2] libcmpiutil: patch rebase for libvirt-cim 6.2 Message-ID: <1355822046-25220-1-git-send-email-xiawenc@linux.vnet.ibm.com> Hi, Danial Sorry for have sent confusing patches, please use this serial for libcmpiutil. Wenchao Xia (2): libcmpiutil: fix potential debug print crash libcmpiutil: add time and thread info in debug log debug_util.c | 19 ++++++++++++++++++- std_indication.c | 14 ++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) From xiawenc at linux.vnet.ibm.com Tue Dec 18 09:14:05 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 17:14:05 +0800 Subject: [Libvirt-cim] [PATCH V3 1/2] libcmpiutil: fix potential debug print crash In-Reply-To: <1355822046-25220-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355822046-25220-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355822046-25220-2-git-send-email-xiawenc@linux.vnet.ibm.com> v2: Rebased. v3: No change. Signed-off-by: Wenchao Xia --- std_indication.c | 14 ++++++++++++-- 1 files changed, 12 insertions(+), 2 deletions(-) diff --git a/std_indication.c b/std_indication.c index f9dbea4..21df1f5 100644 --- a/std_indication.c +++ b/std_indication.c @@ -141,7 +141,12 @@ static CMPIStatus raise(struct std_indication_ctx *ctx, enabled = is_ind_enabled(ctx, ind_name, &s); if (s.rc != CMPI_RC_OK) { - CU_DEBUG("Problem checking enabled: '%s'", CMGetCharPtr(s.msg)); + if (s.msg != NULL) { + CU_DEBUG("Problem checking enabled: '%s'", + CMGetCharPtr(s.msg)); + } else { + CU_DEBUG("Problem checking enabled, msg is NULL"); + } goto out; } @@ -176,7 +181,12 @@ CMPIStatus stdi_deliver(const CMPIBroker *broker, enabled = is_ind_enabled(args->_ctx, ind_name, &s); if (s.rc != CMPI_RC_OK) { - CU_DEBUG("Problem checking enabled: '%s'", CMGetCharPtr(s.msg)); + if (s.msg != NULL) { + CU_DEBUG("Problem checking enabled: '%s'", + CMGetCharPtr(s.msg)); + } else { + CU_DEBUG("Problem checking enabled, msg is NULL"); + } goto out; } -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 09:14:06 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 17:14:06 +0800 Subject: [Libvirt-cim] [PATCH V3 2/2] libcmpiutil: add time and thread info in debug log In-Reply-To: <1355822046-25220-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355822046-25220-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355822046-25220-3-git-send-email-xiawenc@linux.vnet.ibm.com> On server we need these information to debug eaiser. v2: format adjusted. v3: call time and thread function only when debug is enabled, which improves performance when debug is shutdown. Signed-off-by: Wenchao Xia --- debug_util.c | 19 ++++++++++++++++++- 1 files changed, 18 insertions(+), 1 deletions(-) diff --git a/debug_util.c b/debug_util.c index 2912fb6..8c42e9d 100644 --- a/debug_util.c +++ b/debug_util.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include +#include #include "libcmpiutil.h" @@ -32,6 +35,12 @@ static FILE *log = NULL; void debug_print(char *fmt, ...) { char *log_file = NULL; + pthread_t id; + struct timeval tv; + struct timezone tz; + time_t timep; + struct tm *p; + va_list ap; va_start(ap, fmt); @@ -49,8 +58,16 @@ void debug_print(char *fmt, ...) log_init = 1; } - if (log != NULL) + if (log != NULL) { + gettimeofday(&tv, &tz); + time(&timep); + p=localtime(&timep); + id = pthread_self(); + fprintf(log, "[%d-%02d-%02d %02d:%02d:%02d.%06d] [%ld]: ", + (1900+p->tm_year), (1+p->tm_mon), p->tm_mday, p->tm_hour, + p->tm_min, p->tm_sec, (int)tv.tv_usec, id); vfprintf(log, fmt, ap); + } va_end(ap); } -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:31 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:31 +0800 Subject: [Libvirt-cim] [PATCH V3 02/11] do not deregister virt classes in yum upgrade In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-4-git-send-email-xiawenc@linux.vnet.ibm.com> Now yum upgrade will deregister the virt classes, make libvirt-cim not workable. This patch fixed it from now on. v2: Rebased. Signed-off-by: Wenchao Xia --- libvirt-cim.spec.in | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libvirt-cim.spec.in b/libvirt-cim.spec.in index d78eee7..3def978 100644 --- a/libvirt-cim.spec.in +++ b/libvirt-cim.spec.in @@ -104,18 +104,22 @@ rm -fr $RPM_BUILD_ROOT -r %{CIMV2_REG} -m %{CIMV2_MOF} -v >/dev/null 2>&1 || true %preun -%{_datadir}/%{name}/provider-register.sh -d -t pegasus \ +#Deregister only in uninstall, do nothing in upgrade. +if [ "$1" = "0" ]; then + echo "Deleting registered classes in libvirt-cim..." + %{_datadir}/%{name}/provider-register.sh -d -t pegasus \ -n @CIM_VIRT_NS@ \ -r %{REGISTRATION} -m %{SCHEMA} >/dev/null 2>&1 || true -%{_datadir}/%{name}/provider-register.sh -d -t pegasus \ + %{_datadir}/%{name}/provider-register.sh -d -t pegasus \ -n root/interop \ -r %{INTEROP_REG} -m %{INTEROP_MOF} >/dev/null 2>&1 || true -%{_datadir}/%{name}/provider-register.sh -d -t pegasus \ + %{_datadir}/%{name}/provider-register.sh -d -t pegasus \ -n root/PG_InterOp \ -r %{PGINTEROP_REG} -m %{PGINTEROP_MOF} >/dev/null 2>&1 || true -%{_datadir}/%{name}/provider-register.sh -d -t pegasus \ + %{_datadir}/%{name}/provider-register.sh -d -t pegasus \ -n root/cimv2 \ -r %{CIMV2_REG} -m %{CIMV2_MOF} >/dev/null 2>&1 || true +fi %postun -p /sbin/ldconfig -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:29 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:29 +0800 Subject: [Libvirt-cim] [PATCH V3 00/11] bug fix and enhancement patch rebase for 6.2 In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-2-git-send-email-xiawenc@linux.vnet.ibm.com> These are the patches rebased which fix bugs reported for 6.1 or potential problem. Last patch is an enhancement for migration usage. Each patch is stand alone can can be applied independendly. All code change for libvirt-cim are in this serial, Please use it for 6.2, ignoring V2 serials. Wenchao Xia (11): remove script for bridge network do not deregister virt classes in yum upgrade CSI, fix debug print crash CSI, add lock to protect shared data DevicePool, fix debug print crash DevicePool, reimplement get_diskpool_config with libvirt RASDIndication, fix debug print crash device parsing, add debug print CSI Discard libvirt event by default VSSD, fix a error report issue in VSSD enum allow ssh based migration with non root's key file libvirt-cim.conf | 14 + libvirt-cim.spec.in | 12 +- libxkutil/device_parsing.c | 11 +- libxkutil/misc_util.c | 119 ++++- libxkutil/misc_util.h | 3 + libxkutil/xmlgen.c | 9 +- src/Virt_ComputerSystem.c | 46 ++- src/Virt_ComputerSystemIndication.c | 581 +++++++++++++++++++- src/Virt_DevicePool.c | 41 +- src/Virt_ResourceAllocationSettingDataIndication.c | 6 +- src/Virt_VSMigrationService.c | 114 ++++- src/Virt_VSSD.c | 72 ++- src/Virt_VirtualSystemManagementService.c | 36 ++- 13 files changed, 996 insertions(+), 68 deletions(-) From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:35 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:35 +0800 Subject: [Libvirt-cim] [PATCH V3 06/11] DevicePool, reimplement get_diskpool_config with libvirt In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-8-git-send-email-xiawenc@linux.vnet.ibm.com> Original implemetion may return pools with NULL name if some pool disappear between two libvirt pool API call. And caller of this function consider number = 0 as error only but it original return negative value when error before. This patch fix it. V2: Use for instead of while in clean up. Treat zero pool returned from libvirt as normal instead of error. Rebased. v3: fix wrong i++ in for while. Signed-off-by: Wenchao Xia --- src/Virt_DevicePool.c | 39 +++++++++++++++++++++++++++++---------- 1 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index 79dc108..769de63 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -117,52 +117,71 @@ int get_disk_pool(virStoragePoolPtr poolptr, struct virt_pool **pool) return ret; } +/* This function returns the real number of pools, no negative value should be + returned, if error happens it returns zero, otherwise return at least 1. */ static int get_diskpool_config(virConnectPtr conn, struct tmp_disk_pool **_pools) { - int count = 0; + int count = 0, realcount = 0; int i; char ** names = NULL; struct tmp_disk_pool *pools = NULL; + int have_err = 0; count = virConnectNumOfStoragePools(conn); - if (count <= 0) + if (count < 0) { + have_err = 1; goto out; + } else if (count == 0) { + goto out; + } names = calloc(count, sizeof(char *)); if (names == NULL) { CU_DEBUG("Failed to alloc space for %i pool names", count); count = 0; + have_err = 1; goto out; } - if (virConnectListStoragePools(conn, names, count) == -1) { + realcount = virConnectListStoragePools(conn, names, count); + if (realcount == -1) { CU_DEBUG("Failed to get storage pools"); - count = 0; + realcount = 0; + have_err = 1; + goto out; + } + if (realcount == 0) { + CU_DEBUG("zero pools got, but prelist is %d.", count); goto out; } - pools = calloc(count, sizeof(*pools)); + pools = calloc(realcount, sizeof(*pools)); if (pools == NULL) { - CU_DEBUG("Failed to alloc space for %i pool structs", count); + CU_DEBUG("Failed to alloc space for %i pool structs", realcount); + realcount = 0; + have_err = 1; goto out; } - for (i = 0; i < count; i++) { + for (i = 0; i < realcount; i++) { pools[i].tag = strdup(names[i]); pools[i].primordial = false; } out: - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { free(names[i]); + } free(names); - get_disk_parent(&pools, &count); + if (have_err == 0) { + get_disk_parent(&pools, &realcount); + } *_pools = pools; - return count; + return realcount; } static bool diskpool_set_capacity(virConnectPtr conn, -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:34 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:34 +0800 Subject: [Libvirt-cim] [PATCH V3 05/11] DevicePool, fix debug print crash In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-7-git-send-email-xiawenc@linux.vnet.ibm.com> v2: Rebased. Signed-off-by: Wenchao Xia --- src/Virt_DevicePool.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index 202e509..79dc108 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -710,7 +710,7 @@ static bool mempool_set_consumed(CMPIInstance *inst, virConnectPtr conn) dom = virDomainLookupByID(conn, domain_ids[i]); if (dom == NULL) { - CU_DEBUG("Cannot connect to domain %n: excluding", + CU_DEBUG("Cannot connect to domain %d: excluding", domain_ids[i]); continue; } -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:28 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:28 +0800 Subject: [Libvirt-cim] [PATCH V3 00/11] bug fix and enhancement patch rebase for 6.2 Message-ID: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> These are the patches rebased which fix bugs reported for 6.1 or potential problem. Last patch is an enhancement for migration usage. Each patch is stand alone can can be applied independendly. All code change for libvirt-cim are in this serial, Please use it for 6.2, ignoring V2 serials. Wenchao Xia (11): remove script for bridge network do not deregister virt classes in yum upgrade CSI, fix debug print crash CSI, add lock to protect shared data DevicePool, fix debug print crash DevicePool, reimplement get_diskpool_config with libvirt RASDIndication, fix debug print crash device parsing, add debug print CSI Discard libvirt event by default VSSD, fix a error report issue in VSSD enum allow ssh based migration with non root's key file libvirt-cim.conf | 14 + libvirt-cim.spec.in | 12 +- libxkutil/device_parsing.c | 11 +- libxkutil/misc_util.c | 119 ++++- libxkutil/misc_util.h | 3 + libxkutil/xmlgen.c | 9 +- src/Virt_ComputerSystem.c | 46 ++- src/Virt_ComputerSystemIndication.c | 581 +++++++++++++++++++- src/Virt_DevicePool.c | 41 +- src/Virt_ResourceAllocationSettingDataIndication.c | 6 +- src/Virt_VSMigrationService.c | 114 ++++- src/Virt_VSSD.c | 72 ++- src/Virt_VirtualSystemManagementService.c | 36 ++- 13 files changed, 996 insertions(+), 68 deletions(-) From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:33 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:33 +0800 Subject: [Libvirt-cim] [PATCH V3 04/11] CSI, add lock to protect shared data In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-6-git-send-email-xiawenc@linux.vnet.ibm.com> This patch added lock on shared data without which may trigger incorrect data operation. Global lock is used so speed may be slowed down, it can be improved in the future. Original code have a small chance to free thread->args in child thread just after main thread malloc it, for that thread->id is set to zero allowing main thread to enter that code. v2: Rebased. Signed-off-by: Wenchao Xia --- src/Virt_ComputerSystemIndication.c | 39 ++++++++++++++++++++++++++++++++-- 1 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index b1b9fa0..3159ca0 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -174,9 +174,11 @@ static void csi_free_thread_data(void *data) if (data == NULL) return; + pthread_mutex_lock(&lifecycle_mutex); list_free(thread->dom_list); thread->dom_list = NULL; stdi_free_ind_args(&thread->args); + pthread_mutex_unlock(&lifecycle_mutex); } void set_source_inst_props(const CMPIBroker *broker, @@ -490,6 +492,8 @@ static int update_domain_list(virConnectPtr conn, csi_thread_data_t *thread) return s.rc; } +/* following function will protect global data with lifecycle_mutex. + TODO: improve it with seperate lock later. */ static void csi_domain_event_cb(virConnectPtr conn, virDomainPtr dom, int event, @@ -502,10 +506,13 @@ static void csi_domain_event_cb(virConnectPtr conn, char *prefix = class_prefix_name(thread->args->classname); CMPIStatus s = {CMPI_RC_OK, NULL}; + pthread_mutex_lock(&lifecycle_mutex); if (lifecycle_enabled == false || thread->active_filters <= 0) { CU_DEBUG("%s indications deactivated, return", prefix); + pthread_mutex_unlock(&lifecycle_mutex); return; } + pthread_mutex_unlock(&lifecycle_mutex); CU_DEBUG("Event: Domain %s(%d) event: %d detail: %d\n", virDomainGetName(dom), virDomainGetID(dom), event, detail); @@ -537,7 +544,9 @@ static void csi_domain_event_cb(virConnectPtr conn, if (cs_event != CS_CREATED) { char uuid[VIR_UUID_STRING_BUFLEN] = {0}; virDomainGetUUIDString(dom, &uuid[0]); + pthread_mutex_lock(&lifecycle_mutex); dom_xml = list_find(thread->dom_list, uuid); + pthread_mutex_unlock(&lifecycle_mutex); } if (dom_xml == NULL) { @@ -545,12 +554,16 @@ static void csi_domain_event_cb(virConnectPtr conn, goto end; } + pthread_mutex_lock(&lifecycle_mutex); async_ind(thread->args, cs_event, dom_xml, prefix); + pthread_mutex_unlock(&lifecycle_mutex); /* Update the domain list accordingly */ if (event == VIR_DOMAIN_EVENT_DEFINED) { if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) { + pthread_mutex_lock(&lifecycle_mutex); csi_thread_dom_list_append(thread, dom_xml); + pthread_mutex_unlock(&lifecycle_mutex); } else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) { free(dom_xml->name); free(dom_xml->xml); @@ -558,7 +571,9 @@ static void csi_domain_event_cb(virConnectPtr conn, } } else if (event == VIR_DOMAIN_EVENT_DEFINED && detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) { + pthread_mutex_lock(&lifecycle_mutex); list_remove(thread->dom_list, dom_xml); + pthread_mutex_unlock(&lifecycle_mutex); } end: @@ -579,10 +594,12 @@ static CMPI_THREAD_RETURN lifecycle_thread(void *params) if (prefix == NULL) goto init_out; + pthread_mutex_lock(&lifecycle_mutex); conn = connect_by_classname(_BROKER, args->classname, &s); if (conn == NULL) { CU_DEBUG("Unable to start lifecycle thread: " "Failed to connect (cn: %s)", args->classname); + pthread_mutex_unlock(&lifecycle_mutex); goto conn_out; } @@ -594,33 +611,47 @@ static CMPI_THREAD_RETURN lifecycle_thread(void *params) if (cb_id == -1) { CU_DEBUG("Failed to register domain event watch for '%s'", - args->classname) + args->classname); + pthread_mutex_unlock(&lifecycle_mutex); goto cb_out; } CBAttachThread(_BROKER, args->context); /* Get currently defined domains */ - if (update_domain_list(conn, thread) != CMPI_RC_OK) + if (update_domain_list(conn, thread) != CMPI_RC_OK) { + pthread_mutex_unlock(&lifecycle_mutex); goto end; + } + pthread_mutex_unlock(&lifecycle_mutex); CU_DEBUG("Entering CSI event loop (%s)", prefix); - while (thread->active_filters > 0) { + while (1) { + pthread_mutex_lock(&lifecycle_mutex); + if (thread->active_filters <= 0) { + pthread_mutex_unlock(&lifecycle_mutex); + break; + } + pthread_mutex_unlock(&lifecycle_mutex); if (virEventRunDefaultImpl() < 0) { virErrorPtr err = virGetLastError(); CU_DEBUG("Failed to run event loop: %s\n", err && err->message ? err->message : "Unknown error"); } + usleep(1); } CU_DEBUG("Exiting CSI event loop (%s)", prefix); + pthread_mutex_lock(&lifecycle_mutex); CBDetachThread(_BROKER, args->context); + pthread_mutex_unlock(&lifecycle_mutex); end: virConnectDomainEventDeregisterAny(conn, cb_id); cb_out: + pthread_mutex_lock(&lifecycle_mutex); thread->id = 0; thread->active_filters = 0; @@ -628,6 +659,8 @@ static CMPI_THREAD_RETURN lifecycle_thread(void *params) if (thread->args != NULL) stdi_free_ind_args(&thread->args); + pthread_mutex_unlock(&lifecycle_mutex); + conn_out: virConnectClose(conn); -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:36 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:36 +0800 Subject: [Libvirt-cim] [PATCH V3 07/11] RASDIndication, fix debug print crash In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-9-git-send-email-xiawenc@linux.vnet.ibm.com> v2: Rebased. Signed-off-by: Wenchao Xia --- src/Virt_ResourceAllocationSettingDataIndication.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/src/Virt_ResourceAllocationSettingDataIndication.c b/src/Virt_ResourceAllocationSettingDataIndication.c index a386132..93fb563 100644 --- a/src/Virt_ResourceAllocationSettingDataIndication.c +++ b/src/Virt_ResourceAllocationSettingDataIndication.c @@ -122,7 +122,11 @@ static CMPIStatus raise_indication(const CMPIBroker *broker, if (s.rc == CMPI_RC_OK) { CU_DEBUG("Indication delivered"); } else { - CU_DEBUG("Not delivered: %s", CMGetCharPtr(s.msg)); + if (s.msg == NULL) { + CU_DEBUG("Not delivered: msg is NULL."); + } else { + CU_DEBUG("Not delivered: %s", CMGetCharPtr(s.msg)); + } } out: -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:32 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:32 +0800 Subject: [Libvirt-cim] [PATCH V3 03/11] CSI, fix debug print crash In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-5-git-send-email-xiawenc@linux.vnet.ibm.com> v2: Rebased. Signed-off-by: Wenchao Xia --- src/Virt_ComputerSystemIndication.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index 2d0a94e..b1b9fa0 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -503,7 +503,7 @@ static void csi_domain_event_cb(virConnectPtr conn, CMPIStatus s = {CMPI_RC_OK, NULL}; if (lifecycle_enabled == false || thread->active_filters <= 0) { - CU_DEBUG("%s indications deactivated, return"); + CU_DEBUG("%s indications deactivated, return", prefix); return; } -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:37 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:37 +0800 Subject: [Libvirt-cim] [PATCH V3 08/11] device parsing, add debug print In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-10-git-send-email-xiawenc@linux.vnet.ibm.com> Sometime libvirt will fail in these API when there are low level error, what we saw is libvirt can't got xml for some domain. This patch add debug log when met this error, so in future we can know where is wrong better. v2: Rebased. Signed-off-by: Wenchao Xia --- libxkutil/device_parsing.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libxkutil/device_parsing.c b/libxkutil/device_parsing.c index ceb4552..2841662 100644 --- a/libxkutil/device_parsing.c +++ b/libxkutil/device_parsing.c @@ -1251,12 +1251,19 @@ int get_dominfo(virDomainPtr dom, struct domain **dominfo) xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); - if (xml == NULL) + if (xml == NULL) { + CU_DEBUG("Failed to get dom xml with libvirt API."); return 0; + } ret = get_dominfo_from_xml(xml, dominfo); - if (virDomainGetAutostart(dom, &start) != 0) + if (ret != 1) { + CU_DEBUG("Failed to translate xml into struct domain"); + } + if (virDomainGetAutostart(dom, &start) != 0) { + CU_DEBUG("Failed to get dom autostart with libvirt API."); return 0; + } (*dominfo)->autostrt = start; -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:30 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:30 +0800 Subject: [Libvirt-cim] [PATCH V3 01/11] remove script for bridge network In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-3-git-send-email-xiawenc@linux.vnet.ibm.com> libvirt0.9.10 will report error if bridge network was defined with script. This is the fix for it, otherwise VM start would fail. v2: rebased. Signed-off-by: Wenchao Xia --- libxkutil/xmlgen.c | 9 +-------- 1 files changed, 1 insertions(+), 8 deletions(-) diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c index 2dcd0d2..31619d8 100644 --- a/libxkutil/xmlgen.c +++ b/libxkutil/xmlgen.c @@ -269,18 +269,11 @@ static const char *set_net_source(xmlNodePtr nic, return NULL; } - +/* libvirt 0.9.10 report error if script is set with brdige */ static const char *bridge_net_to_xml(xmlNodePtr nic, struct net_device *dev) { - const char *script = "vif-bridge"; - xmlNodePtr tmp; const char *msg = NULL; - tmp = xmlNewChild(nic, NULL, BAD_CAST "script", NULL); - if (tmp == NULL) - return XML_ERROR; - xmlNewProp(tmp, BAD_CAST "path", BAD_CAST script); - msg = set_net_source(nic, dev, "bridge"); return msg; -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:39 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:39 +0800 Subject: [Libvirt-cim] [PATCH V3 10/11] VSSD, fix a error report issue in VSSD enum In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-12-git-send-email-xiawenc@linux.vnet.ibm.com> If user delete a VS and enum VSSD at the sametime, it may have chance to report error, but actually it succeed just with some VS not found. Root cause is race condition between libvirt API for get domain's name&count and the API for get domain's xml. This Patch fixed it. It will continue if found one VS is missing in enum. v2: Rebased and better document. Signed-off-by: Wenchao Xia --- src/Virt_VSSD.c | 72 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/Virt_VSSD.c b/src/Virt_VSSD.c index 499b157..bbf45e8 100644 --- a/src/Virt_VSSD.c +++ b/src/Virt_VSSD.c @@ -36,6 +36,8 @@ #include "Virt_VSSD.h" +#define VSSD_ERROR_RECOVERABLE (2) + const static CMPIBroker *_BROKER; static CMPIStatus _set_fv_prop(const CMPIBroker *broker, @@ -181,8 +183,19 @@ static int instance_from_dom(const CMPIBroker *broker, struct domain *dominfo = NULL; ret = get_dominfo(dom, &dominfo); - if (!ret) + if (!ret) { + int active = virDomainIsActive(dom); + if (active < 0) { + /* ret > 1 indicate that it is recoverable */ + CU_DEBUG("Failed to get dominfo, " + "it may not present now."); + ret = VSSD_ERROR_RECOVERABLE; + } else { + CU_DEBUG("Failed to get dominfo, " + "libvirt level error."); + } goto out; + } op = CMGetObjectPath(inst, NULL); pfx = class_prefix_name(CLASSNAME(op)); @@ -246,6 +259,8 @@ static int instance_from_dom(const CMPIBroker *broker, s = _set_fv_prop(broker, dominfo, inst); if (s.rc != CMPI_RC_OK) { ret = 0; + CU_DEBUG("Failed to set full virtual prop for %d dom.", + dominfo->type); goto out; } } @@ -260,6 +275,7 @@ static int instance_from_dom(const CMPIBroker *broker, if (asprintf(&vsid, "%s:%s", pfx, dominfo->name) == -1) { ret = 0; + CU_DEBUG("Failed in asprintf vsid."); goto out; } @@ -278,7 +294,8 @@ static CMPIInstance *_get_vssd(const CMPIBroker *broker, const CMPIObjectPath *reference, virConnectPtr conn, virDomainPtr dom, - CMPIStatus *s) + CMPIStatus *s, + int *error_below) { CMPIInstance *inst = NULL; @@ -294,10 +311,18 @@ static CMPIInstance *_get_vssd(const CMPIBroker *broker, goto out; } - if (instance_from_dom(broker, dom, inst) != 1) { - cu_statusf(broker, s, - CMPI_RC_ERR_FAILED, - "Unable to get VSSD instance from Domain"); + *error_below = instance_from_dom(broker, dom, inst); + if (*error_below != 1) { + if (*error_below == VSSD_ERROR_RECOVERABLE) { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to get VSSD instance from Domain, " + "Domain may not exist at this moment."); + } else { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to get VSSD instance from Domain"); + } } out: @@ -312,6 +337,7 @@ static CMPIStatus return_enum_vssd(const CMPIObjectPath *reference, virDomainPtr *list; int count; int i; + int error_below; CMPIStatus s = {CMPI_RC_OK, NULL}; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); @@ -327,14 +353,33 @@ static CMPIStatus return_enum_vssd(const CMPIObjectPath *reference, } else if (count == 0) goto out; + int fail_count = 0; for (i = 0; i < count; i++) { CMPIInstance *inst = NULL; - - inst = _get_vssd(_BROKER, reference, conn, list[i], &s); - + + inst = _get_vssd(_BROKER, reference, conn, list[i], + &s, &error_below); + virDomainFree(list[i]); - if (inst == NULL) - continue; + + if ((inst == NULL) || (s.rc != CMPI_RC_OK)) { + fail_count++; + CU_DEBUG("VSSD got %d fail instance, total %d," + " error %d.", + fail_count, count, error_below); + if (error_below == VSSD_ERROR_RECOVERABLE) { + cu_statusf(_BROKER, &s, + CMPI_RC_OK, + "%d/%d VSSD not got," + " some VS may not exist now", + fail_count, count); + CU_DEBUG("Continue to next VSSD for enum."); + continue; + } else { + CU_DEBUG("Met unrecoverable error."); + break; + } + } if (names_only) cu_return_instance_name(results, inst); @@ -358,7 +403,8 @@ CMPIStatus get_vssd_by_name(const CMPIBroker *broker, virDomainPtr dom; CMPIStatus s = {CMPI_RC_OK, NULL}; CMPIInstance *inst = NULL; - + int error_below; + conn = connect_by_classname(broker, CLASSNAME(reference), &s); if (conn == NULL) { cu_statusf(broker, &s, @@ -377,7 +423,7 @@ CMPIStatus get_vssd_by_name(const CMPIBroker *broker, goto out; } - inst = _get_vssd(broker, reference, conn, dom, &s); + inst = _get_vssd(broker, reference, conn, dom, &s, &error_below); virDomainFree(dom); -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:38 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:38 +0800 Subject: [Libvirt-cim] [PATCH V3 09/11] CSI Discard libvirt event by default In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-11-git-send-email-xiawenc@linux.vnet.ibm.com> From cimtest, Calling to virEventRegisterDefaultImpl() of libvirt API, resulting random fail in cases, which seems most likely tog-pegasus's internal data is damaged. The root cause may be: 1 libvirt event API have a bug, we called it from thread A and then do other things in thread B, maybe it did not handle this well. 2 tog-pegasus have confilict with libvirt's event. 3 Potential requirement in libvirt event API or tog-pegasus's thread, which is not document so we used them in a wrong way. To me, most possible is that tog-pegasus tries to manage all threads resulting the error. This patch bring back libvirt-cim's own old event implemention, which is by default used now. CSI from libvirt can still be activated with a macro. This patch also have changed some buglike code of old libvirt-cim's event implemention. Tested with cimtest on following Env, no more strange error found: RH6.3 libvirt-0.9.10-21.el6.x86_64 tog-pegasus-2.11.0-3.el6.x86_64 v2: Rebased. minor change for getting current vm status code in CSI child thread. Comment out the debug print in CSI child thread. Signed-off-by: Wenchao Xia --- src/Virt_ComputerSystem.c | 46 +++- src/Virt_ComputerSystemIndication.c | 540 ++++++++++++++++++++++++++++- src/Virt_VirtualSystemManagementService.c | 36 ++- 3 files changed, 616 insertions(+), 6 deletions(-) diff --git a/src/Virt_ComputerSystem.c b/src/Virt_ComputerSystem.c index e6c7e55..adef85e 100644 --- a/src/Virt_ComputerSystem.c +++ b/src/Virt_ComputerSystem.c @@ -45,8 +45,45 @@ #include "Virt_HostSystem.h" #include "Virt_VirtualSystemSnapshotService.h" +#include "config.h" + const static CMPIBroker *_BROKER; +#ifndef USE_LIBVIRT_EVENT +static bool trigger_mod_indication(const CMPIContext *context, + CMPIInstance *prev_inst, + const CMPIObjectPath *ref) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + const char *ind_name = "ComputerSystemModifiedIndication"; + CMPIInstance *ind = NULL; + char *type = NULL; + + CU_DEBUG("Preparing ComputerSystem indication"); + + ind = get_typed_instance(_BROKER, + CLASSNAME(ref), + ind_name, + NAMESPACE(ref)); + if (ind == NULL) { + CU_DEBUG("Failed to create ind '%s'", ind_name); + goto out; + } + + CU_DEBUG("Setting PreviousInstance"); + CMSetProperty(ind, "PreviousInstance", + (CMPIValue *)&prev_inst, CMPI_instance); + + type = get_typed_class(CLASSNAME(ref), ind_name); + + s = stdi_raise_indication(_BROKER, context, type, NAMESPACE(ref), ind); + + out: + free(type); + return s.rc == CMPI_RC_OK; +} +#endif + /* Set the "Name" property of an instance from a domain */ static int set_name_from_dom(virDomainPtr dom, CMPIInstance *instance) { @@ -1256,8 +1293,15 @@ static CMPIStatus state_change(CMPIMethodMI *self, s = __state_change(name, state, reference); - if (s.rc == CMPI_RC_OK) + if (s.rc == CMPI_RC_OK) { +#ifndef USE_LIBVIRT_EVENT + bool ind_rc= trigger_mod_indication(context, prev_inst, + reference); + if (!ind_rc) + CU_DEBUG("Unable to trigger indication"); +#endif rc = 0; + } out: CMReturnData(results, &rc, CMPI_uint32); diff --git a/src/Virt_ComputerSystemIndication.c b/src/Virt_ComputerSystemIndication.c index 3159ca0..6b5cdd4 100644 --- a/src/Virt_ComputerSystemIndication.c +++ b/src/Virt_ComputerSystemIndication.c @@ -48,6 +48,8 @@ #include "Virt_ComputerSystemIndication.h" #include "Virt_HostSystem.h" +#define WAIT_TIME 60 +#define FAIL_WAIT_TIME 2 #define CSI_NUM_PLATFORMS 3 enum CSI_PLATFORMS { @@ -80,6 +82,7 @@ struct _csi_thread_data_t { }; static const CMPIBroker *_BROKER; +static pthread_cond_t lifecycle_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t lifecycle_mutex = PTHREAD_MUTEX_INITIALIZER; static bool lifecycle_enabled = false; static csi_thread_data_t csi_thread_data[CSI_NUM_PLATFORMS] = {{0}, {0}, {0}}; @@ -580,6 +583,376 @@ static void csi_domain_event_cb(virConnectPtr conn, free(prefix); } +/* libvirt-cim's private CSI implement */ +struct dom_xml { + char uuid[VIR_UUID_STRING_BUFLEN]; + char *xml; + enum {DOM_OFFLINE, + DOM_ONLINE, + DOM_PAUSED, + DOM_CRASHED, + DOM_GONE, + } state; +}; + +static void free_dom_xml (struct dom_xml dom) +{ + free(dom.xml); + dom.xml = NULL; +} + +static char *sys_name_from_xml(char *xml) +{ + char *tmp = NULL; + char *name = NULL; + int rc; + + tmp = strstr(xml, ""); + if (tmp == NULL) + goto out; + + rc = sscanf(tmp, "%a[^<]s", &name); + if (rc != 1) + name = NULL; + + out: + return name; +} + +static int dom_state(virDomainPtr dom) +{ + virDomainInfo info; + int ret; + + ret = virDomainGetInfo(dom, &info); + if (ret != 0) + return DOM_GONE; + + switch (info.state) { + case VIR_DOMAIN_NOSTATE: + case VIR_DOMAIN_RUNNING: + case VIR_DOMAIN_BLOCKED: + return DOM_ONLINE; + + case VIR_DOMAIN_PAUSED: + return DOM_PAUSED; + + case VIR_DOMAIN_SHUTOFF: + return DOM_OFFLINE; + + case VIR_DOMAIN_CRASHED: + return DOM_CRASHED; + + default: + return DOM_GONE; + }; +} + +static CMPIStatus doms_to_xml(struct dom_xml **dom_xml_list, + virDomainPtr *dom_ptr_list, + int dom_ptr_count) +{ + int i; + int rc; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + if (dom_ptr_count <= 0) { + *dom_xml_list = NULL; + return s; + } + *dom_xml_list = calloc(dom_ptr_count, sizeof(struct dom_xml)); + for (i = 0; i < dom_ptr_count; i++) { + rc = virDomainGetUUIDString(dom_ptr_list[i], + (*dom_xml_list)[i].uuid); + if (rc == -1) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to get UUID"); + /* If any domain fails, we fail. */ + break; + } + + (*dom_xml_list)[i].xml = virDomainGetXMLDesc(dom_ptr_list[i], + VIR_DOMAIN_XML_INACTIVE | VIR_DOMAIN_XML_SECURE); + if ((*dom_xml_list)[i].xml == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to get xml desc"); + break; + } + + (*dom_xml_list)[i].state = dom_state(dom_ptr_list[i]); + } + + return s; +} + +static bool dom_changed(struct dom_xml prev_dom, + struct dom_xml *cur_xml, + int cur_count) +{ + int i; + bool ret = false; + + for (i = 0; i < cur_count; i++) { + if (strcmp(cur_xml[i].uuid, prev_dom.uuid) != 0) + continue; + + if (strcmp(cur_xml[i].xml, prev_dom.xml) != 0) { + CU_DEBUG("Domain config changed"); + ret = true; + } + + if (prev_dom.state != cur_xml[i].state) { + CU_DEBUG("Domain state changed"); + ret = true; + } + + break; + } + + return ret; +} + +static bool wait_for_event(int wait_time) +{ + struct timespec timeout; + int ret; + + + clock_gettime(CLOCK_REALTIME, &timeout); + timeout.tv_sec += wait_time; + + ret = pthread_cond_timedwait(&lifecycle_cond, + &lifecycle_mutex, + &timeout); + + return true; +} + +static bool dom_in_list(char *uuid, int count, struct dom_xml *list) +{ + int i; + + for (i = 0; i < count; i++) { + if (STREQ(uuid, list[i].uuid)) + return true; + } + + return false; +} + +static bool async_ind_native(CMPIContext *context, + int ind_type, + struct dom_xml prev_dom, + char *prefix, + struct ind_args *args) +{ + bool rc = false; + char *name = NULL; + char *cn = NULL; + CMPIObjectPath *op; + CMPIInstance *prev_inst; + CMPIInstance *affected_inst; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + CU_DEBUG("Entering native indication diliv with type %d.", ind_type) + if (!lifecycle_enabled) { + CU_DEBUG("CSI not enabled, skipping indication delivery"); + return false; + } + + name = sys_name_from_xml(prev_dom.xml); + CU_DEBUG("Name for system: '%s'", name); + if (name == NULL) { + rc = false; + goto out; + } + + cn = get_typed_class(prefix, "ComputerSystem"); + + op = CMNewObjectPath(_BROKER, args->ns, cn, &s); + if ((s.rc != CMPI_RC_OK) || CMIsNullObject(op)) { + CU_DEBUG("op error"); + goto out; + } + + if (ind_type == CS_CREATED || ind_type == CS_MODIFIED) { + s = get_domain_by_name(_BROKER, op, name, &affected_inst); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("domain by name error"); + goto out; + } + } else if (ind_type == CS_DELETED) { + rc = create_deleted_guest_inst(prev_dom.xml, + args->ns, + prefix, + &affected_inst); + if (!rc) { + CU_DEBUG("Could not recreate guest instance"); + goto out; + } + } else { + CU_DEBUG("Unrecognized indication type"); + goto out; + } + + /* FIXME: We are unable to get the previous CS instance after it has + been modified. Consider keeping track of the previous + state in the place we keep track of the requested state */ + prev_inst = affected_inst; + + CMSetProperty(affected_inst, "Name", + (CMPIValue *)name, CMPI_chars); + CMSetProperty(affected_inst, "UUID", + (CMPIValue *)prev_dom.uuid, CMPI_chars); + + rc = _do_indication(_BROKER, context, prev_inst, affected_inst, + ind_type, prefix, args); + + out: + free(cn); + free(name); + return rc; +} + +static CMPI_THREAD_RETURN lifecycle_thread_native(void *params) +{ + CU_DEBUG("Entering libvirtc-cim native CSI thread."); + csi_thread_data_t *thread = (csi_thread_data_t *) params; + struct ind_args *args = thread->args; + CMPIContext *context = args->context; + char *prefix = class_prefix_name(args->classname); + virConnectPtr conn; + CMPIStatus s; + int retry_time = FAIL_WAIT_TIME; + + struct dom_xml *cur_xml = NULL; + struct dom_xml *prev_xml = NULL; + int prev_count = 0; + int cur_count = 0; + virDomainPtr *tmp_list = NULL; + int CBAttached = 0; + + if (prefix == NULL) + goto init_out; + + pthread_mutex_lock(&lifecycle_mutex); + conn = connect_by_classname(_BROKER, args->classname, &s); + if (conn == NULL) { + CU_DEBUG("Unable to start lifecycle thread: " + "Failed to connect (cn: %s)", args->classname); + pthread_mutex_unlock(&lifecycle_mutex); + goto conn_out; + } + + CBAttachThread(_BROKER, args->context); + CBAttached = 1; + prev_count = get_domain_list(conn, &tmp_list); + s = doms_to_xml(&prev_xml, tmp_list, prev_count); + free_domain_list(tmp_list, prev_count); + free(tmp_list); + if (s.rc != CMPI_RC_OK) + CU_DEBUG("doms_to_xml failed. Attempting to continue."); + + CU_DEBUG("Entering libvirt-cim native CSI event loop (%s)", prefix); + + int i; + while (1) { + if (thread->active_filters <= 0) { + break; + } + + bool res; + bool failure = false; + + cur_count = get_domain_list(conn, &tmp_list); + s = doms_to_xml(&cur_xml, tmp_list, cur_count); + free_domain_list(tmp_list, cur_count); + free(tmp_list); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("doms_to_xml failed. retry in %d seconds", + retry_time); + failure = true; + goto fail; + } + + /* CU_DEBUG("cur_count %d, prev_count %d.", + cur_count, prev_count); */ + for (i = 0; i < cur_count; i++) { + res = dom_in_list(cur_xml[i].uuid, prev_count, prev_xml); + if (!res) { + async_ind_native(context, CS_CREATED, + cur_xml[i], prefix, args); + } + + } + + for (i = 0; i < prev_count; i++) { + res = dom_in_list(prev_xml[i].uuid, cur_count, cur_xml); + if (!res) { + async_ind_native(context, CS_DELETED, + prev_xml[i], prefix, args); + } + } + + for (i = 0; i < prev_count; i++) { + res = dom_changed(prev_xml[i], cur_xml, cur_count); + if (res) { + async_ind_native(context, CS_MODIFIED, + prev_xml[i], prefix, args); + } + free_dom_xml(prev_xml[i]); + } + + fail: + if (failure) { + wait_for_event(FAIL_WAIT_TIME); + } else { + free(prev_xml); + prev_xml = cur_xml; + cur_xml = NULL; + prev_count = cur_count; + cur_count = 0; + wait_for_event(WAIT_TIME); + } + } + + CU_DEBUG("Exiting libvirt-cim native CSI event loop (%s)", prefix); + + if (prev_xml != NULL) { + for (i = 0; i < prev_count; i++) { + free_dom_xml(prev_xml[i]); + } + free(prev_xml); + prev_xml = NULL; + } + + pthread_mutex_unlock(&lifecycle_mutex); + + virConnectClose(conn); + + conn_out: + free(prefix); + + init_out: + pthread_mutex_lock(&lifecycle_mutex); + thread->id = 0; + thread->active_filters = 0; + + /* it seems tog-pegasus try kill this thread after detached, use this + flag to delay detach as much as possible. */ + if (CBAttached > 0) { + CBDetachThread(_BROKER, args->context); + } + if (thread->args != NULL) + stdi_free_ind_args(&thread->args); + + pthread_mutex_unlock(&lifecycle_mutex); + + return (CMPI_THREAD_RETURN) 0; +} + static CMPI_THREAD_RETURN lifecycle_thread(void *params) { csi_thread_data_t *thread = (csi_thread_data_t *) params; @@ -696,13 +1069,24 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, csi_thread_data_t *thread = NULL; static int events_registered = 0; +#ifndef USE_LIBVIRT_EVENT + int use_libvirt_event = 0; +#else + int use_libvirt_event = 1; +#endif + CU_DEBUG("ActivateFilter for %s", CLASSNAME(op)); pthread_mutex_lock(&lifecycle_mutex); - if (events_registered == 0) { - events_registered = 1; - virEventRegisterDefaultImpl(); + if (use_libvirt_event == 1) { + if (events_registered == 0) { + events_registered = 1; + CU_DEBUG("Registering libvirt event."); + virEventRegisterDefaultImpl(); + } + } else { + CU_DEBUG("Using libvirt-cim's event implemention."); } _ctx = (struct std_indication_ctx *)mi->hdl; @@ -753,7 +1137,20 @@ static CMPIStatus ActivateFilter(CMPIIndicationMI* mi, args->_ctx = _ctx; thread->args = args; - thread->id = _BROKER->xft->newThread(lifecycle_thread, thread, 0); + + if (use_libvirt_event == 0) { + thread->id = _BROKER->xft->newThread( + lifecycle_thread_native, + thread, 0); + } else { + thread->id = _BROKER->xft->newThread(lifecycle_thread, + thread, 0); + } + + if (thread->id <= 0) { + CU_DEBUG("Error, failed to create new thread."); + error = true; + } out: if (error == true) { @@ -791,6 +1188,10 @@ static CMPIStatus DeActivateFilter(CMPIIndicationMI* mi, csi_thread_data[platform].active_filters -= 1; pthread_mutex_unlock(&lifecycle_mutex); +#ifndef USE_LIBVIRT_EVENT + pthread_cond_signal(&lifecycle_cond); +#endif + out: return s; } @@ -817,6 +1218,7 @@ static _EI_RTYPE DisableIndications(CMPIIndicationMI* mi, _EI_RET(); } + DECLARE_FILTER(xen_created, "Xen_ComputerSystemCreatedIndication"); DECLARE_FILTER(xen_deleted, "Xen_ComputerSystemDeletedIndication"); DECLARE_FILTER(xen_modified, "Xen_ComputerSystemModifiedIndication"); @@ -840,7 +1242,137 @@ static struct std_ind_filter *filters[] = { NULL, }; +#ifndef USE_LIBVIRT_EVENT +static CMPIStatus trigger_indication(const CMPIContext *context) +{ + CU_DEBUG("triggered"); + pthread_cond_signal(&lifecycle_cond); + return(CMPIStatus){CMPI_RC_OK, NULL}; +} + +static CMPIInstance *get_prev_inst(const CMPIBroker *broker, + const CMPIInstance *ind, + CMPIStatus *s) +{ + CMPIData data; + CMPIInstance *prev_inst = NULL; + + data = CMGetProperty(ind, "PreviousInstance", s); + if (s->rc != CMPI_RC_OK || CMIsNullValue(data)) { + cu_statusf(broker, s, + CMPI_RC_ERR_NO_SUCH_PROPERTY, + "Unable to get PreviousInstance of the indication"); + goto out; + } + + if (data.type != CMPI_instance) { + cu_statusf(broker, s, + CMPI_RC_ERR_TYPE_MISMATCH, + "Indication SourceInstance is of unexpected type"); + goto out; + } + + prev_inst = data.value.inst; + + out: + return prev_inst; +} + +static CMPIStatus raise_indication(const CMPIBroker *broker, + const CMPIContext *ctx, + const CMPIObjectPath *ref, + const CMPIInstance *ind) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *prev_inst; + CMPIInstance *src_inst; + CMPIObjectPath *_ref = NULL; + struct std_indication_ctx *_ctx = NULL; + struct ind_args *args = NULL; + char *prefix = NULL; + bool rc; + + if (!lifecycle_enabled) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "CSI not enabled, skipping indication delivery"); + goto out; + } + + prev_inst = get_prev_inst(broker, ind, &s); + if (s.rc != CMPI_RC_OK || CMIsNullObject(prev_inst)) + goto out; + + _ref = CMGetObjectPath(prev_inst, &s); + if (s.rc != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to get a reference to the guest"); + goto out; + } + + /* FIXME: This is a Pegasus work around. Pegsus loses the namespace + when an ObjectPath is pulled from an instance */ + if (STREQ(NAMESPACE(_ref), "")) + CMSetNameSpace(_ref, "root/virt"); + + s = get_domain_by_ref(broker, _ref, &src_inst); + if (s.rc != CMPI_RC_OK || CMIsNullObject(src_inst)) + goto out; + + _ctx = malloc(sizeof(struct std_indication_ctx)); + if (_ctx == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to allocate indication context"); + goto out; + } + + _ctx->brkr = broker; + _ctx->handler = NULL; + _ctx->filters = filters; + _ctx->enabled = lifecycle_enabled; + + args = malloc(sizeof(struct ind_args)); + if (args == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to allocate ind_args"); + goto out; + } + + args->ns = strdup(NAMESPACE(_ref)); + args->classname = strdup(CLASSNAME(_ref)); + args->_ctx = _ctx; + + prefix = class_prefix_name(args->classname); + + rc = _do_indication(broker, ctx, prev_inst, src_inst, + CS_MODIFIED, prefix, args); + + if (!rc) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Unable to generate indication"); + } + + out: + if (args != NULL) + stdi_free_ind_args(&args); + + if (_ctx != NULL) + free(_ctx); + + free(prefix); + return s; +} +#endif + static struct std_indication_handler csi = { +#ifndef USE_LIBVIRT_EVENT + .raise_fn = raise_indication, + .trigger_fn = trigger_indication, +#endif .activate_fn = ActivateFilter, .deactivate_fn = DeActivateFilter, .enable_fn = EnableIndications, diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 10adf8b..059b852 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -107,6 +107,24 @@ enum ResourceAction { RESOURCE_MOD, }; +#ifndef USE_LIBVIRT_EVENT +static bool trigger_indication(const CMPIContext *context, + const char *base_type, + const CMPIObjectPath *ref) +{ + char *type; + CMPIStatus s; + + type = get_typed_class(CLASSNAME(ref), base_type); + + s = stdi_trigger_indication(_BROKER, context, type, NAMESPACE(ref)); + + free(type); + + return s.rc == CMPI_RC_OK; +} +#endif + #if LIBVIR_VERSION_NUMBER < 9000 /* Network QoS support */ static CMPIStatus add_qos_for_mac(const uint64_t qos, @@ -2166,6 +2184,11 @@ static CMPIStatus define_system(CMPIMethodMI *self, CMAddArg(argsout, "ResultingSystem", &result, CMPI_ref); } +#ifndef USE_LIBVIRT_EVENT + trigger_indication(context, + "ComputerSystemCreatedIndication", + reference); +#endif out: if (s.rc == CMPI_RC_OK) rc = CIM_SVPC_RETURN_COMPLETED; @@ -2268,6 +2291,11 @@ error: NULL, reference, &list); +#ifndef USE_LIBVIRT_EVENT + trigger_indication(context, + "ComputerSystemDeletedIndication", + reference); +#endif } virDomainFree(dom); @@ -2349,8 +2377,14 @@ static CMPIStatus update_system_settings(const CMPIContext *context, connect_and_create(xml, ref, &s); } - if (s.rc == CMPI_RC_OK) + if (s.rc == CMPI_RC_OK) { set_autostart(vssd, ref, dom); +#ifndef USE_LIBVIRT_EVENT + trigger_indication(context, + "ComputerSystemModifiedIndication", + ref); +#endif + } out: free(xml); -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:17:40 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:17:40 +0800 Subject: [Libvirt-cim] [PATCH V3 11/11] allow ssh based migration with non root's key file In-Reply-To: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1355825860-8509-13-git-send-email-xiawenc@linux.vnet.ibm.com> This patch allow libvirt-cim to use non-root's ssh key in migration to avoid exposing root's ssh login on server. In some case server are forbidden to expose or provide any root ssh login, and still use ssh encryption between two migration nodes with key of special account created for virtual machine management. Usage: 1 set temp file in libvirt-cim.conf or not: migrate_ssh_temp_key=[DIR]/[FILE] Note that [DIR] must be full owned by root user and exist, otherwise libvirt will reject the request later. For example set it to /root/VControll_id_rsa If it is set, it tells libvirt-cim a copy is needed to make keyfile in a directory owned by root. If not set, that means keyfile is already in a valid place can be used directly. 2 call migrate API with ssh destination as before, but add one additonal parameter for example: SSH_Key="/home/VController/.ssh/id_rsa" Then that key would be used intead of default root's ssh key. Details: This patch contains two parts, first is adding common code to read config include non-root ssh migration configuration, second is migration logic code. For first part, now config reading is done only once instead improving performance, so change config now needs restart the service. Also abstracted the common config reading code to make each property access more gracefully. For second part, libvirt-cim would run shell command if needed: "cp -f [SSH_Key] [migrate_ssh_temp_key]", then use [migrate_ssh_temp_key] to generate uri suffix for remote connection to migration destination. If copy is not needed, then directly use [SSH_Key]. Note: Test was done when SELinux was shutdown. V2: Rebased and Better documentation. v3: Added some common code to read configuration, Added an option which can disable this function, use just one parameter SSH_Key in API, forbid copy any file to avoid security problem for that now config file controls it. Signed-off-by: Wenchao Xia --- libvirt-cim.conf | 14 +++++ libxkutil/misc_util.c | 119 ++++++++++++++++++++++++++++++++++++----- libxkutil/misc_util.h | 3 + src/Virt_VSMigrationService.c | 114 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 231 insertions(+), 19 deletions(-) diff --git a/libvirt-cim.conf b/libvirt-cim.conf index d3cb2c3..97e6918 100644 --- a/libvirt-cim.conf +++ b/libvirt-cim.conf @@ -11,3 +11,17 @@ # Default value: false # # readonly = false; + +# migrate_ssh_temp_key (string) +# Defines a temp key file which would be used as ssh key in ssh migration, +# Only valid when SSH_Key is set in migration call. +# If SSH_Key is not in a directory owned by root, set this value to a path +# owned by root, tells libvirt-cim copy it there before use it. The directory +# in the path must exist and totally owned by root. +# If SSH_Key is already in a valid place, don't set it to to tell libvirt-cim +# use SSH_Key directly. +# +# Possible values: {any path plus filename on host} +# Default value: NULL, that is not set. +# +# migrate_ssh_temp_key = "/root/vm_migrate_tmp_id_rsa"; diff --git a/libxkutil/misc_util.c b/libxkutil/misc_util.c index 2d149ae..4a16ec2 100644 --- a/libxkutil/misc_util.c +++ b/libxkutil/misc_util.c @@ -106,14 +106,28 @@ static const char *cn_to_uri(const char *classname) return NULL; } -static int is_read_only(void) -{ - int readonly = 0; +typedef enum LibvirtcimConfigType { + CONFIG_BOOL, + CONFIG_STRING, +} LibvirtcimConfigType; + +typedef struct LibvirtcimConfigProperty { + const char *name; + LibvirtcimConfigType value_type; + union { + int value_bool; + char *value_string; + }; + int have_read; +} LibvirtcimConfigProperty; +static int libvirt_cim_config_get(LibvirtcimConfigProperty *prop) +{ #ifdef HAVE_LIBCONFIG config_t conf; - int ret; - const char *readonly_str = "readonly"; + int ret = 0; + int error = 0; + const char *value_string = NULL; config_init(&conf); @@ -121,24 +135,101 @@ static int is_read_only(void) if (ret == CONFIG_FALSE) { CU_DEBUG("Error reading config file at line %d: '%s'\n", conf.error_line, conf.error_text); + error = -1; goto out; } - ret = config_lookup_bool(&conf, readonly_str, &readonly); - if (ret == CONFIG_FALSE) { - CU_DEBUG("'%s' not found in config file, assuming false\n", - readonly_str); - goto out; + switch (prop->value_type) { + case CONFIG_BOOL: + ret = config_lookup_bool(&conf, + prop->name, &prop->value_bool); + if (ret == CONFIG_FALSE) { + CU_DEBUG("Bool property '%s' in config file '%s' " + "not found.", + prop->name, LIBVIRTCIM_CONF); + error = -1; + goto out; + } + + CU_DEBUG("Bool property '%s' in config file '%s' is '%d'.", + prop->name, LIBVIRTCIM_CONF, prop->value_bool); + break; + case CONFIG_STRING: + ret = config_lookup_string(&conf, + prop->name, &value_string); + if (ret == CONFIG_FALSE) { + CU_DEBUG("String property '%s' in config file '%s' " + "not found.", + prop->name, LIBVIRTCIM_CONF); + error = -1; + goto out; + } + + CU_DEBUG("String property '%s' in config file '%s' is '%s'.", + prop->name, LIBVIRTCIM_CONF, value_string); + + if (prop->value_string) { + free(prop->value_string); + } + prop->value_string = strdup(value_string); + if (!prop->value_string) { + CU_DEBUG("Failed in duplicate value '%s'", + value_string); + error = -1; + goto out; + } + break; + default: + CU_DEBUG("Got invalid property type request %d.", + prop->value_type); + error = -1; + break; } - CU_DEBUG("'%s' value in '%s' config file: %d\n", readonly_str, - LIBVIRTCIM_CONF, readonly); out: config_destroy(&conf); + return error; +#else + CU_DEBUG("Built without libconfig, can't read '%s'.",prop->name); + return -2; #endif +} + +static int is_read_only(void) +{ + static LibvirtcimConfigProperty prop; + + if (prop.have_read == 1) { + goto ret; + } + + prop.name = "readonly"; + prop.value_type = CONFIG_BOOL; + prop.value_bool = 0; + libvirt_cim_config_get(&prop); + /* try only once */ + prop.have_read = 1; + +ret: + return prop.value_bool; +} + +const char *get_mig_ssh_tmp_key(void) +{ + static LibvirtcimConfigProperty prop; + + if (prop.have_read == 1) { + goto ret; + } + + prop.name = "migrate_ssh_temp_key"; + prop.value_type = CONFIG_STRING; + libvirt_cim_config_get(&prop); + /* try only once */ + prop.have_read = 1; - /* Default value is 0 (false) */ - return readonly; +ret: + return prop.value_string; } virConnectPtr connect_by_classname(const CMPIBroker *broker, diff --git a/libxkutil/misc_util.h b/libxkutil/misc_util.h index c7a2122..6ce60a0 100644 --- a/libxkutil/misc_util.h +++ b/libxkutil/misc_util.h @@ -151,6 +151,9 @@ int virt_set_status(const CMPIBroker *broker, #define REF2STR(r) CMGetCharPtr(CMObjectPathToString(r, NULL)) +/* get libvirt-cim config */ +const char *get_mig_ssh_tmp_key(void); + /* * Local Variables: * mode: C diff --git a/src/Virt_VSMigrationService.c b/src/Virt_VSMigrationService.c index 76e3d25..14a3004 100644 --- a/src/Virt_VSMigrationService.c +++ b/src/Virt_VSMigrationService.c @@ -150,6 +150,7 @@ static CMPIStatus get_migration_uri(CMPIInstance *msd, static char *dest_uri(const char *cn, const char *dest, + const char *dest_params, uint16_t transport) { const char *prefix; @@ -157,6 +158,7 @@ static char *dest_uri(const char *cn, const char *param = ""; char *uri = NULL; int rc; + int param_labeled = 0; if (STARTS_WITH(cn, "Xen")) prefix = "xen"; @@ -197,16 +199,79 @@ static char *dest_uri(const char *cn, goto out; } - if (!STREQC(param, "")) + if (!STREQC(param, "")) { rc = asprintf(&uri, "%s/%s", uri, param); + param_labeled = 1; + } - if (rc == -1) + if (rc == -1) { uri = NULL; + goto out; + } + if (dest_params) { + if (param_labeled == 0) { + rc = asprintf(&uri, "%s?%s", uri, dest_params); + } else { + /* ? is already added */ + rc = asprintf(&uri, "%s%s", uri, dest_params); + } + if (rc == -1) { + uri = NULL; + goto out; + } + } out: return uri; } +/* libvirt need private key specified must be placed in a directory owned by + root, because libvirt-cim now runs as root. So here the key would be copied, + up layer need to delete that key after migration. This method could allow + libvirt-cim borrow a non-root ssh private key, instead of using root's private + key, avoid security risk. */ +static int ssh_key_cp(const char *src, const char *dest) +{ + char *cmd = NULL; + int rc; + int ret = 0; + FILE *stream = NULL; + char buf[256]; + + rc = asprintf(&cmd, "cp -f %s %s", src, dest); + if (rc == -1) { + cmd = NULL; + ret = -1; + goto out; + } + + CU_DEBUG("executing system cmd [%s].", cmd); + /* Todo: We need a better popen, currently stdout have been closed + and SIGCHILD is handled by tog-pegasus, so fgets always got NULL + making error detection not possible. */ + stream = popen(cmd, "r"); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + ret = -2; + goto out; + } + usleep(10000); + + buf[255] = 0; + while (fgets(buf, sizeof(buf), stream) != NULL) { + CU_DEBUG("Exception got: %s.", buf); + ret = -3; + goto out; + } + + out: + if (stream != NULL) { + pclose(stream); + } + free(cmd); + return ret; +} + static CMPIStatus get_msd_values(const CMPIObjectPath *ref, const char *destination, const CMPIArgs *argsin, @@ -217,6 +282,11 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref, CMPIInstance *msd; uint16_t uri_type; char *uri = NULL; + const char *ssh_key = NULL; + char *dest_params = NULL; + int ret; + + cu_get_str_arg(argsin, "SSH_Key", &ssh_key); s = get_msd(ref, argsin, &msd); if (s.rc != CMPI_RC_OK) @@ -230,7 +300,38 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref, if (s.rc != CMPI_RC_OK) goto out; - uri = dest_uri(CLASSNAME(ref), destination, uri_type); + if (ssh_key) { + CU_DEBUG("Trying migrate with specified ssh key file '%s'.", + ssh_key); + const char * tmp_keyfile = get_mig_ssh_tmp_key(); + const char * final_keyfile = NULL; + const char *errstr; + if (tmp_keyfile) { + CU_DEBUG("Copying ssh keys src '%s', dest '%s'.", + ssh_key, tmp_keyfile); + ret = ssh_key_cp(ssh_key, tmp_keyfile); + if (ret < 0) { + errstr = "Failed to copy ssh key files"; + CU_DEBUG("%s", errstr); + cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, + "%s", errstr); + goto out; + } + final_keyfile = tmp_keyfile; + } else { + final_keyfile = ssh_key; + CU_DEBUG("Skip key copy."); + } + CU_DEBUG("Generating param string with key '%s'.", + final_keyfile); + ret = asprintf(&dest_params, "keyfile=%s", final_keyfile); + if (ret < 0) { + CU_DEBUG("Failed in generating param string."); + goto out; + } + } + + uri = dest_uri(CLASSNAME(ref), destination, dest_params, uri_type); if (uri == NULL) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -238,6 +339,7 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref, goto out; } + CU_DEBUG("Migrate tring to connect remote host with uri %s.", uri); *conn = virConnectOpen(uri); if (*conn == NULL) { CU_DEBUG("Failed to connect to remote host (%s)", uri); @@ -249,7 +351,7 @@ static CMPIStatus get_msd_values(const CMPIObjectPath *ref, out: free(uri); - + free(dest_params); return s; } @@ -1537,7 +1639,7 @@ static CMPIStatus migrate_vs_host(CMPIMethodMI *self, const char *dhost = NULL; CMPIObjectPath *system; const char *name = NULL; - + cu_get_str_arg(argsin, "DestinationHost", &dhost); cu_get_ref_arg(argsin, "ComputerSystem", &system); @@ -1608,6 +1710,7 @@ static struct method_handler vsimth = { .handler = vs_migratable_host, .args = {{"ComputerSystem", CMPI_ref, false}, {"DestinationHost", CMPI_string, false}, + {"SSH_Key", CMPI_string, true}, {"MigrationSettingData", CMPI_instance, true}, {"NewSystemSettingData", CMPI_instance, true}, {"NewResourceSettingData", CMPI_instanceA, true}, @@ -1632,6 +1735,7 @@ static struct method_handler mvsth = { .handler = migrate_vs_host, .args = {{"ComputerSystem", CMPI_ref, false}, {"DestinationHost", CMPI_string, false}, + {"SSH_Key", CMPI_string, true}, {"MigrationSettingData", CMPI_instance, true}, {"NewSystemSettingData", CMPI_instance, true}, {"NewResourceSettingData", CMPI_instanceA, true}, -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 18 10:24:45 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 18 Dec 2012 18:24:45 +0800 Subject: [Libvirt-cim] [RFC] libvirt-cim 0.6.2 candidate patches Message-ID: <50D0446D.8090007@linux.vnet.ibm.com> Hi Danial There are total 13 patch sent for libvirt-cim 0.6.2 as candidate, 11 for libvirt-cim and 2 for libcmpiutils, please pull them if you think those are OK, Version is V3 patch serials. Cimtest was ran and no obviouse problem found. -- Best Regards Wenchao Xia From xiawenc at linux.vnet.ibm.com Wed Dec 19 03:26:24 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Wed, 19 Dec 2012 11:26:24 +0800 Subject: [Libvirt-cim] [PATCH V3 01/11] remove script for bridge network In-Reply-To: References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1355825860-8509-3-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <50D133E0.2080605@linux.vnet.ibm.com> Yes, in lower version I think this xml section should also be removed. > > Are we saying that libvirt-cim 0.6.2 will use libvirt 0.9.10 and higher? > > Regards > Sharad Mishra > Open Virtualization > Linux Technology Center > IBM > > > > From: Wenchao Xia > To: veillard at redhat.com, > Cc: Sharad Mishra/Beaverton/IBM at IBMUS, libvirt-cim at redhat.com, > Wenchao Xia > Date: 12/18/12 02:20 AM > Subject: [PATCH V3 01/11] remove script for bridge network > > > > libvirt0.9.10 will report error if bridge network was defined > with script. This is the fix for it, otherwise VM start would fail. > > v2: > rebased. > > Signed-off-by: Wenchao Xia > --- > libxkutil/xmlgen.c | 9 +-------- > 1 files changed, 1 insertions(+), 8 deletions(-) > > diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c > index 2dcd0d2..31619d8 100644 > --- a/libxkutil/xmlgen.c > +++ b/libxkutil/xmlgen.c > @@ -269,18 +269,11 @@ static const char *set_net_source(xmlNodePtr nic, > return NULL; > } > > - > +/* libvirt 0.9.10 report error if script is set with brdige */ > static const char *bridge_net_to_xml(xmlNodePtr nic, struct net_device > *dev) > { > - const char *script = "vif-bridge"; > - xmlNodePtr tmp; > const char *msg = NULL; > > - tmp = xmlNewChild(nic, NULL, BAD_CAST "script", NULL); > - if (tmp == NULL) > - return XML_ERROR; > - xmlNewProp(tmp, BAD_CAST "path", BAD_CAST script); > - > msg = set_net_source(nic, dev, "bridge"); > > return msg; > -- > 1.7.1 > > -- Best Regards Wenchao Xia From snmishra at linux.vnet.ibm.com Fri Dec 21 17:56:24 2012 From: snmishra at linux.vnet.ibm.com (snmishra at linux.vnet.ibm.com) Date: Fri, 21 Dec 2012 09:56:24 -0800 Subject: [Libvirt-cim] [PATCH V3 01/11] remove script for bridge network In-Reply-To: <50D133E0.2080605@linux.vnet.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1355825860-8509-3-git-send-email-xiawenc@linux.vnet.ibm.com> <50D133E0.2080605@linux.vnet.ibm.com> Message-ID: <20121221095624.Horde.C23za5ir309Q1KLI4_3RoXA@imap.linux.ibm.com> +1 please test and make sure there are no regression. -Sharad Quoting Wenchao Xia : > Yes, in lower version I think this xml section should also be removed. >> >> Are we saying that libvirt-cim 0.6.2 will use libvirt 0.9.10 and higher? >> >> Regards >> Sharad Mishra >> Open Virtualization >> Linux Technology Center >> IBM >> >> >> >> From: Wenchao Xia >> To: veillard at redhat.com, >> Cc: Sharad Mishra/Beaverton/IBM at IBMUS, libvirt-cim at redhat.com, >> Wenchao Xia >> Date: 12/18/12 02:20 AM >> Subject: [PATCH V3 01/11] remove script for bridge network >> >> >> >> libvirt0.9.10 will report error if bridge network was defined >> with script. This is the fix for it, otherwise VM start would fail. >> >> v2: >> rebased. >> >> Signed-off-by: Wenchao Xia >> --- >> libxkutil/xmlgen.c | 9 +-------- >> 1 files changed, 1 insertions(+), 8 deletions(-) >> >> diff --git a/libxkutil/xmlgen.c b/libxkutil/xmlgen.c >> index 2dcd0d2..31619d8 100644 >> --- a/libxkutil/xmlgen.c >> +++ b/libxkutil/xmlgen.c >> @@ -269,18 +269,11 @@ static const char *set_net_source(xmlNodePtr nic, >> return NULL; >> } >> >> - >> +/* libvirt 0.9.10 report error if script is set with brdige */ >> static const char *bridge_net_to_xml(xmlNodePtr nic, struct net_device >> *dev) >> { >> - const char *script = "vif-bridge"; >> - xmlNodePtr tmp; >> const char *msg = NULL; >> >> - tmp = xmlNewChild(nic, NULL, BAD_CAST "script", NULL); >> - if (tmp == NULL) >> - return XML_ERROR; >> - xmlNewProp(tmp, BAD_CAST "path", BAD_CAST script); >> - >> msg = set_net_source(nic, dev, "bridge"); >> >> return msg; >> -- >> 1.7.1 >> >> > > > -- > Best Regards > > Wenchao Xia > > _______________________________________________ > Libvirt-cim mailing list > Libvirt-cim at redhat.com > https://www.redhat.com/mailman/listinfo/libvirt-cim From xiawenc at linux.vnet.ibm.com Mon Dec 24 02:09:29 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Mon, 24 Dec 2012 10:09:29 +0800 Subject: [Libvirt-cim] [PATCH V3 01/11] remove script for bridge network In-Reply-To: <20121221095624.Horde.C23za5ir309Q1KLI4_3RoXA@imap.linux.ibm.com> References: <1355825860-8509-1-git-send-email-xiawenc@linux.vnet.ibm.com> <1355825860-8509-3-git-send-email-xiawenc@linux.vnet.ibm.com> <50D133E0.2080605@linux.vnet.ibm.com> <20121221095624.Horde.C23za5ir309Q1KLI4_3RoXA@imap.linux.ibm.com> Message-ID: <50D7B959.1070205@linux.vnet.ibm.com> ? 2012-12-22 1:56, snmishra at linux.vnet.ibm.com ??: > +1 > > please test and make sure there are no regression. > > -Sharad > Sure, this serial have been tested with cimtest, you can trust me. :) -- Best Regards Wenchao Xia From xiawenc at linux.vnet.ibm.com Tue Dec 25 03:06:36 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 25 Dec 2012 11:06:36 +0800 Subject: [Libvirt-cim] [PATCH V4] VSSD, fix a error report issue in VSSD enum In-Reply-To: <1356404796-15641-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1356404796-15641-1-git-send-email-xiawenc@linux.vnet.ibm.com> Message-ID: <1356404796-15641-2-git-send-email-xiawenc@linux.vnet.ibm.com> If user delete a VS and enum VSSD at the sametime, it may have chance to report error, but actually it succeed just with some VS not found. Root cause is race condition between libvirt API for get domain's name&count and the API for get domain's xml. This Patch fixed it. It will continue if found one VS is missing in enum. v2: Rebased and better document. v3: Rebased. v4: changed CU_DEBUG information when met error in instance_from_dom(). Signed-off-by: Wenchao Xia --- src/Virt_VSSD.c | 71 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/Virt_VSSD.c b/src/Virt_VSSD.c index 499b157..0781c8f 100644 --- a/src/Virt_VSSD.c +++ b/src/Virt_VSSD.c @@ -36,6 +36,8 @@ #include "Virt_VSSD.h" +#define VSSD_ERROR_RECOVERABLE (2) + const static CMPIBroker *_BROKER; static CMPIStatus _set_fv_prop(const CMPIBroker *broker, @@ -181,8 +183,18 @@ static int instance_from_dom(const CMPIBroker *broker, struct domain *dominfo = NULL; ret = get_dominfo(dom, &dominfo); - if (!ret) + if (!ret) { + int active = virDomainIsActive(dom); + if (active < 0) { + /* ret > 1 indicate that it is recoverable */ + CU_DEBUG("Failed to get dominfo, " + "domain may not be active anymore."); + ret = VSSD_ERROR_RECOVERABLE; + } else { + CU_DEBUG("Failed to get dominfo."); + } goto out; + } op = CMGetObjectPath(inst, NULL); pfx = class_prefix_name(CLASSNAME(op)); @@ -246,6 +258,8 @@ static int instance_from_dom(const CMPIBroker *broker, s = _set_fv_prop(broker, dominfo, inst); if (s.rc != CMPI_RC_OK) { ret = 0; + CU_DEBUG("Failed to set full virtual prop for %d dom.", + dominfo->type); goto out; } } @@ -260,6 +274,7 @@ static int instance_from_dom(const CMPIBroker *broker, if (asprintf(&vsid, "%s:%s", pfx, dominfo->name) == -1) { ret = 0; + CU_DEBUG("Failed in asprintf vsid."); goto out; } @@ -278,7 +293,8 @@ static CMPIInstance *_get_vssd(const CMPIBroker *broker, const CMPIObjectPath *reference, virConnectPtr conn, virDomainPtr dom, - CMPIStatus *s) + CMPIStatus *s, + int *error_below) { CMPIInstance *inst = NULL; @@ -294,10 +310,18 @@ static CMPIInstance *_get_vssd(const CMPIBroker *broker, goto out; } - if (instance_from_dom(broker, dom, inst) != 1) { - cu_statusf(broker, s, - CMPI_RC_ERR_FAILED, - "Unable to get VSSD instance from Domain"); + *error_below = instance_from_dom(broker, dom, inst); + if (*error_below != 1) { + if (*error_below == VSSD_ERROR_RECOVERABLE) { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to get VSSD instance from Domain, " + "Domain may not exist at this moment."); + } else { + cu_statusf(broker, s, + CMPI_RC_ERR_FAILED, + "Unable to get VSSD instance from Domain"); + } } out: @@ -312,6 +336,7 @@ static CMPIStatus return_enum_vssd(const CMPIObjectPath *reference, virDomainPtr *list; int count; int i; + int error_below; CMPIStatus s = {CMPI_RC_OK, NULL}; conn = connect_by_classname(_BROKER, CLASSNAME(reference), &s); @@ -327,14 +352,33 @@ static CMPIStatus return_enum_vssd(const CMPIObjectPath *reference, } else if (count == 0) goto out; + int fail_count = 0; for (i = 0; i < count; i++) { CMPIInstance *inst = NULL; - - inst = _get_vssd(_BROKER, reference, conn, list[i], &s); - + + inst = _get_vssd(_BROKER, reference, conn, list[i], + &s, &error_below); + virDomainFree(list[i]); - if (inst == NULL) - continue; + + if ((inst == NULL) || (s.rc != CMPI_RC_OK)) { + fail_count++; + CU_DEBUG("VSSD got %d fail instance, total %d," + " error %d.", + fail_count, count, error_below); + if (error_below == VSSD_ERROR_RECOVERABLE) { + cu_statusf(_BROKER, &s, + CMPI_RC_OK, + "%d/%d VSSD not got," + " some VS may not exist now", + fail_count, count); + CU_DEBUG("Continue to next VSSD for enum."); + continue; + } else { + CU_DEBUG("Met unrecoverable error."); + break; + } + } if (names_only) cu_return_instance_name(results, inst); @@ -358,7 +402,8 @@ CMPIStatus get_vssd_by_name(const CMPIBroker *broker, virDomainPtr dom; CMPIStatus s = {CMPI_RC_OK, NULL}; CMPIInstance *inst = NULL; - + int error_below; + conn = connect_by_classname(broker, CLASSNAME(reference), &s); if (conn == NULL) { cu_statusf(broker, &s, @@ -377,7 +422,7 @@ CMPIStatus get_vssd_by_name(const CMPIBroker *broker, goto out; } - inst = _get_vssd(broker, reference, conn, dom, &s); + inst = _get_vssd(broker, reference, conn, dom, &s, &error_below); virDomainFree(dom); -- 1.7.1 From xiawenc at linux.vnet.ibm.com Tue Dec 25 03:06:35 2012 From: xiawenc at linux.vnet.ibm.com (Wenchao Xia) Date: Tue, 25 Dec 2012 11:06:35 +0800 Subject: [Libvirt-cim] [PATCH V4] DevicePool, reimplement get_diskpool_config with libvirt Message-ID: <1356404796-15641-1-git-send-email-xiawenc@linux.vnet.ibm.com> Original implemetion may return pools with NULL name if some pool disappear between two libvirt pool API call. And caller of this function consider number = 0 as error only but it original return negative value when error before. This patch fix it. V2: Use for instead of while in clean up. Treat zero pool returned from libvirt as normal instead of error. Rebased. v3: fix wrong i++ in for while. v4: changed the function prototype to return negative when error, not return the pool number anymore. In this way code of caller and function in no-use-libvirt-pool case were also changed. Return false in get_disk_parent() when strdup fail. Signed-off-by: Wenchao Xia --- src/Virt_DevicePool.c | 176 +++++++++++++++++++++++++++++++++--------------- 1 files changed, 121 insertions(+), 55 deletions(-) diff --git a/src/Virt_DevicePool.c b/src/Virt_DevicePool.c index 79dc108..bf3dd3b 100644 --- a/src/Virt_DevicePool.c +++ b/src/Virt_DevicePool.c @@ -51,6 +51,21 @@ struct tmp_disk_pool { bool primordial; }; +static void free_diskpool(struct tmp_disk_pool *pools, int count) +{ + int i; + + if (pools == NULL) + return; + + for (i = 0; i < count; i++) { + free(pools[i].tag); + free(pools[i].path); + } + + free(pools); +} + /* * Right now, detect support and use it, if available. * Later, this can be a configure option if needed @@ -78,6 +93,10 @@ static bool get_disk_parent(struct tmp_disk_pool **_pools, } pools[count].tag = strdup("0"); + if (pools[count].tag == NULL) { + count++; + goto free; + } pools[count].path = NULL; pools[count].primordial = true; count++; @@ -85,12 +104,17 @@ static bool get_disk_parent(struct tmp_disk_pool **_pools, *_count = count; *_pools = pools; ret = true; + goto out; + free: + free_diskpool(pools, count); + /* old pool is invalid, update it */ + *_count = 0; + *_pools = NULL; out: return ret; } - #if VIR_USE_LIBVIRT_STORAGE int get_disk_pool(virStoragePoolPtr poolptr, struct virt_pool **pool) { @@ -117,52 +141,85 @@ int get_disk_pool(virStoragePoolPtr poolptr, struct virt_pool **pool) return ret; } +/* This function returns 0 on sucess, negative on fail. */ static int get_diskpool_config(virConnectPtr conn, - struct tmp_disk_pool **_pools) + struct tmp_disk_pool **_pools, + int *_count) { - int count = 0; + int count = 0, realcount = 0; int i; char ** names = NULL; struct tmp_disk_pool *pools = NULL; + int ret = 0; + bool bret; count = virConnectNumOfStoragePools(conn); - if (count <= 0) + if (count < 0) { + ret = count; goto out; + } else if (count == 0) { + goto set_parent; + } names = calloc(count, sizeof(char *)); if (names == NULL) { CU_DEBUG("Failed to alloc space for %i pool names", count); - count = 0; + ret = -1; goto out; } - if (virConnectListStoragePools(conn, names, count) == -1) { - CU_DEBUG("Failed to get storage pools"); - count = 0; - goto out; + realcount = virConnectListStoragePools(conn, names, count); + if (realcount < 0) { + CU_DEBUG("Failed to get storage pools, return %d.", realcount); + ret = realcount; + goto free_names; + } + if (realcount == 0) { + CU_DEBUG("Zero pools got, but prelist is %d.", count); + goto set_parent; } - pools = calloc(count, sizeof(*pools)); + pools = calloc(realcount, sizeof(*pools)); if (pools == NULL) { - CU_DEBUG("Failed to alloc space for %i pool structs", count); - goto out; + CU_DEBUG("Failed to alloc space for %i pool structs", realcount); + ret = -2; + goto free_names; } - for (i = 0; i < count; i++) { + for (i = 0; i < realcount; i++) { pools[i].tag = strdup(names[i]); + if (pools[i].tag == NULL) { + CU_DEBUG("Failed in strdup for name '%s'.", names[i]); + ret = -3; + goto free_pools; + } pools[i].primordial = false; } - out: - for (i = 0; i < count; i++) - free(names[i]); - free(names); - - get_disk_parent(&pools, &count); + set_parent: + bret = get_disk_parent(&pools, &realcount); + if (bret != true) { + CU_DEBUG("Failed in adding parentpool."); + ret = -4; + goto free_pools; + } + /* succeed */ *_pools = pools; + *_count = realcount; + goto free_names; + + free_pools: + free_diskpool(pools, realcount); - return count; + free_names: + for (i = 0; i < count; i++) { + free(names[i]); + } + free(names); + + out: + return ret; } static bool diskpool_set_capacity(virConnectPtr conn, @@ -294,42 +351,59 @@ static int parse_diskpool_line(struct tmp_disk_pool *pool, return (ret == 2); } +/* return 0 on sucess, negative on fail. */ static int get_diskpool_config(virConnectPtr conn, - struct tmp_disk_pool **_pools) + struct tmp_disk_pool **_pools, + int *_count) { const char *path = DISK_POOL_CONFIG; FILE *config; char *line = NULL; size_t len = 0; - int count = 0; - struct tmp_disk_pool *pools = NULL; + int count = 0, ret = 0; + struct tmp_disk_pool *pools = NULL, *new_pools = NULL; + bool bret; config = fopen(path, "r"); if (config == NULL) { CU_DEBUG("Failed to open %s: %m", path); - return 0; + ret = -1; + goto out; } while (getline(&line, &len, config) > 0) { - pools = realloc(pools, - (count + 1) * (sizeof(*pools))); - if (pools == NULL) { + new_pools = realloc(pools, + (count + 1) * (sizeof(*pools))); + if (new_pools == NULL) { CU_DEBUG("Failed to alloc new pool"); - goto out; + ret = -2; + goto free_pools; } + pools = new_pools; if (parse_diskpool_line(&pools[count], line)) count++; } + bret = get_disk_parent(&pools, &count); + if (bret != true) { + CU_DEBUG("Failed in adding parentpool."); + ret = -3; + goto free_pools; + } - get_disk_parent(&pools, &count); - out: - free(line); + /* succeed */ *_pools = pools; - fclose(config); + *_count = count; + goto clean; - return count; + free_pools: + free_diskpool(pools, count); + clean: + free(line); + fclose(config); + out: + return ret; } static bool diskpool_set_capacity(virConnectPtr conn, @@ -367,39 +441,23 @@ static bool diskpool_set_capacity(virConnectPtr conn, } static bool _diskpool_is_member(virConnectPtr conn, - const struct disk_pool *pool, + const struct tmp_disk_pool *pool, const char *file) { return STARTS_WITH(file, pool->path); } #endif -static void free_diskpool(struct tmp_disk_pool *pools, int count) -{ - int i; - - if (pools == NULL) - return; - - for (i = 0; i < count; i++) { - free(pools[i].tag); - free(pools[i].path); - } - - free(pools); -} - static char *_diskpool_member_of(virConnectPtr conn, const char *file) { struct tmp_disk_pool *pools = NULL; int count; - int i; + int i, ret; char *pool = NULL; - count = get_diskpool_config(conn, &pools); - if (count == 0) { - free(pools); + ret = get_diskpool_config(conn, &pools, &count); + if (ret < 0) { return NULL; } @@ -1084,9 +1142,17 @@ static CMPIStatus diskpool_instance(virConnectPtr conn, CMPIStatus s = {CMPI_RC_OK, NULL}; struct tmp_disk_pool *pools = NULL; int count = 0; - int i; + int i, ret; - count = get_diskpool_config(conn, &pools); + ret = get_diskpool_config(conn, &pools, &count); + if (ret < 0) { + CU_DEBUG("Failed to get diskpool config, return is %d.", ret); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to get diskpool config, return is %d.", + ret); + return s; + } if ((id == NULL) && (count == 0)) { CU_DEBUG("No defined DiskPools"); free(pools); -- 1.7.1