1 /*
2 * esx_vi.c: client for the VMware VI API 2.5 to manage ESX hosts
3 *
4 * Copyright (C) 2010-2012 Red Hat, Inc.
5 * Copyright (C) 2009-2012, 2014 Matthias Bolte <matthias.bolte@googlemail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23 #include <config.h>
24
25 #include <libxml/parser.h>
26 #include <libxml/xpathInternals.h>
27
28 #include "virbuffer.h"
29 #include "viralloc.h"
30 #include "virlog.h"
31 #include "viruuid.h"
32 #include "vmx.h"
33 #include "virxml.h"
34 #include "esx_vi.h"
35 #include "esx_vi_methods.h"
36 #include "esx_util.h"
37 #include "virstring.h"
38 #include "virutil.h"
39
40 #define VIR_FROM_THIS VIR_FROM_ESX
41
42 VIR_LOG_INIT("esx.esx_vi");
43
44 #define ESX_VI__SOAP__RESPONSE_XPATH(_type) \
45 ((char *)"/soapenv:Envelope/soapenv:Body/" \
46 "vim:"_type"Response/vim:returnval")
47
48
49
50 #define ESX_VI__TEMPLATE__ALLOC(_type) \
51 int \
52 esxVI_##_type##_Alloc(esxVI_##_type **ptrptr) \
53 { \
54 ESX_VI_CHECK_ARG_LIST(ptrptr); \
55 \
56 *ptrptr = g_new0(esxVI_##_type, 1); \
57 return 0; \
58 }
59
60
61
62 #define ESX_VI__TEMPLATE__FREE(_type, _body) \
63 void \
64 esxVI_##_type##_Free(esxVI_##_type **ptrptr) \
65 { \
66 esxVI_##_type *item G_GNUC_UNUSED; \
67 \
68 if (!ptrptr || !(*ptrptr)) { \
69 return; \
70 } \
71 \
72 item = *ptrptr; \
73 \
74 _body \
75 \
76 g_clear_pointer(ptrptr, g_free); \
77 }
78
79
80
81 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
82 * CURL
83 */
84
85 /* esxVI_CURL_Alloc */
86 ESX_VI__TEMPLATE__ALLOC(CURL)
87
88 /* esxVI_CURL_Free */
89 ESX_VI__TEMPLATE__FREE(CURL,
90 {
91 esxVI_SharedCURL *shared = item->shared;
92 esxVI_MultiCURL *multi = item->multi;
93
94 if (shared) {
95 esxVI_SharedCURL_Remove(shared, item);
96
97 if (shared->count == 0)
98 esxVI_SharedCURL_Free(&shared);
99 }
100
101 if (multi) {
102 esxVI_MultiCURL_Remove(multi, item);
103
104 if (multi->count == 0)
105 esxVI_MultiCURL_Free(&multi);
106 }
107
108 if (item->handle)
109 curl_easy_cleanup(item->handle);
110
111 if (item->headers)
112 curl_slist_free_all(item->headers);
113
114 virMutexDestroy(&item->lock);
115 })
116
117 static size_t
esxVI_CURL_ReadString(char * data,size_t size,size_t nmemb,void * userdata)118 esxVI_CURL_ReadString(char *data, size_t size, size_t nmemb, void *userdata)
119 {
120 const char *content = *(const char **)userdata;
121 size_t available = 0;
122 size_t requested = size * nmemb;
123
124 if (!content)
125 return 0;
126
127 available = strlen(content);
128
129 if (available == 0)
130 return 0;
131
132 if (requested > available)
133 requested = available;
134
135 memcpy(data, content, requested);
136
137 *(const char **)userdata = content + requested;
138
139 return requested;
140 }
141
142 static size_t
esxVI_CURL_WriteBuffer(char * data,size_t size,size_t nmemb,void * userdata)143 esxVI_CURL_WriteBuffer(char *data, size_t size, size_t nmemb, void *userdata)
144 {
145 virBuffer *buffer = userdata;
146
147 if (buffer) {
148 /*
149 * Using a virBuffer to store the download data limits the downloadable
150 * size. This is no problem as esxVI_CURL_Download and esxVI_CURL_Perform
151 * are meant to download small things such as VMX files, VMDK metadata
152 * files and SOAP responses.
153 */
154 if (size * nmemb > INT32_MAX / 2 - virBufferUse(buffer))
155 return 0;
156
157 virBufferAdd(buffer, data, size * nmemb);
158
159 return size * nmemb;
160 }
161
162 return 0;
163 }
164
165 #define ESX_VI__CURL__ENABLE_DEBUG_OUTPUT 0
166
167 #if ESX_VI__CURL__ENABLE_DEBUG_OUTPUT
168 static int
esxVI_CURL_Debug(CURL * curl G_GNUC_UNUSED,curl_infotype type,char * info,size_t size,void * userdata G_GNUC_UNUSED)169 esxVI_CURL_Debug(CURL *curl G_GNUC_UNUSED, curl_infotype type,
170 char *info, size_t size, void *userdata G_GNUC_UNUSED)
171 {
172 g_autofree char *buffer = NULL;
173
174 /*
175 * The libcurl documentation says:
176 *
177 * The data pointed to by the char * passed to this function WILL NOT
178 * be zero terminated, but will be exactly of the size as told by the
179 * size_t argument.
180 *
181 * To handle this properly in order to pass the info string to VIR_DEBUG
182 * a zero terminated copy of the info string has to be allocated.
183 */
184 buffer = g_new0(char, size + 1);
185
186 memcpy(buffer, info, size);
187 buffer[size] = '\0';
188
189 switch (type) {
190 case CURLINFO_TEXT:
191 if (size > 0 && buffer[size - 1] == '\n')
192 buffer[size - 1] = '\0';
193
194 VIR_DEBUG("CURLINFO_TEXT [[[[%s]]]]", buffer);
195 break;
196
197 case CURLINFO_HEADER_IN:
198 VIR_DEBUG("CURLINFO_HEADER_IN [[[[%s]]]]", buffer);
199 break;
200
201 case CURLINFO_HEADER_OUT:
202 VIR_DEBUG("CURLINFO_HEADER_OUT [[[[%s]]]]", buffer);
203 break;
204
205 case CURLINFO_DATA_IN:
206 case CURLINFO_SSL_DATA_IN:
207 VIR_DEBUG("CURLINFO_DATA_IN [[[[%s]]]]", buffer);
208 break;
209
210 case CURLINFO_DATA_OUT:
211 case CURLINFO_SSL_DATA_OUT:
212 VIR_DEBUG("CURLINFO_DATA_OUT [[[[%s]]]]", buffer);
213 break;
214
215 case CURLINFO_END:
216 VIR_DEBUG("CURLINFO_END [[[[%s]]]]", buffer);
217 break;
218
219 default:
220 VIR_DEBUG("unknown");
221 break;
222 }
223
224 return 0;
225 }
226 #endif
227
228 static int
esxVI_CURL_Perform(esxVI_CURL * curl,const char * url)229 esxVI_CURL_Perform(esxVI_CURL *curl, const char *url)
230 {
231 CURLcode errorCode;
232 long responseCode = 0;
233 const char *redirectUrl = NULL;
234
235 errorCode = curl_easy_perform(curl->handle);
236
237 if (errorCode != CURLE_OK) {
238 virReportError(VIR_ERR_INTERNAL_ERROR,
239 _("curl_easy_perform() returned an error: %s (%d) : %s"),
240 curl_easy_strerror(errorCode), errorCode, curl->error);
241 return -1;
242 }
243
244 errorCode = curl_easy_getinfo(curl->handle, CURLINFO_RESPONSE_CODE,
245 &responseCode);
246
247 if (errorCode != CURLE_OK) {
248 virReportError(VIR_ERR_INTERNAL_ERROR,
249 _("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) returned an "
250 "error: %s (%d) : %s"), curl_easy_strerror(errorCode),
251 errorCode, curl->error);
252 return -1;
253 }
254
255 if (responseCode < 0) {
256 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
257 _("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) returned a "
258 "negative response code"));
259 return -1;
260 }
261
262 if (responseCode == 301) {
263 errorCode = curl_easy_getinfo(curl->handle, CURLINFO_REDIRECT_URL,
264 &redirectUrl);
265
266 if (errorCode != CURLE_OK) {
267 virReportError(VIR_ERR_INTERNAL_ERROR,
268 _("curl_easy_getinfo(CURLINFO_REDIRECT_URL) returned "
269 "an error: %s (%d) : %s"),
270 curl_easy_strerror(errorCode),
271 errorCode, curl->error);
272 } else {
273 virReportError(VIR_ERR_INTERNAL_ERROR,
274 _("The server redirects from '%s' to '%s'"), url,
275 redirectUrl);
276 }
277
278 return -1;
279 }
280
281 return responseCode;
282 }
283
284 int
esxVI_CURL_Connect(esxVI_CURL * curl,esxUtil_ParsedUri * parsedUri)285 esxVI_CURL_Connect(esxVI_CURL *curl, esxUtil_ParsedUri *parsedUri)
286 {
287 if (curl->handle) {
288 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid call"));
289 return -1;
290 }
291
292 curl->handle = curl_easy_init();
293
294 if (!curl->handle) {
295 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
296 _("Could not initialize CURL"));
297 return -1;
298 }
299
300 curl->headers = curl_slist_append(curl->headers,
301 "Content-Type: text/xml; charset=UTF-8");
302
303 /*
304 * Add an empty expect header to stop CURL from waiting for a response code
305 * 100 (Continue) from the server before continuing the POST operation.
306 * Waiting for this response would slowdown each communication with the
307 * server by approx. 2 sec, because the server doesn't send the expected
308 * 100 (Continue) response and the wait times out resulting in wasting
309 * approx. 2 sec per POST operation.
310 */
311 curl->headers = curl_slist_append(curl->headers, "Expect:");
312
313 if (!curl->headers) {
314 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
315 _("Could not build CURL header list"));
316 return -1;
317 }
318
319 curl_easy_setopt(curl->handle, CURLOPT_USERAGENT, "libvirt-esx");
320 curl_easy_setopt(curl->handle, CURLOPT_NOSIGNAL, 1);
321 curl_easy_setopt(curl->handle, CURLOPT_HEADER, 0);
322 curl_easy_setopt(curl->handle, CURLOPT_FOLLOWLOCATION, 0);
323 curl_easy_setopt(curl->handle, CURLOPT_SSL_VERIFYPEER,
324 parsedUri->noVerify ? 0 : 1);
325 curl_easy_setopt(curl->handle, CURLOPT_SSL_VERIFYHOST,
326 parsedUri->noVerify ? 0 : 2);
327 curl_easy_setopt(curl->handle, CURLOPT_COOKIEFILE, "");
328 curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->headers);
329 curl_easy_setopt(curl->handle, CURLOPT_READFUNCTION,
330 esxVI_CURL_ReadString);
331 curl_easy_setopt(curl->handle, CURLOPT_WRITEFUNCTION,
332 esxVI_CURL_WriteBuffer);
333 curl_easy_setopt(curl->handle, CURLOPT_ERRORBUFFER, curl->error);
334 #if ESX_VI__CURL__ENABLE_DEBUG_OUTPUT
335 curl_easy_setopt(curl->handle, CURLOPT_DEBUGFUNCTION, esxVI_CURL_Debug);
336 curl_easy_setopt(curl->handle, CURLOPT_VERBOSE, 1);
337 #endif
338
339 if (parsedUri->proxy) {
340 curl_easy_setopt(curl->handle, CURLOPT_PROXY,
341 parsedUri->proxy_hostname);
342 curl_easy_setopt(curl->handle, CURLOPT_PROXYTYPE,
343 parsedUri->proxy_type);
344 curl_easy_setopt(curl->handle, CURLOPT_PROXYPORT,
345 parsedUri->proxy_port);
346 }
347
348 if (virMutexInit(&curl->lock) < 0) {
349 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
350 _("Could not initialize CURL mutex"));
351 return -1;
352 }
353
354 return 0;
355 }
356
357 int
esxVI_CURL_Download(esxVI_CURL * curl,const char * url,char ** content,unsigned long long offset,unsigned long long * length)358 esxVI_CURL_Download(esxVI_CURL *curl, const char *url, char **content,
359 unsigned long long offset, unsigned long long *length)
360 {
361 g_autofree char *range = NULL;
362 g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
363 int responseCode = 0;
364
365 ESX_VI_CHECK_ARG_LIST(content);
366
367 if (length && *length > 0) {
368 /*
369 * Using a virBuffer to store the download data limits the downloadable
370 * size. This is no problem as esxVI_CURL_Download is meant to download
371 * small things such as VMX of VMDK metadata files.
372 */
373 if (*length > INT32_MAX / 2) {
374 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
375 _("Download length it too large"));
376 return -1;
377 }
378
379 range = g_strdup_printf("%llu-%llu", offset, offset + *length - 1);
380 } else if (offset > 0) {
381 range = g_strdup_printf("%llu-", offset);
382 }
383
384 virMutexLock(&curl->lock);
385
386 curl_easy_setopt(curl->handle, CURLOPT_URL, url);
387 curl_easy_setopt(curl->handle, CURLOPT_RANGE, range);
388 curl_easy_setopt(curl->handle, CURLOPT_WRITEDATA, &buffer);
389 curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 0);
390 curl_easy_setopt(curl->handle, CURLOPT_HTTPGET, 1);
391
392 responseCode = esxVI_CURL_Perform(curl, url);
393
394 virMutexUnlock(&curl->lock);
395
396 if (responseCode < 0) {
397 return -1;
398 } else if (responseCode != 200 && responseCode != 206) {
399 virReportError(VIR_ERR_INTERNAL_ERROR,
400 _("HTTP response code %d for download from '%s'"),
401 responseCode, url);
402 return -1;
403 }
404
405 if (length)
406 *length = virBufferUse(&buffer);
407
408 *content = virBufferContentAndReset(&buffer);
409
410 if (!(*content))
411 return -1;
412
413 return 0;
414 }
415
416 int
esxVI_CURL_Upload(esxVI_CURL * curl,const char * url,const char * content)417 esxVI_CURL_Upload(esxVI_CURL *curl, const char *url, const char *content)
418 {
419 int responseCode = 0;
420
421 if (!content) {
422 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
423 return -1;
424 }
425
426 virMutexLock(&curl->lock);
427
428 curl_easy_setopt(curl->handle, CURLOPT_URL, url);
429 curl_easy_setopt(curl->handle, CURLOPT_RANGE, NULL);
430 curl_easy_setopt(curl->handle, CURLOPT_READDATA, &content);
431 curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1);
432 curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, strlen(content));
433
434 responseCode = esxVI_CURL_Perform(curl, url);
435
436 virMutexUnlock(&curl->lock);
437
438 if (responseCode < 0) {
439 return -1;
440 } else if (responseCode != 200 && responseCode != 201) {
441 virReportError(VIR_ERR_INTERNAL_ERROR,
442 _("HTTP response code %d for upload to '%s'"),
443 responseCode, url);
444 return -1;
445 }
446
447 return 0;
448 }
449
450
451
452 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
453 * SharedCURL
454 */
455
456 static void
esxVI_SharedCURL_Lock(CURL * handle G_GNUC_UNUSED,curl_lock_data data,curl_lock_access access_ G_GNUC_UNUSED,void * userptr)457 esxVI_SharedCURL_Lock(CURL *handle G_GNUC_UNUSED, curl_lock_data data,
458 curl_lock_access access_ G_GNUC_UNUSED, void *userptr)
459 {
460 size_t i;
461 esxVI_SharedCURL *shared = userptr;
462
463 switch ((int)data) {
464 case CURL_LOCK_DATA_SHARE:
465 i = 0;
466 break;
467
468 case CURL_LOCK_DATA_COOKIE:
469 i = 1;
470 break;
471
472 case CURL_LOCK_DATA_DNS:
473 i = 2;
474 break;
475
476 default:
477 VIR_ERROR(_("Trying to lock unknown SharedCURL lock %d"), (int)data);
478 return;
479 }
480
481 virMutexLock(&shared->locks[i]);
482 }
483
484 static void
esxVI_SharedCURL_Unlock(CURL * handle G_GNUC_UNUSED,curl_lock_data data,void * userptr)485 esxVI_SharedCURL_Unlock(CURL *handle G_GNUC_UNUSED, curl_lock_data data,
486 void *userptr)
487 {
488 size_t i;
489 esxVI_SharedCURL *shared = userptr;
490
491 switch ((int)data) {
492 case CURL_LOCK_DATA_SHARE:
493 i = 0;
494 break;
495
496 case CURL_LOCK_DATA_COOKIE:
497 i = 1;
498 break;
499
500 case CURL_LOCK_DATA_DNS:
501 i = 2;
502 break;
503
504 default:
505 VIR_ERROR(_("Trying to unlock unknown SharedCURL lock %d"), (int)data);
506 return;
507 }
508
509 virMutexUnlock(&shared->locks[i]);
510 }
511
512 /* esxVI_SharedCURL_Alloc */
513 ESX_VI__TEMPLATE__ALLOC(SharedCURL)
514
515 /* esxVI_SharedCURL_Free */
516 ESX_VI__TEMPLATE__FREE(SharedCURL,
517 {
518 size_t i;
519
520 if (item->count > 0) {
521 /* Better leak than crash */
522 VIR_ERROR(_("Trying to free SharedCURL object that is still in use"));
523 return;
524 }
525
526 if (item->handle)
527 curl_share_cleanup(item->handle);
528
529 for (i = 0; i < G_N_ELEMENTS(item->locks); ++i)
530 virMutexDestroy(&item->locks[i]);
531 })
532
533 int
esxVI_SharedCURL_Add(esxVI_SharedCURL * shared,esxVI_CURL * curl)534 esxVI_SharedCURL_Add(esxVI_SharedCURL *shared, esxVI_CURL *curl)
535 {
536 size_t i;
537
538 if (!curl->handle) {
539 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
540 _("Cannot share uninitialized CURL handle"));
541 return -1;
542 }
543
544 if (curl->shared) {
545 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
546 _("Cannot share CURL handle that is already shared"));
547 return -1;
548 }
549
550 if (!shared->handle) {
551 shared->handle = curl_share_init();
552
553 if (!shared->handle) {
554 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
555 _("Could not initialize CURL (share)"));
556 return -1;
557 }
558
559 curl_share_setopt(shared->handle, CURLSHOPT_LOCKFUNC,
560 esxVI_SharedCURL_Lock);
561 curl_share_setopt(shared->handle, CURLSHOPT_UNLOCKFUNC,
562 esxVI_SharedCURL_Unlock);
563 curl_share_setopt(shared->handle, CURLSHOPT_USERDATA, shared);
564 curl_share_setopt(shared->handle, CURLSHOPT_SHARE,
565 CURL_LOCK_DATA_COOKIE);
566 curl_share_setopt(shared->handle, CURLSHOPT_SHARE,
567 CURL_LOCK_DATA_DNS);
568
569 for (i = 0; i < G_N_ELEMENTS(shared->locks); ++i) {
570 if (virMutexInit(&shared->locks[i]) < 0) {
571 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
572 _("Could not initialize a CURL (share) mutex"));
573 return -1;
574 }
575 }
576 }
577
578 virMutexLock(&curl->lock);
579
580 curl_easy_setopt(curl->handle, CURLOPT_SHARE, shared->handle);
581
582 curl->shared = shared;
583 ++shared->count;
584
585 virMutexUnlock(&curl->lock);
586
587 return 0;
588 }
589
590 int
esxVI_SharedCURL_Remove(esxVI_SharedCURL * shared,esxVI_CURL * curl)591 esxVI_SharedCURL_Remove(esxVI_SharedCURL *shared, esxVI_CURL *curl)
592 {
593 if (!curl->handle) {
594 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
595 _("Cannot unshare uninitialized CURL handle"));
596 return -1;
597 }
598
599 if (!curl->shared) {
600 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
601 _("Cannot unshare CURL handle that is not shared"));
602 return -1;
603 }
604
605 if (curl->shared != shared) {
606 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CURL (share) mismatch"));
607 return -1;
608 }
609
610 virMutexLock(&curl->lock);
611
612 curl_easy_setopt(curl->handle, CURLOPT_SHARE, NULL);
613
614 curl->shared = NULL;
615 --shared->count;
616
617 virMutexUnlock(&curl->lock);
618
619 return 0;
620 }
621
622
623
624 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
625 * MultiCURL
626 */
627
628
629 /* esxVI_MultiCURL_Alloc */
630 ESX_VI__TEMPLATE__ALLOC(MultiCURL)
631
632 /* esxVI_MultiCURL_Free */
633 ESX_VI__TEMPLATE__FREE(MultiCURL,
634 {
635 if (item->count > 0) {
636 /* Better leak than crash */
637 VIR_ERROR(_("Trying to free MultiCURL object that is still in use"));
638 return;
639 }
640
641 if (item->handle)
642 curl_multi_cleanup(item->handle);
643 })
644
645 int
esxVI_MultiCURL_Add(esxVI_MultiCURL * multi,esxVI_CURL * curl)646 esxVI_MultiCURL_Add(esxVI_MultiCURL *multi, esxVI_CURL *curl)
647 {
648 if (!curl->handle) {
649 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
650 _("Cannot add uninitialized CURL handle to a multi handle"));
651 return -1;
652 }
653
654 if (curl->multi) {
655 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
656 _("Cannot add CURL handle to a multi handle twice"));
657 return -1;
658 }
659
660 if (!multi->handle) {
661 multi->handle = curl_multi_init();
662
663 if (!multi->handle) {
664 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
665 _("Could not initialize CURL (multi)"));
666 return -1;
667 }
668
669 }
670
671 virMutexLock(&curl->lock);
672
673 curl_multi_add_handle(multi->handle, curl->handle);
674
675 curl->multi = multi;
676 ++multi->count;
677
678 virMutexUnlock(&curl->lock);
679
680 return 0;
681 }
682
683 int
esxVI_MultiCURL_Remove(esxVI_MultiCURL * multi,esxVI_CURL * curl)684 esxVI_MultiCURL_Remove(esxVI_MultiCURL *multi, esxVI_CURL *curl)
685 {
686 if (!curl->handle) {
687 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
688 _("Cannot remove uninitialized CURL handle from a "
689 "multi handle"));
690 return -1;
691 }
692
693 if (!curl->multi) {
694 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
695 _("Cannot remove CURL handle from a multi handle when it "
696 "wasn't added before"));
697 return -1;
698 }
699
700 if (curl->multi != multi) {
701 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CURL (multi) mismatch"));
702 return -1;
703 }
704
705 virMutexLock(&curl->lock);
706
707 curl_multi_remove_handle(multi->handle, curl->handle);
708
709 curl->multi = NULL;
710 --multi->count;
711
712 virMutexUnlock(&curl->lock);
713
714 return 0;
715 }
716
717
718 int
esxVI_MultiCURL_Wait(esxVI_MultiCURL * multi,int * runningHandles)719 esxVI_MultiCURL_Wait(esxVI_MultiCURL *multi, int *runningHandles)
720 {
721 long timeout = -1;
722 CURLMcode errorCode;
723
724 curl_multi_timeout(multi->handle, &timeout);
725
726 if (timeout < 0)
727 timeout = 1000; /* default to 1 sec timeout */
728
729 errorCode = curl_multi_wait(multi->handle, NULL, 0, timeout, NULL);
730
731 if (errorCode != CURLM_OK) {
732 virReportError(VIR_ERR_INTERNAL_ERROR,
733 _("Could not wait for transfer: %s (%d)"),
734 curl_multi_strerror(errorCode), errorCode);
735 return -1;
736 }
737
738 return esxVI_MultiCURL_Perform(multi, runningHandles);
739 }
740
741 int
esxVI_MultiCURL_Perform(esxVI_MultiCURL * multi,int * runningHandles)742 esxVI_MultiCURL_Perform(esxVI_MultiCURL *multi, int *runningHandles)
743 {
744 CURLMcode errorCode;
745
746 do {
747 errorCode = curl_multi_perform(multi->handle, runningHandles);
748 } while (errorCode == CURLM_CALL_MULTI_PERFORM);
749
750 if (errorCode != CURLM_OK) {
751 virReportError(VIR_ERR_INTERNAL_ERROR,
752 _("Could not transfer data: %s (%d)"),
753 curl_multi_strerror(errorCode), errorCode);
754 return -1;
755 }
756
757 return 0;
758 }
759
760 /* Returns -1 on error, 0 if there is no DONE message, 1 if there is a DONE message */
761 int
esxVI_MultiCURL_CheckFirstMessage(esxVI_MultiCURL * multi,long * responseCode,CURLcode * errorCode)762 esxVI_MultiCURL_CheckFirstMessage(esxVI_MultiCURL *multi, long *responseCode,
763 CURLcode *errorCode)
764 {
765 int messagesInQueue;
766 CURLMsg* msg = curl_multi_info_read(multi->handle, &messagesInQueue);
767
768 *responseCode = 0;
769
770 if (!msg || msg->msg != CURLMSG_DONE)
771 return 0;
772
773 *errorCode = msg->data.result;
774
775 if (*errorCode != CURLE_OK)
776 return -1;
777
778 curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, responseCode);
779
780 return 1;
781 }
782
783
784
785 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
786 * Context
787 */
788
789 /* esxVI_Context_Alloc */
790 ESX_VI__TEMPLATE__ALLOC(Context)
791
792 /* esxVI_Context_Free */
793 ESX_VI__TEMPLATE__FREE(Context,
794 {
795 if (item->sessionLock)
796 virMutexDestroy(item->sessionLock);
797
798 esxVI_CURL_Free(&item->curl);
799 g_free(item->url);
800 g_free(item->ipAddress);
801 g_free(item->username);
802 g_free(item->password);
803 esxVI_ServiceContent_Free(&item->service);
804 esxVI_UserSession_Free(&item->session);
805 g_free(item->sessionLock);
806 esxVI_Datacenter_Free(&item->datacenter);
807 g_free(item->datacenterPath);
808 esxVI_ComputeResource_Free(&item->computeResource);
809 g_free(item->computeResourcePath);
810 esxVI_HostSystem_Free(&item->hostSystem);
811 g_free(item->hostSystemName);
812 esxVI_SelectionSpec_Free(&item->selectSet_folderToChildEntity);
813 esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToParent);
814 esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToVm);
815 esxVI_SelectionSpec_Free(&item->selectSet_hostSystemToDatastore);
816 esxVI_SelectionSpec_Free(&item->selectSet_computeResourceToHost);
817 esxVI_SelectionSpec_Free(&item->selectSet_computeResourceToParentToParent);
818 esxVI_SelectionSpec_Free(&item->selectSet_datacenterToNetwork);
819 })
820
821 int
esxVI_Context_Connect(esxVI_Context * ctx,const char * url,const char * ipAddress,const char * username,const char * password,esxUtil_ParsedUri * parsedUri)822 esxVI_Context_Connect(esxVI_Context *ctx, const char *url,
823 const char *ipAddress, const char *username,
824 const char *password, esxUtil_ParsedUri *parsedUri)
825 {
826 g_autofree char *escapedPassword = NULL;
827
828 if (!ctx || !url || !ipAddress || !username ||
829 !password || ctx->url || ctx->service || ctx->curl) {
830 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
831 return -1;
832 }
833
834 escapedPassword = esxUtil_EscapeForXml(password);
835
836 if (!escapedPassword) {
837 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
838 _("Failed to escape password for XML"));
839 return -1;
840 }
841
842 if (esxVI_CURL_Alloc(&ctx->curl) < 0 ||
843 esxVI_CURL_Connect(ctx->curl, parsedUri) < 0) {
844 return -1;
845 }
846
847 ctx->url = g_strdup(url);
848 ctx->ipAddress = g_strdup(ipAddress);
849 ctx->username = g_strdup(username);
850 ctx->password = g_strdup(password);
851
852 ctx->sessionLock = g_new0(virMutex, 1);
853
854
855 if (virMutexInit(ctx->sessionLock) < 0) {
856 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
857 _("Could not initialize session mutex"));
858 return -1;
859 }
860
861 if (esxVI_RetrieveServiceContent(ctx, &ctx->service) < 0)
862 return -1;
863
864 if (STRNEQ(ctx->service->about->apiType, "HostAgent") &&
865 STRNEQ(ctx->service->about->apiType, "VirtualCenter")) {
866 virReportError(VIR_ERR_INTERNAL_ERROR,
867 _("Expecting VI API type 'HostAgent' or 'VirtualCenter' "
868 "but found '%s'"), ctx->service->about->apiType);
869 return -1;
870 }
871
872 if (virParseVersionString(ctx->service->about->apiVersion,
873 &ctx->apiVersion, true) < 0) {
874 virReportError(VIR_ERR_INTERNAL_ERROR,
875 _("Could not parse VI API version '%s'"),
876 ctx->service->about->apiVersion);
877 return -1;
878 }
879
880 if (ctx->apiVersion < 1000000 * 2 + 1000 * 5 /* 2.5 */) {
881 virReportError(VIR_ERR_INTERNAL_ERROR,
882 _("Minimum supported %s version is %s but found version '%s'"),
883 "VI API", "2.5", ctx->service->about->apiVersion);
884 return -1;
885 }
886
887 if (virParseVersionString(ctx->service->about->version,
888 &ctx->productVersion, true) < 0) {
889 virReportError(VIR_ERR_INTERNAL_ERROR,
890 _("Could not parse product version '%s'"),
891 ctx->service->about->version);
892 return -1;
893 }
894
895 if (STREQ(ctx->service->about->productLineId, "gsx")) {
896 if (ctx->productVersion < 1000000 * 2 + 1000 * 0 /* 2.0 */) {
897 virReportError(VIR_ERR_INTERNAL_ERROR,
898 _("Minimum supported %s version is %s but found version '%s'"),
899 esxVI_ProductLineToDisplayName(esxVI_ProductLine_GSX),
900 "2.0", ctx->service->about->version);
901 return -1;
902 }
903
904 ctx->productLine = esxVI_ProductLine_GSX;
905 } else if (STREQ(ctx->service->about->productLineId, "esx") ||
906 STREQ(ctx->service->about->productLineId, "embeddedEsx")) {
907 if (ctx->productVersion < 1000000 * 3 + 1000 * 5 /* 3.5 */) {
908 virReportError(VIR_ERR_INTERNAL_ERROR,
909 _("Minimum supported %s version is %s but found version '%s'"),
910 esxVI_ProductLineToDisplayName(esxVI_ProductLine_ESX),
911 "3.5", ctx->service->about->version);
912 return -1;
913 }
914
915 ctx->productLine = esxVI_ProductLine_ESX;
916 } else if (STREQ(ctx->service->about->productLineId, "vpx")) {
917 if (ctx->productVersion < 1000000 * 2 + 1000 * 5 /* 2.5 */) {
918 virReportError(VIR_ERR_INTERNAL_ERROR,
919 _("Minimum supported %s version is %s but found version '%s'"),
920 esxVI_ProductLineToDisplayName(esxVI_ProductLine_VPX),
921 "2.5", ctx->service->about->version);
922 return -1;
923 }
924
925 ctx->productLine = esxVI_ProductLine_VPX;
926 } else {
927 virReportError(VIR_ERR_INTERNAL_ERROR,
928 _("Expecting product 'gsx' or 'esx' or 'embeddedEsx' "
929 "or 'vpx' but found '%s'"),
930 ctx->service->about->productLineId);
931 return -1;
932 }
933
934 if (ctx->productLine == esxVI_ProductLine_ESX) {
935 /*
936 * FIXME: Actually this should be detected by really calling
937 * QueryVirtualDiskUuid and checking if a NotImplemented fault is
938 * returned. But currently we don't deserialized the details of a
939 * possible fault and therefore we don't know if the fault was a
940 * NotImplemented fault or not.
941 */
942 ctx->hasQueryVirtualDiskUuid = true;
943 }
944
945 if (ctx->productLine == esxVI_ProductLine_VPX)
946 ctx->hasSessionIsActive = true;
947
948
949
950 if (esxVI_Login(ctx, username, escapedPassword, NULL, &ctx->session) < 0 ||
951 esxVI_BuildSelectSetCollection(ctx) < 0) {
952 return -1;
953 }
954
955 return 0;
956 }
957
958 int
esxVI_Context_LookupManagedObjects(esxVI_Context * ctx)959 esxVI_Context_LookupManagedObjects(esxVI_Context *ctx)
960 {
961 /* Lookup Datacenter */
962 if (esxVI_LookupDatacenter(ctx, NULL, ctx->service->rootFolder, NULL,
963 &ctx->datacenter,
964 esxVI_Occurrence_RequiredItem) < 0) {
965 return -1;
966 }
967
968 ctx->datacenterPath = g_strdup(ctx->datacenter->name);
969
970 /* Lookup (Cluster)ComputeResource */
971 if (esxVI_LookupComputeResource(ctx, NULL, ctx->datacenter->hostFolder,
972 NULL, &ctx->computeResource,
973 esxVI_Occurrence_RequiredItem) < 0) {
974 return -1;
975 }
976
977 if (!ctx->computeResource->resourcePool) {
978 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
979 _("Could not retrieve resource pool"));
980 return -1;
981 }
982
983 ctx->computeResourcePath = g_strdup(ctx->computeResource->name);
984
985 /* Lookup HostSystem */
986 if (esxVI_LookupHostSystem(ctx, NULL, ctx->computeResource->_reference,
987 NULL, &ctx->hostSystem,
988 esxVI_Occurrence_RequiredItem) < 0) {
989 return -1;
990 }
991
992 ctx->hostSystemName = g_strdup(ctx->hostSystem->name);
993
994 return 0;
995 }
996
997 int
esxVI_Context_LookupManagedObjectsByPath(esxVI_Context * ctx,const char * path)998 esxVI_Context_LookupManagedObjectsByPath(esxVI_Context *ctx, const char *path)
999 {
1000 int result = -1;
1001 g_autofree char *tmp = NULL;
1002 char *saveptr = NULL;
1003 char *previousItem = NULL;
1004 char *item = NULL;
1005 g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
1006 esxVI_ManagedObjectReference *root = NULL;
1007 esxVI_Folder *folder = NULL;
1008
1009 tmp = g_strdup(path);
1010
1011 /* Lookup Datacenter */
1012 item = strtok_r(tmp, "/", &saveptr);
1013
1014 if (!item) {
1015 virReportError(VIR_ERR_INVALID_ARG,
1016 _("Path '%s' does not specify a datacenter"), path);
1017 goto cleanup;
1018 }
1019
1020 root = ctx->service->rootFolder;
1021
1022 while (!ctx->datacenter && item) {
1023 esxVI_Folder_Free(&folder);
1024
1025 /* Try to lookup item as a folder */
1026 if (esxVI_LookupFolder(ctx, item, root, NULL, &folder,
1027 esxVI_Occurrence_OptionalItem) < 0) {
1028 goto cleanup;
1029 }
1030
1031 if (folder) {
1032 /* It's a folder, use it as new lookup root */
1033 if (root != ctx->service->rootFolder)
1034 esxVI_ManagedObjectReference_Free(&root);
1035
1036 root = folder->_reference;
1037 folder->_reference = NULL;
1038 } else {
1039 /* Try to lookup item as a datacenter */
1040 if (esxVI_LookupDatacenter(ctx, item, root, NULL, &ctx->datacenter,
1041 esxVI_Occurrence_OptionalItem) < 0) {
1042 goto cleanup;
1043 }
1044 }
1045
1046 /* Build datacenter path */
1047 if (virBufferUse(&buffer) > 0)
1048 virBufferAddChar(&buffer, '/');
1049
1050 virBufferAdd(&buffer, item, -1);
1051
1052 previousItem = item;
1053 item = strtok_r(NULL, "/", &saveptr);
1054 }
1055
1056 if (!ctx->datacenter) {
1057 virReportError(VIR_ERR_INTERNAL_ERROR,
1058 _("Could not find datacenter specified in '%s'"), path);
1059 goto cleanup;
1060 }
1061
1062 ctx->datacenterPath = virBufferContentAndReset(&buffer);
1063
1064 /* Lookup (Cluster)ComputeResource */
1065 if (!item) {
1066 virReportError(VIR_ERR_INVALID_ARG,
1067 _("Path '%s' does not specify a compute resource"), path);
1068 goto cleanup;
1069 }
1070
1071 if (root != ctx->service->rootFolder)
1072 esxVI_ManagedObjectReference_Free(&root);
1073
1074 root = ctx->datacenter->hostFolder;
1075
1076 while (!ctx->computeResource && item) {
1077 esxVI_Folder_Free(&folder);
1078
1079 /* Try to lookup item as a folder */
1080 if (esxVI_LookupFolder(ctx, item, root, NULL, &folder,
1081 esxVI_Occurrence_OptionalItem) < 0) {
1082 goto cleanup;
1083 }
1084
1085 if (folder) {
1086 /* It's a folder, use it as new lookup root */
1087 if (root != ctx->datacenter->hostFolder)
1088 esxVI_ManagedObjectReference_Free(&root);
1089
1090 root = folder->_reference;
1091 folder->_reference = NULL;
1092 } else {
1093 /* Try to lookup item as a compute resource */
1094 if (esxVI_LookupComputeResource(ctx, item, root, NULL,
1095 &ctx->computeResource,
1096 esxVI_Occurrence_OptionalItem) < 0) {
1097 goto cleanup;
1098 }
1099 }
1100
1101 /* Build compute resource path */
1102 if (virBufferUse(&buffer) > 0)
1103 virBufferAddChar(&buffer, '/');
1104
1105 virBufferAdd(&buffer, item, -1);
1106
1107 previousItem = item;
1108 item = strtok_r(NULL, "/", &saveptr);
1109 }
1110
1111 if (!ctx->computeResource) {
1112 virReportError(VIR_ERR_INTERNAL_ERROR,
1113 _("Could not find compute resource specified in '%s'"),
1114 path);
1115 goto cleanup;
1116 }
1117
1118 if (!ctx->computeResource->resourcePool) {
1119 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1120 _("Could not retrieve resource pool"));
1121 goto cleanup;
1122 }
1123
1124 ctx->computeResourcePath = virBufferContentAndReset(&buffer);
1125
1126 /* Lookup HostSystem */
1127 if (STREQ(ctx->computeResource->_reference->type,
1128 "ClusterComputeResource")) {
1129 if (!item) {
1130 virReportError(VIR_ERR_INVALID_ARG,
1131 _("Path '%s' does not specify a host system"), path);
1132 goto cleanup;
1133 }
1134
1135 /* The path specified a cluster, it has to specify a host system too */
1136 previousItem = item;
1137 item = strtok_r(NULL, "/", &saveptr);
1138 }
1139
1140 if (item) {
1141 virReportError(VIR_ERR_INVALID_ARG,
1142 _("Path '%s' ends with an excess item"), path);
1143 goto cleanup;
1144 }
1145
1146 ctx->hostSystemName = g_strdup(previousItem);
1147
1148 if (esxVI_LookupHostSystem(ctx, ctx->hostSystemName,
1149 ctx->computeResource->_reference, NULL,
1150 &ctx->hostSystem,
1151 esxVI_Occurrence_OptionalItem) < 0) {
1152 goto cleanup;
1153 }
1154
1155 if (!ctx->hostSystem) {
1156 virReportError(VIR_ERR_INTERNAL_ERROR,
1157 _("Could not find host system specified in '%s'"), path);
1158 goto cleanup;
1159 }
1160
1161 result = 0;
1162
1163 cleanup:
1164 if (root != ctx->service->rootFolder &&
1165 (!ctx->datacenter || root != ctx->datacenter->hostFolder)) {
1166 esxVI_ManagedObjectReference_Free(&root);
1167 }
1168
1169 esxVI_Folder_Free(&folder);
1170
1171 return result;
1172 }
1173
1174 int
esxVI_Context_LookupManagedObjectsByHostSystemIp(esxVI_Context * ctx,const char * hostSystemIPAddress)1175 esxVI_Context_LookupManagedObjectsByHostSystemIp(esxVI_Context *ctx,
1176 const char *hostSystemIPAddress)
1177 {
1178 int result = -1;
1179 esxVI_ManagedObjectReference *managedObjectReference = NULL;
1180
1181 /* Lookup HostSystem */
1182 if (esxVI_FindByIp(ctx, NULL, hostSystemIPAddress, esxVI_Boolean_False,
1183 &managedObjectReference) < 0 ||
1184 esxVI_LookupHostSystem(ctx, NULL, managedObjectReference, NULL,
1185 &ctx->hostSystem,
1186 esxVI_Occurrence_RequiredItem) < 0) {
1187 goto cleanup;
1188 }
1189
1190 /* Lookup (Cluster)ComputeResource */
1191 if (esxVI_LookupComputeResource(ctx, NULL, ctx->hostSystem->_reference,
1192 NULL, &ctx->computeResource,
1193 esxVI_Occurrence_RequiredItem) < 0) {
1194 goto cleanup;
1195 }
1196
1197 if (!ctx->computeResource->resourcePool) {
1198 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1199 _("Could not retrieve resource pool"));
1200 goto cleanup;
1201 }
1202
1203 /* Lookup Datacenter */
1204 if (esxVI_LookupDatacenter(ctx, NULL, ctx->computeResource->_reference,
1205 NULL, &ctx->datacenter,
1206 esxVI_Occurrence_RequiredItem) < 0) {
1207 goto cleanup;
1208 }
1209
1210 result = 0;
1211
1212 cleanup:
1213 esxVI_ManagedObjectReference_Free(&managedObjectReference);
1214
1215 return result;
1216 }
1217
1218 int
esxVI_Context_Execute(esxVI_Context * ctx,const char * methodName,const char * request,esxVI_Response ** response,esxVI_Occurrence occurrence)1219 esxVI_Context_Execute(esxVI_Context *ctx, const char *methodName,
1220 const char *request, esxVI_Response **response,
1221 esxVI_Occurrence occurrence)
1222 {
1223 int result = -1;
1224 g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
1225 esxVI_Fault *fault = NULL;
1226 g_autofree char *xpathExpression = NULL;
1227 g_autoptr(xmlXPathContext) xpathContext = NULL;
1228 xmlNodePtr responseNode = NULL;
1229
1230 if (!request || !response || *response) {
1231 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1232 return -1;
1233 }
1234
1235 if (esxVI_Response_Alloc(response) < 0)
1236 return -1;
1237
1238 virMutexLock(&ctx->curl->lock);
1239
1240 curl_easy_setopt(ctx->curl->handle, CURLOPT_URL, ctx->url);
1241 curl_easy_setopt(ctx->curl->handle, CURLOPT_RANGE, NULL);
1242 curl_easy_setopt(ctx->curl->handle, CURLOPT_WRITEDATA, &buffer);
1243 curl_easy_setopt(ctx->curl->handle, CURLOPT_UPLOAD, 0);
1244 curl_easy_setopt(ctx->curl->handle, CURLOPT_POSTFIELDS, request);
1245 curl_easy_setopt(ctx->curl->handle, CURLOPT_POSTFIELDSIZE, strlen(request));
1246
1247 (*response)->responseCode = esxVI_CURL_Perform(ctx->curl, ctx->url);
1248
1249 virMutexUnlock(&ctx->curl->lock);
1250
1251 if ((*response)->responseCode < 0)
1252 goto cleanup;
1253
1254 (*response)->content = virBufferContentAndReset(&buffer);
1255
1256 if ((*response)->responseCode == 500 || (*response)->responseCode == 200) {
1257 (*response)->document = virXMLParseStringCtxt((*response)->content,
1258 _("(esx execute response)"),
1259 &xpathContext);
1260
1261 if (!(*response)->document)
1262 goto cleanup;
1263
1264 xmlXPathRegisterNs(xpathContext, BAD_CAST "soapenv",
1265 BAD_CAST "http://schemas.xmlsoap.org/soap/envelope/");
1266 xmlXPathRegisterNs(xpathContext, BAD_CAST "vim", BAD_CAST "urn:vim25");
1267
1268 if ((*response)->responseCode == 500) {
1269 (*response)->node =
1270 virXPathNode("/soapenv:Envelope/soapenv:Body/soapenv:Fault",
1271 xpathContext);
1272
1273 if (!(*response)->node) {
1274 virReportError(VIR_ERR_INTERNAL_ERROR,
1275 _("HTTP response code %d for call to '%s'. "
1276 "Fault is unknown, XPath evaluation failed"),
1277 (*response)->responseCode, methodName);
1278 goto cleanup;
1279 }
1280
1281 if (esxVI_Fault_Deserialize((*response)->node, &fault) < 0) {
1282 virReportError(VIR_ERR_INTERNAL_ERROR,
1283 _("HTTP response code %d for call to '%s'. "
1284 "Fault is unknown, deserialization failed"),
1285 (*response)->responseCode, methodName);
1286 goto cleanup;
1287 }
1288
1289 virReportError(VIR_ERR_INTERNAL_ERROR,
1290 _("HTTP response code %d for call to '%s'. "
1291 "Fault: %s - %s"), (*response)->responseCode,
1292 methodName, fault->faultcode, fault->faultstring);
1293
1294 /* FIXME: Dump raw response until detail part gets deserialized */
1295 VIR_DEBUG("HTTP response code %d for call to '%s' [[[[%s]]]]",
1296 (*response)->responseCode, methodName,
1297 (*response)->content);
1298
1299 goto cleanup;
1300 } else {
1301 xpathExpression = g_strdup_printf("/soapenv:Envelope/soapenv:Body/vim:%sResponse",
1302 methodName);
1303
1304 responseNode = virXPathNode(xpathExpression, xpathContext);
1305
1306 if (!responseNode) {
1307 virReportError(VIR_ERR_INTERNAL_ERROR,
1308 _("XPath evaluation of response for call to '%s' "
1309 "failed"), methodName);
1310 goto cleanup;
1311 }
1312
1313 xpathContext->node = responseNode;
1314 (*response)->node = virXPathNode("./vim:returnval", xpathContext);
1315
1316 switch (occurrence) {
1317 case esxVI_Occurrence_RequiredItem:
1318 if (!(*response)->node) {
1319 virReportError(VIR_ERR_INTERNAL_ERROR,
1320 _("Call to '%s' returned an empty result, "
1321 "expecting a non-empty result"), methodName);
1322 goto cleanup;
1323 } else if ((*response)->node->next) {
1324 virReportError(VIR_ERR_INTERNAL_ERROR,
1325 _("Call to '%s' returned a list, expecting "
1326 "exactly one item"), methodName);
1327 goto cleanup;
1328 }
1329
1330 break;
1331
1332 case esxVI_Occurrence_RequiredList:
1333 if (!(*response)->node) {
1334 virReportError(VIR_ERR_INTERNAL_ERROR,
1335 _("Call to '%s' returned an empty result, "
1336 "expecting a non-empty result"), methodName);
1337 goto cleanup;
1338 }
1339
1340 break;
1341
1342 case esxVI_Occurrence_OptionalItem:
1343 if ((*response)->node &&
1344 (*response)->node->next) {
1345 virReportError(VIR_ERR_INTERNAL_ERROR,
1346 _("Call to '%s' returned a list, expecting "
1347 "exactly one item"), methodName);
1348 goto cleanup;
1349 }
1350
1351 break;
1352
1353 case esxVI_Occurrence_OptionalList:
1354 /* Any amount of items is valid */
1355 break;
1356
1357 case esxVI_Occurrence_None:
1358 if ((*response)->node) {
1359 virReportError(VIR_ERR_INTERNAL_ERROR,
1360 _("Call to '%s' returned something, expecting "
1361 "an empty result"), methodName);
1362 goto cleanup;
1363 }
1364
1365 break;
1366
1367 case esxVI_Occurrence_Undefined:
1368 default:
1369 virReportEnumRangeError(esxVI_Occurrence, occurrence);
1370 goto cleanup;
1371 }
1372 }
1373 } else {
1374 virReportError(VIR_ERR_HTTP_ERROR,
1375 _("HTTP response code %d for call to '%s'"),
1376 (*response)->responseCode, methodName);
1377 goto cleanup;
1378 }
1379
1380 result = 0;
1381
1382 cleanup:
1383 if (result < 0) {
1384 esxVI_Response_Free(response);
1385 esxVI_Fault_Free(&fault);
1386 }
1387
1388 return result;
1389 }
1390
1391
1392
1393 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1394 * Response
1395 */
1396
1397 /* esxVI_Response_Alloc */
1398 ESX_VI__TEMPLATE__ALLOC(Response)
1399
1400 /* esxVI_Response_Free */
1401 ESX_VI__TEMPLATE__FREE(Response,
1402 {
1403 g_free(item->content);
1404
1405 xmlFreeDoc(item->document);
1406 })
1407
1408
1409
1410 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1411 * Enumeration
1412 */
1413
1414 int
esxVI_Enumeration_CastFromAnyType(const esxVI_Enumeration * enumeration,esxVI_AnyType * anyType,int * value)1415 esxVI_Enumeration_CastFromAnyType(const esxVI_Enumeration *enumeration,
1416 esxVI_AnyType *anyType, int *value)
1417 {
1418 size_t i;
1419
1420 if (!anyType || !value) {
1421 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1422 return -1;
1423 }
1424
1425 *value = 0; /* undefined */
1426
1427 if (anyType->type != enumeration->type) {
1428 virReportError(VIR_ERR_INTERNAL_ERROR,
1429 _("Expecting type '%s' but found '%s'"),
1430 esxVI_Type_ToString(enumeration->type),
1431 esxVI_AnyType_TypeToString(anyType));
1432 return -1;
1433 }
1434
1435 for (i = 0; enumeration->values[i].name; ++i) {
1436 if (STREQ(anyType->value, enumeration->values[i].name)) {
1437 *value = enumeration->values[i].value;
1438 return 0;
1439 }
1440 }
1441
1442 virReportError(VIR_ERR_INTERNAL_ERROR,
1443 _("Unknown value '%s' for %s"), anyType->value,
1444 esxVI_Type_ToString(enumeration->type));
1445
1446 return -1;
1447 }
1448
1449 int
esxVI_Enumeration_Serialize(const esxVI_Enumeration * enumeration,int value,const char * element,virBuffer * output)1450 esxVI_Enumeration_Serialize(const esxVI_Enumeration *enumeration,
1451 int value, const char *element, virBuffer *output)
1452 {
1453 size_t i;
1454 const char *name = NULL;
1455
1456 if (!element || !output) {
1457 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1458 return -1;
1459 }
1460
1461 if (value == 0) { /* undefined */
1462 return 0;
1463 }
1464
1465 for (i = 0; enumeration->values[i].name; ++i) {
1466 if (value == enumeration->values[i].value) {
1467 name = enumeration->values[i].name;
1468 break;
1469 }
1470 }
1471
1472 if (!name) {
1473 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1474 return -1;
1475 }
1476
1477 ESV_VI__XML_TAG__OPEN(output, element,
1478 esxVI_Type_ToString(enumeration->type));
1479
1480 virBufferAdd(output, name, -1);
1481
1482 ESV_VI__XML_TAG__CLOSE(output, element);
1483
1484 return 0;
1485 }
1486
1487 int
esxVI_Enumeration_Deserialize(const esxVI_Enumeration * enumeration,xmlNodePtr node,int * value)1488 esxVI_Enumeration_Deserialize(const esxVI_Enumeration *enumeration,
1489 xmlNodePtr node, int *value)
1490 {
1491 size_t i;
1492 int result = -1;
1493 g_autofree char *name = NULL;
1494
1495 if (!value) {
1496 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1497 return -1;
1498 }
1499
1500 *value = 0; /* undefined */
1501
1502 if (esxVI_String_DeserializeValue(node, &name) < 0)
1503 return -1;
1504
1505 for (i = 0; enumeration->values[i].name; ++i) {
1506 if (STREQ(name, enumeration->values[i].name)) {
1507 *value = enumeration->values[i].value;
1508 result = 0;
1509 break;
1510 }
1511 }
1512
1513 if (result < 0) {
1514 virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown value '%s' for %s"),
1515 name, esxVI_Type_ToString(enumeration->type));
1516 }
1517
1518 return result;
1519 }
1520
1521
1522
1523 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1524 * List
1525 */
1526
1527 int
esxVI_List_Append(esxVI_List ** list,esxVI_List * item)1528 esxVI_List_Append(esxVI_List **list, esxVI_List *item)
1529 {
1530 esxVI_List *next = NULL;
1531
1532 if (!list || !item) {
1533 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1534 return -1;
1535 }
1536
1537 if (!(*list)) {
1538 *list = item;
1539 return 0;
1540 }
1541
1542 next = *list;
1543
1544 while (next->_next)
1545 next = next->_next;
1546
1547 next->_next = item;
1548
1549 return 0;
1550 }
1551
1552 int
esxVI_List_DeepCopy(esxVI_List ** destList,esxVI_List * srcList,esxVI_List_DeepCopyFunc deepCopyFunc,esxVI_List_FreeFunc freeFunc)1553 esxVI_List_DeepCopy(esxVI_List **destList, esxVI_List *srcList,
1554 esxVI_List_DeepCopyFunc deepCopyFunc,
1555 esxVI_List_FreeFunc freeFunc)
1556 {
1557 esxVI_List *dest = NULL;
1558 esxVI_List *src = NULL;
1559
1560 ESX_VI_CHECK_ARG_LIST(destList);
1561
1562 for (src = srcList; src; src = src->_next) {
1563 if (deepCopyFunc(&dest, src) < 0 ||
1564 esxVI_List_Append(destList, dest) < 0) {
1565 goto failure;
1566 }
1567
1568 dest = NULL;
1569 }
1570
1571 return 0;
1572
1573 failure:
1574 freeFunc(&dest);
1575 freeFunc(destList);
1576
1577 return -1;
1578 }
1579
1580 int
esxVI_List_CastFromAnyType(esxVI_AnyType * anyType,esxVI_List ** list,esxVI_List_CastFromAnyTypeFunc castFromAnyTypeFunc,esxVI_List_FreeFunc freeFunc)1581 esxVI_List_CastFromAnyType(esxVI_AnyType *anyType, esxVI_List **list,
1582 esxVI_List_CastFromAnyTypeFunc castFromAnyTypeFunc,
1583 esxVI_List_FreeFunc freeFunc)
1584 {
1585 int result = -1;
1586 xmlNodePtr childNode = NULL;
1587 esxVI_AnyType *childAnyType = NULL;
1588 esxVI_List *item = NULL;
1589
1590 if (!list || *list || !castFromAnyTypeFunc || !freeFunc) {
1591 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1592 return -1;
1593 }
1594
1595 if (!anyType)
1596 return 0;
1597
1598 if (! STRPREFIX(anyType->other, "ArrayOf")) {
1599 virReportError(VIR_ERR_INTERNAL_ERROR,
1600 _("Expecting type to begin with 'ArrayOf' but found '%s'"),
1601 anyType->other);
1602 return -1;
1603 }
1604
1605 for (childNode = anyType->node->children; childNode;
1606 childNode = childNode->next) {
1607 if (childNode->type != XML_ELEMENT_NODE) {
1608 virReportError(VIR_ERR_INTERNAL_ERROR,
1609 _("Wrong XML element type %d"), childNode->type);
1610 goto cleanup;
1611 }
1612
1613 esxVI_AnyType_Free(&childAnyType);
1614
1615 if (esxVI_AnyType_Deserialize(childNode, &childAnyType) < 0 ||
1616 castFromAnyTypeFunc(childAnyType, &item) < 0 ||
1617 esxVI_List_Append(list, item) < 0) {
1618 goto cleanup;
1619 }
1620
1621 item = NULL;
1622 }
1623
1624 result = 0;
1625
1626 cleanup:
1627 if (result < 0) {
1628 freeFunc(&item);
1629 freeFunc(list);
1630 }
1631
1632 esxVI_AnyType_Free(&childAnyType);
1633
1634 return result;
1635 }
1636
1637 int
esxVI_List_Serialize(esxVI_List * list,const char * element,virBuffer * output,esxVI_List_SerializeFunc serializeFunc)1638 esxVI_List_Serialize(esxVI_List *list, const char *element,
1639 virBuffer *output,
1640 esxVI_List_SerializeFunc serializeFunc)
1641 {
1642 esxVI_List *item = NULL;
1643
1644 if (!element || !output || !serializeFunc) {
1645 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1646 return -1;
1647 }
1648
1649 if (!list)
1650 return 0;
1651
1652 for (item = list; item; item = item->_next) {
1653 if (serializeFunc(item, element, output) < 0)
1654 return -1;
1655 }
1656
1657 return 0;
1658 }
1659
1660 int
esxVI_List_Deserialize(xmlNodePtr node,esxVI_List ** list,esxVI_List_DeserializeFunc deserializeFunc,esxVI_List_FreeFunc freeFunc)1661 esxVI_List_Deserialize(xmlNodePtr node, esxVI_List **list,
1662 esxVI_List_DeserializeFunc deserializeFunc,
1663 esxVI_List_FreeFunc freeFunc)
1664 {
1665 esxVI_List *item = NULL;
1666
1667 if (!list || *list || !deserializeFunc || !freeFunc) {
1668 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1669 return -1;
1670 }
1671
1672 if (!node)
1673 return 0;
1674
1675 for (; node; node = node->next) {
1676 if (node->type != XML_ELEMENT_NODE) {
1677 virReportError(VIR_ERR_INTERNAL_ERROR,
1678 _("Wrong XML element type %d"), node->type);
1679 goto failure;
1680 }
1681
1682 if (deserializeFunc(node, &item) < 0 ||
1683 esxVI_List_Append(list, item) < 0) {
1684 goto failure;
1685 }
1686
1687 item = NULL;
1688 }
1689
1690 return 0;
1691
1692 failure:
1693 freeFunc(&item);
1694 freeFunc(list);
1695
1696 return -1;
1697 }
1698
1699
1700
1701 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1702 * Utility and Convenience Functions
1703 *
1704 * Function naming scheme:
1705 * - 'lookup' functions query the ESX or vCenter for information
1706 * - 'get' functions get information from a local object
1707 */
1708
1709 int
esxVI_BuildSelectSet(esxVI_SelectionSpec ** selectSet,const char * name,const char * type,const char * path,const char * selectSetNames)1710 esxVI_BuildSelectSet(esxVI_SelectionSpec **selectSet,
1711 const char *name, const char *type,
1712 const char *path, const char *selectSetNames)
1713 {
1714 esxVI_TraversalSpec *traversalSpec = NULL;
1715 esxVI_SelectionSpec *selectionSpec = NULL;
1716 const char *currentSelectSetName = NULL;
1717
1718 if (!selectSet) {
1719 /*
1720 * Don't check for *selectSet != NULL here because selectSet is a list
1721 * and might contain items already. This function appends to selectSet.
1722 */
1723 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1724 return -1;
1725 }
1726
1727 if (esxVI_TraversalSpec_Alloc(&traversalSpec) < 0)
1728 goto failure;
1729
1730 traversalSpec->name = g_strdup(name);
1731 traversalSpec->type = g_strdup(type);
1732 traversalSpec->path = g_strdup(path);
1733 traversalSpec->skip = esxVI_Boolean_False;
1734
1735 if (selectSetNames) {
1736 currentSelectSetName = selectSetNames;
1737
1738 while (currentSelectSetName && *currentSelectSetName != '\0') {
1739 if (esxVI_SelectionSpec_Alloc(&selectionSpec) < 0)
1740 goto failure;
1741
1742 selectionSpec->name = g_strdup(currentSelectSetName);
1743
1744 if (esxVI_SelectionSpec_AppendToList(&traversalSpec->selectSet,
1745 selectionSpec) < 0)
1746 goto failure;
1747
1748 selectionSpec = NULL;
1749 currentSelectSetName += strlen(currentSelectSetName) + 1;
1750 }
1751 }
1752
1753 if (esxVI_SelectionSpec_AppendToList(selectSet,
1754 esxVI_SelectionSpec_DynamicCast
1755 (traversalSpec)) < 0) {
1756 goto failure;
1757 }
1758
1759 return 0;
1760
1761 failure:
1762 esxVI_TraversalSpec_Free(&traversalSpec);
1763 esxVI_SelectionSpec_Free(&selectionSpec);
1764
1765 return -1;
1766 }
1767
1768
1769
1770 int
esxVI_BuildSelectSetCollection(esxVI_Context * ctx)1771 esxVI_BuildSelectSetCollection(esxVI_Context *ctx)
1772 {
1773 /* Folder -> childEntity (ManagedEntity) */
1774 if (esxVI_BuildSelectSet(&ctx->selectSet_folderToChildEntity,
1775 "folderToChildEntity",
1776 "Folder", "childEntity", NULL) < 0) {
1777 return -1;
1778 }
1779
1780 /* ComputeResource -> host (HostSystem) */
1781 if (esxVI_BuildSelectSet(&ctx->selectSet_computeResourceToHost,
1782 "computeResourceToHost",
1783 "ComputeResource", "host", NULL) < 0) {
1784 return -1;
1785 }
1786
1787 /* ComputeResource -> datastore (Datastore) *//*
1788 if (esxVI_BuildSelectSet(&ctx->selectSet_computeResourceToDatastore,
1789 "computeResourceToDatastore",
1790 "ComputeResource", "datastore", NULL) < 0) {
1791 return -1;
1792 }*/
1793
1794 /* ResourcePool -> resourcePool (ResourcePool) *//*
1795 if (esxVI_BuildSelectSet(&ctx->selectSet_resourcePoolToVm,
1796 "resourcePoolToResourcePool",
1797 "ResourcePool", "resourcePool",
1798 "resourcePoolToResourcePool\0"
1799 "resourcePoolToVm\0") < 0) {
1800 return -1;
1801 }*/
1802
1803 /* ResourcePool -> vm (VirtualMachine) *//*
1804 if (esxVI_BuildSelectSet(&ctx->selectSet_resourcePoolToVm,
1805 "resourcePoolToVm",
1806 "ResourcePool", "vm", NULL) < 0) {
1807 return -1;
1808 }*/
1809
1810 /* HostSystem -> parent (ComputeResource) */
1811 if (esxVI_BuildSelectSet(&ctx->selectSet_hostSystemToParent,
1812 "hostSystemToParent",
1813 "HostSystem", "parent", NULL) < 0) {
1814 return -1;
1815 }
1816
1817 /* HostSystem -> vm (VirtualMachine) */
1818 if (esxVI_BuildSelectSet(&ctx->selectSet_hostSystemToVm,
1819 "hostSystemToVm",
1820 "HostSystem", "vm", NULL) < 0) {
1821 return -1;
1822 }
1823
1824 /* HostSystem -> datastore (Datastore) */
1825 if (esxVI_BuildSelectSet(&ctx->selectSet_hostSystemToDatastore,
1826 "hostSystemToDatastore",
1827 "HostSystem", "datastore", NULL) < 0) {
1828 return -1;
1829 }
1830
1831 /* Folder -> parent (Folder, Datacenter) */
1832 if (esxVI_BuildSelectSet(&ctx->selectSet_computeResourceToParentToParent,
1833 "managedEntityToParent",
1834 "ManagedEntity", "parent", NULL) < 0) {
1835 return -1;
1836 }
1837
1838 /* ComputeResource -> parent (Folder) */
1839 if (esxVI_BuildSelectSet(&ctx->selectSet_computeResourceToParentToParent,
1840 "computeResourceToParent",
1841 "ComputeResource", "parent",
1842 "managedEntityToParent\0") < 0) {
1843 return -1;
1844 }
1845
1846 /* Datacenter -> network (Network) */
1847 if (esxVI_BuildSelectSet(&ctx->selectSet_datacenterToNetwork,
1848 "datacenterToNetwork",
1849 "Datacenter", "network", NULL) < 0) {
1850 return -1;
1851 }
1852
1853 return 0;
1854 }
1855
1856
1857
1858 /*
1859 * Cannot use the SessionIsActive() function here, because at least
1860 * ESX Server 3.5.0 build-64607 and ESX 4.0.0 build-171294 return an
1861 * method-not-implemented fault when calling it. The vCenter Server
1862 * implements this method, but because it can be used to check any
1863 * session it requires the Sessions.ValidateSession privilege that is
1864 * considered as an admin privilege.
1865 *
1866 * Instead query the session manager for the current session of this
1867 * connection and re-login if there is no current session.
1868 */
1869 int
esxVI_EnsureSession(esxVI_Context * ctx)1870 esxVI_EnsureSession(esxVI_Context *ctx)
1871 {
1872 int result = -1;
1873 esxVI_String *propertyNameList = NULL;
1874 esxVI_ObjectContent *sessionManager = NULL;
1875 esxVI_DynamicProperty *dynamicProperty = NULL;
1876 esxVI_UserSession *currentSession = NULL;
1877 g_autofree char *escapedPassword = NULL;
1878
1879 if (!ctx->sessionLock) {
1880 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid call, no mutex"));
1881 return -1;
1882 }
1883
1884 virMutexLock(ctx->sessionLock);
1885
1886 if (!ctx->session) {
1887 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid call, no session"));
1888 goto cleanup;
1889 }
1890
1891 escapedPassword = esxUtil_EscapeForXml(ctx->password);
1892
1893 if (!escapedPassword) {
1894 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1895 _("Failed to escape password for XML"));
1896 goto cleanup;
1897 }
1898
1899 if (esxVI_String_AppendValueToList(&propertyNameList,
1900 "currentSession") < 0 ||
1901 esxVI_LookupObjectContentByType(ctx, ctx->service->sessionManager,
1902 "SessionManager", propertyNameList,
1903 &sessionManager,
1904 esxVI_Occurrence_RequiredItem) < 0) {
1905 goto cleanup;
1906 }
1907
1908 for (dynamicProperty = sessionManager->propSet; dynamicProperty;
1909 dynamicProperty = dynamicProperty->_next) {
1910 if (STREQ(dynamicProperty->name, "currentSession")) {
1911 if (esxVI_UserSession_CastFromAnyType(dynamicProperty->val,
1912 ¤tSession) < 0) {
1913 goto cleanup;
1914 }
1915
1916 break;
1917 } else {
1918 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
1919 }
1920 }
1921
1922 if (!currentSession) {
1923 esxVI_UserSession_Free(&ctx->session);
1924
1925 if (esxVI_Login(ctx, ctx->username, escapedPassword, NULL,
1926 &ctx->session) < 0) {
1927 goto cleanup;
1928 }
1929 } else if (STRNEQ(ctx->session->key, currentSession->key)) {
1930 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1931 _("Key of the current session differs from the key at "
1932 "last login"));
1933 goto cleanup;
1934 }
1935
1936 result = 0;
1937
1938 cleanup:
1939 virMutexUnlock(ctx->sessionLock);
1940
1941 esxVI_String_Free(&propertyNameList);
1942 esxVI_ObjectContent_Free(&sessionManager);
1943 esxVI_UserSession_Free(¤tSession);
1944
1945 return result;
1946 }
1947
1948
1949
1950 int
esxVI_LookupObjectContentByType(esxVI_Context * ctx,esxVI_ManagedObjectReference * root,const char * type,esxVI_String * propertyNameList,esxVI_ObjectContent ** objectContentList,esxVI_Occurrence occurrence)1951 esxVI_LookupObjectContentByType(esxVI_Context *ctx,
1952 esxVI_ManagedObjectReference *root,
1953 const char *type,
1954 esxVI_String *propertyNameList,
1955 esxVI_ObjectContent **objectContentList,
1956 esxVI_Occurrence occurrence)
1957 {
1958 int result = -1;
1959 esxVI_ObjectSpec *objectSpec = NULL;
1960 bool objectSpec_isAppended = false;
1961 esxVI_PropertySpec *propertySpec = NULL;
1962 bool propertySpec_isAppended = false;
1963 esxVI_PropertyFilterSpec *propertyFilterSpec = NULL;
1964
1965 ESX_VI_CHECK_ARG_LIST(objectContentList);
1966
1967 if (esxVI_ObjectSpec_Alloc(&objectSpec) < 0)
1968 return -1;
1969
1970 objectSpec->obj = root;
1971 objectSpec->skip = esxVI_Boolean_False;
1972
1973 if (STRNEQ(root->type, type) || STREQ(root->type, "Folder")) {
1974 if (STREQ(root->type, "Folder")) {
1975 if (STREQ(type, "Folder") || STREQ(type, "Datacenter") ||
1976 STREQ(type, "ComputeResource") ||
1977 STREQ(type, "ClusterComputeResource")) {
1978 objectSpec->selectSet = ctx->selectSet_folderToChildEntity;
1979 } else {
1980 virReportError(VIR_ERR_INTERNAL_ERROR,
1981 _("Invalid lookup of '%s' from '%s'"),
1982 type, root->type);
1983 goto cleanup;
1984 }
1985 } else if (STREQ(root->type, "ComputeResource") ||
1986 STREQ(root->type, "ClusterComputeResource")) {
1987 if (STREQ(type, "HostSystem")) {
1988 objectSpec->selectSet = ctx->selectSet_computeResourceToHost;
1989 } else if (STREQ(type, "Datacenter")) {
1990 objectSpec->selectSet = ctx->selectSet_computeResourceToParentToParent;
1991 } else {
1992 virReportError(VIR_ERR_INTERNAL_ERROR,
1993 _("Invalid lookup of '%s' from '%s'"),
1994 type, root->type);
1995 goto cleanup;
1996 }
1997 } else if (STREQ(root->type, "HostSystem")) {
1998 if (STREQ(type, "ComputeResource") ||
1999 STREQ(type, "ClusterComputeResource")) {
2000 objectSpec->selectSet = ctx->selectSet_hostSystemToParent;
2001 } else if (STREQ(type, "VirtualMachine")) {
2002 objectSpec->selectSet = ctx->selectSet_hostSystemToVm;
2003 } else if (STREQ(type, "Datastore")) {
2004 objectSpec->selectSet = ctx->selectSet_hostSystemToDatastore;
2005 } else {
2006 virReportError(VIR_ERR_INTERNAL_ERROR,
2007 _("Invalid lookup of '%s' from '%s'"),
2008 type, root->type);
2009 goto cleanup;
2010 }
2011 } else if (STREQ(root->type, "Datacenter")) {
2012 if (STREQ(type, "Network")) {
2013 objectSpec->selectSet = ctx->selectSet_datacenterToNetwork;
2014 } else {
2015 virReportError(VIR_ERR_INTERNAL_ERROR,
2016 _("Invalid lookup of '%s' from '%s'"),
2017 type, root->type);
2018 goto cleanup;
2019 }
2020 } else {
2021 virReportError(VIR_ERR_INTERNAL_ERROR,
2022 _("Invalid lookup from '%s'"), root->type);
2023 goto cleanup;
2024 }
2025 }
2026
2027 if (esxVI_PropertySpec_Alloc(&propertySpec) < 0)
2028 goto cleanup;
2029
2030 propertySpec->type = (char *)type;
2031 propertySpec->pathSet = propertyNameList;
2032
2033 if (esxVI_PropertyFilterSpec_Alloc(&propertyFilterSpec) < 0 ||
2034 esxVI_PropertySpec_AppendToList(&propertyFilterSpec->propSet,
2035 propertySpec) < 0) {
2036 goto cleanup;
2037 }
2038
2039 propertySpec_isAppended = true;
2040
2041 if (esxVI_ObjectSpec_AppendToList(&propertyFilterSpec->objectSet,
2042 objectSpec) < 0) {
2043 goto cleanup;
2044 }
2045
2046 objectSpec_isAppended = true;
2047
2048 if (esxVI_RetrieveProperties(ctx, propertyFilterSpec,
2049 objectContentList) < 0) {
2050 goto cleanup;
2051 }
2052
2053 if (!(*objectContentList)) {
2054 switch (occurrence) {
2055 case esxVI_Occurrence_OptionalItem:
2056 case esxVI_Occurrence_OptionalList:
2057 result = 0;
2058 break;
2059
2060 case esxVI_Occurrence_RequiredItem:
2061 virReportError(VIR_ERR_INTERNAL_ERROR,
2062 _("Could not lookup '%s' from '%s'"),
2063 type, root->type);
2064 break;
2065
2066 case esxVI_Occurrence_RequiredList:
2067 virReportError(VIR_ERR_INTERNAL_ERROR,
2068 _("Could not lookup '%s' list from '%s'"),
2069 type, root->type);
2070 break;
2071
2072 case esxVI_Occurrence_None:
2073 case esxVI_Occurrence_Undefined:
2074 default:
2075 virReportEnumRangeError(esxVI_Occurrence, occurrence);
2076 break;
2077 }
2078
2079 goto cleanup;
2080 }
2081
2082 result = 0;
2083
2084 cleanup:
2085 /*
2086 * Remove values given by the caller from the data structures to prevent
2087 * them from being freed by the call to esxVI_PropertyFilterSpec_Free().
2088 * objectSpec cannot be NULL here.
2089 */
2090 objectSpec->obj = NULL;
2091 objectSpec->selectSet = NULL;
2092
2093 if (propertySpec) {
2094 propertySpec->type = NULL;
2095 propertySpec->pathSet = NULL;
2096 }
2097
2098 if (!objectSpec_isAppended)
2099 esxVI_ObjectSpec_Free(&objectSpec);
2100
2101 if (!propertySpec_isAppended)
2102 esxVI_PropertySpec_Free(&propertySpec);
2103
2104 esxVI_PropertyFilterSpec_Free(&propertyFilterSpec);
2105
2106 return result;
2107 }
2108
2109
2110
2111 int
esxVI_GetManagedEntityStatus(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_ManagedEntityStatus * managedEntityStatus)2112 esxVI_GetManagedEntityStatus(esxVI_ObjectContent *objectContent,
2113 const char *propertyName,
2114 esxVI_ManagedEntityStatus *managedEntityStatus)
2115 {
2116 esxVI_DynamicProperty *dynamicProperty;
2117
2118 for (dynamicProperty = objectContent->propSet; dynamicProperty;
2119 dynamicProperty = dynamicProperty->_next) {
2120 if (STREQ(dynamicProperty->name, propertyName)) {
2121 return esxVI_ManagedEntityStatus_CastFromAnyType
2122 (dynamicProperty->val, managedEntityStatus);
2123 }
2124 }
2125
2126 virReportError(VIR_ERR_INTERNAL_ERROR,
2127 _("Missing '%s' property while looking for "
2128 "ManagedEntityStatus"), propertyName);
2129
2130 return -1;
2131 }
2132
2133
2134
2135 int
esxVI_GetVirtualMachinePowerState(esxVI_ObjectContent * virtualMachine,esxVI_VirtualMachinePowerState * powerState)2136 esxVI_GetVirtualMachinePowerState(esxVI_ObjectContent *virtualMachine,
2137 esxVI_VirtualMachinePowerState *powerState)
2138 {
2139 esxVI_DynamicProperty *dynamicProperty;
2140
2141 for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
2142 dynamicProperty = dynamicProperty->_next) {
2143 if (STREQ(dynamicProperty->name, "runtime.powerState")) {
2144 return esxVI_VirtualMachinePowerState_CastFromAnyType
2145 (dynamicProperty->val, powerState);
2146 }
2147 }
2148
2149 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2150 _("Missing 'runtime.powerState' property"));
2151
2152 return -1;
2153 }
2154
2155
2156
2157 int
esxVI_GetVirtualMachineQuestionInfo(esxVI_ObjectContent * virtualMachine,esxVI_VirtualMachineQuestionInfo ** questionInfo)2158 esxVI_GetVirtualMachineQuestionInfo
2159 (esxVI_ObjectContent *virtualMachine,
2160 esxVI_VirtualMachineQuestionInfo **questionInfo)
2161 {
2162 esxVI_DynamicProperty *dynamicProperty;
2163
2164 ESX_VI_CHECK_ARG_LIST(questionInfo);
2165
2166 for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
2167 dynamicProperty = dynamicProperty->_next) {
2168 if (STREQ(dynamicProperty->name, "runtime.question")) {
2169 if (esxVI_VirtualMachineQuestionInfo_CastFromAnyType
2170 (dynamicProperty->val, questionInfo) < 0) {
2171 return -1;
2172 }
2173 }
2174 }
2175
2176 return 0;
2177 }
2178
2179
2180 int
esxVI_GetVirtualMachineMORef(esxVI_ObjectContent * virtualMachine,char ** moref)2181 esxVI_GetVirtualMachineMORef(esxVI_ObjectContent *virtualMachine,
2182 char **moref)
2183 {
2184 for (; virtualMachine != NULL; virtualMachine = virtualMachine->_next) {
2185 if (virtualMachine->obj &&
2186 STREQ(virtualMachine->obj->type, "VirtualMachine") &&
2187 virtualMachine->obj->value) {
2188 *moref = g_strdup(virtualMachine->obj->value);
2189 return 0;
2190 }
2191 }
2192 return -1;
2193 }
2194
2195 int
esxVI_GetBoolean(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_Boolean * value,esxVI_Occurrence occurrence)2196 esxVI_GetBoolean(esxVI_ObjectContent *objectContent, const char *propertyName,
2197 esxVI_Boolean *value, esxVI_Occurrence occurrence)
2198 {
2199 esxVI_DynamicProperty *dynamicProperty;
2200
2201 if (!value || *value != esxVI_Boolean_Undefined) {
2202 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2203 return -1;
2204 }
2205
2206 for (dynamicProperty = objectContent->propSet; dynamicProperty;
2207 dynamicProperty = dynamicProperty->_next) {
2208 if (STREQ(dynamicProperty->name, propertyName)) {
2209 if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2210 esxVI_Type_Boolean) < 0) {
2211 return -1;
2212 }
2213
2214 *value = dynamicProperty->val->boolean;
2215 break;
2216 }
2217 }
2218
2219 if (*value == esxVI_Boolean_Undefined &&
2220 occurrence == esxVI_Occurrence_RequiredItem) {
2221 virReportError(VIR_ERR_INTERNAL_ERROR,
2222 _("Missing '%s' property"), propertyName);
2223 return -1;
2224 }
2225
2226 return 0;
2227 }
2228
2229
2230
2231 int
esxVI_GetInt(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_Int ** value,esxVI_Occurrence occurrence)2232 esxVI_GetInt(esxVI_ObjectContent *objectContent, const char *propertyName,
2233 esxVI_Int **value, esxVI_Occurrence occurrence)
2234 {
2235 esxVI_DynamicProperty *dynamicProperty;
2236
2237 ESX_VI_CHECK_ARG_LIST(value);
2238
2239 for (dynamicProperty = objectContent->propSet; dynamicProperty;
2240 dynamicProperty = dynamicProperty->_next) {
2241 if (STREQ(dynamicProperty->name, propertyName)) {
2242 if (esxVI_Int_CastFromAnyType(dynamicProperty->val, value) < 0)
2243 return -1;
2244
2245 break;
2246 }
2247 }
2248
2249 if (!(*value) && occurrence == esxVI_Occurrence_RequiredItem) {
2250 virReportError(VIR_ERR_INTERNAL_ERROR,
2251 _("Missing '%s' property"), propertyName);
2252 return -1;
2253 }
2254
2255 return 0;
2256 }
2257
2258
2259
2260 int
esxVI_GetLong(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_Long ** value,esxVI_Occurrence occurrence)2261 esxVI_GetLong(esxVI_ObjectContent *objectContent, const char *propertyName,
2262 esxVI_Long **value, esxVI_Occurrence occurrence)
2263 {
2264 esxVI_DynamicProperty *dynamicProperty;
2265
2266 ESX_VI_CHECK_ARG_LIST(value);
2267
2268 for (dynamicProperty = objectContent->propSet; dynamicProperty;
2269 dynamicProperty = dynamicProperty->_next) {
2270 if (STREQ(dynamicProperty->name, propertyName)) {
2271 if (esxVI_Long_CastFromAnyType(dynamicProperty->val, value) < 0)
2272 return -1;
2273
2274 break;
2275 }
2276 }
2277
2278 if (!(*value) && occurrence == esxVI_Occurrence_RequiredItem) {
2279 virReportError(VIR_ERR_INTERNAL_ERROR,
2280 _("Missing '%s' property"), propertyName);
2281 return -1;
2282 }
2283
2284 return 0;
2285 }
2286
2287
2288
2289 int
esxVI_GetStringValue(esxVI_ObjectContent * objectContent,const char * propertyName,char ** value,esxVI_Occurrence occurrence)2290 esxVI_GetStringValue(esxVI_ObjectContent *objectContent,
2291 const char *propertyName,
2292 char **value, esxVI_Occurrence occurrence)
2293 {
2294 esxVI_DynamicProperty *dynamicProperty;
2295
2296 ESX_VI_CHECK_ARG_LIST(value);
2297
2298 for (dynamicProperty = objectContent->propSet; dynamicProperty;
2299 dynamicProperty = dynamicProperty->_next) {
2300 if (STREQ(dynamicProperty->name, propertyName)) {
2301 if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2302 esxVI_Type_String) < 0) {
2303 return -1;
2304 }
2305
2306 *value = dynamicProperty->val->string;
2307 break;
2308 }
2309 }
2310
2311 if (!(*value) && occurrence == esxVI_Occurrence_RequiredItem) {
2312 virReportError(VIR_ERR_INTERNAL_ERROR,
2313 _("Missing '%s' property"), propertyName);
2314 return -1;
2315 }
2316
2317 return 0;
2318 }
2319
2320
2321
2322 int
esxVI_GetManagedObjectReference(esxVI_ObjectContent * objectContent,const char * propertyName,esxVI_ManagedObjectReference ** value,esxVI_Occurrence occurrence)2323 esxVI_GetManagedObjectReference(esxVI_ObjectContent *objectContent,
2324 const char *propertyName,
2325 esxVI_ManagedObjectReference **value,
2326 esxVI_Occurrence occurrence)
2327 {
2328 esxVI_DynamicProperty *dynamicProperty;
2329
2330 ESX_VI_CHECK_ARG_LIST(value);
2331
2332 for (dynamicProperty = objectContent->propSet; dynamicProperty;
2333 dynamicProperty = dynamicProperty->_next) {
2334 if (STREQ(dynamicProperty->name, propertyName)) {
2335 if (esxVI_ManagedObjectReference_CastFromAnyType
2336 (dynamicProperty->val, value) < 0) {
2337 return -1;
2338 }
2339
2340 break;
2341 }
2342 }
2343
2344 if (!(*value) && occurrence == esxVI_Occurrence_RequiredItem) {
2345 virReportError(VIR_ERR_INTERNAL_ERROR,
2346 _("Missing '%s' property"), propertyName);
2347 return -1;
2348 }
2349
2350 return 0;
2351 }
2352
2353
2354
2355 int
esxVI_LookupNumberOfDomainsByPowerState(esxVI_Context * ctx,esxVI_VirtualMachinePowerState powerState,bool inverse)2356 esxVI_LookupNumberOfDomainsByPowerState(esxVI_Context *ctx,
2357 esxVI_VirtualMachinePowerState powerState,
2358 bool inverse)
2359 {
2360 bool success = false;
2361 esxVI_String *propertyNameList = NULL;
2362 esxVI_ObjectContent *virtualMachineList = NULL;
2363 esxVI_ObjectContent *virtualMachine = NULL;
2364 esxVI_DynamicProperty *dynamicProperty = NULL;
2365 esxVI_VirtualMachinePowerState powerState_;
2366 int count = 0;
2367
2368 if (esxVI_String_AppendValueToList(&propertyNameList,
2369 "runtime.powerState") < 0 ||
2370 esxVI_LookupVirtualMachineList(ctx, propertyNameList,
2371 &virtualMachineList) < 0) {
2372 goto cleanup;
2373 }
2374
2375 for (virtualMachine = virtualMachineList; virtualMachine;
2376 virtualMachine = virtualMachine->_next) {
2377 for (dynamicProperty = virtualMachine->propSet;
2378 dynamicProperty;
2379 dynamicProperty = dynamicProperty->_next) {
2380 if (STREQ(dynamicProperty->name, "runtime.powerState")) {
2381 if (esxVI_VirtualMachinePowerState_CastFromAnyType
2382 (dynamicProperty->val, &powerState_) < 0) {
2383 goto cleanup;
2384 }
2385
2386 if ((!inverse && powerState_ == powerState) ||
2387 (inverse && powerState_ != powerState)) {
2388 count++;
2389 }
2390 } else {
2391 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
2392 }
2393 }
2394 }
2395
2396 success = true;
2397
2398 cleanup:
2399 esxVI_String_Free(&propertyNameList);
2400 esxVI_ObjectContent_Free(&virtualMachineList);
2401
2402 return success ? count : -1;
2403 }
2404
2405
2406
2407 int
esxVI_GetVirtualMachineIdentity(esxVI_ObjectContent * virtualMachine,int * id,char ** name,unsigned char * uuid)2408 esxVI_GetVirtualMachineIdentity(esxVI_ObjectContent *virtualMachine,
2409 int *id, char **name, unsigned char *uuid)
2410 {
2411 const char *uuid_string = NULL;
2412 esxVI_DynamicProperty *dynamicProperty = NULL;
2413 esxVI_ManagedEntityStatus configStatus = esxVI_ManagedEntityStatus_Undefined;
2414
2415 if (STRNEQ(virtualMachine->obj->type, "VirtualMachine")) {
2416 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2417 _("ObjectContent does not reference a virtual machine"));
2418 return -1;
2419 }
2420
2421 if (id) {
2422 if (esxUtil_ParseVirtualMachineIDString
2423 (virtualMachine->obj->value, id) < 0 || *id <= 0) {
2424 virReportError(VIR_ERR_INTERNAL_ERROR,
2425 _("Could not parse positive integer from '%s'"),
2426 virtualMachine->obj->value);
2427 goto failure;
2428 }
2429 }
2430
2431 if (name) {
2432 if (*name) {
2433 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2434 goto failure;
2435 }
2436
2437 for (dynamicProperty = virtualMachine->propSet;
2438 dynamicProperty;
2439 dynamicProperty = dynamicProperty->_next) {
2440 if (STREQ(dynamicProperty->name, "name")) {
2441 if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2442 esxVI_Type_String) < 0) {
2443 goto failure;
2444 }
2445
2446 *name = g_strdup(dynamicProperty->val->string);
2447
2448 if (virVMXUnescapeHexPercent(*name) < 0) {
2449 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2450 _("Domain name contains invalid escape sequence"));
2451 goto failure;
2452 }
2453
2454 break;
2455 }
2456 }
2457
2458 if (!(*name)) {
2459 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2460 _("Could not get name of virtual machine"));
2461 goto failure;
2462 }
2463 }
2464
2465 if (uuid) {
2466 if (esxVI_GetManagedEntityStatus(virtualMachine, "configStatus",
2467 &configStatus) < 0) {
2468 goto failure;
2469 }
2470
2471 if (configStatus == esxVI_ManagedEntityStatus_Green) {
2472 for (dynamicProperty = virtualMachine->propSet;
2473 dynamicProperty;
2474 dynamicProperty = dynamicProperty->_next) {
2475 if (STREQ(dynamicProperty->name, "config.uuid")) {
2476 if (esxVI_AnyType_ExpectType(dynamicProperty->val,
2477 esxVI_Type_String) < 0) {
2478 goto failure;
2479 }
2480
2481 uuid_string = dynamicProperty->val->string;
2482 break;
2483 }
2484 }
2485
2486 if (!uuid_string) {
2487 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2488 _("Could not get UUID of virtual machine"));
2489 goto failure;
2490 }
2491
2492 if (virUUIDParse(uuid_string, uuid) < 0) {
2493 virReportError(VIR_ERR_INTERNAL_ERROR,
2494 _("Could not parse UUID from string '%s'"),
2495 uuid_string);
2496 goto failure;
2497 }
2498 } else {
2499 memset(uuid, 0, VIR_UUID_BUFLEN);
2500
2501 VIR_WARN("Cannot access UUID, because 'configStatus' property "
2502 "indicates a config problem");
2503 }
2504 }
2505
2506 return 0;
2507
2508 failure:
2509 if (name)
2510 g_clear_pointer(name, g_free);
2511
2512 return -1;
2513 }
2514
2515
2516
2517 int
esxVI_GetNumberOfSnapshotTrees(esxVI_VirtualMachineSnapshotTree * snapshotTreeList,bool recurse,bool leaves)2518 esxVI_GetNumberOfSnapshotTrees
2519 (esxVI_VirtualMachineSnapshotTree *snapshotTreeList, bool recurse,
2520 bool leaves)
2521 {
2522 int count = 0;
2523 esxVI_VirtualMachineSnapshotTree *snapshotTree;
2524
2525 for (snapshotTree = snapshotTreeList; snapshotTree;
2526 snapshotTree = snapshotTree->_next) {
2527 if (!(leaves && snapshotTree->childSnapshotList))
2528 count++;
2529 if (recurse)
2530 count += esxVI_GetNumberOfSnapshotTrees
2531 (snapshotTree->childSnapshotList, true, leaves);
2532 }
2533
2534 return count;
2535 }
2536
2537
2538
2539 int
esxVI_GetSnapshotTreeNames(esxVI_VirtualMachineSnapshotTree * snapshotTreeList,char ** names,int nameslen,bool recurse,bool leaves)2540 esxVI_GetSnapshotTreeNames(esxVI_VirtualMachineSnapshotTree *snapshotTreeList,
2541 char **names, int nameslen, bool recurse,
2542 bool leaves)
2543 {
2544 int count = 0;
2545 int result;
2546 size_t i;
2547 esxVI_VirtualMachineSnapshotTree *snapshotTree;
2548
2549 for (snapshotTree = snapshotTreeList;
2550 snapshotTree && count < nameslen;
2551 snapshotTree = snapshotTree->_next) {
2552 if (!(leaves && snapshotTree->childSnapshotList)) {
2553 names[count] = g_strdup(snapshotTree->name);
2554
2555 count++;
2556 }
2557
2558 if (count >= nameslen)
2559 break;
2560
2561 if (recurse) {
2562 result = esxVI_GetSnapshotTreeNames(snapshotTree->childSnapshotList,
2563 names + count,
2564 nameslen - count,
2565 true, leaves);
2566
2567 if (result < 0)
2568 goto failure;
2569
2570 count += result;
2571 }
2572 }
2573
2574 return count;
2575
2576 failure:
2577 for (i = 0; i < count; ++i)
2578 VIR_FREE(names[i]);
2579
2580 return -1;
2581 }
2582
2583
2584
2585 int
esxVI_GetSnapshotTreeByName(esxVI_VirtualMachineSnapshotTree * snapshotTreeList,const char * name,esxVI_VirtualMachineSnapshotTree ** snapshotTree,esxVI_VirtualMachineSnapshotTree ** snapshotTreeParent,esxVI_Occurrence occurrence)2586 esxVI_GetSnapshotTreeByName
2587 (esxVI_VirtualMachineSnapshotTree *snapshotTreeList, const char *name,
2588 esxVI_VirtualMachineSnapshotTree **snapshotTree,
2589 esxVI_VirtualMachineSnapshotTree **snapshotTreeParent,
2590 esxVI_Occurrence occurrence)
2591 {
2592 esxVI_VirtualMachineSnapshotTree *candidate;
2593
2594 if (!snapshotTree || *snapshotTree ||
2595 (snapshotTreeParent && *snapshotTreeParent)) {
2596 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2597 return -1;
2598 }
2599
2600 for (candidate = snapshotTreeList; candidate;
2601 candidate = candidate->_next) {
2602 if (STREQ(candidate->name, name)) {
2603 *snapshotTree = candidate;
2604 if (snapshotTreeParent)
2605 *snapshotTreeParent = NULL;
2606 return 1;
2607 }
2608
2609 if (esxVI_GetSnapshotTreeByName(candidate->childSnapshotList, name,
2610 snapshotTree, snapshotTreeParent,
2611 occurrence) > 0) {
2612 if (snapshotTreeParent && !(*snapshotTreeParent))
2613 *snapshotTreeParent = candidate;
2614
2615 return 1;
2616 }
2617 }
2618
2619 if (occurrence == esxVI_Occurrence_OptionalItem) {
2620 return 0;
2621 } else {
2622 virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
2623 _("Could not find snapshot with name '%s'"), name);
2624
2625 return -1;
2626 }
2627 }
2628
2629
2630
2631 int
esxVI_GetSnapshotTreeBySnapshot(esxVI_VirtualMachineSnapshotTree * snapshotTreeList,esxVI_ManagedObjectReference * snapshot,esxVI_VirtualMachineSnapshotTree ** snapshotTree)2632 esxVI_GetSnapshotTreeBySnapshot
2633 (esxVI_VirtualMachineSnapshotTree *snapshotTreeList,
2634 esxVI_ManagedObjectReference *snapshot,
2635 esxVI_VirtualMachineSnapshotTree **snapshotTree)
2636 {
2637 esxVI_VirtualMachineSnapshotTree *candidate;
2638
2639 ESX_VI_CHECK_ARG_LIST(snapshotTree);
2640
2641 for (candidate = snapshotTreeList; candidate;
2642 candidate = candidate->_next) {
2643 if (STREQ(candidate->snapshot->value, snapshot->value)) {
2644 *snapshotTree = candidate;
2645 return 0;
2646 }
2647
2648 if (esxVI_GetSnapshotTreeBySnapshot(candidate->childSnapshotList,
2649 snapshot, snapshotTree) >= 0) {
2650 return 0;
2651 }
2652 }
2653
2654 virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
2655 _("Could not find domain snapshot with internal name '%s'"),
2656 snapshot->value);
2657
2658 return -1;
2659 }
2660
2661
2662
2663 int
esxVI_LookupHostSystemProperties(esxVI_Context * ctx,esxVI_String * propertyNameList,esxVI_ObjectContent ** hostSystem)2664 esxVI_LookupHostSystemProperties(esxVI_Context *ctx,
2665 esxVI_String *propertyNameList,
2666 esxVI_ObjectContent **hostSystem)
2667 {
2668 return esxVI_LookupObjectContentByType(ctx, ctx->hostSystem->_reference,
2669 "HostSystem", propertyNameList,
2670 hostSystem,
2671 esxVI_Occurrence_RequiredItem);
2672 }
2673
2674
2675
2676 int
esxVI_LookupVirtualMachineList(esxVI_Context * ctx,esxVI_String * propertyNameList,esxVI_ObjectContent ** virtualMachineList)2677 esxVI_LookupVirtualMachineList(esxVI_Context *ctx,
2678 esxVI_String *propertyNameList,
2679 esxVI_ObjectContent **virtualMachineList)
2680 {
2681 /* FIXME: Switch from ctx->hostSystem to ctx->computeResource->resourcePool
2682 * for cluster support */
2683 return esxVI_LookupObjectContentByType(ctx, ctx->hostSystem->_reference,
2684 "VirtualMachine", propertyNameList,
2685 virtualMachineList,
2686 esxVI_Occurrence_OptionalList);
2687 }
2688
2689
2690
2691 int
esxVI_LookupVirtualMachineByUuid(esxVI_Context * ctx,const unsigned char * uuid,esxVI_String * propertyNameList,esxVI_ObjectContent ** virtualMachine,esxVI_Occurrence occurrence)2692 esxVI_LookupVirtualMachineByUuid(esxVI_Context *ctx, const unsigned char *uuid,
2693 esxVI_String *propertyNameList,
2694 esxVI_ObjectContent **virtualMachine,
2695 esxVI_Occurrence occurrence)
2696 {
2697 int result = -1;
2698 esxVI_ManagedObjectReference *managedObjectReference = NULL;
2699 char uuid_string[VIR_UUID_STRING_BUFLEN] = "";
2700
2701 ESX_VI_CHECK_ARG_LIST(virtualMachine);
2702
2703 virUUIDFormat(uuid, uuid_string);
2704
2705 if (esxVI_FindByUuid(ctx, ctx->datacenter->_reference, uuid_string,
2706 esxVI_Boolean_True, esxVI_Boolean_Undefined,
2707 &managedObjectReference) < 0) {
2708 return -1;
2709 }
2710
2711 if (!managedObjectReference) {
2712 if (occurrence == esxVI_Occurrence_OptionalItem) {
2713 result = 0;
2714
2715 goto cleanup;
2716 } else {
2717 virReportError(VIR_ERR_NO_DOMAIN,
2718 _("Could not find domain with UUID '%s'"),
2719 uuid_string);
2720 goto cleanup;
2721 }
2722 }
2723
2724 if (esxVI_LookupObjectContentByType(ctx, managedObjectReference,
2725 "VirtualMachine", propertyNameList,
2726 virtualMachine,
2727 esxVI_Occurrence_RequiredItem) < 0) {
2728 goto cleanup;
2729 }
2730
2731 result = 0;
2732
2733 cleanup:
2734 esxVI_ManagedObjectReference_Free(&managedObjectReference);
2735
2736 return result;
2737 }
2738
2739
2740
2741 int
esxVI_LookupVirtualMachineByName(esxVI_Context * ctx,const char * name,esxVI_String * propertyNameList,esxVI_ObjectContent ** virtualMachine,esxVI_Occurrence occurrence)2742 esxVI_LookupVirtualMachineByName(esxVI_Context *ctx, const char *name,
2743 esxVI_String *propertyNameList,
2744 esxVI_ObjectContent **virtualMachine,
2745 esxVI_Occurrence occurrence)
2746 {
2747 int result = -1;
2748 esxVI_String *completePropertyNameList = NULL;
2749 esxVI_ObjectContent *virtualMachineList = NULL;
2750 esxVI_ObjectContent *candidate = NULL;
2751
2752 ESX_VI_CHECK_ARG_LIST(virtualMachine);
2753
2754 if (esxVI_String_DeepCopyList(&completePropertyNameList,
2755 propertyNameList) < 0 ||
2756 esxVI_String_AppendValueToList(&completePropertyNameList, "name") < 0 ||
2757 esxVI_LookupVirtualMachineList(ctx, completePropertyNameList,
2758 &virtualMachineList) < 0) {
2759 goto cleanup;
2760 }
2761
2762 for (candidate = virtualMachineList; candidate;
2763 candidate = candidate->_next) {
2764 g_autofree char *name_candidate = NULL;
2765
2766 if (esxVI_GetVirtualMachineIdentity(candidate, NULL, &name_candidate,
2767 NULL) < 0) {
2768 goto cleanup;
2769 }
2770
2771 if (STRNEQ(name, name_candidate))
2772 continue;
2773
2774 if (esxVI_ObjectContent_DeepCopy(virtualMachine, candidate) < 0)
2775 goto cleanup;
2776
2777 break;
2778 }
2779
2780 if (!(*virtualMachine) && occurrence != esxVI_Occurrence_OptionalItem) {
2781 virReportError(VIR_ERR_NO_DOMAIN,
2782 _("Could not find domain with name '%s'"), name);
2783 goto cleanup;
2784 }
2785
2786 result = 0;
2787
2788 cleanup:
2789 esxVI_String_Free(&completePropertyNameList);
2790 esxVI_ObjectContent_Free(&virtualMachineList);
2791 return result;
2792 }
2793
2794
2795
2796 int
esxVI_LookupVirtualMachineByUuidAndPrepareForTask(esxVI_Context * ctx,const unsigned char * uuid,esxVI_String * propertyNameList,esxVI_ObjectContent ** virtualMachine,bool autoAnswer)2797 esxVI_LookupVirtualMachineByUuidAndPrepareForTask
2798 (esxVI_Context *ctx, const unsigned char *uuid,
2799 esxVI_String *propertyNameList, esxVI_ObjectContent **virtualMachine,
2800 bool autoAnswer)
2801 {
2802 int result = -1;
2803 esxVI_String *completePropertyNameList = NULL;
2804 esxVI_VirtualMachineQuestionInfo *questionInfo = NULL;
2805 esxVI_TaskInfo *pendingTaskInfoList = NULL;
2806 bool blocked;
2807
2808 if (esxVI_String_DeepCopyList(&completePropertyNameList,
2809 propertyNameList) < 0 ||
2810 esxVI_String_AppendValueListToList(&completePropertyNameList,
2811 "runtime.question\0"
2812 "recentTask\0") < 0 ||
2813 esxVI_LookupVirtualMachineByUuid(ctx, uuid, completePropertyNameList,
2814 virtualMachine,
2815 esxVI_Occurrence_RequiredItem) < 0 ||
2816 esxVI_GetVirtualMachineQuestionInfo(*virtualMachine,
2817 &questionInfo) < 0 ||
2818 esxVI_LookupPendingTaskInfoListByVirtualMachine
2819 (ctx, *virtualMachine, &pendingTaskInfoList) < 0) {
2820 goto cleanup;
2821 }
2822
2823 if (questionInfo &&
2824 esxVI_HandleVirtualMachineQuestion(ctx, (*virtualMachine)->obj,
2825 questionInfo, autoAnswer,
2826 &blocked) < 0) {
2827 goto cleanup;
2828 }
2829
2830 if (pendingTaskInfoList) {
2831 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2832 _("Other tasks are pending for this domain"));
2833 goto cleanup;
2834 }
2835
2836 result = 0;
2837
2838 cleanup:
2839 esxVI_String_Free(&completePropertyNameList);
2840 esxVI_VirtualMachineQuestionInfo_Free(&questionInfo);
2841 esxVI_TaskInfo_Free(&pendingTaskInfoList);
2842
2843 return result;
2844 }
2845
2846
2847
2848 int
esxVI_LookupDatastoreList(esxVI_Context * ctx,esxVI_String * propertyNameList,esxVI_ObjectContent ** datastoreList)2849 esxVI_LookupDatastoreList(esxVI_Context *ctx, esxVI_String *propertyNameList,
2850 esxVI_ObjectContent **datastoreList)
2851 {
2852 /* FIXME: Switch from ctx->hostSystem to ctx->computeResource for cluster
2853 * support */
2854 return esxVI_LookupObjectContentByType(ctx, ctx->hostSystem->_reference,
2855 "Datastore", propertyNameList,
2856 datastoreList,
2857 esxVI_Occurrence_OptionalList);
2858 }
2859
2860
2861
2862 int
esxVI_LookupDatastoreByName(esxVI_Context * ctx,const char * name,esxVI_String * propertyNameList,esxVI_ObjectContent ** datastore,esxVI_Occurrence occurrence)2863 esxVI_LookupDatastoreByName(esxVI_Context *ctx, const char *name,
2864 esxVI_String *propertyNameList,
2865 esxVI_ObjectContent **datastore,
2866 esxVI_Occurrence occurrence)
2867 {
2868 int result = -1;
2869 esxVI_String *completePropertyNameList = NULL;
2870 esxVI_ObjectContent *datastoreList = NULL;
2871 esxVI_ObjectContent *candidate = NULL;
2872 char *name_candidate;
2873
2874 ESX_VI_CHECK_ARG_LIST(datastore);
2875
2876 /* Get all datastores */
2877 if (esxVI_String_DeepCopyList(&completePropertyNameList,
2878 propertyNameList) < 0 ||
2879 esxVI_String_AppendValueToList(&completePropertyNameList,
2880 "summary.name") < 0 ||
2881 esxVI_LookupDatastoreList(ctx, completePropertyNameList,
2882 &datastoreList) < 0) {
2883 goto cleanup;
2884 }
2885
2886 /* Search for a matching datastore */
2887 for (candidate = datastoreList; candidate;
2888 candidate = candidate->_next) {
2889 name_candidate = NULL;
2890
2891 if (esxVI_GetStringValue(candidate, "summary.name", &name_candidate,
2892 esxVI_Occurrence_RequiredItem) < 0) {
2893 goto cleanup;
2894 }
2895
2896 if (STREQ(name_candidate, name)) {
2897 if (esxVI_ObjectContent_DeepCopy(datastore, candidate) < 0)
2898 goto cleanup;
2899
2900 /* Found datastore with matching name */
2901 result = 0;
2902
2903 goto cleanup;
2904 }
2905 }
2906
2907 if (!(*datastore) && occurrence != esxVI_Occurrence_OptionalItem) {
2908 virReportError(VIR_ERR_INTERNAL_ERROR,
2909 _("Could not find datastore with name '%s'"), name);
2910 goto cleanup;
2911 }
2912
2913 result = 0;
2914
2915 cleanup:
2916 esxVI_String_Free(&completePropertyNameList);
2917 esxVI_ObjectContent_Free(&datastoreList);
2918
2919 return result;
2920 }
2921
2922
2923 int
esxVI_LookupDatastoreByAbsolutePath(esxVI_Context * ctx,const char * absolutePath,esxVI_String * propertyNameList,esxVI_ObjectContent ** datastore,esxVI_Occurrence occurrence)2924 esxVI_LookupDatastoreByAbsolutePath(esxVI_Context *ctx,
2925 const char *absolutePath,
2926 esxVI_String *propertyNameList,
2927 esxVI_ObjectContent **datastore,
2928 esxVI_Occurrence occurrence)
2929 {
2930 int result = -1;
2931 esxVI_String *completePropertyNameList = NULL;
2932 esxVI_ObjectContent *datastoreList = NULL;
2933 esxVI_ObjectContent *candidate = NULL;
2934 esxVI_DynamicProperty *dynamicProperty = NULL;
2935 esxVI_DatastoreHostMount *datastoreHostMountList = NULL;
2936 esxVI_DatastoreHostMount *datastoreHostMount = NULL;
2937
2938 ESX_VI_CHECK_ARG_LIST(datastore);
2939
2940 /* Get all datastores */
2941 if (esxVI_String_DeepCopyList(&completePropertyNameList,
2942 propertyNameList) < 0 ||
2943 esxVI_String_AppendValueToList(&completePropertyNameList, "host") < 0 ||
2944 esxVI_LookupDatastoreList(ctx, completePropertyNameList,
2945 &datastoreList) < 0) {
2946 goto cleanup;
2947 }
2948
2949 /* Search for a matching datastore */
2950 for (candidate = datastoreList; candidate;
2951 candidate = candidate->_next) {
2952 esxVI_DatastoreHostMount_Free(&datastoreHostMountList);
2953
2954 for (dynamicProperty = candidate->propSet; dynamicProperty;
2955 dynamicProperty = dynamicProperty->_next) {
2956 if (STREQ(dynamicProperty->name, "host")) {
2957 if (esxVI_DatastoreHostMount_CastListFromAnyType
2958 (dynamicProperty->val, &datastoreHostMountList) < 0) {
2959 goto cleanup;
2960 }
2961
2962 break;
2963 }
2964 }
2965
2966 if (!datastoreHostMountList)
2967 continue;
2968
2969 for (datastoreHostMount = datastoreHostMountList;
2970 datastoreHostMount;
2971 datastoreHostMount = datastoreHostMount->_next) {
2972 if (STRNEQ(ctx->hostSystem->_reference->value,
2973 datastoreHostMount->key->value)) {
2974 continue;
2975 }
2976
2977 if (STRPREFIX(absolutePath, datastoreHostMount->mountInfo->path)) {
2978 if (esxVI_ObjectContent_DeepCopy(datastore, candidate) < 0)
2979 goto cleanup;
2980
2981 /* Found datastore with matching mount path */
2982 result = 0;
2983
2984 goto cleanup;
2985 }
2986 }
2987 }
2988
2989 if (!(*datastore) && occurrence != esxVI_Occurrence_OptionalItem) {
2990 virReportError(VIR_ERR_INTERNAL_ERROR,
2991 _("Could not find datastore containing absolute path '%s'"),
2992 absolutePath);
2993 goto cleanup;
2994 }
2995
2996 result = 0;
2997
2998 cleanup:
2999 esxVI_String_Free(&completePropertyNameList);
3000 esxVI_ObjectContent_Free(&datastoreList);
3001 esxVI_DatastoreHostMount_Free(&datastoreHostMountList);
3002
3003 return result;
3004 }
3005
3006
3007
3008 int
esxVI_LookupDatastoreHostMount(esxVI_Context * ctx,esxVI_ManagedObjectReference * datastore,esxVI_DatastoreHostMount ** hostMount,esxVI_Occurrence occurrence)3009 esxVI_LookupDatastoreHostMount(esxVI_Context *ctx,
3010 esxVI_ManagedObjectReference *datastore,
3011 esxVI_DatastoreHostMount **hostMount,
3012 esxVI_Occurrence occurrence)
3013 {
3014 int result = -1;
3015 esxVI_String *propertyNameList = NULL;
3016 esxVI_ObjectContent *objectContent = NULL;
3017 esxVI_DynamicProperty *dynamicProperty = NULL;
3018 esxVI_DatastoreHostMount *hostMountList = NULL;
3019 esxVI_DatastoreHostMount *candidate = NULL;
3020
3021 ESX_VI_CHECK_ARG_LIST(hostMount);
3022
3023 if (esxVI_String_AppendValueToList(&propertyNameList, "host") < 0 ||
3024 esxVI_LookupObjectContentByType(ctx, datastore, "Datastore",
3025 propertyNameList, &objectContent,
3026 esxVI_Occurrence_RequiredItem) < 0) {
3027 goto cleanup;
3028 }
3029
3030 for (dynamicProperty = objectContent->propSet; dynamicProperty;
3031 dynamicProperty = dynamicProperty->_next) {
3032 if (STREQ(dynamicProperty->name, "host")) {
3033 if (esxVI_DatastoreHostMount_CastListFromAnyType
3034 (dynamicProperty->val, &hostMountList) < 0) {
3035 goto cleanup;
3036 }
3037
3038 break;
3039 } else {
3040 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3041 }
3042 }
3043
3044 for (candidate = hostMountList; candidate;
3045 candidate = candidate->_next) {
3046 if (STRNEQ(ctx->hostSystem->_reference->value, candidate->key->value))
3047 continue;
3048
3049 if (esxVI_DatastoreHostMount_DeepCopy(hostMount, candidate) < 0)
3050 goto cleanup;
3051
3052 break;
3053 }
3054
3055 if (!(*hostMount) && occurrence == esxVI_Occurrence_RequiredItem) {
3056 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3057 _("Could not lookup datastore host mount"));
3058 goto cleanup;
3059 }
3060
3061 result = 0;
3062
3063 cleanup:
3064 esxVI_String_Free(&propertyNameList);
3065 esxVI_ObjectContent_Free(&objectContent);
3066 esxVI_DatastoreHostMount_Free(&hostMountList);
3067
3068 return result;
3069 }
3070
3071
3072 int
esxVI_LookupTaskInfoByTask(esxVI_Context * ctx,esxVI_ManagedObjectReference * task,esxVI_TaskInfo ** taskInfo)3073 esxVI_LookupTaskInfoByTask(esxVI_Context *ctx,
3074 esxVI_ManagedObjectReference *task,
3075 esxVI_TaskInfo **taskInfo)
3076 {
3077 int result = -1;
3078 esxVI_String *propertyNameList = NULL;
3079 esxVI_ObjectContent *objectContent = NULL;
3080 esxVI_DynamicProperty *dynamicProperty = NULL;
3081
3082 ESX_VI_CHECK_ARG_LIST(taskInfo);
3083
3084 if (esxVI_String_AppendValueToList(&propertyNameList, "info") < 0 ||
3085 esxVI_LookupObjectContentByType(ctx, task, "Task", propertyNameList,
3086 &objectContent,
3087 esxVI_Occurrence_RequiredItem) < 0) {
3088 goto cleanup;
3089 }
3090
3091 for (dynamicProperty = objectContent->propSet; dynamicProperty;
3092 dynamicProperty = dynamicProperty->_next) {
3093 if (STREQ(dynamicProperty->name, "info")) {
3094 if (esxVI_TaskInfo_CastFromAnyType(dynamicProperty->val,
3095 taskInfo) < 0) {
3096 goto cleanup;
3097 }
3098
3099 result = 0;
3100 break;
3101 } else {
3102 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3103 }
3104 }
3105
3106 cleanup:
3107 esxVI_String_Free(&propertyNameList);
3108 esxVI_ObjectContent_Free(&objectContent);
3109
3110 return result;
3111 }
3112
3113
3114
3115 int
esxVI_LookupPendingTaskInfoListByVirtualMachine(esxVI_Context * ctx,esxVI_ObjectContent * virtualMachine,esxVI_TaskInfo ** pendingTaskInfoList)3116 esxVI_LookupPendingTaskInfoListByVirtualMachine
3117 (esxVI_Context *ctx, esxVI_ObjectContent *virtualMachine,
3118 esxVI_TaskInfo **pendingTaskInfoList)
3119 {
3120 int result = -1;
3121 esxVI_String *propertyNameList = NULL;
3122 esxVI_ManagedObjectReference *recentTaskList = NULL;
3123 esxVI_ManagedObjectReference *recentTask = NULL;
3124 esxVI_DynamicProperty *dynamicProperty = NULL;
3125 esxVI_TaskInfo *taskInfo = NULL;
3126
3127 ESX_VI_CHECK_ARG_LIST(pendingTaskInfoList);
3128
3129 /* Get list of recent tasks */
3130 for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
3131 dynamicProperty = dynamicProperty->_next) {
3132 if (STREQ(dynamicProperty->name, "recentTask")) {
3133 if (esxVI_ManagedObjectReference_CastListFromAnyType
3134 (dynamicProperty->val, &recentTaskList) < 0) {
3135 goto cleanup;
3136 }
3137
3138 break;
3139 }
3140 }
3141
3142 /* Lookup task info for each task */
3143 for (recentTask = recentTaskList; recentTask;
3144 recentTask = recentTask->_next) {
3145 if (esxVI_LookupTaskInfoByTask(ctx, recentTask, &taskInfo) < 0)
3146 goto cleanup;
3147
3148 if (taskInfo->state == esxVI_TaskInfoState_Queued ||
3149 taskInfo->state == esxVI_TaskInfoState_Running) {
3150 if (esxVI_TaskInfo_AppendToList(pendingTaskInfoList,
3151 taskInfo) < 0) {
3152 goto cleanup;
3153 }
3154
3155 taskInfo = NULL;
3156 } else {
3157 esxVI_TaskInfo_Free(&taskInfo);
3158 }
3159 }
3160
3161 result = 0;
3162
3163 cleanup:
3164 if (result < 0)
3165 esxVI_TaskInfo_Free(pendingTaskInfoList);
3166
3167 esxVI_String_Free(&propertyNameList);
3168 esxVI_ManagedObjectReference_Free(&recentTaskList);
3169 esxVI_TaskInfo_Free(&taskInfo);
3170
3171 return result;
3172 }
3173
3174
3175
3176 int
esxVI_LookupAndHandleVirtualMachineQuestion(esxVI_Context * ctx,const unsigned char * uuid,esxVI_Occurrence occurrence,bool autoAnswer,bool * blocked)3177 esxVI_LookupAndHandleVirtualMachineQuestion(esxVI_Context *ctx,
3178 const unsigned char *uuid,
3179 esxVI_Occurrence occurrence,
3180 bool autoAnswer, bool *blocked)
3181 {
3182 int result = -1;
3183 esxVI_ObjectContent *virtualMachine = NULL;
3184 esxVI_String *propertyNameList = NULL;
3185 esxVI_VirtualMachineQuestionInfo *questionInfo = NULL;
3186
3187 if (esxVI_String_AppendValueToList(&propertyNameList,
3188 "runtime.question") < 0 ||
3189 esxVI_LookupVirtualMachineByUuid(ctx, uuid, propertyNameList,
3190 &virtualMachine, occurrence) < 0) {
3191 goto cleanup;
3192 }
3193
3194 if (virtualMachine) {
3195 if (esxVI_GetVirtualMachineQuestionInfo(virtualMachine,
3196 &questionInfo) < 0) {
3197 goto cleanup;
3198 }
3199
3200 if (questionInfo &&
3201 esxVI_HandleVirtualMachineQuestion(ctx, virtualMachine->obj,
3202 questionInfo, autoAnswer,
3203 blocked) < 0) {
3204 goto cleanup;
3205 }
3206 }
3207
3208 result = 0;
3209
3210 cleanup:
3211 esxVI_ObjectContent_Free(&virtualMachine);
3212 esxVI_String_Free(&propertyNameList);
3213 esxVI_VirtualMachineQuestionInfo_Free(&questionInfo);
3214
3215 return result;
3216 }
3217
3218
3219
3220 int
esxVI_LookupRootSnapshotTreeList(esxVI_Context * ctx,const unsigned char * virtualMachineUuid,esxVI_VirtualMachineSnapshotTree ** rootSnapshotTreeList)3221 esxVI_LookupRootSnapshotTreeList
3222 (esxVI_Context *ctx, const unsigned char *virtualMachineUuid,
3223 esxVI_VirtualMachineSnapshotTree **rootSnapshotTreeList)
3224 {
3225 int result = -1;
3226 esxVI_String *propertyNameList = NULL;
3227 esxVI_ObjectContent *virtualMachine = NULL;
3228 esxVI_DynamicProperty *dynamicProperty = NULL;
3229
3230 ESX_VI_CHECK_ARG_LIST(rootSnapshotTreeList);
3231
3232 if (esxVI_String_AppendValueToList(&propertyNameList,
3233 "snapshot.rootSnapshotList") < 0 ||
3234 esxVI_LookupVirtualMachineByUuid(ctx, virtualMachineUuid,
3235 propertyNameList, &virtualMachine,
3236 esxVI_Occurrence_RequiredItem) < 0) {
3237 goto cleanup;
3238 }
3239
3240 for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
3241 dynamicProperty = dynamicProperty->_next) {
3242 if (STREQ(dynamicProperty->name, "snapshot.rootSnapshotList")) {
3243 if (esxVI_VirtualMachineSnapshotTree_CastListFromAnyType
3244 (dynamicProperty->val, rootSnapshotTreeList) < 0) {
3245 goto cleanup;
3246 }
3247
3248 break;
3249 } else {
3250 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3251 }
3252 }
3253
3254 result = 0;
3255
3256 cleanup:
3257 if (result < 0)
3258 esxVI_VirtualMachineSnapshotTree_Free(rootSnapshotTreeList);
3259
3260 esxVI_String_Free(&propertyNameList);
3261 esxVI_ObjectContent_Free(&virtualMachine);
3262
3263 return result;
3264 }
3265
3266
3267
3268 int
esxVI_LookupCurrentSnapshotTree(esxVI_Context * ctx,const unsigned char * virtualMachineUuid,esxVI_VirtualMachineSnapshotTree ** currentSnapshotTree,esxVI_Occurrence occurrence)3269 esxVI_LookupCurrentSnapshotTree
3270 (esxVI_Context *ctx, const unsigned char *virtualMachineUuid,
3271 esxVI_VirtualMachineSnapshotTree **currentSnapshotTree,
3272 esxVI_Occurrence occurrence)
3273 {
3274 int result = -1;
3275 esxVI_String *propertyNameList = NULL;
3276 esxVI_ObjectContent *virtualMachine = NULL;
3277 esxVI_DynamicProperty *dynamicProperty = NULL;
3278 esxVI_ManagedObjectReference *currentSnapshot = NULL;
3279 esxVI_VirtualMachineSnapshotTree *rootSnapshotTreeList = NULL;
3280 esxVI_VirtualMachineSnapshotTree *snapshotTree = NULL;
3281
3282 ESX_VI_CHECK_ARG_LIST(currentSnapshotTree);
3283
3284 if (esxVI_String_AppendValueListToList(&propertyNameList,
3285 "snapshot.currentSnapshot\0"
3286 "snapshot.rootSnapshotList\0") < 0 ||
3287 esxVI_LookupVirtualMachineByUuid(ctx, virtualMachineUuid,
3288 propertyNameList, &virtualMachine,
3289 esxVI_Occurrence_RequiredItem) < 0) {
3290 goto cleanup;
3291 }
3292
3293 for (dynamicProperty = virtualMachine->propSet; dynamicProperty;
3294 dynamicProperty = dynamicProperty->_next) {
3295 if (STREQ(dynamicProperty->name, "snapshot.currentSnapshot")) {
3296 if (esxVI_ManagedObjectReference_CastFromAnyType
3297 (dynamicProperty->val, ¤tSnapshot) < 0) {
3298 goto cleanup;
3299 }
3300 } else if (STREQ(dynamicProperty->name, "snapshot.rootSnapshotList")) {
3301 if (esxVI_VirtualMachineSnapshotTree_CastListFromAnyType
3302 (dynamicProperty->val, &rootSnapshotTreeList) < 0) {
3303 goto cleanup;
3304 }
3305 } else {
3306 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3307 }
3308 }
3309
3310 if (!currentSnapshot) {
3311 if (occurrence == esxVI_Occurrence_OptionalItem) {
3312 result = 0;
3313
3314 goto cleanup;
3315 } else {
3316 virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
3317 _("Domain has no current snapshot"));
3318 goto cleanup;
3319 }
3320 }
3321
3322 if (!rootSnapshotTreeList) {
3323 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3324 _("Could not lookup root snapshot list"));
3325 goto cleanup;
3326 }
3327
3328 if (esxVI_GetSnapshotTreeBySnapshot(rootSnapshotTreeList, currentSnapshot,
3329 &snapshotTree) < 0 ||
3330 esxVI_VirtualMachineSnapshotTree_DeepCopy(currentSnapshotTree,
3331 snapshotTree) < 0) {
3332 goto cleanup;
3333 }
3334
3335 result = 0;
3336
3337 cleanup:
3338 esxVI_String_Free(&propertyNameList);
3339 esxVI_ObjectContent_Free(&virtualMachine);
3340 esxVI_ManagedObjectReference_Free(¤tSnapshot);
3341 esxVI_VirtualMachineSnapshotTree_Free(&rootSnapshotTreeList);
3342
3343 return result;
3344 }
3345
3346
3347
3348 int
esxVI_LookupFileInfoByDatastorePath(esxVI_Context * ctx,const char * datastorePath,bool lookupFolder,esxVI_FileInfo ** fileInfo,esxVI_Occurrence occurrence)3349 esxVI_LookupFileInfoByDatastorePath(esxVI_Context *ctx,
3350 const char *datastorePath,
3351 bool lookupFolder,
3352 esxVI_FileInfo **fileInfo,
3353 esxVI_Occurrence occurrence)
3354 {
3355 int result = -1;
3356 g_autofree char *datastoreName = NULL;
3357 g_autofree char *directoryName = NULL;
3358 g_autofree char *directoryAndFileName = NULL;
3359 g_autofree char *fileName = NULL;
3360 size_t length;
3361 g_autofree char *datastorePathWithoutFileName = NULL;
3362 esxVI_String *propertyNameList = NULL;
3363 esxVI_ObjectContent *datastore = NULL;
3364 esxVI_ManagedObjectReference *hostDatastoreBrowser = NULL;
3365 esxVI_HostDatastoreBrowserSearchSpec *searchSpec = NULL;
3366 esxVI_FolderFileQuery *folderFileQuery = NULL;
3367 esxVI_VmDiskFileQuery *vmDiskFileQuery = NULL;
3368 esxVI_IsoImageFileQuery *isoImageFileQuery = NULL;
3369 esxVI_FloppyImageFileQuery *floppyImageFileQuery = NULL;
3370 esxVI_ManagedObjectReference *task = NULL;
3371 esxVI_TaskInfoState taskInfoState;
3372 g_autofree char *taskInfoErrorMessage = NULL;
3373 esxVI_TaskInfo *taskInfo = NULL;
3374 esxVI_HostDatastoreBrowserSearchResults *searchResults = NULL;
3375
3376 ESX_VI_CHECK_ARG_LIST(fileInfo);
3377
3378 if (esxUtil_ParseDatastorePath(datastorePath, &datastoreName,
3379 &directoryName, &directoryAndFileName) < 0) {
3380 goto cleanup;
3381 }
3382
3383 if (STREQ(directoryName, directoryAndFileName)) {
3384 /*
3385 * The <path> part of the datastore path didn't contain a '/', assume
3386 * that the <path> part is actually the file name.
3387 */
3388 datastorePathWithoutFileName = g_strdup_printf("[%s]", datastoreName);
3389
3390 fileName = g_strdup(directoryAndFileName);
3391 } else {
3392 datastorePathWithoutFileName = g_strdup_printf("[%s] %s", datastoreName,
3393 directoryName);
3394
3395 length = strlen(directoryName);
3396
3397 if (directoryAndFileName[length] != '/' ||
3398 directoryAndFileName[length + 1] == '\0') {
3399 virReportError(VIR_ERR_INTERNAL_ERROR,
3400 _("Datastore path '%s' doesn't reference a file"),
3401 datastorePath);
3402 goto cleanup;
3403 }
3404
3405 fileName = g_strdup(directoryAndFileName + length + 1);
3406 }
3407
3408 /* Lookup HostDatastoreBrowser */
3409 if (esxVI_String_AppendValueToList(&propertyNameList, "browser") < 0 ||
3410 esxVI_LookupDatastoreByName(ctx, datastoreName, propertyNameList,
3411 &datastore,
3412 esxVI_Occurrence_RequiredItem) < 0 ||
3413 esxVI_GetManagedObjectReference(datastore, "browser",
3414 &hostDatastoreBrowser,
3415 esxVI_Occurrence_RequiredItem) < 0) {
3416 goto cleanup;
3417 }
3418
3419 /* Build HostDatastoreBrowserSearchSpec */
3420 if (esxVI_HostDatastoreBrowserSearchSpec_Alloc(&searchSpec) < 0 ||
3421 esxVI_FileQueryFlags_Alloc(&searchSpec->details) < 0) {
3422 goto cleanup;
3423 }
3424
3425 searchSpec->details->fileType = esxVI_Boolean_True;
3426 searchSpec->details->fileSize = esxVI_Boolean_True;
3427 searchSpec->details->modification = esxVI_Boolean_False;
3428
3429 if (lookupFolder) {
3430 if (esxVI_FolderFileQuery_Alloc(&folderFileQuery) < 0 ||
3431 esxVI_FileQuery_AppendToList
3432 (&searchSpec->query,
3433 esxVI_FileQuery_DynamicCast(folderFileQuery)) < 0) {
3434 goto cleanup;
3435 }
3436 folderFileQuery = NULL;
3437 } else {
3438 if (esxVI_VmDiskFileQuery_Alloc(&vmDiskFileQuery) < 0 ||
3439 esxVI_VmDiskFileQueryFlags_Alloc(&vmDiskFileQuery->details) < 0 ||
3440 esxVI_FileQuery_AppendToList
3441 (&searchSpec->query,
3442 esxVI_FileQuery_DynamicCast(vmDiskFileQuery)) < 0) {
3443 goto cleanup;
3444 }
3445
3446 vmDiskFileQuery->details->diskType = esxVI_Boolean_False;
3447 vmDiskFileQuery->details->capacityKb = esxVI_Boolean_True;
3448 vmDiskFileQuery->details->hardwareVersion = esxVI_Boolean_False;
3449 vmDiskFileQuery->details->controllerType = esxVI_Boolean_True;
3450 vmDiskFileQuery->details->diskExtents = esxVI_Boolean_False;
3451 vmDiskFileQuery = NULL;
3452
3453 if (esxVI_IsoImageFileQuery_Alloc(&isoImageFileQuery) < 0 ||
3454 esxVI_FileQuery_AppendToList
3455 (&searchSpec->query,
3456 esxVI_FileQuery_DynamicCast(isoImageFileQuery)) < 0) {
3457 goto cleanup;
3458 }
3459 isoImageFileQuery = NULL;
3460
3461 if (esxVI_FloppyImageFileQuery_Alloc(&floppyImageFileQuery) < 0 ||
3462 esxVI_FileQuery_AppendToList
3463 (&searchSpec->query,
3464 esxVI_FileQuery_DynamicCast(floppyImageFileQuery)) < 0) {
3465 goto cleanup;
3466 }
3467 floppyImageFileQuery = NULL;
3468 }
3469
3470 if (esxVI_String_Alloc(&searchSpec->matchPattern) < 0)
3471 goto cleanup;
3472
3473 searchSpec->matchPattern->value = fileName;
3474
3475 /* Search datastore for file */
3476 if (esxVI_SearchDatastore_Task(ctx, hostDatastoreBrowser,
3477 datastorePathWithoutFileName, searchSpec,
3478 &task) < 0 ||
3479 esxVI_WaitForTaskCompletion(ctx, task, NULL, esxVI_Occurrence_None,
3480 false, &taskInfoState,
3481 &taskInfoErrorMessage) < 0) {
3482 goto cleanup;
3483 }
3484
3485 if (taskInfoState != esxVI_TaskInfoState_Success) {
3486 virReportError(VIR_ERR_INTERNAL_ERROR,
3487 _("Could not search in datastore '%s': %s"),
3488 datastoreName, taskInfoErrorMessage);
3489 goto cleanup;
3490 }
3491
3492 if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo) < 0 ||
3493 esxVI_HostDatastoreBrowserSearchResults_CastFromAnyType
3494 (taskInfo->result, &searchResults) < 0) {
3495 goto cleanup;
3496 }
3497
3498 /* Interpret search result */
3499 if (!searchResults->file) {
3500 if (occurrence == esxVI_Occurrence_OptionalItem) {
3501 result = 0;
3502
3503 goto cleanup;
3504 } else {
3505 virReportError(VIR_ERR_NO_STORAGE_VOL,
3506 _("No storage volume with key or path '%s'"),
3507 datastorePath);
3508 goto cleanup;
3509 }
3510 }
3511
3512 *fileInfo = g_steal_pointer(&searchResults->file);
3513
3514 result = 0;
3515
3516 cleanup:
3517 /* Don't double free fileName */
3518 if (searchSpec && searchSpec->matchPattern)
3519 searchSpec->matchPattern->value = NULL;
3520
3521 esxVI_String_Free(&propertyNameList);
3522 esxVI_ObjectContent_Free(&datastore);
3523 esxVI_ManagedObjectReference_Free(&hostDatastoreBrowser);
3524 esxVI_HostDatastoreBrowserSearchSpec_Free(&searchSpec);
3525 esxVI_ManagedObjectReference_Free(&task);
3526 esxVI_TaskInfo_Free(&taskInfo);
3527 esxVI_HostDatastoreBrowserSearchResults_Free(&searchResults);
3528 esxVI_FolderFileQuery_Free(&folderFileQuery);
3529 esxVI_VmDiskFileQuery_Free(&vmDiskFileQuery);
3530 esxVI_IsoImageFileQuery_Free(&isoImageFileQuery);
3531 esxVI_FloppyImageFileQuery_Free(&floppyImageFileQuery);
3532
3533 return result;
3534 }
3535
3536
3537
3538 int
esxVI_LookupDatastoreContentByDatastoreName(esxVI_Context * ctx,const char * datastoreName,esxVI_HostDatastoreBrowserSearchResults ** searchResultsList)3539 esxVI_LookupDatastoreContentByDatastoreName
3540 (esxVI_Context *ctx, const char *datastoreName,
3541 esxVI_HostDatastoreBrowserSearchResults **searchResultsList)
3542 {
3543 int result = -1;
3544 esxVI_String *propertyNameList = NULL;
3545 esxVI_ObjectContent *datastore = NULL;
3546 esxVI_ManagedObjectReference *hostDatastoreBrowser = NULL;
3547 esxVI_HostDatastoreBrowserSearchSpec *searchSpec = NULL;
3548 esxVI_VmDiskFileQuery *vmDiskFileQuery = NULL;
3549 esxVI_IsoImageFileQuery *isoImageFileQuery = NULL;
3550 esxVI_FloppyImageFileQuery *floppyImageFileQuery = NULL;
3551 g_autofree char *datastorePath = NULL;
3552 esxVI_ManagedObjectReference *task = NULL;
3553 esxVI_TaskInfoState taskInfoState;
3554 g_autofree char *taskInfoErrorMessage = NULL;
3555 esxVI_TaskInfo *taskInfo = NULL;
3556
3557 ESX_VI_CHECK_ARG_LIST(searchResultsList);
3558
3559 /* Lookup Datastore and HostDatastoreBrowser */
3560 if (esxVI_String_AppendValueToList(&propertyNameList, "browser") < 0 ||
3561 esxVI_LookupDatastoreByName(ctx, datastoreName, propertyNameList,
3562 &datastore,
3563 esxVI_Occurrence_RequiredItem) < 0 ||
3564 esxVI_GetManagedObjectReference(datastore, "browser",
3565 &hostDatastoreBrowser,
3566 esxVI_Occurrence_RequiredItem) < 0) {
3567 goto cleanup;
3568 }
3569
3570 /* Build HostDatastoreBrowserSearchSpec */
3571 if (esxVI_HostDatastoreBrowserSearchSpec_Alloc(&searchSpec) < 0 ||
3572 esxVI_FileQueryFlags_Alloc(&searchSpec->details) < 0) {
3573 goto cleanup;
3574 }
3575
3576 searchSpec->details->fileType = esxVI_Boolean_True;
3577 searchSpec->details->fileSize = esxVI_Boolean_True;
3578 searchSpec->details->modification = esxVI_Boolean_False;
3579
3580 if (esxVI_VmDiskFileQuery_Alloc(&vmDiskFileQuery) < 0 ||
3581 esxVI_VmDiskFileQueryFlags_Alloc(&vmDiskFileQuery->details) < 0 ||
3582 esxVI_FileQuery_AppendToList
3583 (&searchSpec->query,
3584 esxVI_FileQuery_DynamicCast(vmDiskFileQuery)) < 0) {
3585 goto cleanup;
3586 }
3587
3588 vmDiskFileQuery->details->diskType = esxVI_Boolean_False;
3589 vmDiskFileQuery->details->capacityKb = esxVI_Boolean_True;
3590 vmDiskFileQuery->details->hardwareVersion = esxVI_Boolean_False;
3591 vmDiskFileQuery->details->controllerType = esxVI_Boolean_True;
3592 vmDiskFileQuery->details->diskExtents = esxVI_Boolean_False;
3593 vmDiskFileQuery = NULL;
3594
3595 if (esxVI_IsoImageFileQuery_Alloc(&isoImageFileQuery) < 0 ||
3596 esxVI_FileQuery_AppendToList
3597 (&searchSpec->query,
3598 esxVI_FileQuery_DynamicCast(isoImageFileQuery)) < 0) {
3599 goto cleanup;
3600 }
3601 isoImageFileQuery = NULL;
3602
3603 if (esxVI_FloppyImageFileQuery_Alloc(&floppyImageFileQuery) < 0 ||
3604 esxVI_FileQuery_AppendToList
3605 (&searchSpec->query,
3606 esxVI_FileQuery_DynamicCast(floppyImageFileQuery)) < 0) {
3607 goto cleanup;
3608 }
3609 floppyImageFileQuery = NULL;
3610
3611 /* Search datastore for files */
3612 datastorePath = g_strdup_printf("[%s]", datastoreName);
3613
3614 if (esxVI_SearchDatastoreSubFolders_Task(ctx, hostDatastoreBrowser,
3615 datastorePath, searchSpec,
3616 &task) < 0 ||
3617 esxVI_WaitForTaskCompletion(ctx, task, NULL, esxVI_Occurrence_None,
3618 false, &taskInfoState,
3619 &taskInfoErrorMessage) < 0) {
3620 goto cleanup;
3621 }
3622
3623 if (taskInfoState != esxVI_TaskInfoState_Success) {
3624 virReportError(VIR_ERR_INTERNAL_ERROR,
3625 _("Could not search in datastore '%s': %s"),
3626 datastoreName, taskInfoErrorMessage);
3627 goto cleanup;
3628 }
3629
3630 if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo) < 0 ||
3631 esxVI_HostDatastoreBrowserSearchResults_CastListFromAnyType
3632 (taskInfo->result, searchResultsList) < 0) {
3633 goto cleanup;
3634 }
3635
3636 result = 0;
3637
3638 cleanup:
3639 esxVI_String_Free(&propertyNameList);
3640 esxVI_ObjectContent_Free(&datastore);
3641 esxVI_ManagedObjectReference_Free(&hostDatastoreBrowser);
3642 esxVI_HostDatastoreBrowserSearchSpec_Free(&searchSpec);
3643 esxVI_ManagedObjectReference_Free(&task);
3644 esxVI_TaskInfo_Free(&taskInfo);
3645 esxVI_VmDiskFileQuery_Free(&vmDiskFileQuery);
3646 esxVI_IsoImageFileQuery_Free(&isoImageFileQuery);
3647 esxVI_FloppyImageFileQuery_Free(&floppyImageFileQuery);
3648
3649 return result;
3650 }
3651
3652
3653
3654 int
esxVI_LookupStorageVolumeKeyByDatastorePath(esxVI_Context * ctx,const char * datastorePath,char ** key)3655 esxVI_LookupStorageVolumeKeyByDatastorePath(esxVI_Context *ctx,
3656 const char *datastorePath,
3657 char **key)
3658 {
3659 int result = -1;
3660 esxVI_FileInfo *fileInfo = NULL;
3661 g_autofree char *uuid_string = NULL;
3662
3663 ESX_VI_CHECK_ARG_LIST(key);
3664
3665 if (ctx->hasQueryVirtualDiskUuid) {
3666 if (esxVI_LookupFileInfoByDatastorePath
3667 (ctx, datastorePath, false, &fileInfo,
3668 esxVI_Occurrence_RequiredItem) < 0) {
3669 goto cleanup;
3670 }
3671
3672 if (esxVI_VmDiskFileInfo_DynamicCast(fileInfo)) {
3673 /* VirtualDisks have a UUID, use it as key */
3674 if (esxVI_QueryVirtualDiskUuid(ctx, datastorePath,
3675 ctx->datacenter->_reference,
3676 &uuid_string) < 0) {
3677 goto cleanup;
3678 }
3679
3680 *key = g_new0(char, VIR_UUID_STRING_BUFLEN);
3681
3682 if (esxUtil_ReformatUuid(uuid_string, *key) < 0)
3683 goto cleanup;
3684 }
3685 }
3686
3687 if (!(*key)) {
3688 /* Other files don't have a UUID, fall back to the path as key */
3689 *key = g_strdup(datastorePath);
3690 }
3691
3692 result = 0;
3693
3694 cleanup:
3695 esxVI_FileInfo_Free(&fileInfo);
3696 return result;
3697 }
3698
3699
3700
3701 int
esxVI_LookupAutoStartDefaults(esxVI_Context * ctx,esxVI_AutoStartDefaults ** defaults)3702 esxVI_LookupAutoStartDefaults(esxVI_Context *ctx,
3703 esxVI_AutoStartDefaults **defaults)
3704 {
3705 int result = -1;
3706 esxVI_String *propertyNameList = NULL;
3707 esxVI_ObjectContent *hostAutoStartManager = NULL;
3708 esxVI_DynamicProperty *dynamicProperty = NULL;
3709
3710 ESX_VI_CHECK_ARG_LIST(defaults);
3711
3712 /*
3713 * Lookup HostAutoStartManagerConfig from the HostAutoStartManager because
3714 * for some reason this is much faster than looking up the same info from
3715 * the HostSystem config.
3716 */
3717 if (esxVI_String_AppendValueToList(&propertyNameList,
3718 "config.defaults") < 0 ||
3719 esxVI_LookupObjectContentByType
3720 (ctx, ctx->hostSystem->configManager->autoStartManager,
3721 "HostAutoStartManager", propertyNameList,
3722 &hostAutoStartManager, esxVI_Occurrence_RequiredItem) < 0) {
3723 goto cleanup;
3724 }
3725
3726 for (dynamicProperty = hostAutoStartManager->propSet;
3727 dynamicProperty; dynamicProperty = dynamicProperty->_next) {
3728 if (STREQ(dynamicProperty->name, "config.defaults")) {
3729 if (esxVI_AutoStartDefaults_CastFromAnyType(dynamicProperty->val,
3730 defaults) < 0) {
3731 goto cleanup;
3732 }
3733
3734 break;
3735 }
3736 }
3737
3738 if (!(*defaults)) {
3739 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3740 _("Could not retrieve the AutoStartDefaults object"));
3741 goto cleanup;
3742 }
3743
3744 result = 0;
3745
3746 cleanup:
3747 esxVI_String_Free(&propertyNameList);
3748 esxVI_ObjectContent_Free(&hostAutoStartManager);
3749
3750 return result;
3751 }
3752
3753
3754
3755 int
esxVI_LookupAutoStartPowerInfoList(esxVI_Context * ctx,esxVI_AutoStartPowerInfo ** powerInfoList)3756 esxVI_LookupAutoStartPowerInfoList(esxVI_Context *ctx,
3757 esxVI_AutoStartPowerInfo **powerInfoList)
3758 {
3759 int result = -1;
3760 esxVI_String *propertyNameList = NULL;
3761 esxVI_ObjectContent *hostAutoStartManager = NULL;
3762 esxVI_DynamicProperty *dynamicProperty = NULL;
3763
3764 ESX_VI_CHECK_ARG_LIST(powerInfoList);
3765
3766 /*
3767 * Lookup HostAutoStartManagerConfig from the HostAutoStartManager because
3768 * for some reason this is much faster than looking up the same info from
3769 * the HostSystem config.
3770 */
3771 if (esxVI_String_AppendValueToList(&propertyNameList,
3772 "config.powerInfo") < 0 ||
3773 esxVI_LookupObjectContentByType
3774 (ctx, ctx->hostSystem->configManager->autoStartManager,
3775 "HostAutoStartManager", propertyNameList,
3776 &hostAutoStartManager, esxVI_Occurrence_RequiredItem) < 0) {
3777 goto cleanup;
3778 }
3779
3780 for (dynamicProperty = hostAutoStartManager->propSet;
3781 dynamicProperty; dynamicProperty = dynamicProperty->_next) {
3782 if (STREQ(dynamicProperty->name, "config.powerInfo")) {
3783 if (esxVI_AutoStartPowerInfo_CastListFromAnyType
3784 (dynamicProperty->val, powerInfoList) < 0) {
3785 goto cleanup;
3786 }
3787
3788 break;
3789 }
3790 }
3791
3792 result = 0;
3793
3794 cleanup:
3795 esxVI_String_Free(&propertyNameList);
3796 esxVI_ObjectContent_Free(&hostAutoStartManager);
3797
3798 return result;
3799 }
3800
3801
3802
3803 int
esxVI_LookupPhysicalNicList(esxVI_Context * ctx,esxVI_PhysicalNic ** physicalNicList)3804 esxVI_LookupPhysicalNicList(esxVI_Context *ctx,
3805 esxVI_PhysicalNic **physicalNicList)
3806 {
3807 int result = -1;
3808 esxVI_String *propertyNameList = NULL;
3809 esxVI_ObjectContent *hostSystem = NULL;
3810 esxVI_DynamicProperty *dynamicProperty = NULL;
3811
3812 ESX_VI_CHECK_ARG_LIST(physicalNicList);
3813
3814 if (esxVI_String_AppendValueToList(&propertyNameList,
3815 "config.network.pnic") < 0 ||
3816 esxVI_LookupHostSystemProperties(ctx, propertyNameList,
3817 &hostSystem) < 0) {
3818 goto cleanup;
3819 }
3820
3821 for (dynamicProperty = hostSystem->propSet; dynamicProperty;
3822 dynamicProperty = dynamicProperty->_next) {
3823 if (STREQ(dynamicProperty->name, "config.network.pnic")) {
3824 if (esxVI_PhysicalNic_CastListFromAnyType(dynamicProperty->val,
3825 physicalNicList) < 0) {
3826 goto cleanup;
3827 }
3828 } else {
3829 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3830 }
3831 }
3832
3833 result = 0;
3834
3835 cleanup:
3836 esxVI_String_Free(&propertyNameList);
3837 esxVI_ObjectContent_Free(&hostSystem);
3838
3839 return result;
3840 }
3841
3842
3843
3844 int
esxVI_LookupPhysicalNicByName(esxVI_Context * ctx,const char * name,esxVI_PhysicalNic ** physicalNic,esxVI_Occurrence occurrence)3845 esxVI_LookupPhysicalNicByName(esxVI_Context *ctx, const char *name,
3846 esxVI_PhysicalNic **physicalNic,
3847 esxVI_Occurrence occurrence)
3848 {
3849 int result = -1;
3850 esxVI_PhysicalNic *physicalNicList = NULL;
3851 esxVI_PhysicalNic *candidate = NULL;
3852
3853 ESX_VI_CHECK_ARG_LIST(physicalNic);
3854
3855 if (esxVI_LookupPhysicalNicList(ctx, &physicalNicList) < 0)
3856 goto cleanup;
3857
3858 /* Search for a matching physical NIC */
3859 for (candidate = physicalNicList; candidate;
3860 candidate = candidate->_next) {
3861 if (STRCASEEQ(candidate->device, name)) {
3862 if (esxVI_PhysicalNic_DeepCopy(physicalNic, candidate) < 0)
3863 goto cleanup;
3864
3865 /* Found physical NIC with matching name */
3866 result = 0;
3867
3868 goto cleanup;
3869 }
3870 }
3871
3872 if (!(*physicalNic) && occurrence != esxVI_Occurrence_OptionalItem) {
3873 virReportError(VIR_ERR_NO_INTERFACE,
3874 _("Could not find physical NIC with name '%s'"), name);
3875 goto cleanup;
3876 }
3877
3878 result = 0;
3879
3880 cleanup:
3881 esxVI_PhysicalNic_Free(&physicalNicList);
3882
3883 return result;
3884 }
3885
3886
3887
3888 int
esxVI_LookupPhysicalNicByMACAddress(esxVI_Context * ctx,const char * mac,esxVI_PhysicalNic ** physicalNic,esxVI_Occurrence occurrence)3889 esxVI_LookupPhysicalNicByMACAddress(esxVI_Context *ctx, const char *mac,
3890 esxVI_PhysicalNic **physicalNic,
3891 esxVI_Occurrence occurrence)
3892 {
3893 int result = -1;
3894 esxVI_PhysicalNic *physicalNicList = NULL;
3895 esxVI_PhysicalNic *candidate = NULL;
3896
3897 ESX_VI_CHECK_ARG_LIST(physicalNic);
3898
3899 if (esxVI_LookupPhysicalNicList(ctx, &physicalNicList) < 0)
3900 goto cleanup;
3901
3902 /* Search for a matching physical NIC */
3903 for (candidate = physicalNicList; candidate;
3904 candidate = candidate->_next) {
3905 if (STRCASEEQ(candidate->mac, mac)) {
3906 if (esxVI_PhysicalNic_DeepCopy(physicalNic, candidate) < 0)
3907 goto cleanup;
3908
3909 /* Found physical NIC with matching MAC address */
3910 result = 0;
3911
3912 goto cleanup;
3913 }
3914 }
3915
3916 if (!(*physicalNic) && occurrence != esxVI_Occurrence_OptionalItem) {
3917 virReportError(VIR_ERR_NO_INTERFACE,
3918 _("Could not find physical NIC with MAC address '%s'"), mac);
3919 goto cleanup;
3920 }
3921
3922 result = 0;
3923
3924 cleanup:
3925 esxVI_PhysicalNic_Free(&physicalNicList);
3926
3927 return result;
3928 }
3929
3930
3931
3932 int
esxVI_LookupHostVirtualSwitchList(esxVI_Context * ctx,esxVI_HostVirtualSwitch ** hostVirtualSwitchList)3933 esxVI_LookupHostVirtualSwitchList(esxVI_Context *ctx,
3934 esxVI_HostVirtualSwitch **hostVirtualSwitchList)
3935 {
3936 int result = -1;
3937 esxVI_String *propertyNameList = NULL;
3938 esxVI_ObjectContent *hostSystem = NULL;
3939 esxVI_DynamicProperty *dynamicProperty = NULL;
3940
3941 ESX_VI_CHECK_ARG_LIST(hostVirtualSwitchList);
3942
3943 if (esxVI_String_AppendValueToList(&propertyNameList,
3944 "config.network.vswitch") < 0 ||
3945 esxVI_LookupHostSystemProperties(ctx, propertyNameList,
3946 &hostSystem) < 0) {
3947 goto cleanup;
3948 }
3949
3950 for (dynamicProperty = hostSystem->propSet; dynamicProperty;
3951 dynamicProperty = dynamicProperty->_next) {
3952 if (STREQ(dynamicProperty->name, "config.network.vswitch")) {
3953 if (esxVI_HostVirtualSwitch_CastListFromAnyType
3954 (dynamicProperty->val, hostVirtualSwitchList) < 0) {
3955 goto cleanup;
3956 }
3957 } else {
3958 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
3959 }
3960 }
3961
3962 result = 0;
3963
3964 cleanup:
3965 esxVI_String_Free(&propertyNameList);
3966 esxVI_ObjectContent_Free(&hostSystem);
3967
3968 return result;
3969 }
3970
3971
3972
3973 int
esxVI_LookupHostVirtualSwitchByName(esxVI_Context * ctx,const char * name,esxVI_HostVirtualSwitch ** hostVirtualSwitch,esxVI_Occurrence occurrence)3974 esxVI_LookupHostVirtualSwitchByName(esxVI_Context *ctx, const char *name,
3975 esxVI_HostVirtualSwitch **hostVirtualSwitch,
3976 esxVI_Occurrence occurrence)
3977 {
3978 int result = -1;
3979 esxVI_HostVirtualSwitch *hostVirtualSwitchList = NULL;
3980 esxVI_HostVirtualSwitch *candidate = NULL;
3981
3982 ESX_VI_CHECK_ARG_LIST(hostVirtualSwitch);
3983
3984 if (esxVI_LookupHostVirtualSwitchList(ctx, &hostVirtualSwitchList) < 0)
3985 goto cleanup;
3986
3987 /* Search for a matching HostVirtualSwitch */
3988 for (candidate = hostVirtualSwitchList; candidate;
3989 candidate = candidate->_next) {
3990 if (STREQ(candidate->name, name)) {
3991 if (esxVI_HostVirtualSwitch_DeepCopy(hostVirtualSwitch,
3992 candidate) < 0) {
3993 goto cleanup;
3994 }
3995
3996 /* Found HostVirtualSwitch with matching name */
3997 result = 0;
3998
3999 goto cleanup;
4000 }
4001 }
4002
4003 if (!(*hostVirtualSwitch) &&
4004 occurrence != esxVI_Occurrence_OptionalItem) {
4005 virReportError(VIR_ERR_NO_NETWORK,
4006 _("Could not find HostVirtualSwitch with name '%s'"),
4007 name);
4008 goto cleanup;
4009 }
4010
4011 result = 0;
4012
4013 cleanup:
4014 esxVI_HostVirtualSwitch_Free(&hostVirtualSwitchList);
4015
4016 return result;
4017 }
4018
4019
4020
4021 int
esxVI_LookupHostPortGroupList(esxVI_Context * ctx,esxVI_HostPortGroup ** hostPortGroupList)4022 esxVI_LookupHostPortGroupList(esxVI_Context *ctx,
4023 esxVI_HostPortGroup **hostPortGroupList)
4024 {
4025 int result = -1;
4026 esxVI_String *propertyNameList = NULL;
4027 esxVI_ObjectContent *hostSystem = NULL;
4028 esxVI_DynamicProperty *dynamicProperty = NULL;
4029
4030 ESX_VI_CHECK_ARG_LIST(hostPortGroupList);
4031
4032 if (esxVI_String_AppendValueToList(&propertyNameList,
4033 "config.network.portgroup") < 0 ||
4034 esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4035 &hostSystem) < 0) {
4036 goto cleanup;
4037 }
4038
4039 for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4040 dynamicProperty = dynamicProperty->_next) {
4041 if (STREQ(dynamicProperty->name, "config.network.portgroup")) {
4042 if (esxVI_HostPortGroup_CastListFromAnyType
4043 (dynamicProperty->val, hostPortGroupList) < 0) {
4044 goto cleanup;
4045 }
4046
4047 break;
4048 } else {
4049 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4050 }
4051 }
4052
4053 result = 0;
4054
4055 cleanup:
4056 esxVI_String_Free(&propertyNameList);
4057 esxVI_ObjectContent_Free(&hostSystem);
4058
4059 return result;
4060 }
4061
4062
4063
4064 int
esxVI_LookupNetworkList(esxVI_Context * ctx,esxVI_String * propertyNameList,esxVI_ObjectContent ** networkList)4065 esxVI_LookupNetworkList(esxVI_Context *ctx, esxVI_String *propertyNameList,
4066 esxVI_ObjectContent **networkList)
4067 {
4068 return esxVI_LookupObjectContentByType(ctx, ctx->datacenter->_reference,
4069 "Network", propertyNameList,
4070 networkList,
4071 esxVI_Occurrence_OptionalList);
4072 }
4073
4074
4075
4076 int
esxVI_HandleVirtualMachineQuestion(esxVI_Context * ctx,esxVI_ManagedObjectReference * virtualMachine,esxVI_VirtualMachineQuestionInfo * questionInfo,bool autoAnswer,bool * blocked)4077 esxVI_HandleVirtualMachineQuestion
4078 (esxVI_Context *ctx, esxVI_ManagedObjectReference *virtualMachine,
4079 esxVI_VirtualMachineQuestionInfo *questionInfo, bool autoAnswer,
4080 bool *blocked)
4081 {
4082 esxVI_ElementDescription *elementDescription = NULL;
4083 g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
4084 esxVI_ElementDescription *answerChoice = NULL;
4085 int answerIndex = 0;
4086 g_autofree char *possibleAnswers = NULL;
4087
4088 if (!blocked) {
4089 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
4090 return -1;
4091 }
4092
4093 *blocked = false;
4094
4095 if (questionInfo->choice->choiceInfo) {
4096 for (elementDescription = questionInfo->choice->choiceInfo;
4097 elementDescription;
4098 elementDescription = elementDescription->_next) {
4099 virBufferAsprintf(&buffer, "'%s'", elementDescription->label);
4100
4101 if (elementDescription->_next)
4102 virBufferAddLit(&buffer, ", ");
4103
4104 if (!answerChoice &&
4105 questionInfo->choice->defaultIndex &&
4106 questionInfo->choice->defaultIndex->value == answerIndex) {
4107 answerChoice = elementDescription;
4108 }
4109
4110 ++answerIndex;
4111 }
4112
4113 possibleAnswers = virBufferContentAndReset(&buffer);
4114 }
4115
4116 if (autoAnswer) {
4117 if (!possibleAnswers) {
4118 virReportError(VIR_ERR_INTERNAL_ERROR,
4119 _("Pending question blocks virtual machine execution, "
4120 "question is '%s', no possible answers"),
4121 questionInfo->text);
4122
4123 *blocked = true;
4124 return -1;
4125 } else if (!answerChoice) {
4126 virReportError(VIR_ERR_INTERNAL_ERROR,
4127 _("Pending question blocks virtual machine execution, "
4128 "question is '%s', possible answers are %s, but no "
4129 "default answer is specified"), questionInfo->text,
4130 possibleAnswers);
4131
4132 *blocked = true;
4133 return -1;
4134 }
4135
4136 VIR_INFO("Pending question blocks virtual machine execution, "
4137 "question is '%s', possible answers are %s, responding "
4138 "with default answer '%s'", questionInfo->text,
4139 possibleAnswers, answerChoice->label);
4140
4141 if (esxVI_AnswerVM(ctx, virtualMachine, questionInfo->id,
4142 answerChoice->key) < 0) {
4143 return -1;
4144 }
4145 } else {
4146 if (possibleAnswers) {
4147 virReportError(VIR_ERR_INTERNAL_ERROR,
4148 _("Pending question blocks virtual machine execution, "
4149 "question is '%s', possible answers are %s"),
4150 questionInfo->text, possibleAnswers);
4151 } else {
4152 virReportError(VIR_ERR_INTERNAL_ERROR,
4153 _("Pending question blocks virtual machine execution, "
4154 "question is '%s', no possible answers"),
4155 questionInfo->text);
4156 }
4157
4158 *blocked = true;
4159 return -1;
4160 }
4161
4162 return 0;
4163
4164 }
4165
4166
4167
4168 int
esxVI_WaitForTaskCompletion(esxVI_Context * ctx,esxVI_ManagedObjectReference * task,const unsigned char * virtualMachineUuid,esxVI_Occurrence virtualMachineOccurrence,bool autoAnswer,esxVI_TaskInfoState * finalState,char ** errorMessage)4169 esxVI_WaitForTaskCompletion(esxVI_Context *ctx,
4170 esxVI_ManagedObjectReference *task,
4171 const unsigned char *virtualMachineUuid,
4172 esxVI_Occurrence virtualMachineOccurrence,
4173 bool autoAnswer, esxVI_TaskInfoState *finalState,
4174 char **errorMessage)
4175 {
4176 int result = -1;
4177 esxVI_ObjectSpec *objectSpec = NULL;
4178 bool objectSpec_isAppended = false;
4179 esxVI_PropertySpec *propertySpec = NULL;
4180 bool propertySpec_isAppended = false;
4181 esxVI_PropertyFilterSpec *propertyFilterSpec = NULL;
4182 esxVI_ManagedObjectReference *propertyFilter = NULL;
4183 char *version = NULL;
4184 esxVI_UpdateSet *updateSet = NULL;
4185 esxVI_PropertyFilterUpdate *propertyFilterUpdate = NULL;
4186 esxVI_ObjectUpdate *objectUpdate = NULL;
4187 esxVI_PropertyChange *propertyChange = NULL;
4188 esxVI_AnyType *propertyValue = NULL;
4189 esxVI_TaskInfoState state = esxVI_TaskInfoState_Undefined;
4190 bool blocked;
4191 esxVI_TaskInfo *taskInfo = NULL;
4192
4193 ESX_VI_CHECK_ARG_LIST(errorMessage);
4194
4195 version = g_strdup("");
4196
4197 if (esxVI_ObjectSpec_Alloc(&objectSpec) < 0)
4198 goto cleanup;
4199
4200 objectSpec->obj = task;
4201 objectSpec->skip = esxVI_Boolean_False;
4202
4203 if (esxVI_PropertySpec_Alloc(&propertySpec) < 0)
4204 goto cleanup;
4205
4206 propertySpec->type = task->type;
4207
4208 if (esxVI_String_AppendValueToList(&propertySpec->pathSet,
4209 "info.state") < 0 ||
4210 esxVI_PropertyFilterSpec_Alloc(&propertyFilterSpec) < 0 ||
4211 esxVI_PropertySpec_AppendToList(&propertyFilterSpec->propSet,
4212 propertySpec) < 0) {
4213 goto cleanup;
4214 }
4215
4216 propertySpec_isAppended = true;
4217
4218 if (esxVI_ObjectSpec_AppendToList(&propertyFilterSpec->objectSet,
4219 objectSpec) < 0) {
4220 goto cleanup;
4221 }
4222
4223 objectSpec_isAppended = true;
4224
4225 if (esxVI_CreateFilter(ctx, propertyFilterSpec, esxVI_Boolean_True,
4226 &propertyFilter) < 0) {
4227 goto cleanup;
4228 }
4229
4230 while (state != esxVI_TaskInfoState_Success &&
4231 state != esxVI_TaskInfoState_Error) {
4232 esxVI_UpdateSet_Free(&updateSet);
4233
4234 if (virtualMachineUuid) {
4235 if (esxVI_LookupAndHandleVirtualMachineQuestion
4236 (ctx, virtualMachineUuid, virtualMachineOccurrence,
4237 autoAnswer, &blocked) < 0) {
4238 /*
4239 * FIXME: Disable error reporting here, so possible errors from
4240 * esxVI_LookupTaskInfoByTask() and esxVI_CancelTask()
4241 * don't overwrite the actual error
4242 */
4243 if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo))
4244 goto cleanup;
4245
4246 if (taskInfo->cancelable == esxVI_Boolean_True) {
4247 if (esxVI_CancelTask(ctx, task) < 0 && blocked) {
4248 VIR_ERROR(_("Cancelable task is blocked by an "
4249 "unanswered question but cancellation "
4250 "failed"));
4251 }
4252 } else if (blocked) {
4253 VIR_ERROR(_("Non-cancelable task is blocked by an "
4254 "unanswered question"));
4255 }
4256
4257 /* FIXME: Enable error reporting here again */
4258
4259 goto cleanup;
4260 }
4261 }
4262
4263 if (esxVI_WaitForUpdates(ctx, version, &updateSet) < 0)
4264 goto cleanup;
4265
4266 g_free(version);
4267 version = g_strdup(updateSet->version);
4268
4269 if (!updateSet->filterSet)
4270 continue;
4271
4272 for (propertyFilterUpdate = updateSet->filterSet;
4273 propertyFilterUpdate;
4274 propertyFilterUpdate = propertyFilterUpdate->_next) {
4275 for (objectUpdate = propertyFilterUpdate->objectSet;
4276 objectUpdate; objectUpdate = objectUpdate->_next) {
4277 for (propertyChange = objectUpdate->changeSet;
4278 propertyChange;
4279 propertyChange = propertyChange->_next) {
4280 if (STREQ(propertyChange->name, "info.state")) {
4281 if (propertyChange->op == esxVI_PropertyChangeOp_Add ||
4282 propertyChange->op == esxVI_PropertyChangeOp_Assign) {
4283 propertyValue = propertyChange->val;
4284 } else {
4285 propertyValue = NULL;
4286 }
4287 }
4288 }
4289 }
4290 }
4291
4292 if (!propertyValue)
4293 continue;
4294
4295 if (esxVI_TaskInfoState_CastFromAnyType(propertyValue, &state) < 0)
4296 goto cleanup;
4297 }
4298
4299 if (esxVI_DestroyPropertyFilter(ctx, propertyFilter) < 0)
4300 VIR_DEBUG("DestroyPropertyFilter failed");
4301
4302 if (esxVI_TaskInfoState_CastFromAnyType(propertyValue, finalState) < 0)
4303 goto cleanup;
4304
4305 if (*finalState != esxVI_TaskInfoState_Success) {
4306 if (esxVI_LookupTaskInfoByTask(ctx, task, &taskInfo))
4307 goto cleanup;
4308
4309 if (!taskInfo->error) {
4310 *errorMessage = g_strdup(_("Unknown error"));
4311 } else if (!taskInfo->error->localizedMessage) {
4312 *errorMessage = g_strdup(taskInfo->error->fault->_actualType);
4313 } else {
4314 *errorMessage = g_strdup_printf("%s - %s",
4315 taskInfo->error->fault->_actualType,
4316 taskInfo->error->localizedMessage);
4317 }
4318 }
4319
4320 result = 0;
4321
4322 cleanup:
4323 /*
4324 * Remove values given by the caller from the data structures to prevent
4325 * them from being freed by the call to esxVI_PropertyFilterSpec_Free().
4326 */
4327 if (objectSpec)
4328 objectSpec->obj = NULL;
4329
4330 if (propertySpec)
4331 propertySpec->type = NULL;
4332
4333 if (!objectSpec_isAppended)
4334 esxVI_ObjectSpec_Free(&objectSpec);
4335
4336 if (!propertySpec_isAppended)
4337 esxVI_PropertySpec_Free(&propertySpec);
4338
4339 esxVI_PropertyFilterSpec_Free(&propertyFilterSpec);
4340 esxVI_ManagedObjectReference_Free(&propertyFilter);
4341 g_free(version);
4342 esxVI_UpdateSet_Free(&updateSet);
4343 esxVI_TaskInfo_Free(&taskInfo);
4344
4345 return result;
4346 }
4347
4348
4349
4350 int
esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo * parsedHostCpuIdInfo,esxVI_HostCpuIdInfo * hostCpuIdInfo)4351 esxVI_ParseHostCpuIdInfo(esxVI_ParsedHostCpuIdInfo *parsedHostCpuIdInfo,
4352 esxVI_HostCpuIdInfo *hostCpuIdInfo)
4353 {
4354 int expectedLength = 39; /* = strlen("----:----:----:----:----:----:----:----"); */
4355 char *input[4] = { hostCpuIdInfo->eax, hostCpuIdInfo->ebx,
4356 hostCpuIdInfo->ecx, hostCpuIdInfo->edx };
4357 char *output[4] = { parsedHostCpuIdInfo->eax, parsedHostCpuIdInfo->ebx,
4358 parsedHostCpuIdInfo->ecx, parsedHostCpuIdInfo->edx };
4359 const char *name[4] = { "eax", "ebx", "ecx", "edx" };
4360 size_t r, i, o;
4361
4362 memset(parsedHostCpuIdInfo, 0, sizeof(*parsedHostCpuIdInfo));
4363
4364 parsedHostCpuIdInfo->level = hostCpuIdInfo->level->value;
4365
4366 for (r = 0; r < 4; ++r) {
4367 if (strlen(input[r]) != expectedLength) {
4368 virReportError(VIR_ERR_INTERNAL_ERROR,
4369 _("HostCpuIdInfo register '%s' has an unexpected length"),
4370 name[r]);
4371 return -1;
4372 }
4373
4374 /* Strip the ':' and invert the "bit" order from 31..0 to 0..31 */
4375 for (i = 0, o = 31; i < expectedLength; i += 5, o -= 4) {
4376 output[r][o] = input[r][i];
4377 output[r][o - 1] = input[r][i + 1];
4378 output[r][o - 2] = input[r][i + 2];
4379 output[r][o - 3] = input[r][i + 3];
4380
4381 if (i + 4 < expectedLength && input[r][i + 4] != ':') {
4382 virReportError(VIR_ERR_INTERNAL_ERROR,
4383 _("HostCpuIdInfo register '%s' has an unexpected format"),
4384 name[r]);
4385 return -1;
4386 }
4387 }
4388 }
4389
4390 return 0;
4391 }
4392
4393
4394
4395 const char *
esxVI_ProductLineToDisplayName(esxVI_ProductLine productLine)4396 esxVI_ProductLineToDisplayName(esxVI_ProductLine productLine)
4397 {
4398 switch (productLine) {
4399 case esxVI_ProductLine_GSX:
4400 return "Server/GSX";
4401
4402 case esxVI_ProductLine_ESX:
4403 return "ESX(i)";
4404
4405 case esxVI_ProductLine_VPX:
4406 return "vCenter/VPX";
4407
4408 default:
4409 return "<unknown>";
4410 }
4411 }
4412
4413
4414
4415 int
esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductLine productLine,unsigned long productVersion)4416 esxVI_ProductVersionToDefaultVirtualHWVersion(esxVI_ProductLine productLine,
4417 unsigned long productVersion)
4418 {
4419 /* product version == 1000000 * major + 1000 * minor + micro */
4420 int major = productVersion / 1000000;
4421 int minor = productVersion / 1000 - major * 1000;
4422
4423 /*
4424 * virtualHW.version compatibility matrix:
4425 *
4426 * 4 7 8 9 10 API
4427 * ESX 3.5 + 2.5
4428 * ESX 4.0 + + 4.0
4429 * ESX 4.1 + + 4.1
4430 * ESX 5.0 + + + 5.0
4431 * ESX 5.1 + + + + 5.1
4432 * ESX 5.5 + + + + + 5.5
4433 * ESX 6.0 + + + + + 6.0
4434 * GSX 2.0 + + 2.5
4435 */
4436 switch (productLine) {
4437 case esxVI_ProductLine_GSX:
4438 return 7;
4439
4440 case esxVI_ProductLine_ESX:
4441 switch (major) {
4442 case 3:
4443 return 4;
4444
4445 case 4:
4446 return 7;
4447
4448 case 5:
4449 if (minor < 5)
4450 return 9;
4451
4452 return 10;
4453
4454 case 6:
4455 return 10;
4456
4457 default:
4458 return 8;
4459 }
4460
4461 case esxVI_ProductLine_VPX:
4462 switch (major) {
4463 case 2:
4464 return 4;
4465
4466 case 4:
4467 return 7;
4468
4469 case 5:
4470 if (minor < 5)
4471 return 9;
4472
4473 return 10;
4474
4475 case 6:
4476 return 10;
4477
4478 default:
4479 return 8;
4480 }
4481
4482 default:
4483 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4484 _("Unexpected product line"));
4485 return -1;
4486 }
4487 }
4488
4489
4490
4491 int
esxVI_LookupHostInternetScsiHbaStaticTargetByName(esxVI_Context * ctx,const char * name,esxVI_HostInternetScsiHbaStaticTarget ** target,esxVI_Occurrence occurrence)4492 esxVI_LookupHostInternetScsiHbaStaticTargetByName
4493 (esxVI_Context *ctx, const char *name,
4494 esxVI_HostInternetScsiHbaStaticTarget **target, esxVI_Occurrence occurrence)
4495 {
4496 int result = -1;
4497 esxVI_HostInternetScsiHba *hostInternetScsiHba = NULL;
4498 esxVI_HostInternetScsiHbaStaticTarget *candidate = NULL;
4499
4500 if (esxVI_LookupHostInternetScsiHba(ctx, &hostInternetScsiHba) < 0) {
4501 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4502 _("Unable to obtain hostInternetScsiHba"));
4503 goto cleanup;
4504 }
4505
4506 if (!hostInternetScsiHba) {
4507 /* iSCSI adapter may not be enabled for this host */
4508 return 0;
4509 }
4510
4511 for (candidate = hostInternetScsiHba->configuredStaticTarget;
4512 candidate; candidate = candidate->_next) {
4513 if (STREQ(candidate->iScsiName, name))
4514 break;
4515 }
4516
4517 if (!candidate) {
4518 if (occurrence == esxVI_Occurrence_RequiredItem) {
4519 virReportError(VIR_ERR_NO_STORAGE_POOL,
4520 _("Could not find storage pool with name: %s"), name);
4521 }
4522
4523 goto cleanup;
4524 }
4525
4526 if (esxVI_HostInternetScsiHbaStaticTarget_DeepCopy(target, candidate) < 0)
4527 goto cleanup;
4528
4529 result = 0;
4530
4531 cleanup:
4532 esxVI_HostInternetScsiHba_Free(&hostInternetScsiHba);
4533
4534 return result;
4535 }
4536
4537
4538
4539 int
esxVI_LookupHostInternetScsiHba(esxVI_Context * ctx,esxVI_HostInternetScsiHba ** hostInternetScsiHba)4540 esxVI_LookupHostInternetScsiHba(esxVI_Context *ctx,
4541 esxVI_HostInternetScsiHba **hostInternetScsiHba)
4542 {
4543 int result = -1;
4544 esxVI_DynamicProperty *dynamicProperty = NULL;
4545 esxVI_ObjectContent *hostSystem = NULL;
4546 esxVI_String *propertyNameList = NULL;
4547 esxVI_HostHostBusAdapter *hostHostBusAdapterList = NULL;
4548 esxVI_HostHostBusAdapter *hostHostBusAdapter = NULL;
4549
4550 if (esxVI_String_AppendValueToList
4551 (&propertyNameList, "config.storageDevice.hostBusAdapter") < 0 ||
4552 esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4553 &hostSystem) < 0) {
4554 goto cleanup;
4555 }
4556
4557 for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4558 dynamicProperty = dynamicProperty->_next) {
4559 if (STREQ(dynamicProperty->name,
4560 "config.storageDevice.hostBusAdapter")) {
4561 if (esxVI_HostHostBusAdapter_CastListFromAnyType
4562 (dynamicProperty->val, &hostHostBusAdapterList) < 0 ||
4563 !hostHostBusAdapterList) {
4564 goto cleanup;
4565 }
4566 } else {
4567 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4568 }
4569 }
4570
4571 /* See vSphere API documentation about HostInternetScsiHba for details */
4572 for (hostHostBusAdapter = hostHostBusAdapterList;
4573 hostHostBusAdapter;
4574 hostHostBusAdapter = hostHostBusAdapter->_next) {
4575 esxVI_HostInternetScsiHba *candidate =
4576 esxVI_HostInternetScsiHba_DynamicCast(hostHostBusAdapter);
4577
4578 if (candidate) {
4579 if (esxVI_HostInternetScsiHba_DeepCopy(hostInternetScsiHba,
4580 candidate) < 0) {
4581 goto cleanup;
4582 }
4583 break;
4584 }
4585 }
4586
4587 result = 0;
4588
4589 cleanup:
4590 esxVI_String_Free(&propertyNameList);
4591 esxVI_ObjectContent_Free(&hostSystem);
4592 esxVI_HostHostBusAdapter_Free(&hostHostBusAdapterList);
4593
4594 return result;
4595 }
4596
4597
4598
4599 int
esxVI_LookupScsiLunList(esxVI_Context * ctx,esxVI_ScsiLun ** scsiLunList)4600 esxVI_LookupScsiLunList(esxVI_Context *ctx, esxVI_ScsiLun **scsiLunList)
4601 {
4602 int result = -1;
4603 esxVI_String *propertyNameList = NULL;
4604 esxVI_ObjectContent *hostSystem = NULL;
4605 esxVI_DynamicProperty *dynamicProperty;
4606
4607 if (esxVI_String_AppendValueToList(&propertyNameList,
4608 "config.storageDevice.scsiLun") < 0 ||
4609 esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4610 &hostSystem) < 0) {
4611 goto cleanup;
4612 }
4613
4614 for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4615 dynamicProperty = dynamicProperty->_next) {
4616 if (STREQ(dynamicProperty->name, "config.storageDevice.scsiLun")) {
4617 if (esxVI_ScsiLun_CastListFromAnyType(dynamicProperty->val,
4618 scsiLunList) < 0) {
4619 goto cleanup;
4620 }
4621
4622 break;
4623 } else {
4624 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4625 }
4626 }
4627
4628 result = 0;
4629
4630 cleanup:
4631 esxVI_String_Free(&propertyNameList);
4632 esxVI_ObjectContent_Free(&hostSystem);
4633
4634 return result;
4635 }
4636
4637
4638
4639 int
esxVI_LookupHostScsiTopologyLunListByTargetName(esxVI_Context * ctx,const char * name,esxVI_HostScsiTopologyLun ** hostScsiTopologyLunList)4640 esxVI_LookupHostScsiTopologyLunListByTargetName
4641 (esxVI_Context *ctx, const char *name,
4642 esxVI_HostScsiTopologyLun **hostScsiTopologyLunList)
4643 {
4644 int result = -1;
4645 esxVI_DynamicProperty *dynamicProperty = NULL;
4646 esxVI_ObjectContent *hostSystem = NULL;
4647 esxVI_String *propertyNameList = NULL;
4648 esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL;
4649 esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL;
4650 esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL;
4651 bool found = false;
4652 esxVI_HostInternetScsiTargetTransport *candidate = NULL;
4653
4654 ESX_VI_CHECK_ARG_LIST(hostScsiTopologyLunList);
4655
4656 if (esxVI_String_AppendValueToList
4657 (&propertyNameList,
4658 "config.storageDevice.scsiTopology.adapter") < 0 ||
4659 esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4660 &hostSystem) < 0) {
4661 goto cleanup;
4662 }
4663
4664 for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4665 dynamicProperty = dynamicProperty->_next) {
4666 if (STREQ(dynamicProperty->name,
4667 "config.storageDevice.scsiTopology.adapter")) {
4668 esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
4669
4670 if (esxVI_HostScsiTopologyInterface_CastListFromAnyType
4671 (dynamicProperty->val, &hostScsiInterfaceList) < 0) {
4672 goto cleanup;
4673 }
4674
4675 break;
4676 } else {
4677 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4678 }
4679 }
4680
4681 if (hostScsiInterfaceList == NULL) {
4682 /* iSCSI adapter may not be enabled */
4683 return 0;
4684 }
4685
4686 /* See vSphere API documentation about HostScsiTopologyInterface */
4687 for (hostScsiInterface = hostScsiInterfaceList;
4688 hostScsiInterface && !found;
4689 hostScsiInterface = hostScsiInterface->_next) {
4690 for (hostScsiTopologyTarget = hostScsiInterface->target;
4691 hostScsiTopologyTarget;
4692 hostScsiTopologyTarget = hostScsiTopologyTarget->_next) {
4693 candidate = esxVI_HostInternetScsiTargetTransport_DynamicCast
4694 (hostScsiTopologyTarget->transport);
4695
4696 if (candidate && STREQ(candidate->iScsiName, name)) {
4697 found = true;
4698 break;
4699 }
4700 }
4701 }
4702
4703 if (!found || !hostScsiTopologyTarget)
4704 goto cleanup;
4705
4706 if (!hostScsiTopologyTarget->lun) {
4707 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4708 _("Target not found"));
4709 goto cleanup;
4710 }
4711
4712 if (esxVI_HostScsiTopologyLun_DeepCopyList(hostScsiTopologyLunList,
4713 hostScsiTopologyTarget->lun) < 0) {
4714 goto cleanup;
4715 }
4716
4717 result = 0;
4718
4719 cleanup:
4720 esxVI_String_Free(&propertyNameList);
4721 esxVI_ObjectContent_Free(&hostSystem);
4722 esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
4723
4724 return result;
4725 }
4726
4727
4728
4729 int
esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context * ctx,const char * key,char ** poolName)4730 esxVI_LookupStoragePoolNameByScsiLunKey(esxVI_Context *ctx,
4731 const char *key,
4732 char **poolName)
4733 {
4734 int result = -1;
4735 esxVI_DynamicProperty *dynamicProperty = NULL;
4736 esxVI_ObjectContent *hostSystem = NULL;
4737 esxVI_String *propertyNameList = NULL;
4738 esxVI_HostScsiTopologyInterface *hostScsiInterfaceList = NULL;
4739 esxVI_HostScsiTopologyInterface *hostScsiInterface = NULL;
4740 esxVI_HostScsiTopologyTarget *hostScsiTopologyTarget = NULL;
4741 esxVI_HostInternetScsiTargetTransport *candidate;
4742 esxVI_HostScsiTopologyLun *hostScsiTopologyLun;
4743 bool found = false;
4744
4745 ESX_VI_CHECK_ARG_LIST(poolName);
4746
4747 if (esxVI_String_AppendValueToList
4748 (&propertyNameList,
4749 "config.storageDevice.scsiTopology.adapter") < 0 ||
4750 esxVI_LookupHostSystemProperties(ctx, propertyNameList,
4751 &hostSystem) < 0) {
4752 goto cleanup;
4753 }
4754
4755 for (dynamicProperty = hostSystem->propSet; dynamicProperty;
4756 dynamicProperty = dynamicProperty->_next) {
4757 if (STREQ(dynamicProperty->name,
4758 "config.storageDevice.scsiTopology.adapter")) {
4759 esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
4760
4761 if (esxVI_HostScsiTopologyInterface_CastListFromAnyType
4762 (dynamicProperty->val, &hostScsiInterfaceList) < 0) {
4763 goto cleanup;
4764 }
4765
4766 break;
4767 } else {
4768 VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
4769 }
4770 }
4771
4772 if (!hostScsiInterfaceList) {
4773 /* iSCSI adapter may not be enabled */
4774 return 0;
4775 }
4776
4777 /* See vSphere API documentation about HostScsiTopologyInterface */
4778 for (hostScsiInterface = hostScsiInterfaceList;
4779 hostScsiInterface && !found;
4780 hostScsiInterface = hostScsiInterface->_next) {
4781 for (hostScsiTopologyTarget = hostScsiInterface->target;
4782 hostScsiTopologyTarget;
4783 hostScsiTopologyTarget = hostScsiTopologyTarget->_next) {
4784 candidate = esxVI_HostInternetScsiTargetTransport_DynamicCast
4785 (hostScsiTopologyTarget->transport);
4786
4787 if (candidate) {
4788 /* iterate hostScsiTopologyLun list to find matching key */
4789 for (hostScsiTopologyLun = hostScsiTopologyTarget->lun;
4790 hostScsiTopologyLun;
4791 hostScsiTopologyLun = hostScsiTopologyLun->_next) {
4792 if (STREQ(hostScsiTopologyLun->scsiLun, key))
4793 *poolName = g_strdup(candidate->iScsiName);
4794 }
4795
4796 /* hostScsiTopologyLun iteration done, terminate loop */
4797 break;
4798 }
4799 }
4800 }
4801
4802 result = 0;
4803
4804 cleanup:
4805 esxVI_ObjectContent_Free(&hostSystem);
4806 esxVI_String_Free(&propertyNameList);
4807 esxVI_HostScsiTopologyInterface_Free(&hostScsiInterfaceList);
4808
4809 return result;
4810 }
4811
4812
4813
4814 #define ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE_IGNORE(_name) \
4815 if (STREQ(dynamicProperty->name, #_name)) { \
4816 continue; \
4817 }
4818
4819
4820
4821 #define ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE(_type, _name) \
4822 if (STREQ(dynamicProperty->name, #_name)) { \
4823 if (esxVI_##_type##_CastFromAnyType(dynamicProperty->val, \
4824 &(*ptrptr)->_name) < 0) { \
4825 goto cleanup; \
4826 } \
4827 \
4828 continue; \
4829 }
4830
4831
4832
4833 #define ESX_VI__TEMPLATE__PROPERTY__CAST_LIST_FROM_ANY_TYPE(_type, _name) \
4834 if (STREQ(dynamicProperty->name, #_name)) { \
4835 if (esxVI_##_type##_CastListFromAnyType(dynamicProperty->val, \
4836 &(*ptrptr)->_name) < 0) { \
4837 goto cleanup; \
4838 } \
4839 \
4840 continue; \
4841 }
4842
4843
4844
4845 #define ESX_VI__TEMPLATE__PROPERTY__CAST_VALUE_FROM_ANY_TYPE(_type, _name) \
4846 if (STREQ(dynamicProperty->name, #_name)) { \
4847 if (esxVI_##_type##_CastValueFromAnyType(dynamicProperty->val, \
4848 &(*ptrptr)->_name) < 0) { \
4849 goto cleanup; \
4850 } \
4851 \
4852 continue; \
4853 }
4854
4855
4856
4857 #define ESX_VI__TEMPLATE__LOOKUP(_type, _complete_properties, \
4858 _cast_from_anytype) \
4859 int \
4860 esxVI_Lookup##_type(esxVI_Context *ctx, const char* name /* optional */, \
4861 esxVI_ManagedObjectReference *root, \
4862 esxVI_String *selectedPropertyNameList /* optional */,\
4863 esxVI_##_type **ptrptr, esxVI_Occurrence occurrence) \
4864 { \
4865 int result = -1; \
4866 const char *completePropertyNameValueList = _complete_properties; \
4867 esxVI_String *propertyNameList = NULL; \
4868 esxVI_ObjectContent *objectContent = NULL; \
4869 esxVI_ObjectContent *objectContentList = NULL; \
4870 esxVI_DynamicProperty *dynamicProperty = NULL; \
4871 \
4872 if (!ptrptr || *ptrptr) { \
4873 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", \
4874 _("Invalid argument")); \
4875 return -1; \
4876 } \
4877 \
4878 propertyNameList = selectedPropertyNameList; \
4879 \
4880 if (!propertyNameList && \
4881 esxVI_String_AppendValueListToList \
4882 (&propertyNameList, completePropertyNameValueList) < 0) { \
4883 goto cleanup; \
4884 } \
4885 \
4886 if (esxVI_LookupManagedObjectHelper(ctx, name, root, #_type, \
4887 propertyNameList, &objectContent, \
4888 &objectContentList, \
4889 occurrence) < 0) { \
4890 goto cleanup; \
4891 } \
4892 \
4893 if (!objectContent) { \
4894 /* not found, exit early */ \
4895 result = 0; \
4896 goto cleanup; \
4897 } \
4898 \
4899 if (esxVI_##_type##_Alloc(ptrptr) < 0) { \
4900 goto cleanup; \
4901 } \
4902 \
4903 if (esxVI_ManagedObjectReference_DeepCopy(&(*ptrptr)->_reference, \
4904 objectContent->obj) < 0) { \
4905 goto cleanup; \
4906 } \
4907 \
4908 for (dynamicProperty = objectContent->propSet; \
4909 dynamicProperty; \
4910 dynamicProperty = dynamicProperty->_next) { \
4911 _cast_from_anytype \
4912 \
4913 VIR_WARN("Unexpected '%s' property", dynamicProperty->name); \
4914 } \
4915 \
4916 if (esxVI_##_type##_Validate(*ptrptr, selectedPropertyNameList) < 0) {\
4917 goto cleanup; \
4918 } \
4919 \
4920 result = 0; \
4921 \
4922 cleanup: \
4923 if (result < 0) { \
4924 esxVI_##_type##_Free(ptrptr); \
4925 } \
4926 \
4927 if (propertyNameList != selectedPropertyNameList) { \
4928 esxVI_String_Free(&propertyNameList); \
4929 } \
4930 \
4931 esxVI_ObjectContent_Free(&objectContentList); \
4932 \
4933 return result; \
4934 }
4935
4936
4937
4938 static int
esxVI_LookupManagedObjectHelper(esxVI_Context * ctx,const char * name,esxVI_ManagedObjectReference * root,const char * type,esxVI_String * propertyNameList,esxVI_ObjectContent ** objectContent,esxVI_ObjectContent ** objectContentList,esxVI_Occurrence occurrence)4939 esxVI_LookupManagedObjectHelper(esxVI_Context *ctx,
4940 const char *name /* optional */,
4941 esxVI_ManagedObjectReference *root,
4942 const char *type,
4943 esxVI_String *propertyNameList,
4944 esxVI_ObjectContent **objectContent,
4945 esxVI_ObjectContent **objectContentList,
4946 esxVI_Occurrence occurrence)
4947 {
4948 int result = -1;
4949 esxVI_ObjectContent *candidate = NULL;
4950 char *name_candidate;
4951
4952 if (!objectContent || *objectContent ||
4953 !objectContentList || *objectContentList) {
4954 virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
4955 return -1;
4956 }
4957
4958 if (!esxVI_String_ListContainsValue(propertyNameList, "name")) {
4959 virReportError(VIR_ERR_INTERNAL_ERROR,
4960 _("Missing 'name' property in %s lookup"), type);
4961 goto cleanup;
4962 }
4963
4964 if (esxVI_LookupObjectContentByType(ctx, root, type, propertyNameList,
4965 objectContentList,
4966 esxVI_Occurrence_OptionalList) < 0) {
4967 goto cleanup;
4968 }
4969
4970 /* Search for a matching item */
4971 if (name) {
4972 for (candidate = *objectContentList; candidate;
4973 candidate = candidate->_next) {
4974 name_candidate = NULL;
4975
4976 if (esxVI_GetStringValue(candidate, "name", &name_candidate,
4977 esxVI_Occurrence_RequiredItem) < 0) {
4978 goto cleanup;
4979 }
4980
4981 if (STREQ(name_candidate, name)) {
4982 /* Found item with matching name */
4983 break;
4984 }
4985 }
4986 } else {
4987 candidate = *objectContentList;
4988 }
4989
4990 if (!candidate) {
4991 if (occurrence != esxVI_Occurrence_OptionalItem) {
4992 if (name) {
4993 virReportError(VIR_ERR_INTERNAL_ERROR,
4994 _("Could not find %s with name '%s'"), type, name);
4995 } else {
4996 virReportError(VIR_ERR_INTERNAL_ERROR,
4997 _("Could not find %s"), type);
4998 }
4999
5000 goto cleanup;
5001 }
5002
5003 result = 0;
5004
5005 goto cleanup;
5006 }
5007
5008 result = 0;
5009
5010 cleanup:
5011 if (result < 0) {
5012 esxVI_ObjectContent_Free(objectContentList);
5013 } else {
5014 *objectContent = candidate;
5015 }
5016
5017 return result;
5018 }
5019
5020
5021
5022 #include "esx_vi.generated.c"
5023