There is a lots of possibilities to retrieve hostname information from
domain. Libvirt could use lease information from dnsmasq to get current
hostname too. QEMU supports QEMU-agent but it can use lease source. See
'domifaddr' as an example.
This commit still adds lease options for QEMU. It will get the first
hostname available from domain networks.
This case, every driver has a default section inside switch to keep
compatibility. So, if someone call 'domhostname' without specifying
source, it will get the default option.
Signed-off-by: Julio Faracco <jcfaracco(a)gmail.com>
---
include/libvirt/libvirt-domain.h | 5 +++
src/lxc/lxc_driver.c | 71 ++++++++++++++++++++++++++++++++
src/openvz/openvz_driver.c | 30 ++++++++++----
src/qemu/qemu_driver.c | 69 ++++++++++++++++++++++++++-----
tools/virsh-domain.c | 25 ++++++++++-
5 files changed, 178 insertions(+), 22 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index a2f007568c..b37f33d5d0 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -4790,6 +4790,11 @@ typedef struct _virTypedParameter virMemoryParameter;
*/
typedef virMemoryParameter *virMemoryParameterPtr;
+typedef enum {
+ VIR_DOMAIN_HOSTNAME_SRC_LEASE = (1 << 0), /* Parse DHCP lease file */
+ VIR_DOMAIN_HOSTNAME_SRC_AGENT = (1 << 1), /* Query qemu guest agent */
+} virDomainHostnameSource;
+
typedef enum {
VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE = 0, /* Parse DHCP lease file */
VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT = 1, /* Query qemu guest agent */
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 826bf074e3..3221b06261 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -5321,6 +5321,76 @@ lxcDomainGetCPUStats(virDomainPtr dom,
return ret;
}
+static char *
+lxcDomainGetHostname(virDomainPtr dom,
+ unsigned int flags)
+{
+ virDomainObjPtr vm = NULL;
+ char macaddr[VIR_MAC_STRING_BUFLEN];
+ g_autoptr(virNetwork) network = NULL;
+ virNetworkDHCPLeasePtr *leases = NULL;
+ int n_leases;
+ size_t i, j;
+ char *hostname = NULL;
+
+ virCheckFlags(VIR_DOMAIN_HOSTNAME_SRC_LEASE |
+ VIR_DOMAIN_HOSTNAME_SRC_AGENT, NULL);
+
+ if (!(vm = lxcDomObjFromDomain(dom)))
+ return NULL;
+
+ if (virDomainGetHostnameEnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+
+ switch (flags) {
+ default:
+ case VIR_DOMAIN_HOSTNAME_SRC_LEASE:
+ for (i = 0; i < vm->def->nnets; i++) {
+ if (vm->def->nets[i]->type != VIR_DOMAIN_NET_TYPE_NETWORK)
+ continue;
+
+ virMacAddrFormat(&(vm->def->nets[i]->mac), macaddr);
+ virObjectUnref(network);
+ network = virNetworkLookupByName(dom->conn,
+
vm->def->nets[i]->data.network.name);
+
+ if ((n_leases = virNetworkGetDHCPLeases(network, macaddr,
+ &leases, 0)) < 0)
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("There is no available hostname %d"),
+ flags);
+
+ for (j = 0; j < n_leases; j++) {
+ virNetworkDHCPLeasePtr lease = leases[j];
+ if (lease->hostname) {
+ hostname = g_strdup(lease->hostname);
+
+ for (j = 0; j < n_leases; j++)
+ virNetworkDHCPLeaseFree(leases[j]);
+
+ VIR_FREE(leases);
+
+ goto cleanup;
+ }
+ }
+
+ for (j = 0; j < n_leases; j++)
+ virNetworkDHCPLeaseFree(leases[j]);
+
+ VIR_FREE(leases);
+ }
+ break;
+ case VIR_DOMAIN_HOSTNAME_SRC_AGENT:
+ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
+ _("Unknown hostname data source %d"),
+ flags);
+ break;
+ }
+
+ cleanup:
+ virDomainObjEndAPI(&vm);
+ return hostname;
+}
static int
lxcNodeGetFreePages(virConnectPtr conn,
@@ -5467,6 +5537,7 @@ static virHypervisorDriver lxcHypervisorDriver = {
.domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
.domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
.domainGetCPUStats = lxcDomainGetCPUStats, /* 1.2.2 */
+ .domainGetHostname = lxcDomainGetHostname, /* 5.9.0 */
.nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
.nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
.domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index e07b3b302d..c9f8255f19 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -301,19 +301,31 @@ openvzDomainGetHostname(virDomainPtr dom, unsigned int flags)
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
- virCheckFlags(0, NULL);
+ virCheckFlags(VIR_DOMAIN_HOSTNAME_SRC_LEASE |
+ VIR_DOMAIN_HOSTNAME_SRC_AGENT, NULL);
+
if (!(vm = openvzDomObjFromDomain(driver, dom->uuid)))
return NULL;
- hostname = openvzVEGetStringParam(dom, "hostname");
- if (hostname == NULL)
- goto cleanup;
+ switch (flags) {
+ default:
+ hostname = openvzVEGetStringParam(dom, "hostname");
+ if (hostname == NULL)
+ goto cleanup;
- /* vzlist prints an unset hostname as '-' */
- if (STREQ(hostname, "-")) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("Hostname of '%s' is unset"),
vm->def->name);
- VIR_FREE(hostname);
+ /* vzlist prints an unset hostname as '-' */
+ if (STREQ(hostname, "-")) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Hostname of '%s' is unset"),
vm->def->name);
+ VIR_FREE(hostname);
+ }
+ break;
+ case VIR_DOMAIN_HOSTNAME_SRC_AGENT:
+ case VIR_DOMAIN_HOSTNAME_SRC_LEASE:
+ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
+ _("Unknown hostname data source %d"),
+ flags);
+ break;
}
cleanup:
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b5300241a8..928f75cafe 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -20090,9 +20090,15 @@ qemuDomainGetHostname(virDomainPtr dom,
virQEMUDriverPtr driver = dom->conn->privateData;
virDomainObjPtr vm = NULL;
qemuAgentPtr agent;
+ char macaddr[VIR_MAC_STRING_BUFLEN];
+ g_autoptr(virNetwork) network = NULL;
+ virNetworkDHCPLeasePtr *leases = NULL;
+ int n_leases;
+ size_t i, j;
char *hostname = NULL;
- virCheckFlags(0, NULL);
+ virCheckFlags(VIR_DOMAIN_HOSTNAME_SRC_LEASE |
+ VIR_DOMAIN_HOSTNAME_SRC_AGENT, NULL);
if (!(vm = qemuDomainObjFromDomain(dom)))
return NULL;
@@ -20100,21 +20106,62 @@ qemuDomainGetHostname(virDomainPtr dom,
if (virDomainGetHostnameEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
- if (qemuDomainObjBeginAgentJob(driver, vm, QEMU_AGENT_JOB_QUERY) < 0)
- goto cleanup;
-
if (virDomainObjCheckActive(vm) < 0)
goto endjob;
- if (!qemuDomainAgentAvailable(vm, true))
- goto endjob;
+ switch (flags) {
+ default:
+ case VIR_DOMAIN_HOSTNAME_SRC_AGENT:
+ if (qemuDomainObjBeginAgentJob(driver, vm, QEMU_AGENT_JOB_QUERY) < 0)
+ goto cleanup;
- agent = qemuDomainObjEnterAgent(vm);
- ignore_value(qemuAgentGetHostname(agent, &hostname));
- qemuDomainObjExitAgent(vm, agent);
+ if (!qemuDomainAgentAvailable(vm, true))
+ goto endjob;
- endjob:
- qemuDomainObjEndAgentJob(vm);
+ agent = qemuDomainObjEnterAgent(vm);
+ ignore_value(qemuAgentGetHostname(agent, &hostname));
+ qemuDomainObjExitAgent(vm, agent);
+
+ endjob:
+ qemuDomainObjEndAgentJob(vm);
+ break;
+ case VIR_DOMAIN_HOSTNAME_SRC_LEASE:
+ for (i = 0; i < vm->def->nnets; i++) {
+ if (vm->def->nets[i]->type != VIR_DOMAIN_NET_TYPE_NETWORK)
+ continue;
+
+ virMacAddrFormat(&(vm->def->nets[i]->mac), macaddr);
+ virObjectUnref(network);
+ network = virNetworkLookupByName(dom->conn,
+
vm->def->nets[i]->data.network.name);
+
+ if ((n_leases = virNetworkGetDHCPLeases(network, macaddr,
+ &leases, 0)) < 0)
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("There is no available hostname %d"),
+ flags);
+
+ for (j = 0; j < n_leases; j++) {
+ virNetworkDHCPLeasePtr lease = leases[j];
+ if (lease->hostname) {
+ hostname = g_strdup(lease->hostname);
+
+ for (j = 0; j < n_leases; j++)
+ virNetworkDHCPLeaseFree(leases[j]);
+
+ VIR_FREE(leases);
+
+ goto cleanup;
+ }
+ }
+
+ for (j = 0; j < n_leases; j++)
+ virNetworkDHCPLeaseFree(leases[j]);
+
+ VIR_FREE(leases);
+ }
+ break;
+ }
cleanup:
virDomainObjEndAPI(&vm);
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 6be9780836..01de6b633a 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -11669,6 +11669,10 @@ static const vshCmdInfo info_domhostname[] = {
static const vshCmdOptDef opts_domhostname[] = {
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
+ {.name = "source",
+ .type = VSH_OT_STRING,
+ .flags = VSH_OFLAG_NONE,
+ .help = N_("address source: 'lease' or 'agent'")},
{.name = NULL}
};
@@ -11678,21 +11682,38 @@ cmdDomHostname(vshControl *ctl, const vshCmd *cmd)
char *hostname;
virDomainPtr dom;
bool ret = false;
+ const char *sourcestr = NULL;
+ int flags = 0; /* Use default value. Drivers can have its own default. */
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
return false;
- hostname = virDomainGetHostname(dom, 0);
+ if (vshCommandOptStringReq(ctl, cmd, "source", &sourcestr) < 0)
+ goto error;
+
+ if (sourcestr) {
+ if (STREQ(sourcestr, "lease")) {
+ flags |= VIR_DOMAIN_HOSTNAME_SRC_LEASE;
+ } else if (STREQ(sourcestr, "agent")) {
+ flags |= VIR_DOMAIN_HOSTNAME_SRC_AGENT;
+ } else {
+ vshError(ctl, _("Unknown data source '%s'"), sourcestr);
+ goto error;
+ }
+ }
+
+ hostname = virDomainGetHostname(dom, flags);
if (hostname == NULL) {
vshError(ctl, "%s", _("failed to get hostname"));
goto error;
}
vshPrint(ctl, "%s\n", hostname);
+
+ VIR_FREE(hostname);
ret = true;
error:
- VIR_FREE(hostname);
virshDomainFree(dom);
return ret;
}
--
2.20.1