[libvirt] [PATCH] Fix failing virGetHostname.

Cole Robinson crobinso at redhat.com
Fri May 21 16:27:27 UTC 2010


On 05/20/2010 03:57 PM, Chris Lalancette wrote:
> We've been running into a lot of situations where
> virGetHostname() is returning "localhost", where a plain
> gethostname() would have returned the correct thing.  This
> is because virGetHostname() is *always* trying to canonicalize
> the name returned from gethostname(), even when it doesn't
> have to.
> 
> This patch changes virGetHostname so that if the value returned
> from gethostname() is already FQDN or localhost, it returns
> that string directly.  If the value returned from gethostname()
> is a shortened hostname, then we try to canonicalize it.  If
> that succeeds, we returned the canonicalized hostname.  If
> that fails, and/or returns "localhost", then we just return
> the original string we got from gethostname() and hope for
> the best.
> 
> Note that after this patch it is up to clients to check whether
> "localhost" is an allowed return value.  The only place
> where it's currently not is in qemu migration.
> 
> Signed-off-by: Chris Lalancette <clalance at redhat.com>
> ---
>  src/libvirt_private.syms |    1 -
>  src/qemu/qemu_driver.c   |   15 +++++--
>  src/util/util.c          |   94 ++++++++++++++++++++++++---------------------
>  src/util/util.h          |    1 -
>  4 files changed, 60 insertions(+), 51 deletions(-)
> 
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 104278f..130a2a1 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -653,7 +653,6 @@ virExecDaemonize;
>  virSetCloseExec;
>  virSetNonBlock;
>  virFormatMacAddr;
> -virGetHostnameLocalhost;
>  virGetHostname;
>  virParseMacAddr;
>  virFileDeletePid;
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 0af64c7..cfa5964 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -10017,7 +10017,7 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
>      virDomainDefPtr def = NULL;
>      virDomainObjPtr vm = NULL;
>      int this_port;
> -    char *hostname;
> +    char *hostname = NULL;
>      char migrateFrom [64];
>      const char *p;
>      virDomainEventPtr event = NULL;
> @@ -10057,9 +10057,15 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
>          if (port == QEMUD_MIGRATION_NUM_PORTS) port = 0;
>  
>          /* Get hostname */
> -        if ((hostname = virGetHostnameLocalhost(0)) == NULL)
> +        if ((hostname = virGetHostname(NULL)) == NULL)
>              goto cleanup;
>  
> +        if (STRPREFIX(hostname, "localhost")) {
> +            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                            _("hostname on destination resolved to localhost, but migration requires an FQDN"));
> +            goto cleanup;
> +        }
> +
>          /* XXX this really should have been a properly well-formed
>           * URI, but we can't add in tcp:// now without breaking
>           * compatability with old targets. We at least make the
> @@ -10067,7 +10073,6 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
>           */
>          /* Caller frees */
>          internalret = virAsprintf(uri_out, "tcp:%s:%d", hostname, this_port);
> -        VIR_FREE(hostname);
>          if (internalret < 0) {
>              virReportOOMError();
>              goto cleanup;
> @@ -10171,10 +10176,10 @@ endjob:
>          vm = NULL;
>  
>  cleanup:
> +    VIR_FREE(hostname);
>      virDomainDefFree(def);
> -    if (ret != 0) {
> +    if (ret != 0)
>          VIR_FREE(*uri_out);
> -    }
>      if (vm)
>          virDomainObjUnlock(vm);
>      if (event)
> diff --git a/src/util/util.c b/src/util/util.c
> index e937d39..930bfac 100644
> --- a/src/util/util.c
> +++ b/src/util/util.c
> @@ -2367,11 +2367,31 @@ char *virIndexToDiskName(int idx, const char *prefix)
>  # define AI_CANONIDN 0
>  #endif
>  
> -char *virGetHostnameLocalhost(int allow_localhost)
> +/* Who knew getting a hostname could be so delicate.  In Linux (and Unices
> + * in general), many things depend on "hostname" returning a value that will
> + * resolve one way or another.  In the modern world where networks frequently
> + * come and go this is often being hard-coded to resolve to "localhost".  If
> + * it *doesn't* resolve to localhost, then we would prefer to have the FQDN.
> + * That leads us to 3 possibilities:
> + *
> + * 1)  gethostname() returns an FQDN (not localhost) - we return the string
> + *     as-is, it's all of the information we want
> + * 2)  gethostname() returns "localhost" - we return localhost; doing further
> + *     work to try to resolve it is pointless
> + * 3)  gethostname() returns a shortened hostname - in this case, we want to
> + *     try to resolve this to a fully-qualified name.  Therefore we pass it
> + *     to getaddrinfo().  There are two possible responses:
> + *     a)  getaddrinfo() resolves to a FQDN - return the FQDN
> + *     b)  getaddrinfo() resolves to localhost - in this case, the data we got
> + *         from gethostname() is actually more useful than what we got from
> + *         getaddrinfo().  Return the value from gethostname() and hope for
> + *         the best.
> + */
> +char *virGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
>  {

Hmm, why isn't one of the fallback options:

if (conn)
    hostname = parse_uri(conn.get_uri())
    if hostname != "localhost":
	return hostname

Seems like if MigratePrepare2 dconn is the remote connection, we are
guaranteed to have a resolvable hostname in the URI (well, resolvable to
the source connection at least).

- Cole




More information about the libvir-list mailing list