esx_util.c 13.6 KB
Newer Older
1 2

/*
3
 * esx_util.c: utility functions for the VMware ESX driver
4
 *
5
 * Copyright (C) 2010 Red Hat, Inc.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * 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 "datatypes.h"
#include "qparams.h"
#include "util.h"
#include "memory.h"
#include "logging.h"
#include "uuid.h"
36
#include "esx_private.h"
37 38 39 40
#include "esx_util.h"

#define VIR_FROM_THIS VIR_FROM_ESX

41

42

43
int
44
esxUtil_ParseQuery(esxUtil_ParsedQuery **parsedQuery, xmlURIPtr uri)
45
{
M
Matthias Bolte 已提交
46
    int result = -1;
47 48
    struct qparam_set *queryParamSet = NULL;
    struct qparam *queryParam = NULL;
49 50 51
    int i;
    int noVerify;
    int autoAnswer;
52

53 54 55
    if (parsedQuery == NULL || *parsedQuery != NULL) {
        ESX_VI_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
        return -1;
56 57
    }

58 59 60
    if (VIR_ALLOC(*parsedQuery) < 0) {
        virReportOOMError();
        return -1;
61 62
    }

63
#ifdef HAVE_XMLURI_QUERY_RAW
64
    queryParamSet = qparam_query_parse(uri->query_raw);
65
#else
66
    queryParamSet = qparam_query_parse(uri->query);
67 68 69
#endif

    if (queryParamSet == NULL) {
70
        goto cleanup;
71 72 73 74 75
    }

    for (i = 0; i < queryParamSet->n; i++) {
        queryParam = &queryParamSet->p[i];

76
        if (STRCASEEQ(queryParam->name, "transport")) {
77
            VIR_FREE((*parsedQuery)->transport);
78

79
            (*parsedQuery)->transport = strdup(queryParam->value);
80

81
            if ((*parsedQuery)->transport == NULL) {
82
                virReportOOMError();
M
Matthias Bolte 已提交
83
                goto cleanup;
84 85
            }

86 87
            if (STRNEQ((*parsedQuery)->transport, "http") &&
                STRNEQ((*parsedQuery)->transport, "https")) {
88
                ESX_ERROR(VIR_ERR_INVALID_ARG,
89
                          _("Query parameter 'transport' has unexpected value "
90 91
                            "'%s' (should be http|https)"),
                          (*parsedQuery)->transport);
M
Matthias Bolte 已提交
92
                goto cleanup;
93
            }
94
        } else if (STRCASEEQ(queryParam->name, "vcenter")) {
95
            VIR_FREE((*parsedQuery)->vCenter);
96

97
            (*parsedQuery)->vCenter = strdup(queryParam->value);
98

99
            if ((*parsedQuery)->vCenter == NULL) {
100
                virReportOOMError();
M
Matthias Bolte 已提交
101
                goto cleanup;
102
            }
103
        } else if (STRCASEEQ(queryParam->name, "no_verify")) {
104 105
            if (virStrToLong_i(queryParam->value, NULL, 10, &noVerify) < 0 ||
                (noVerify != 0 && noVerify != 1)) {
106
                ESX_ERROR(VIR_ERR_INVALID_ARG,
107 108
                          _("Query parameter 'no_verify' has unexpected value "
                            "'%s' (should be 0 or 1)"), queryParam->value);
M
Matthias Bolte 已提交
109
                goto cleanup;
110
            }
111

112 113 114 115
            (*parsedQuery)->noVerify = noVerify != 0;
        } else if (STRCASEEQ(queryParam->name, "auto_answer")) {
            if (virStrToLong_i(queryParam->value, NULL, 10, &autoAnswer) < 0 ||
                (autoAnswer != 0 && autoAnswer != 1)) {
116
                ESX_ERROR(VIR_ERR_INVALID_ARG,
117 118
                          _("Query parameter 'auto_answer' has unexpected "
                            "value '%s' (should be 0 or 1)"), queryParam->value);
M
Matthias Bolte 已提交
119
                goto cleanup;
120
            }
121 122

            (*parsedQuery)->autoAnswer = autoAnswer != 0;
123 124 125 126 127 128
        } else {
            VIR_WARN("Ignoring unexpected query parameter '%s'",
                     queryParam->name);
        }
    }

129 130
    if ((*parsedQuery)->transport == NULL) {
        (*parsedQuery)->transport = strdup("https");
131

132
        if ((*parsedQuery)->transport == NULL) {
133
            virReportOOMError();
M
Matthias Bolte 已提交
134
            goto cleanup;
135 136 137
        }
    }

M
Matthias Bolte 已提交
138
    result = 0;
139

M
Matthias Bolte 已提交
140 141
  cleanup:
    if (result < 0) {
142
        esxUtil_FreeParsedQuery(parsedQuery);
143 144
    }

M
Matthias Bolte 已提交
145 146
    if (queryParamSet != NULL) {
        free_qparam_set(queryParamSet);
147 148
    }

M
Matthias Bolte 已提交
149
    return result;
150 151 152 153
}



154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169

void
esxUtil_FreeParsedQuery(esxUtil_ParsedQuery **parsedQuery)
{
    if (parsedQuery == NULL || *parsedQuery == NULL) {
        return;
    }

    VIR_FREE((*parsedQuery)->transport);
    VIR_FREE((*parsedQuery)->vCenter);

    VIR_FREE(*parsedQuery);
}



170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
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;
}



M
Matthias Bolte 已提交
193
int
194
esxUtil_ParseDatastoreRelatedPath(const char *datastoreRelatedPath,
M
Matthias Bolte 已提交
195 196 197
                                  char **datastoreName,
                                  char **directoryName, char **fileName)
{
M
Matthias Bolte 已提交
198
    int result = -1;
199 200 201 202
    char *copyOfDatastoreRelatedPath = NULL;
    char *tmp = NULL;
    char *saveptr = NULL;
    char *preliminaryDatastoreName = NULL;
M
Matthias Bolte 已提交
203 204 205 206 207 208
    char *directoryAndFileName = NULL;
    char *separator = NULL;

    if (datastoreName == NULL || *datastoreName != NULL ||
        directoryName == NULL || *directoryName != NULL ||
        fileName == NULL || *fileName != NULL) {
209
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
210
        return -1;
M
Matthias Bolte 已提交
211 212
    }

213 214
    if (esxVI_String_DeepCopyValue(&copyOfDatastoreRelatedPath,
                                   datastoreRelatedPath) < 0) {
M
Matthias Bolte 已提交
215
        goto cleanup;
216 217 218 219 220 221
    }

    /* Expected format: '[<datastore>] <path>' */
    if ((tmp = STRSKIP(copyOfDatastoreRelatedPath, "[")) == NULL ||
        (preliminaryDatastoreName = strtok_r(tmp, "]", &saveptr)) == NULL ||
        (directoryAndFileName = strtok_r(NULL, "", &saveptr)) == NULL) {
222
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
223 224
                  _("Datastore related path '%s' doesn't have expected format "
                    "'[<datastore>] <path>'"), datastoreRelatedPath);
