libvirt/src/esx/esx_util.c

489 lines
12 KiB
C
Raw Normal View History

/*
* esx_util.c: utility methods for the VMware ESX driver
*
* Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.com>
* Copyright (C) 2009 Maximilian Wilhelm <max@rfc2324.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <config.h>
#include <netdb.h>
#include "internal.h"
#include "virterror_internal.h"
#include "datatypes.h"
#include "qparams.h"
#include "util.h"
#include "memory.h"
#include "logging.h"
#include "uuid.h"
#include "esx_util.h"
#define VIR_FROM_THIS VIR_FROM_ESX
#define ESX_ERROR(conn, code, fmt...) \
virReportErrorHelper (conn, VIR_FROM_ESX, code, __FILE__, __FUNCTION__, \
__LINE__, fmt)
char *
esxUtil_RequestUsername(virConnectAuthPtr auth, const char *default_username,
const char *server)
{
unsigned int ncred;
virConnectCredential cred;
char *prompt = NULL;
memset(&cred, 0, sizeof(virConnectCredential));
if (virAsprintf(&prompt, "Enter username for %s [%s]", server,
default_username) < 0) {
return NULL;
}
for (ncred = 0; ncred < auth->ncredtype; ncred++) {
if (auth->credtype[ncred] != VIR_CRED_AUTHNAME) {
continue;
}
cred.type = VIR_CRED_AUTHNAME;
cred.prompt = prompt;
cred.challenge = NULL;
cred.defresult = default_username;
cred.result = NULL;
cred.resultlen = 0;
if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) {
VIR_FREE(cred.result);
}
break;
}
VIR_FREE(prompt);
return cred.result;
}
char *
esxUtil_RequestPassword(virConnectAuthPtr auth, const char *username,
const char *server)
{
unsigned int ncred;
virConnectCredential cred;
char *prompt;
memset(&cred, 0, sizeof(virConnectCredential));
if (virAsprintf(&prompt, "Enter %s password for %s", username,
server) < 0) {
return NULL;
}
for (ncred = 0; ncred < auth->ncredtype; ncred++) {
if (auth->credtype[ncred] != VIR_CRED_PASSPHRASE &&
auth->credtype[ncred] != VIR_CRED_NOECHOPROMPT) {
continue;
}
cred.type = auth->credtype[ncred];
cred.prompt = prompt;
cred.challenge = NULL;
cred.defresult = NULL;
cred.result = NULL;
cred.resultlen = 0;
if ((*(auth->cb))(&cred, 1, auth->cbdata) < 0) {
VIR_FREE(cred.result);
}
break;
}
VIR_FREE(prompt);
return cred.result;
}
int
esxUtil_ParseQuery(virConnectPtr conn, char **transport, char **vcenter)
{
int result = 0;
int i;
struct qparam_set *queryParamSet = NULL;
struct qparam *queryParam = NULL;
if (transport != NULL) {
*transport = NULL;
}
if (vcenter != NULL) {
*vcenter = NULL;
}
#ifdef HAVE_XMLURI_QUERY_RAW
queryParamSet = qparam_query_parse(conn->uri->query_raw);
#else
queryParamSet = qparam_query_parse(conn->uri->query);
#endif
if (queryParamSet == NULL) {
goto failure;
}
for (i = 0; i < queryParamSet->n; i++) {
queryParam = &queryParamSet->p[i];
if (STRCASEEQ(queryParam->name, "transport") && transport != NULL) {
*transport = strdup(queryParam->value);
if (*transport == NULL) {
virReportOOMError(conn);
goto failure;
}
if (STRNEQ(*transport, "http") && STRNEQ(*transport, "https")) {
ESX_ERROR(conn, VIR_ERR_INVALID_ARG,
"Query parameter 'transport' has unexpected value "
"'%s' (should be http|https)", *transport);
goto failure;
}
} else if (STRCASEEQ(queryParam->name, "vcenter") && vcenter != NULL) {
*vcenter = strdup(queryParam->value);
if (*vcenter == NULL) {
virReportOOMError(conn);
goto failure;
}
} else {
VIR_WARN("Ignoring unexpected query parameter '%s'",
queryParam->name);
}
}
if (transport != NULL && *transport == NULL) {
*transport = strdup("https");
if (*transport == NULL) {
virReportOOMError(conn);
goto failure;
}
}
cleanup:
if (queryParamSet != NULL) {
free_qparam_set(queryParamSet);
}
return result;
failure:
if (transport != NULL) {
VIR_FREE(*transport);
}
if (vcenter != NULL) {
VIR_FREE(*vcenter);
}
result = -1;
goto cleanup;
}
int
esxUtil_ParseVirtualMachineIDString(const char *id_string, int *id)
{
/* Try to parse an integer from the complete string. */
if (virStrToLong_i(id_string, NULL, 10, id) == 0) {
return 0;
}
/*
* If that fails try to parse an integer from the string tail
* assuming the naming scheme Virtual Center seems to use.
*/
if (STRPREFIX(id_string, "vm-")) {
if (virStrToLong_i(id_string + 3, NULL, 10, id) == 0) {
return 0;
}
}
return -1;
}
int
esxUtil_ResolveHostname(virConnectPtr conn, const char *hostname,
char *ip_address, size_t ip_address_length)
{
struct addrinfo hints;
struct addrinfo *result = NULL;
int errcode;
memset(&hints, 0, sizeof (struct addrinfo));
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
errcode = getaddrinfo(hostname, NULL, &hints, &result);
if (errcode != 0) {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"IP address lookup for host '%s' failed: %s", hostname,
gai_strerror(errcode));
return -1;
}
if (result == NULL) {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"No IP address for host '%s' found: %s", hostname,
gai_strerror(errcode));
return -1;
}
errcode = getnameinfo(result->ai_addr, result->ai_addrlen, ip_address,
ip_address_length, NULL, 0, NI_NUMERICHOST);
if (errcode != 0) {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Formating IP address for host '%s' failed: %s", hostname,
gai_strerror(errcode));
freeaddrinfo(result);
return -1;
}
freeaddrinfo(result);
return 0;
}
int
esxUtil_GetConfigString(virConnectPtr conn, virConfPtr conf, const char *name,
char **string, int optional)
{
virConfValuePtr value;
*string = NULL;
value = virConfGetValue(conf, name);
if (value == NULL) {
if (optional) {
return 0;
}
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Missing essential config entry '%s'", name);
return -1;
}
if (value->type != VIR_CONF_STRING) {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Config entry '%s' must be a string", name);
return -1;
}
if (value->str == NULL) {
if (optional) {
return 0;
}
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Missing essential config entry '%s'", name);
return -1;
}
*string = strdup(value->str);
if (*string == NULL) {
virReportOOMError(conn);
return -1;
}
return 0;
}
int
esxUtil_GetConfigUUID(virConnectPtr conn, virConfPtr conf, const char *name,
unsigned char *uuid, int optional)
{
virConfValuePtr value;
value = virConfGetValue(conf, name);
if (value == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Missing essential config entry '%s'", name);
return -1;
}
}
if (value->type != VIR_CONF_STRING) {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Config entry '%s' must be a string", name);
return -1;
}
if (value->str == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Missing essential config entry '%s'", name);
return -1;
}
}
virUUIDParse(value->str, uuid);
return 0;
}
int
esxUtil_GetConfigLong(virConnectPtr conn, virConfPtr conf, const char *name,
long long *number, long long default_, int optional)
{
virConfValuePtr value;
*number = default_;
value = virConfGetValue(conf, name);
if (value == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Missing essential config entry '%s'", name);
return -1;
}
}
if (value->type == VIR_CONF_STRING) {
if (value->str == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Missing essential config entry '%s'", name);
return -1;
}
}
if (STREQ(value->str, "unlimited")) {
*number = -1;
} else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Config entry '%s' must represent an integer value",
name);
return -1;
}
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Config entry '%s' must be a string", name);
return -1;
}
return 0;
}
int
esxUtil_GetConfigBoolean(virConnectPtr conn, virConfPtr conf,
const char *name, int *boolean, int default_,
int optional)
{
virConfValuePtr value;
*boolean = default_;
value = virConfGetValue(conf, name);
if (value == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Missing essential config entry '%s'", name);
return -1;
}
}
if (value->type == VIR_CONF_STRING) {
if (value->str == NULL) {
if (optional) {
return 0;
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Missing essential config entry '%s'", name);
return -1;
}
}
if (STRCASEEQ(value->str, "true")) {
*boolean = 1;
} else if (STRCASEEQ(value->str, "false")) {
*boolean = 0;
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Config entry '%s' must represent a boolean value "
"(true|false)", name);
return -1;
}
} else {
ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
"Config entry '%s' must be a string", name);
return -1;
}
return 0;
}
int
esxUtil_EqualSuffix(const char *string, const char* suffix)
{
int difference = (int)strlen(string) - (int)strlen(suffix);
if (difference < 0) {
return -1;
} else {
return STRCASEEQ(string + difference, suffix);
}
}