Addition to the commit log: tests/qemuagenttest.c * Add a test case for qemuAgentGetInterfaces
On Fri, Aug 23, 2013 at 3:48 AM, nehaljwani <nehaljw.k...@gmail.com> wrote: > By querying the qemu guest agent with the QMP command > "guest-network-get-interfaces" and converting the received > JSON output to structured objects. > > src/qemu/qemu_agent.h: > * Define qemuAgentGetInterfaces > > src/qemu/qemu_agent.c: > * Implement qemuAgentGetInterface > > src/qemu/qemu_driver.c: > * New function qemuDomainInterfacesAddresses > > src/remote_protocol-sructs: > * Define new structs > > --- > src/qemu/qemu_agent.c | 157 > +++++++++++++++++++++++++++++++++++++++++++++++++ > src/qemu/qemu_agent.h | 3 + > src/qemu/qemu_driver.c | 55 +++++++++++++++++ > tests/qemuagenttest.c | 90 +++++++++++++++++++++++++++- > 4 files changed, 304 insertions(+), 1 deletion(-) > > diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c > index 2cd0ccc..015e752 100644 > --- a/src/qemu/qemu_agent.c > +++ b/src/qemu/qemu_agent.c > @@ -844,6 +844,7 @@ static int qemuAgentSend(qemuAgentPtr mon, > VIR_DEBUG("Attempt to send command while error is set %s", > NULLSTR(mon->lastError.message)); > virSetError(&mon->lastError); > + printf("Upper\n"); > return -1; > } > > @@ -862,6 +863,7 @@ static int qemuAgentSend(qemuAgentPtr mon, > while (!mon->msg->finished) { > if ((then && virCondWaitUntil(&mon->notify, &mon->parent.lock, > then) < 0) || > (!then && virCondWait(&mon->notify, &mon->parent.lock) < 0)) { > + > if (errno == ETIMEDOUT) { > virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s", > _("Guest agent not available for now")); > @@ -1319,6 +1321,161 @@ cleanup: > return ret; > } > > + > +int > +qemuAgentGetInterfaces(qemuAgentPtr mon, > + virDomainInterfacePtr **ifaces) > +{ > + int ret = -1; > + size_t i, j; > + int size = -1; > + virJSONValuePtr cmd = NULL; > + virJSONValuePtr reply = NULL; > + virJSONValuePtr ret_array = NULL; > + int ifaces_count = 0; > + virDomainInterfacePtr *ifaces_ret = NULL; > + > + if (!(cmd = qemuAgentMakeCommand("guest-network-get-interfaces", > NULL))) > + return -1; > + > + if (qemuAgentCommand(mon, cmd, &reply, > VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0 || > + qemuAgentCheckError(cmd, reply) < 0) { > + goto cleanup; > + } > + > + if (!(ret_array = virJSONValueObjectGet(reply, "return"))) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("qemu agent didn't provide 'return' field")); > + goto cleanup; > + } > + > + if ((size = virJSONValueArraySize(ret_array)) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("qemu agent didn't return an array of > interfaces")); > + goto cleanup; > + } > + > + ifaces_count = (unsigned int) size; > + > + if (VIR_ALLOC_N(ifaces_ret, size) < 0) > + goto cleanup; > + > + for (i = 0; i < size; i++) { > + virJSONValuePtr tmp_iface = virJSONValueArrayGet(ret_array, i); > + virJSONValuePtr ip_addr_arr = NULL; > + const char *name, *hwaddr; > + int ip_addr_arr_size; > + > + if (VIR_ALLOC(ifaces_ret[i]) < 0) > + goto cleanup; > + > + /* Shouldn't happen but doesn't hurt to check neither */ > + if (!tmp_iface) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("something has went really wrong")); > + goto error; > + } > + > + /* interface name is required to be presented */ > + name = virJSONValueObjectGetString(tmp_iface, "name"); > + if (!name) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("qemu agent didn't provide 'name' field")); > + goto error; > + } > + > + if (VIR_STRDUP(ifaces_ret[i]->name, name) < 0) > + goto error; > + > + /* hwaddr might be omitted */ > + hwaddr = virJSONValueObjectGetString(tmp_iface, > "hardware-address"); > + if (hwaddr && VIR_STRDUP(ifaces_ret[i]->hwaddr, hwaddr) < 0) > + goto error; > + > + /* as well as IP address which - moreover - > + * can be presented multiple times */ > + ip_addr_arr = virJSONValueObjectGet(tmp_iface, "ip-addresses"); > + if (!ip_addr_arr) > + continue; > + > + if ((ip_addr_arr_size = virJSONValueArraySize(ip_addr_arr)) < 0) > + /* Mmm, empty 'ip-address'? */ > + continue; > + > + (*(ifaces_ret)[i]).naddrs = (unsigned int) ip_addr_arr_size; > + > + if (VIR_ALLOC_N((*(ifaces_ret)[i]).addrs, ip_addr_arr_size) < 0) > + goto error; > + > + for (j = 0; j < ip_addr_arr_size; j++) { > + virJSONValuePtr ip_addr_obj = > virJSONValueArrayGet(ip_addr_arr, j); > + virDomainIPAddressPtr ip_addr = &ifaces_ret[i]->addrs[j]; > + const char *type, *addr; > + > + /* Shouldn't happen but doesn't hurt to check neither */ > + if (!ip_addr_obj) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("something has went really wrong")); > + goto error; > + } > + > + type = virJSONValueObjectGetString(ip_addr_obj, > "ip-address-type"); > + if (!type) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("qemu agent didn't provide > 'ip-address-type'" > + " field for interface '%s'"), name); > + goto error; > + } else if (STREQ(type, "ipv4")) { > + ip_addr->type = VIR_IP_ADDR_TYPE_IPV4; > + } else if (STREQ(type, "ipv6")) { > + ip_addr->type = VIR_IP_ADDR_TYPE_IPV6; > + } else { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("unknown ip address type '%s'"), > + type); > + goto error; > + } > + > + addr = virJSONValueObjectGetString(ip_addr_obj, "ip-address"); > + if (!addr) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("qemu agent didn't provide 'ip-address'" > + " field for interface '%s'"), name); > + goto error; > + } > + if (VIR_STRDUP(ip_addr->addr, addr) < 0) > + goto error; > + > + if (virJSONValueObjectGetNumberInt(ip_addr_obj, "prefix", > + &ip_addr->prefix) < 0) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("malformed 'prefix' field")); > + goto error; > + } > + } > + } > + > + *ifaces = ifaces_ret; > + ifaces_ret = NULL; > + ret = ifaces_count; > + > +cleanup: > + virJSONValueFree(cmd); > + virJSONValueFree(reply); > + return ret; > + > +error: > + if (ifaces_ret) { > + for (i = 0; i < ifaces_count; i++) { > + if (ifaces_ret[i]) > + virDomainInterfaceFree(ifaces_ret[i]); > + } > + } > + VIR_FREE(ifaces_ret); > + goto cleanup; > +} > + > + > /* > * qemuAgentFSThaw: > * @mon: Agent > diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h > index 5fbacdb..58b56fd 100644 > --- a/src/qemu/qemu_agent.h > +++ b/src/qemu/qemu_agent.h > @@ -76,6 +76,9 @@ int qemuAgentFSThaw(qemuAgentPtr mon); > int qemuAgentSuspend(qemuAgentPtr mon, > unsigned int target); > > +int qemuAgentGetInterfaces(qemuAgentPtr mon, > + virDomainInterfacePtr **ifaces); > + > int qemuAgentArbitraryCommand(qemuAgentPtr mon, > const char *cmd, > char **result, > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c > index 0a8e518..0cd266f 100644 > --- a/src/qemu/qemu_driver.c > +++ b/src/qemu/qemu_driver.c > @@ -16035,6 +16035,60 @@ qemuNodeSuspendForDuration(virConnectPtr conn, > return nodeSuspendForDuration(target, duration, flags); > } > > +static int > +qemuDomainInterfacesAddresses(virDomainPtr dom, > + virDomainInterfacePtr **ifaces, > + unsigned int flags) > +{ > + virQEMUDriverPtr driver = dom->conn->privateData; > + qemuDomainObjPrivatePtr priv = NULL; > + virDomainObjPtr vm = NULL; > + int ret = -1; > + > + virCheckFlags(0, -1); > + > + if (!(vm = qemuDomObjFromDomain(dom))) > + goto cleanup; > + > + if (!virDomainObjIsActive(vm)) { > + virReportError(VIR_ERR_OPERATION_INVALID, "%s", > + _("domain is not running")); > + goto cleanup; > + } > + > + priv = vm->privateData; > + > + if (virDomainInterfacesAddressesEnsureACL(dom->conn, vm->def) < 0) > + goto cleanup; > + > + if (priv->agentError) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("QEMU guest agent is not " > + "available due to an error")); > + goto cleanup; > + } > + > + if (!priv->agent) { > + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", > + _("QEMU guest agent is not configured")); > + goto cleanup; > + } > + > + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) > + goto cleanup; > + > + qemuDomainObjEnterAgent(vm); > + ret = qemuAgentGetInterfaces(priv->agent, ifaces); > + qemuDomainObjExitAgent(vm); > + > + if (qemuDomainObjEndJob(driver, vm) == 0) > + vm = NULL; > + > +cleanup: > + if (vm) > + virObjectUnlock(vm); > + return ret; > +} > > static virDriver qemuDriver = { > .no = VIR_DRV_QEMU, > @@ -16130,6 +16184,7 @@ static virDriver qemuDriver = { > .domainMemoryPeek = qemuDomainMemoryPeek, /* 0.4.4 */ > .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */ > .nodeGetCPUStats = qemuNodeGetCPUStats, /* 0.9.3 */ > + .domainInterfacesAddresses = qemuDomainInterfacesAddresses, /* 1.1.2 > */ > .nodeGetMemoryStats = qemuNodeGetMemoryStats, /* 0.9.3 */ > .nodeGetCellsFreeMemory = qemuNodeGetCellsFreeMemory, /* 0.4.4 */ > .nodeGetFreeMemory = qemuNodeGetFreeMemory, /* 0.4.4 */ > diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c > index 4e27981..6b6c47f 100644 > --- a/tests/qemuagenttest.c > +++ b/tests/qemuagenttest.c > @@ -31,6 +31,8 @@ > > #define VIR_FROM_THIS VIR_FROM_NONE > > + > + > static int > testQemuAgentFSFreeze(const void *data) > { > @@ -271,6 +273,7 @@ cleanup: > } > > > + > static int > testQemuAgentShutdown(const void *data) > { > @@ -496,7 +499,7 @@ testQemuAgentArbitraryCommand(const void *data) > goto cleanup; > > if (qemuAgentArbitraryCommand(qemuMonitorTestGetAgent(test), > - "{\"execute\":\"ble\"}", > + "{\"execute\":\"ble\"}", > &reply, > VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < > 0) > goto cleanup; > @@ -576,6 +579,90 @@ cleanup: > return ret; > } > > +static const char testQemuAgentGetInterfacesResponse[] = > + "{\"return\": " > + " [" > + " {\"name\":\"lo\"," > + " \"ip-addresses\":" > + " [" > + " {\"ip-address-type\":\"ipv4\"," > + " \"ip-address\":\"127.0.0.1\"," > + " \"prefix\":8" > + " }," > + " {\"ip-address-type\":\"ipv6\"," > + " \"ip-address\":\"::1\"," > + " \"prefix\":128" > + " }" > + " ]," > + " \"hardware-address\":\"00:00:00:00:00:00\"" > + " }," > + " {\"name\":\"eth0\"," > + " \"ip-addresses\":" > + " [" > + " {\"ip-address-type\":\"ipv4\"," > + " \"ip-address\":\"192.168.102.142\"," > + " \"prefix\":24" > + " }," > + " {\"ip-address-type\":\"ipv6\"," > + " \"ip-address\":\"fe80::5054:ff:fe89:ad35\"," > + " \"prefix\":64" > + " }" > + " ]," > + " \"hardware-address\":\"52:54:00:89:ad:35\"" > + " }," > + " {\"name\":\"eth1\"," > + " \"ip-addresses\":" > + " [" > + " {\"ip-address-type\":\"ipv4\"," > + " \"ip-address\":\"192.168.103.83\"," > + " \"prefix\":24" > + " }," > + " {\"ip-address-type\":\"ipv6\"," > + " \"ip-address\":\"fe80::5054:ff:fed3:39ee\"," > + " \"prefix\":64" > + " }" > + " ]," > + " \"hardware-address\":\"52:54:00:d3:39:ee\"" > + " }" > + " ]" > + "}"; > + > +static int > +testQemuAgentGetInterfaces(const void *data) > +{ > + virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; > + qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt); > + int ret = -1; > + int ifaces_count = 0; > + virDomainInterfacePtr *ifaces; > + > + if (!test) > + return -1; > + > + if (qemuMonitorTestAddAgentSyncResponse(test) < 0) > + goto cleanup; > + > + if (qemuMonitorTestAddItem(test, "guest-network-get-interfaces", > + testQemuAgentGetInterfacesResponse) < 0) > + goto cleanup; > + > + if ((ifaces_count = > qemuAgentGetInterfaces(qemuMonitorTestGetAgent(test), > + &ifaces)) < 0) { > + goto cleanup; > + } > + > + if (ifaces_count != 3) { > + virReportError(VIR_ERR_INTERNAL_ERROR, > + "expected 3 interfaces, got %d", ret); > + goto cleanup; > + } > + > + ret = 0; > + > +cleanup: > + qemuMonitorTestFree(test); > + return ret; > +} > > static int > mymain(void) > @@ -605,6 +692,7 @@ mymain(void) > DO_TEST(Shutdown); > DO_TEST(CPU); > DO_TEST(ArbitraryCommand); > + DO_TEST(GetInterfaces); > > DO_TEST(Timeout); /* Timeout should always be called last */ > > -- > 1.7.11.7 > > -- Nehal J. Wani UG3, BTech CS+MS(CL) IIIT-Hyderabad http://commandlinewani.blogspot.com
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list