M
Matthias Bolte 已提交
225
        goto cleanup;
M
Matthias Bolte 已提交
226 227
    }

228 229
    if (esxVI_String_DeepCopyValue(datastoreName,
                                   preliminaryDatastoreName) < 0) {
M
Matthias Bolte 已提交
230
        goto cleanup;
231 232 233 234
    }

    directoryAndFileName += strspn(directoryAndFileName, " ");

M
Matthias Bolte 已提交
235 236 237 238 239 240 241
    /* Split <path> into <directory>/<file>, where <directory> is optional */
    separator = strrchr(directoryAndFileName, '/');

    if (separator != NULL) {
        *separator++ = '\0';

        if (*separator == '\0') {
242
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
243
                      _("Datastore related path '%s' doesn't reference a file"),
M
Matthias Bolte 已提交
244
                      datastoreRelatedPath);
M
Matthias Bolte 已提交
245
            goto cleanup;
M
Matthias Bolte 已提交
246 247
        }

248 249 250
        if (esxVI_String_DeepCopyValue(directoryName,
                                       directoryAndFileName) < 0 ||
            esxVI_String_DeepCopyValue(fileName, separator) < 0) {
M
Matthias Bolte 已提交
251
            goto cleanup;
M
Matthias Bolte 已提交
252 253
        }
    } else {
254
        if (esxVI_String_DeepCopyValue(fileName, directoryAndFileName) < 0) {
M
Matthias Bolte 已提交
255
            goto cleanup;
256
        }
M
Matthias Bolte 已提交
257 258
    }

M
Matthias Bolte 已提交
259 260
    result = 0;

M
Matthias Bolte 已提交
261
  cleanup:
M
Matthias Bolte 已提交
262 263 264 265 266 267
    if (result < 0) {
        VIR_FREE(*datastoreName);
        VIR_FREE(*directoryName);
        VIR_FREE(*fileName);
    }

268
    VIR_FREE(copyOfDatastoreRelatedPath);
M
Matthias Bolte 已提交
269 270 271 272 273 274

    return result;
}



275
int
276
esxUtil_ResolveHostname(const char *hostname,
M
Matthias Bolte 已提交
277
                        char *ipAddress, size_t ipAddress_length)
