esx_util.c 16.1 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;
M
Matthias Bolte 已提交
52
    char *tmp;
53

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

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

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

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

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

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

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

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

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

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

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

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

            (*parsedQuery)->autoAnswer = autoAnswer != 0;
M
Matthias Bolte 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
        } else if (STRCASEEQ(queryParam->name, "proxy")) {
            /* Expected format: [<type>://]<hostname>[:<port>] */
            (*parsedQuery)->proxy = true;
            (*parsedQuery)->proxy_type = CURLPROXY_HTTP;
            VIR_FREE((*parsedQuery)->proxy_hostname);
            (*parsedQuery)->proxy_port = 1080;

            if ((tmp = STRSKIP(queryParam->value, "http://")) != NULL) {
                (*parsedQuery)->proxy_type = CURLPROXY_HTTP;
            } else if ((tmp = STRSKIP(queryParam->value, "socks://")) != NULL ||
                       (tmp = STRSKIP(queryParam->value, "socks5://")) != NULL) {
                (*parsedQuery)->proxy_type = CURLPROXY_SOCKS5;
            } else if ((tmp = STRSKIP(queryParam->value, "socks4://")) != NULL) {
                (*parsedQuery)->proxy_type = CURLPROXY_SOCKS4;
            } else if ((tmp = STRSKIP(queryParam->value, "socks4a://")) != NULL) {
                (*parsedQuery)->proxy_type = CURLPROXY_SOCKS4A;
            } else if ((tmp = strstr(queryParam->value, "://")) != NULL) {
                *tmp = '\0';

                ESX_ERROR(VIR_ERR_INVALID_ARG,
                          _("Query parameter 'proxy' contains unexpected "
                            "type '%s' (should be (http|socks(|4|4a|5))"),
                          queryParam->value);
                goto cleanup;
            } else {
                tmp = queryParam->value;
            }

            (*parsedQuery)->proxy_hostname = strdup(tmp);

            if ((*parsedQuery)->proxy_hostname == NULL) {
                virReportOOMError();
                goto cleanup;
            }

            if ((tmp = strchr((*parsedQuery)->proxy_hostname, ':')) != NULL) {
                if (tmp == (*parsedQuery)->proxy_hostname) {
                    ESX_ERROR(VIR_ERR_INVALID_ARG, "%s",
                              _("Query parameter 'proxy' doesn't contain a "
                                "hostname"));
                    goto cleanup;
                }

                *tmp++ = '\0';

                if (virStrToLong_i(tmp, NULL, 10,
                                   &(*parsedQuery)->proxy_port) < 0 ||
                    (*parsedQuery)->proxy_port < 1 ||
                    (*parsedQuery)->proxy_port > 65535) {
                    ESX_ERROR(VIR_ERR_INVALID_ARG,
                              _("Query parameter 'proxy' has unexpected port"
                                "value '%s' (should be [1..65535])"), tmp);
                    goto cleanup;
                }
            }
179 180 181 182 183 184
        } else {
            VIR_WARN("Ignoring unexpected query parameter '%s'",
                     queryParam->name);
        }
    }

185 186
    if ((*parsedQuery)->transport == NULL) {
        (*parsedQuery)->transport = strdup("https");
187

188
        if ((*parsedQuery)->transport == NULL) {
189
            virReportOOMError();
M
Matthias Bolte 已提交
190
            goto cleanup;
191 192 193
        }
    }

M
Matthias Bolte 已提交
194
    result = 0;
195

M
Matthias Bolte 已提交
196 197
  cleanup:
    if (result < 0) {
198
        esxUtil_FreeParsedQuery(parsedQuery);
199 200
    }

M
Matthias Bolte 已提交
201 202
    if (queryParamSet != NULL) {
        free_qparam_set(queryParamSet);
203 204
    }

M
Matthias Bolte 已提交
205
    return result;
206 207 208 209
}



210 211 212 213 214 215 216 217 218 219

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

    VIR_FREE((*parsedQuery)->transport);
    VIR_FREE((*parsedQuery)->vCenter);
