Add missing libxml2-tools dependency
[archive/platform/upstream/libvirt.git] / tests / qemuagenttest.c
1 /*
2  * Copyright (C) 2013, 2014 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <http://www.gnu.org/licenses/>.
17  *
18  */
19
20 #include <config.h>
21
22 #include "testutils.h"
23 #include "testutilsqemu.h"
24 #include "qemumonitortestutils.h"
25 #include "qemu/qemu_conf.h"
26 #include "qemu/qemu_agent.h"
27 #include "virthread.h"
28 #include "virerror.h"
29 #include "virstring.h"
30
31
32 #define VIR_FROM_THIS VIR_FROM_NONE
33
34 static int
35 testQemuAgentFSFreeze(const void *data)
36 {
37     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
38     qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
39     const char *mountpoints[] = {"/fs1", "/fs2", "/fs3", "/fs4", "/fs5"};
40     int ret = -1;
41
42     if (!test)
43         return -1;
44
45     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
46         goto cleanup;
47
48     if (qemuMonitorTestAddItem(test, "guest-fsfreeze-freeze",
49                                "{ \"return\" : 5 }") < 0)
50         goto cleanup;
51
52     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
53         goto cleanup;
54
55     if (qemuMonitorTestAddItem(test, "guest-fsfreeze-freeze",
56                                "{ \"return\" : 7 }") < 0)
57         goto cleanup;
58
59     if ((ret = qemuAgentFSFreeze(qemuMonitorTestGetAgent(test),
60                                  mountpoints, 5)) < 0)
61         goto cleanup;
62
63     if (ret != 5) {
64         virReportError(VIR_ERR_INTERNAL_ERROR,
65                        "expected 5 frozen filesystems, got %d", ret);
66         goto cleanup;
67     }
68
69     if ((ret = qemuAgentFSFreeze(qemuMonitorTestGetAgent(test), NULL, 0)) < 0)
70         goto cleanup;
71
72     if (ret != 7) {
73         virReportError(VIR_ERR_INTERNAL_ERROR,
74                        "expected 7 frozen filesystems, got %d", ret);
75         goto cleanup;
76     }
77
78     ret = 0;
79
80  cleanup:
81     qemuMonitorTestFree(test);
82     return ret;
83 }
84
85
86 static int
87 testQemuAgentFSThaw(const void *data)
88 {
89     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
90     qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
91     int ret = -1;
92
93     if (!test)
94         return -1;
95
96     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
97         goto cleanup;
98
99     if (qemuMonitorTestAddItem(test, "guest-fsfreeze-thaw",
100                                "{ \"return\" : 5 }") < 0)
101         goto cleanup;
102
103     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
104         goto cleanup;
105
106     if (qemuMonitorTestAddItem(test, "guest-fsfreeze-thaw",
107                                "{ \"return\" : 7 }") < 0)
108         goto cleanup;
109
110     if ((ret = qemuAgentFSThaw(qemuMonitorTestGetAgent(test))) < 0)
111         goto cleanup;
112
113     if (ret != 5) {
114         virReportError(VIR_ERR_INTERNAL_ERROR,
115                        "expected 5 thawed filesystems, got %d", ret);
116         goto cleanup;
117     }
118
119     if ((ret = qemuAgentFSThaw(qemuMonitorTestGetAgent(test))) < 0)
120         goto cleanup;
121
122     if (ret != 7) {
123         virReportError(VIR_ERR_INTERNAL_ERROR,
124                        "expected 7 thawed filesystems, got %d", ret);
125         goto cleanup;
126     }
127
128     ret = 0;
129
130  cleanup:
131     qemuMonitorTestFree(test);
132     return ret;
133 }
134
135
136 static int
137 testQemuAgentFSTrim(const void *data)
138 {
139     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
140     qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
141     int ret = -1;
142
143     if (!test)
144         return -1;
145
146     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
147         goto cleanup;
148
149     if (qemuMonitorTestAddItemParams(test, "guest-fstrim",
150                                      "{ \"return\" : {} }",
151                                      "minimum", "1337",
152                                      NULL) < 0)
153         goto cleanup;
154
155     if (qemuAgentFSTrim(qemuMonitorTestGetAgent(test), 1337) < 0)
156         goto cleanup;
157
158     ret = 0;
159
160  cleanup:
161     qemuMonitorTestFree(test);
162     return ret;
163 }
164
165
166 static int
167 testQemuAgentSuspend(const void *data)
168 {
169     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
170     qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
171     int ret = -1;
172     size_t i;
173
174     if (!test)
175         return -1;
176
177     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
178         goto cleanup;
179
180     if (qemuMonitorTestAddItem(test, "guest-suspend-ram",
181                                "{ \"return\" : {} }") < 0)
182         goto cleanup;
183
184     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
185         goto cleanup;
186
187     if (qemuMonitorTestAddItem(test, "guest-suspend-disk",
188                                "{ \"return\" : {} }") < 0)
189         goto cleanup;
190
191     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
192         goto cleanup;
193
194     if (qemuMonitorTestAddItem(test, "guest-suspend-hybrid",
195                                "{ \"return\" : {} }") < 0)
196         goto cleanup;
197
198     /* try the commands - fail if ordering changes */
199     for (i = 0; i < VIR_NODE_SUSPEND_TARGET_LAST; i++) {
200         if (qemuAgentSuspend(qemuMonitorTestGetAgent(test), i) < 0)
201             goto cleanup;
202     }
203
204     ret = 0;
205
206  cleanup:
207     qemuMonitorTestFree(test);
208     return ret;
209 }
210
211
212 struct qemuAgentShutdownTestData {
213     const char *mode;
214     qemuAgentEvent event;
215 };
216
217
218 static int
219 qemuAgentShutdownTestMonitorHandler(qemuMonitorTestPtr test,
220                                     qemuMonitorTestItemPtr item,
221                                     const char *cmdstr)
222 {
223     struct qemuAgentShutdownTestData *data;
224     virJSONValuePtr val = NULL;
225     virJSONValuePtr args;
226     const char *cmdname;
227     const char *mode;
228     int ret = -1;
229
230     data = qemuMonitorTestItemGetPrivateData(item);
231
232     if (!(val = virJSONValueFromString(cmdstr)))
233         return -1;
234
235     if (!(cmdname = virJSONValueObjectGetString(val, "execute"))) {
236         ret = qemuMonitorReportError(test, "Missing command name in %s", cmdstr);
237         goto cleanup;
238     }
239
240     if (STRNEQ(cmdname, "guest-shutdown")) {
241         ret = qemuMonitorTestAddUnexpectedErrorResponse(test);
242         goto cleanup;
243     }
244
245     if (!(args = virJSONValueObjectGet(val, "arguments"))) {
246         ret = qemuMonitorReportError(test,
247                                      "Missing arguments section");
248         goto cleanup;
249     }
250
251     if (!(mode = virJSONValueObjectGetString(args, "mode"))) {
252         ret = qemuMonitorReportError(test, "Missing shutdown mode");
253         goto cleanup;
254     }
255
256     if (STRNEQ(mode, data->mode)) {
257         ret = qemuMonitorReportError(test,
258                                      "expected shutdown mode '%s' got '%s'",
259                                      data->mode, mode);
260         goto cleanup;
261     }
262
263     /* now don't reply but return a qemu agent event */
264     qemuAgentNotifyEvent(qemuMonitorTestGetAgent(test),
265                          data->event);
266
267     ret = 0;
268
269  cleanup:
270     virJSONValueFree(val);
271     return ret;
272
273 }
274
275
276 static int
277 testQemuAgentShutdown(const void *data)
278 {
279     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
280     qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
281     struct qemuAgentShutdownTestData priv;
282     int ret = -1;
283
284     if (!test)
285         return -1;
286
287     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
288         goto cleanup;
289
290     priv.event = QEMU_AGENT_EVENT_SHUTDOWN;
291     priv.mode = "halt";
292
293     if (qemuMonitorTestAddHandler(test, qemuAgentShutdownTestMonitorHandler,
294                                   &priv, NULL) < 0)
295         goto cleanup;
296
297     if (qemuAgentShutdown(qemuMonitorTestGetAgent(test),
298                           QEMU_AGENT_SHUTDOWN_HALT) < 0)
299         goto cleanup;
300
301     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
302         goto cleanup;
303
304     priv.event = QEMU_AGENT_EVENT_SHUTDOWN;
305     priv.mode = "powerdown";
306
307     if (qemuMonitorTestAddHandler(test, qemuAgentShutdownTestMonitorHandler,
308                                   &priv, NULL) < 0)
309         goto cleanup;
310
311     if (qemuAgentShutdown(qemuMonitorTestGetAgent(test),
312                           QEMU_AGENT_SHUTDOWN_POWERDOWN) < 0)
313         goto cleanup;
314
315     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
316         goto cleanup;
317
318     priv.event = QEMU_AGENT_EVENT_RESET;
319     priv.mode = "reboot";
320
321     if (qemuMonitorTestAddHandler(test, qemuAgentShutdownTestMonitorHandler,
322                                   &priv, NULL) < 0)
323         goto cleanup;
324
325     if (qemuAgentShutdown(qemuMonitorTestGetAgent(test),
326                           QEMU_AGENT_SHUTDOWN_REBOOT) < 0)
327         goto cleanup;
328
329     /* check negative response, so that we can verify that the agent breaks
330      * out from sleep */
331
332     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
333         goto cleanup;
334
335     if (qemuMonitorTestAddItem(test, "guest-shutdown",
336                                "{\"error\":"
337                                "    {\"class\":\"CommandDisabled\","
338                                "     \"desc\":\"The command guest-shutdown has "
339                                                "been disabled for this instance\","
340                                "     \"data\":{\"name\":\"guest-shutdown\"}"
341                                "    }"
342                                "}") < 0)
343         goto cleanup;
344
345     if (qemuAgentShutdown(qemuMonitorTestGetAgent(test),
346                           QEMU_AGENT_SHUTDOWN_REBOOT) != -1) {
347         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
348                        "agent shutdown command should have failed");
349         goto cleanup;
350     }
351
352     ret = 0;
353
354  cleanup:
355     qemuMonitorTestFree(test);
356     return ret;
357 }
358
359
360 static const char testQemuAgentCPUResponse[] =
361     "{\"return\": "
362     "   ["
363     "       {\"online\": true,"
364     "        \"can-offline\": false,"
365     "        \"logical-id\": 0"
366     "       },"
367     "       {\"online\": true,"
368     "        \"can-offline\": true,"
369     "        \"logical-id\": 1"
370     "       },"
371     "       {\"online\": true,"
372     "        \"can-offline\": true,"
373     "        \"logical-id\": 2"
374     "        },"
375     "       {\"online\": false,"
376     "        \"can-offline\": true,"
377     "        \"logical-id\": 3"
378     "       }"
379     "   ]"
380     "}";
381
382 static const char testQemuAgentCPUArguments1[] =
383     "[{\"logical-id\":0,\"online\":true},"
384      "{\"logical-id\":1,\"online\":false},"
385      "{\"logical-id\":2,\"online\":true},"
386      "{\"logical-id\":3,\"online\":false}]";
387
388 static const char testQemuAgentCPUArguments2[] =
389     "[{\"logical-id\":0,\"online\":true},"
390      "{\"logical-id\":1,\"online\":true},"
391      "{\"logical-id\":2,\"online\":true},"
392      "{\"logical-id\":3,\"online\":true}]";
393
394 static int
395 testQemuAgentCPU(const void *data)
396 {
397     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
398     qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
399     qemuAgentCPUInfoPtr cpuinfo = NULL;
400     int nvcpus;
401     int ret = -1;
402
403     if (!test)
404         return -1;
405
406     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
407         goto cleanup;
408
409     if (qemuMonitorTestAddItem(test, "guest-get-vcpus",
410                                testQemuAgentCPUResponse) < 0)
411         goto cleanup;
412
413     /* get cpus */
414     if ((nvcpus = qemuAgentGetVCPUs(qemuMonitorTestGetAgent(test),
415                                     &cpuinfo)) < 0)
416         goto cleanup;
417
418     if (nvcpus != 4) {
419         virReportError(VIR_ERR_INTERNAL_ERROR,
420                        "Expected '4' cpus, got '%d'", nvcpus);
421         goto cleanup;
422     }
423
424     /* try to unplug one */
425     if (qemuAgentUpdateCPUInfo(2, cpuinfo, nvcpus) < 0)
426         goto cleanup;
427
428     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
429         goto cleanup;
430
431     if (qemuMonitorTestAddItemParams(test, "guest-set-vcpus",
432                                      "{ \"return\" : 4 }",
433                                      "vcpus", testQemuAgentCPUArguments1,
434                                      NULL) < 0)
435         goto cleanup;
436
437     if ((nvcpus = qemuAgentSetVCPUs(qemuMonitorTestGetAgent(test),
438                                     cpuinfo, nvcpus)) < 0)
439         goto cleanup;
440
441     if (nvcpus != 4) {
442         virReportError(VIR_ERR_INTERNAL_ERROR,
443                        "Expected '4' cpus updated , got '%d'", nvcpus);
444         goto cleanup;
445     }
446
447     /* try to hotplug two */
448     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
449         goto cleanup;
450
451     if (qemuMonitorTestAddItemParams(test, "guest-set-vcpus",
452                                      "{ \"return\" : 4 }",
453                                      "vcpus", testQemuAgentCPUArguments2,
454                                      NULL) < 0)
455         goto cleanup;
456
457     if (qemuAgentUpdateCPUInfo(4, cpuinfo, nvcpus) < 0)
458         goto cleanup;
459
460     if ((nvcpus = qemuAgentSetVCPUs(qemuMonitorTestGetAgent(test),
461                                     cpuinfo, nvcpus)) < 0)
462         goto cleanup;
463
464     if (nvcpus != 4) {
465         virReportError(VIR_ERR_INTERNAL_ERROR,
466                        "Expected '4' cpus updated , got '%d'", nvcpus);
467         goto cleanup;
468     }
469
470     ret = 0;
471
472  cleanup:
473     VIR_FREE(cpuinfo);
474     qemuMonitorTestFree(test);
475     return ret;
476 }
477
478
479 static const char testQemuAgentArbitraryCommandResponse[] =
480     "{\"return\":\"bla\"}";
481
482 static int
483 testQemuAgentArbitraryCommand(const void *data)
484 {
485     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
486     qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
487     int ret = -1;
488     char *reply = NULL;
489
490     if (!test)
491         return -1;
492
493     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
494         goto cleanup;
495
496     if (qemuMonitorTestAddItem(test, "ble",
497                                testQemuAgentArbitraryCommandResponse) < 0)
498         goto cleanup;
499
500     if (qemuAgentArbitraryCommand(qemuMonitorTestGetAgent(test),
501                                   "{\"execute\":\"ble\"}",
502                                   &reply,
503                                   VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
504         goto cleanup;
505
506     if (STRNEQ(reply, testQemuAgentArbitraryCommandResponse)) {
507         virReportError(VIR_ERR_INTERNAL_ERROR,
508                        "invalid processing of guest agent reply: "
509                        "got '%s' expected '%s'",
510                        reply, testQemuAgentArbitraryCommandResponse);
511         goto cleanup;
512     }
513
514     ret = 0;
515
516  cleanup:
517     VIR_FREE(reply);
518     qemuMonitorTestFree(test);
519     return ret;
520 }
521
522
523 static int
524 qemuAgentTimeoutTestMonitorHandler(qemuMonitorTestPtr test ATTRIBUTE_UNUSED,
525                                    qemuMonitorTestItemPtr item ATTRIBUTE_UNUSED,
526                                    const char *cmdstr ATTRIBUTE_UNUSED)
527 {
528     return 0;
529 }
530
531
532 static int
533 testQemuAgentTimeout(const void *data)
534 {
535     virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
536     qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
537     char *reply = NULL;
538     int ret = -1;
539
540     if (!test)
541         return -1;
542
543     if (virTestGetExpensive() == 0) {
544         ret = EXIT_AM_SKIP;
545         goto cleanup;
546     }
547
548     if (qemuMonitorTestAddHandler(test, qemuAgentTimeoutTestMonitorHandler,
549                                   NULL, NULL) < 0)
550         goto cleanup;
551
552     if (qemuAgentFSFreeze(qemuMonitorTestGetAgent(test), NULL, 0) != -1) {
553         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
554                        "agent command should have failed");
555         goto cleanup;
556     }
557
558     /* test timeout */
559     if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
560         goto cleanup;
561
562     if (qemuMonitorTestAddHandler(test, qemuAgentTimeoutTestMonitorHandler,
563                                   NULL, NULL) < 0)
564         goto cleanup;
565
566     if (qemuAgentArbitraryCommand(qemuMonitorTestGetAgent(test),
567                                   "{\"execute\":\"ble\"}",
568                                   &reply,
569                                   1) != -2) {
570         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
571                        "agent command didn't time out");
572         goto cleanup;
573     }
574
575     ret = 0;
576
577  cleanup:
578     VIR_FREE(reply);
579     qemuMonitorTestFree(test);
580     return ret;
581 }
582
583
584 static int
585 mymain(void)
586 {
587     int ret = 0;
588     virDomainXMLOptionPtr xmlopt;
589
590 #if !WITH_YAJL
591     fputs("libvirt not compiled with yajl, skipping this test\n", stderr);
592     return EXIT_AM_SKIP;
593 #endif
594
595     if (virThreadInitialize() < 0 ||
596         !(xmlopt = virQEMUDriverCreateXMLConf(NULL)))
597         return EXIT_FAILURE;
598
599     virEventRegisterDefaultImpl();
600
601 #define DO_TEST(name)                                           \
602     if (virtTestRun(# name, testQemuAgent ## name, xmlopt) < 0) \
603         ret = -1
604
605     DO_TEST(FSFreeze);
606     DO_TEST(FSThaw);
607     DO_TEST(FSTrim);
608     DO_TEST(Suspend);
609     DO_TEST(Shutdown);
610     DO_TEST(CPU);
611     DO_TEST(ArbitraryCommand);
612
613     DO_TEST(Timeout); /* Timeout should always be called last */
614
615     virObjectUnref(xmlopt);
616
617     return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
618 }
619
620 VIRT_TEST_MAIN(mymain)