278 279 280 281 282
{
    struct addrinfo hints;
    struct addrinfo *result = NULL;
    int errcode;

M
Matthias Bolte 已提交
283
    memset(&hints, 0, sizeof (hints));
284 285 286 287 288 289 290 291 292

    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) {
293
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
294
                  _("IP address lookup for host '%s' failed: %s"), hostname,
295 296 297 298 299
                  gai_strerror(errcode));
        return -1;
    }

    if (result == NULL) {
300
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
301
                  _("No IP address for host '%s' found: %s"), hostname,
302 303 304 305
                  gai_strerror(errcode));
        return -1;
    }

M
Matthias Bolte 已提交
306 307
    errcode = getnameinfo(result->ai_addr, result->ai_addrlen, ipAddress,
                          ipAddress_length, NULL, 0, NI_NUMERICHOST);
308 309

    if (errcode != 0) {
310
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
311
                  _("Formating IP address for host '%s' failed: %s"), hostname,
312 313 314 315 316 317 318 319 320 321 322 323 324
                  gai_strerror(errcode));
        freeaddrinfo(result);
        return -1;
    }

    freeaddrinfo(result);

    return 0;
}



int
325 326
esxUtil_GetConfigString(virConfPtr conf, const char *name, char **string,
                        int optional)
327 328 329 330 331 332 333 334 335 336 337
{
    virConfValuePtr value;

    *string = NULL;
    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        }

338
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
339
                  _("Missing essential config entry '%s'"), name);
340 341 342 343
        return -1;
    }

    if (value->type != VIR_CONF_STRING) {
344
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
345
                  _("Config entry '%s' must be a string"), name);
346 347 348 349 350 351 352 353
        return -1;
    }

    if (value->str == NULL) {
        if (optional) {
            return 0;
        }

354
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
355
                  _("Missing essential config entry '%s'"), name);
356 357 358 359 360 361
        return -1;
    }

    *string = strdup(value->str);

    if (*string == NULL) {
362
        virReportOOMError();
363 364 365 366 367 368 369 370 371
        return -1;
    }

    return 0;
}



int
372 373
esxUtil_GetConfigUUID(virConfPtr conf, const char *name, unsigned char *uuid,
                      int optional)
374 375 376 377 378 379 380 381 382
{
    virConfValuePtr value;

    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        } else {
383
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
384
                      _("Missing essential config entry '%s'"), name);
385 386 387 388 389
            return -1;
        }
    }

    if (value->type != VIR_CONF_STRING) {
390
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
391
                  _("Config entry '%s' must be a string"), name);
392 393 394 395 396 397 398
        return -1;
    }

    if (value->str == NULL) {
        if (optional) {
            return 0;
        } else {
399
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
400
                      _("Missing essential config entry '%s'"), name);
401 402 403 404
            return -1;
        }
    }

405
    if (virUUIDParse(value->str, uuid) < 0) {
406
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
407
                  _("Could not parse UUID from string '%s'"), value->str);
408 409
        return -1;
    }
410 411 412 413 414 415 416

    return 0;
}



int
417 418
esxUtil_GetConfigLong(virConfPtr conf, const char *name, long long *number,
                      long long default_, int optional)
419 420 421 422 423 424 425 426 427 428
{
    virConfValuePtr value;

    *number = default_;
    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        } else {
429
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
430
                      _("Missing essential config entry '%s'"), name);
431 432 433 434 435 436 437 438 439
            return -1;
        }
    }

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
440
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
441
                          _("Missing essential config entry '%s'"), name);
442 443 444 445 446 447 448
                return -1;
            }
        }

        if (STREQ(value->str, "unlimited")) {
            *number = -1;
        } else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
449
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
450
                      _("Config entry '%s' must represent an integer value"),
451 452 453 454
                      name);
            return -1;
        }
    } else {
455
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
456
                  _("Config entry '%s' must be a string"), name);
457 458 459 460 461 462 463 464 465
        return -1;
    }

    return 0;
}



int
466 467
esxUtil_GetConfigBoolean(virConfPtr conf, const char *name, int *boolean_,
                         int default_, int optional)
468 469 470
{
    virConfValuePtr value;

M
Matthias Bolte 已提交
471
    *boolean_ = default_;
472 473 474 475 476 477
    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        } else {
478
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
479
                      _("Missing essential config entry '%s'"), name);
480 481 482 483 484 485 486 487 488
            return -1;
        }
    }

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
489
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
490
                          _("Missing essential config entry '%s'"), name);
491 492 493 494 495
                return -1;
            }
        }

        if (STRCASEEQ(value->str, "true")) {
M
Matthias Bolte 已提交
496
            *boolean_ = 1;
497
        } else if (STRCASEEQ(value->str, "false")) {
M
Matthias Bolte 已提交
498
            *boolean_ = 0;
499
        } else {
500
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
501 502
                      _("Config entry '%s' must represent a boolean value "
                        "(true|false)"), name);
503 504 505
            return -1;
        }
    } else {
506
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
507
                  _("Config entry '%s' must be a string"), name);
508 509 510 511 512
        return -1;
    }

    return 0;
}