M
Matthias Bolte 已提交
220
    VIR_FREE((*parsedQuery)->proxy_hostname);
221 222 223 224 225 226

    VIR_FREE(*parsedQuery);
}



227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
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 已提交
250
int
251
esxUtil_ParseDatastoreRelatedPath(const char *datastoreRelatedPath,
M
Matthias Bolte 已提交
252 253 254
                                  char **datastoreName,
                                  char **directoryName, char **fileName)
{
M
Matthias Bolte 已提交
255
    int result = -1;
256 257 258 259
    char *copyOfDatastoreRelatedPath = NULL;
    char *tmp = NULL;
    char *saveptr = NULL;
    char *preliminaryDatastoreName = NULL;
M
Matthias Bolte 已提交
260 261 262 263 264 265
    char *directoryAndFileName = NULL;
    char *separator = NULL;

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

270 271
    if (esxVI_String_DeepCopyValue(&copyOfDatastoreRelatedPath,
                                   datastoreRelatedPath) < 0) {
M
Matthias Bolte 已提交
272
        goto cleanup;
273 274 275 276 277 278
    }

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

285 286
    if (esxVI_String_DeepCopyValue(datastoreName,
                                   preliminaryDatastoreName) < 0) {
M
Matthias Bolte 已提交
287
        goto cleanup;
288 289 290 291
    }

    directoryAndFileName += strspn(directoryAndFileName, " ");

M
Matthias Bolte 已提交
292 293 294 295 296 297 298
    /* Split <path> into <directory>/<file>, where <directory> is optional */
    separator = strrchr(directoryAndFileName, '/');

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

        if (*separator == '\0') {
299
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
300
                      _("Datastore related path '%s' doesn't reference a file"),
M
Matthias Bolte 已提交
301
                      datastoreRelatedPath);
M
Matthias Bolte 已提交
302
            goto cleanup;
M
Matthias Bolte 已提交
303 304
        }

305 306 307
        if (esxVI_String_DeepCopyValue(directoryName,
                                       directoryAndFileName) < 0 ||
            esxVI_String_DeepCopyValue(fileName, separator) < 0) {
M
Matthias Bolte 已提交
308
            goto cleanup;
M
Matthias Bolte 已提交
309 310
        }
    } else {
311
        if (esxVI_String_DeepCopyValue(fileName, directoryAndFileName) < 0) {
M
Matthias Bolte 已提交
312
            goto cleanup;
313
        }
M
Matthias Bolte 已提交
314 315
    }

M
Matthias Bolte 已提交
316 317
    result = 0;

M
Matthias Bolte 已提交
318
  cleanup:
M
Matthias Bolte 已提交
319 320 321 322 323 324
    if (result < 0) {
        VIR_FREE(*datastoreName);
        VIR_FREE(*directoryName);
        VIR_FREE(*fileName);
    }

325
    VIR_FREE(copyOfDatastoreRelatedPath);
M
Matthias Bolte 已提交
326 327 328 329 330 331

    return result;
}



332
int
333
esxUtil_ResolveHostname(const char *hostname,
M
Matthias Bolte 已提交
334
                        char *ipAddress, size_t ipAddress_length)
335 336 337 338 339
{
    struct addrinfo hints;
    struct addrinfo *result = NULL;
    int errcode;

M
Matthias Bolte 已提交
340
    memset(&hints, 0, sizeof (hints));
341 342 343 344 345 346 347 348 349

    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) {
350
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
351
                  _("IP address lookup for host '%s' failed: %s"), hostname,
352 353 354 355 356
                  gai_strerror(errcode));
        return -1;
    }

    if (result == NULL) {
357
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
358
                  _("No IP address for host '%s' found: %s"), hostname,
359 360 361 362
                  gai_strerror(errcode));
        return -1;
    }

M
Matthias Bolte 已提交
363 364
    errcode = getnameinfo(result->ai_addr, result->ai_addrlen, ipAddress,
                          ipAddress_length, NULL, 0, NI_NUMERICHOST);
