[PATCH V2 00/11] bug fix and enhancement patch rebase for 6.2

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(-)

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 <xiawenc@linux.vnet.ibm.com> --- 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

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 <xiawenc@linux.vnet.ibm.com> --- 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

v2: Rebased. Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- 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

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 <xiawenc@linux.vnet.ibm.com> --- 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

v2: Rebased. Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- 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

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 <xiawenc@linux.vnet.ibm.com> --- 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

v2: Rebased. Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com> --- 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

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 <xiawenc@linux.vnet.ibm.com> --- 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 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 <xiawenc@linux.vnet.ibm.com> --- 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, "<name>"); + if (tmp == NULL) + goto out; + + rc = sscanf(tmp, "<name>%a[^<]s</name>", &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

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 <xiawenc@linux.vnet.ibm.com> --- 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

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 <xiawenc@linux.vnet.ibm.com> --- 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
participants (1)
-
Wenchao Xia