365 366

    if (errcode != 0) {
367
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
368
                  _("Formating IP address for host '%s' failed: %s"), hostname,
369 370 371 372 373 374 375 376 377 378 379 380 381
                  gai_strerror(errcode));
        freeaddrinfo(result);
        return -1;
    }

    freeaddrinfo(result);

    return 0;
}



int
382
esxUtil_GetConfigString(virConfPtr conf, const char *name, char **string,
383
                        bool optional)
384 385 386 387 388 389 390 391 392 393 394
{
    virConfValuePtr value;

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

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

395
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
396
                  _("Missing essential config entry '%s'"), name);
397 398 399 400
        return -1;
    }

    if (value->type != VIR_CONF_STRING) {
401
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
402
                  _("Config entry '%s' must be a string"), name);
403 404 405 406 407 408 409 410
        return -1;
    }

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

411
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
412
                  _("Missing essential config entry '%s'"), name);
413 414 415 416 417 418
        return -1;
    }

    *string = strdup(value->str);

    if (*string == NULL) {
419
        virReportOOMError();
420 421 422 423 424 425 426 427 428
        return -1;
    }

    return 0;
}



int
429
esxUtil_GetConfigUUID(virConfPtr conf, const char *name, unsigned char *uuid,
430
                      bool optional)
431 432 433 434 435 436 437 438 439
{
    virConfValuePtr value;

    value = virConfGetValue(conf, name);

    if (value == 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
            return -1;
        }
    }

    if (value->type != VIR_CONF_STRING) {
447
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
448
                  _("Config entry '%s' must be a string"), name);
449 450 451 452 453 454 455
        return -1;
    }

    if (value->str == NULL) {
        if (optional) {
            return 0;
        } else {
456
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
457
                      _("Missing essential config entry '%s'"), name);
458 459 460 461
            return -1;
        }
    }

462
    if (virUUIDParse(value->str, uuid) < 0) {
463
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
464
                  _("Could not parse UUID from string '%s'"), value->str);
465 466
        return -1;
    }
467 468 469 470 471 472 473

    return 0;
}



int
474
esxUtil_GetConfigLong(virConfPtr conf, const char *name, long long *number,
475
                      long long default_, bool optional)
476 477 478 479 480 481 482 483 484 485
{
    virConfValuePtr value;

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

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

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
497
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
498
                          _("Missing essential config entry '%s'"), name);
499 500 501 502 503 504 505
                return -1;
            }
        }

        if (STREQ(value->str, "unlimited")) {
            *number = -1;
        } else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
506
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
507
                      _("Config entry '%s' must represent an integer value"),
508 509 510 511
                      name);
            return -1;
        }
    } else {
512
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
513
                  _("Config entry '%s' must be a string"), name);
514 515 516 517 518 519 520 521 522
        return -1;
    }

    return 0;
}



int
523 524
esxUtil_GetConfigBoolean(virConfPtr conf, const char *name, bool *boolean_,
                         bool default_, bool optional)
525 526 527
{
    virConfValuePtr value;

M
Matthias Bolte 已提交
528
    *boolean_ = default_;
529 530 531 532 533 534
    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        } else {
535
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
536
                      _("Missing essential config entry '%s'"), name);
537 538 539 540 541 542 543 544 545
            return -1;
        }
    }

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
546
                ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
547
                          _("Missing essential config entry '%s'"), name);
548 549 550 551 552
                return -1;
            }
        }

        if (STRCASEEQ(value->str, "true")) {
M
Matthias Bolte 已提交
553
            *boolean_ = 1;
554
        } else if (STRCASEEQ(value->str, "false")) {
M
Matthias Bolte 已提交
555
            *boolean_ = 0;
556
        } else {
557
            ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
558 559
                      _("Config entry '%s' must represent a boolean value "
                        "(true|false)"), name);
560 561 562
            return -1;
        }
    } else {
563
        ESX_ERROR(VIR_ERR_INTERNAL_ERROR,
564
                  _("Config entry '%s' must be a string"), name);
565 566 567 568 569
        return -1;
    }

    return 0;
}