More updates
[handlervirt.git] / handler_virt.c
blob026c01f318f1c5af392c37e4caa13ee01f94e9f7
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* Cherokee
5 * Authors:
6 * Alvaro Lopez Ortega <alvaro@alobbs.com>
7 * Stefan de Konink <stefan@konink.de>
9 * Copyright (C) 2001-2008 Alvaro Lopez Ortega
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
26 // #define LINUX_CMDLINE "root=/dev/xvda ro ip=%s:1.2.3.4:%s:%s::eth0:off"
28 #define VIRT_INTERFACE_XML \
29 " <interface type='bridge'>" \
30 " <source bridge='xenbr0'/>" \
31 " <mac address='%s'/>" \
32 " <ip address='%s' />" \
33 " <script path='vif-bridge'/>" \
34 " </interface>"
36 //" <target dev='vif1.0'/>" \
38 #define VIRT_DISK_XML \
39 " <disk type='file' device='disk'>" \
40 " <driver name='tap' type='aio' />" \
41 " <source file='%s'/>" \
42 " <target dev='%s' bus='xen'/>" \
43 " </disk>"
45 #define VIRT_DOMAIN_CMD_IP "ip=%s:1.2.3.4:%s:255.255.255.0::eth0:off"
47 #define VIRT_DOMAIN_XML \
48 "<domain type='xen'>" \
49 " <name>%s_%s</name>" \
50 " <os>" \
51 " <type>linux</type>" \
52 " <kernel>/usr/lib/xen/boot/linux-2.6.20-xen-r6</kernel>" \
53 " <cmdline> root=/dev/xvda ro %s</cmdline>" \
54 " </os>" \
55 " <memory>%d</memory>" \
56 " <vcpu>%d</vcpu>" \
57 " <on_poweroff>destroy</on_poweroff>" \
58 " <on_reboot>restart</on_reboot>" \
59 " <on_crash>destroy</on_crash>" \
60 " <devices>" \
61 " %s" \
62 " </devices>" \
63 "</domain>"
65 #define VIRT_STORAGE_XML \
66 "<volume type='%s'>" \
67 " <name>%s_%s</name>" \
68 " <allocation>%lu</allocation>" \
69 " <capacity unit='%s'>%lu</capacity>" \
70 " <target>" \
71 " <path>%s_%s</path>" \
72 " <permissions>" \
73 " <owner>0744</owner>" \
74 " <group>0744</group>" \
75 " <mode>0744</mode>" \
76 " <label>%s_%s</label>" \
77 " </permissions>" \
78 " </target>" \
79 "</volume>"
82 #include "handler_virt.h"
83 #include "handler_avahi.h"
84 #include <cherokee/cherokee.h>
85 #include <libxml/parser.h>
86 #include <libxml/xpath.h>
89 /* Plug-in initialization
91 * In this function you can use any of these:
92 * http_delete | http_get | http_post | http_put
94 * For a full list: cherokee_http_method_t
96 * It is what your handler to be implements.
99 PLUGIN_INFO_HANDLER_EASIEST_INIT (virt, http_get | http_post);
102 /* Methods implementation
104 static ret_t
105 props_free (cherokee_handler_virt_props_t *props)
108 cherokee_buffer_mrproper(&props->xsl);
109 cherokee_buffer_mrproper(&props->virt);
110 return cherokee_module_props_free_base (MODULE_PROPS(props));
114 ret_t
115 cherokee_handler_virt_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
117 cherokee_list_t *i;
118 cherokee_handler_virt_props_t *props;
120 /* Instance a new property object
123 if (*_props == NULL) {
124 CHEROKEE_NEW_STRUCT (n, handler_virt_props);
126 cherokee_handler_avahi_props_init_base (PROP_AVAHI(n), MODULE_PROPS_FREE(props_free));
128 /* Look at handler_virt.h
129 * This is an virt of configuration.
131 n->authenticate = true; /* by default we are secure! */
132 n->read_only = true; /* by default we are secure! */
133 cherokee_buffer_init (&n->xsl); /* we support a custom header */
134 cherokee_buffer_init (&n->virt); /* your first xenserver */
136 *_props = MODULE_PROPS(n);
139 props = PROP_VIRT(*_props);
141 cherokee_config_node_foreach (i, conf) {
142 cherokee_config_node_t *subconf = CONFIG_NODE(i);
144 if (equal_buf_str (&subconf->key, "authenticate")) {
145 props->authenticate = atoi(subconf->val.buf);
147 else if (equal_buf_str (&subconf->key, "read_only")) {
148 props->read_only = atoi(subconf->val.buf);
150 else if (equal_buf_str (&subconf->key, "xsl")) {
151 cherokee_buffer_add_buffer (&props->xsl, &subconf->val);
153 else if (equal_buf_str (&subconf->key, "virt")) {
154 cherokee_buffer_add_buffer (&props->virt, &subconf->val);
159 /* Init base class
162 return cherokee_handler_avahi_configure (conf, srv, _props);
166 ret_t
167 cherokee_handler_virt_init (cherokee_handler_virt_t *hdl)
169 int isroot = false;
170 int len;
171 char *this, *next;
173 cherokee_connection_t *conn = HANDLER_CONN(hdl);
174 cherokee_buffer_init(&hdl->user);
175 cherokee_buffer_init(&hdl->vm);
177 hdl->action = nothing;
179 cherokee_buffer_add (&conn->pathinfo,
180 conn->request.buf + conn->web_directory.len,
181 conn->request.len - conn->web_directory.len);
183 this = conn->pathinfo.buf + 1;
184 next = strchr(this, '/');
187 if ((!next && (this && (len = strlen(this)) == 0)) || (next && ((len = next - this) == 0)) )
188 hdl->action = showall;
189 else {
190 cherokee_buffer_add (&hdl->user, this, len);
193 if (HDL_VIRT_PROPS(hdl)->authenticate) {
194 if (!conn->validator ||
195 (conn->validator &&
196 (!cherokee_buffer_cmp_buf(&conn->validator->user, &hdl->user) &&
197 !(isroot = cherokee_buffer_cmp (&conn->validator->user, "root", 4))))) {
198 hdl->action = nothing; /* just in case */
199 conn->error_code = http_unauthorized;
200 return ret_error;
202 } else {
203 isroot = true;
206 if (hdl->action == showall) {
207 if (!isroot) {
208 hdl->action = nothing;
209 conn->error_code = http_unauthorized;
210 return ret_error;
211 } else {
212 return virt_build_page(hdl);
217 if (!next) {
218 hdl->action = showuservms;
219 return virt_build_page(hdl);
220 } else {
221 this = next + 1;
222 next = strchr(this, '/');
224 if ( ( !next && (this && (len = strlen(this)) == 0) ) || (next && ((len = next - this) == 0)) ) {
225 //if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
226 hdl->action = showuservms;
227 return virt_build_page(hdl);
231 cherokee_buffer_add (&hdl->vm, this, len);
233 if (!next) {
234 hdl->action = domainGetXMLDesc;
235 return virt_build_page(hdl);
236 } else {
237 this = next + 1;
238 next = strchr(this, '/');
240 if (( !next && (this && (len = strlen(this)) == 0) ) || (next && ((len = next - this) == 0)) ) {
241 hdl->action = domainGetXMLDesc;
242 return virt_build_page(hdl);
246 /* TODO: it would be nice to filter read_only methods already on this point */
247 hdl->action = not_implemented;
248 switch (conn->header.method) {
249 case http_get:
250 if (strncmp(this, "virDomain", 9) == 0) {
251 if (strncmp(this+9, "Get", 3) == 0) {
252 if (strcmp(this+12, "ID") == 0) hdl->action = domainGetID;
253 else if (strcmp(this+12, "Name") == 0) hdl->action = domainGetName;
254 else if (strcmp(this+12, "MaxMemory") == 0) hdl->action = domainGetMaxMemory;
255 else if (strcmp(this+12, "MaxVcpus") == 0) hdl->action = domainGetMaxVcpus;
256 else if (strcmp(this+12, "OSType") == 0) hdl->action = domainGetOSType;
257 else if (strcmp(this+12, "UUID") == 0) hdl->action = domainGetUUID;
258 else if (strcmp(this+12, "UUIDString") == 0) hdl->action = domainGetUUIDString;
259 else if (strcmp(this+12, "XMLDesc") == 0) hdl->action = domainGetXMLDesc;
262 else if (strcmp(this+9, "Create") == 0) hdl->action = domainCreate;
263 else if (strcmp(this+9, "Destroy") == 0) hdl->action = domainDestroy;
264 else if (strcmp(this+9, "Reboot") == 0) hdl->action = domainReboot;
265 else if (strcmp(this+9, "Shutdown") == 0) hdl->action = domainShutdown;
267 else if (strcmp(this+9, "Save") == 0) hdl->action = domainSave;
268 else if (strcmp(this+9, "Restore") == 0) hdl->action = domainRestore;
270 else if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice_args;
272 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML_args;
273 else if (strcmp(this+9, "Undefine") == 0) hdl->action = domainUndefine;
276 else if (strncmp(this, "virStorage", 10) == 0) {
277 if (strncmp(this+10, "Vol", 3) == 0) {
278 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML_args;
279 else if (strcmp(this+13, "Delete") == 0) hdl->action = storageVolDelete_args;
280 else if (strcmp(this+13, "CloneXML") == 0) hdl->action = storageVolCloneXML_args;
281 else if (strcmp(this+13, "CloneStatus") == 0) hdl->action = storageVolCloneStatus_args;
282 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl->action = storageVolGetXMLDesc_args;
283 else if (strcmp(this+13, "SetPassword") == 0) hdl->action = storageVolSetPassword_args;
286 else if (strncmp(this, "virGraph", 8) == 0) {
287 if (strcmp(this+8, "Load") == 0) hdl->action = graphLoad_args;
288 if (strcmp(this+8, "Interface") == 0) hdl->action = graphInterface_args;
290 break;
292 case http_post: {
293 off_t postl;
294 cherokee_post_get_len (&conn->post, &postl);
296 if (postl <= 0 || postl >= (INT_MAX-1)) {
297 TRACE("virt", "post without post");
298 conn->error_code = http_bad_request;
299 return ret_error;
302 if (strncmp(this, "virDomain", 9) == 0) {
303 if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice;
304 else if (strcmp(this+9, "DetachDevice") == 0) hdl->action = domainDetachDevice;
305 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML;
307 else if (strncmp(this, "virStorage", 10) == 0) {
308 if (strncmp(this+10, "Vol", 3) == 0) {
309 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML;
313 break;
316 default:
317 return ret_error;
320 if (hdl->action <= 0) {
321 TRACE("virt", "There was no action specified");
322 conn->error_code = http_bad_request;
323 return ret_error;
327 return virt_build_page(hdl);
330 ret_t
331 cherokee_handler_virt_free (cherokee_handler_virt_t *hdl)
333 cherokee_buffer_mrproper (&hdl->buffer);
334 cherokee_buffer_mrproper (&hdl->user);
335 cherokee_buffer_mrproper (&hdl->vm);
337 return ret_ok;
340 ret_t
341 cherokee_handler_virt_step (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
343 if (cherokee_buffer_is_empty (&hdl->buffer))
344 return ret_eof;
346 cherokee_buffer_add (buffer, hdl->buffer.buf, 1024);
347 cherokee_buffer_move_to_begin (&hdl->buffer, 1024);
349 if (cherokee_buffer_is_empty (&hdl->buffer))
350 return ret_eof_have_data;
352 return ret_ok;
355 ret_t
356 cherokee_handler_virt_add_headers (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
358 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
360 if (hdl->action > xml)
361 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
362 else if (hdl->action > graph) {
363 cherokee_buffer_add_str (buffer, "Content-Type: image/png"CRLF);
364 } else
365 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
367 return ret_ok;
371 static ret_t
372 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
373 virConnectPtr conn = NULL;
374 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
375 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
377 cherokee_buffer_add_va (&uri, "xen://%s/", value);
379 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
380 if (!(conn = virConnectOpen (uri.buf))) {
381 return ret_error;
385 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
386 return ret_error;
387 } else {
388 virDomainPtr dom;
389 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
390 return ret_error;
391 } else {
392 char *xml = virDomainGetXMLDesc(dom, 0);
393 cherokee_buffer_add(buf, xml, strlen(xml));
395 virConnectClose(conn);
398 cherokee_buffer_mrproper(&uri);
400 return ret_ok;
403 static ret_t save_xml(cherokee_handler_virt_t *hdl, virDomainPtr result, cherokee_buffer_t *buf) {
404 ret_t ret = ret_error;
405 FILE *fd;
406 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
407 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s", hdl->user.buf);
409 mkdir(path.buf, 0755);
410 cherokee_buffer_add_va (&path, "/%s", hdl->vm.buf);
412 mkdir(path.buf, 0755);
413 cherokee_buffer_add_str (&path, "/index.xml");
415 if ((fd = fopen(path.buf, "w")) == NULL) {
416 perror(__func__);
417 } else {
418 char *output = virDomainGetXMLDesc(result, VIR_DOMAIN_XML_INACTIVE);
419 fwrite(output, strlen(output), sizeof(char), fd);
420 fclose(fd);
421 if (buf)
422 cherokee_buffer_add(buf, output, strlen(output));
423 free(output);
424 ret = ret_ok;
426 cherokee_buffer_mrproper(&path);
427 return ret;
431 static ret_t
432 virt_virt_function(cherokee_handler_virt_t *hdl, virDomainPtr dom, virConnectPtr virConn) {
433 cherokee_connection_t *conn = HANDLER_CONN(hdl);
434 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
436 switch (hdl->action) {
437 /* Returns the status of a clone copy */
438 case storageVolCloneStatus_args: {
439 ret_t ret;
440 void *name;
441 struct stat statbuf;
442 cherokee_buffer_t queue = CHEROKEE_BUF_INIT;
444 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
445 if (unlikely(ret < ret_ok)) {
446 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
447 conn->error_code = http_bad_request;
448 return ret_error;
451 cherokee_buffer_add_va (&queue, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
453 if (stat(queue.buf, &statbuf) != 0) {
454 conn->error_code = http_not_found;
455 ret = ret_error;
456 } else {
457 char hardlink[1024];
458 int namelen;
459 if ((namelen = readlink(queue.buf, hardlink, 1023)) == -1) {
460 conn->error_code = http_internal_error;
461 ret = ret_error;
462 } else {
463 hardlink[namelen] = '\0';
464 if (stat(hardlink, &statbuf) != 0) {
465 conn->error_code = http_internal_error;
466 ret = ret_error;
467 } else {
468 struct stat statbuf2;
469 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
470 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.busy", hdl->user.buf, name);
471 if (stat(busy.buf, &statbuf2) != 0) {
472 conn->error_code = http_internal_error;
473 ret = ret_error;
474 } else {
475 cherokee_buffer_add_va (buf, "%f", (float)((float)statbuf2.st_size / (float)statbuf.st_size));
476 ret = ret_ok;
478 cherokee_buffer_mrproper(&busy);
483 cherokee_buffer_mrproper(&queue);
484 return ret;
485 break;
488 /* Save the memory of a domain to a file and suspend the domain */
489 case domainSave: {
490 ret_t ret = ret_ok;
491 int result;
492 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
493 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
494 if ((result = virDomainSave(dom, path.buf)) != 0) {
495 TRACE("virt", "Saving of %s/%s failed", hdl->user.buf, hdl->vm.buf);
496 conn->error_code = http_internal_error;
497 ret = ret_error;
499 cherokee_buffer_mrproper(&path);
501 cherokee_buffer_add_long10(buf, result);
502 return ret;
503 break;
506 /* Restore the memory of a domain from a file and resume the domain */
507 case domainRestore: {
508 ret_t ret = ret_ok;
509 struct stat statbuf;
510 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
511 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
513 if (stat(path.buf, &statbuf) == 0) {
514 int result;
515 if ((result = virDomainRestore(virConn, path.buf)) != 0) {
516 TRACE("virt", "Restoring of %s/%s failed", hdl->user.buf, hdl->vm.buf);
517 conn->error_code = http_internal_error;
518 ret = ret_error;
520 cherokee_buffer_add_long10(buf, result);
521 } else {
522 TRACE("virt", "Memory file for %s/%s does not exist", hdl->user.buf, hdl->vm.buf);
523 conn->error_code = http_not_found;
524 ret = ret_error;
527 cherokee_buffer_mrproper(&path);
528 return ret;
529 break;
532 case domainUndefine: {
533 int result;
534 if ((result = virDomainUndefine(dom)) != 0) {
535 conn->error_code = http_internal_error; /* TODO */
538 cherokee_buffer_add_long10(buf, result);
539 break;
542 case domainAttachDevice_args: {
543 int result;
544 void *temp;
545 ret_t ret;
547 ret = cherokee_avl_get_ptr (conn->arguments, "type", &temp);
549 if (ret == ret_ok) {
550 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
552 if (strcmp(temp, "disk") == 0) {
553 void *device;
554 if ((ret = cherokee_avl_get_ptr (conn->arguments, "device", &device)) == ret_ok) {
555 void *file;
556 if ((ret = cherokee_avl_get_ptr (conn->arguments, "file", &file)) == ret_ok) {
557 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
558 } else {
559 virStorageVolPtr volume = virt_get_vol_by_args(hdl, virConn, 1);
561 if (volume == NULL) {
562 return ret_error;
565 file = virStorageVolGetPath(volume);
566 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
567 free(file);
569 virStorageVolFree(volume);
570 ret = ret_ok;
575 else if (strcmp(temp, "interface") == 0) {
576 void *mac, *ip;
577 if ((ret = cherokee_avl_get_ptr (conn->arguments, "mac", &mac)) == ret_ok && (ret = cherokee_avl_get_ptr (conn->arguments, "ip", &ip)) == ret_ok) {
578 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
579 } else {
580 char *mac = NULL;
581 char *ip = NULL;
582 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
583 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
584 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0)
585 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
586 cherokee_buffer_mrproper(&domu);
590 if (ret == ret_ok && (result = virDomainAttachDevice(dom, (const char *) xml.buf)) == 0) {
591 ret = ret_ok;
592 } else {
593 conn->error_code = http_internal_error;
594 return ret_error;
597 cherokee_buffer_add_long10(buf, result);
598 cherokee_buffer_mrproper(&xml);
599 } else {
600 TRACE("virt", "DeviceAttach_args; type was not specified");
601 conn->error_code = http_bad_request;
602 return ret_error;
605 break;
608 case domainAttachDevice: {
609 off_t postl;
610 int result;
611 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
612 cherokee_post_get_len (&conn->post, &postl);
613 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
614 if ((result = virDomainAttachDevice(dom, (const char *) post.buf)) != 0)
615 conn->error_code = http_internal_error;
617 cherokee_buffer_mrproper(&post);
618 cherokee_buffer_add_long10(buf, result);
619 break;
623 case domainGetXMLDesc: {
624 char *xml = virDomainGetXMLDesc(dom, 0);
625 cherokee_buffer_add(buf, xml, strlen(xml));
626 free(xml);
627 break;
631 case domainDetachDevice: {
632 off_t postl;
633 int result;
634 ret_t ret;
635 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
636 cherokee_post_get_len (&conn->post, &postl);
637 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
639 xmlDocPtr doc = xmlParseMemory((const char *) post.buf, post.len);
640 if (doc == NULL) {
641 TRACE("virt", "DeviceAttach; XML document unparceble");
642 conn->error_code = http_bad_request;
643 ret = ret_error;
644 } else
645 ret = ret_ok;
647 if (ret == ret_ok) {
648 if ((result = virDomainDetachDevice(dom, (const char *) post.buf)) != 0) {
649 conn->error_code = http_internal_error;
650 /* TODO: betere afhandeling */
652 xmlXPathContextPtr context = xmlXPathNewContext(doc);
653 if (context != NULL) {
654 xmlXPathObjectPtr obj = xmlXPathEval("string(//interface/mac/@address)", context);
655 xmlXPathFreeContext(context);
656 if ((obj != NULL) && (obj->type == XPATH_STRING) &&
657 (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
658 removeOldMac("dv28", (char *) obj->stringval);
660 xmlXPathFreeObject(obj);
663 xmlFreeDoc(doc);
664 xmlCleanupParser();
667 cherokee_buffer_mrproper(&post);
668 cherokee_buffer_add_long10(buf, result);
669 break;
672 case domainGetID: {
673 cherokee_buffer_add_ulong10(buf, virDomainGetID(dom));
674 break;
676 case domainGetMaxMemory: {
677 cherokee_buffer_add_ulong10(buf, virDomainGetMaxMemory (dom));
678 break;
680 case domainGetMaxVcpus: {
681 cherokee_buffer_add_long10(buf, virDomainGetMaxVcpus (dom));
682 break;
684 case domainGetName: {
685 const char *name = virDomainGetName (dom);
686 cherokee_buffer_add(buf, name, strlen(name));
687 break;
689 case domainGetUUID: {
690 unsigned char uuid[VIR_UUID_BUFLEN];
691 if (virDomainGetUUID(dom, uuid) == 0) {
692 cherokee_buffer_add_str(buf, uuid);
693 } else {
694 conn->error_code = http_internal_error;
695 return ret_error;
697 break;
699 case domainGetUUIDString: {
700 unsigned char uuid[VIR_UUID_STRING_BUFLEN];
701 if (virDomainGetUUIDString(dom, uuid) == 0) {
702 cherokee_buffer_add_str(buf, uuid);
703 } else {
704 conn->error_code = http_internal_error;
705 return ret_error;
707 break;
710 case domainCreate: {
711 cherokee_buffer_add_long10(buf, virDomainCreate (dom));
712 break;
715 case domainDestroy: {
716 cherokee_buffer_add_long10(buf, virDomainDestroy (dom));
717 break;
720 case domainReboot: {
721 cherokee_buffer_add_long10(buf, virDomainReboot (dom, 0));
722 break;
725 case domainShutdown: {
726 cherokee_buffer_add_long10(buf, virDomainShutdown (dom));
727 break;
731 case domainGetOSType: {
732 char *ostype = virDomainGetOSType(dom);
733 cherokee_buffer_add(buf, ostype, strlen(ostype));
734 free(ostype);
735 break;
742 if (hdl->action == domainUndefine) {
743 /* Remove VM data from filesystem */
744 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
745 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/index.xml", hdl->user.buf, hdl->vm.buf);
746 unlink(path.buf); /* TODO: instead of delet replace */
747 cherokee_buffer_mrproper(&path);
748 } else {
749 save_xml(hdl, dom, NULL);
752 return ret_ok;
755 static virStoragePoolPtr
756 virt_get_pool_by_args(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
757 cherokee_connection_t *conn = HANDLER_CONN(hdl);
758 virStoragePoolPtr pool;
759 void *temp;
760 ret_t ret;
762 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
763 if (unlikely(ret < ret_ok)) {
764 TRACE("virt", "virStoragePoolPtr; Pool argument not specified");
765 conn->error_code = http_bad_request;
766 return NULL;
769 pool = virStoragePoolLookupByName(virConn, temp);
771 return pool;
774 static virStorageVolPtr
775 virt_get_vol_by_args(cherokee_handler_virt_t *hdl, virConnectPtr virConn, unsigned short int prefix) {
776 cherokee_connection_t *conn = HANDLER_CONN(hdl);
777 virStoragePoolPtr pool;
778 virStorageVolPtr volume;
779 void *temp;
780 ret_t ret;
782 pool = virt_get_pool_by_args(hdl, virConn);
784 if (pool == NULL) {
785 conn->error_code = http_not_found;
786 return NULL;
789 virStoragePoolRefresh(pool, 0); /* TODO: might be better to do it outside */
791 ret = cherokee_avl_get_ptr (conn->arguments, "volume", &temp);
792 if (unlikely(ret < ret_ok)) {
793 TRACE("virt", "virStorageVolPtr; Volume argument not specified");
794 conn->error_code = http_bad_request;
795 return NULL;
798 if (prefix == 1) {
799 cherokee_buffer_t fullvol = CHEROKEE_BUF_INIT;
800 cherokee_buffer_add_va (&fullvol, "%s_%s", hdl->user.buf, temp);
801 volume = virStorageVolLookupByName(pool, fullvol.buf);
802 cherokee_buffer_mrproper(&fullvol);
803 } else {
804 volume = virStorageVolLookupByName(pool, temp);
807 if (volume == NULL)
808 conn->error_code = http_not_found;
810 virStoragePoolFree(pool);
812 return volume;
815 /* This function is the home for all functions that need a working
816 * pool/volume combination */
817 static ret_t
818 virt_pool_vol(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
819 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
820 cherokee_connection_t *conn = HANDLER_CONN(hdl);
821 virStorageVolPtr volume;
822 ret_t ret = ret_ok;
824 /* We only allow clone to run 'unsafe', others get prefixed */
825 volume = virt_get_vol_by_args(hdl, virConn, (hdl->action != storageVolCloneXML_args));
827 /* If the volume doesn't exist, no point to continue */
828 if (volume == NULL)
829 return ret_error;
831 switch (hdl->action) {
832 /* Sets the password of a specific volume, requires the password= option */
833 case storageVolSetPassword_args: {
834 void *temp;
835 ret = cherokee_avl_get_ptr (conn->arguments, "password", &temp);
836 if (unlikely(ret < ret_ok)) {
837 TRACE("virt", "storageVolSetPassword_args; password argument not specified");
838 conn->error_code = http_bad_request;
839 goto virt_pool_vol_cleanup;
840 } else {
841 cherokee_buffer_t cmd_passwd = CHEROKEE_BUF_INIT;
842 cherokee_buffer_add_va (&cmd_passwd, "/usr/sbin/passwdchanger.sh %s %s\n", virStorageVolGetKey(volume), temp);
843 cherokee_buffer_add_long10(buf, system(cmd_passwd.buf));
844 cherokee_buffer_mrproper(&cmd_passwd);
846 break;
849 /* Removes a volume */
850 case storageVolDelete_args: {
851 cherokee_buffer_add_long10(buf, virStorageVolDelete(volume, 0));
852 break;
855 /* Gives a description of a storage volume in XML */
856 case storageVolGetXMLDesc_args: {
857 char *xml = virStorageVolGetXMLDesc(volume, 0);
858 cherokee_buffer_add(buf, xml, strlen(xml));
859 free(xml);
860 break;
863 /* Clones a volume, insecure method! requires a new name= */
864 case storageVolCloneXML_args: {
865 void *name;
866 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
868 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
869 if (unlikely(ret < ret_ok)) {
870 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
871 conn->error_code = http_bad_request;
872 goto virt_pool_vol_cleanup;
875 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
877 if (unlikely(symlink(virStorageVolGetKey(volume), busy.buf) == 1)) {
878 conn->error_code = http_internal_error;
879 ret = ret_error;
880 } else {
881 cherokee_buffer_add_str(buf, "QUEUED");
884 cherokee_buffer_mrproper(&busy);
886 break;
891 virt_pool_vol_cleanup:
892 /* And in the end we need to free the volume we have used */
893 virStorageVolFree(volume);
895 return ret;
898 static ret_t
899 virt_virt_new(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
900 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
901 cherokee_connection_t *conn = HANDLER_CONN(hdl);
902 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
903 virStoragePoolPtr pool = NULL;
904 ret_t ret = ret_ok;
906 switch (hdl->action) {
908 case storageVolCreateXML_args: {
909 void *temp, *type, *name, *unit;
910 unsigned long int capacity, allocation;
912 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
913 if (unlikely(ret < ret_ok)) {
914 TRACE("virt", "storageVolCreateXML_args; pool argument not specified");
915 conn->error_code = http_bad_request;
916 goto virt_virt_new_cleanup;
919 pool = virStoragePoolLookupByName(virConn, temp);
921 if (pool == NULL) {
922 conn->error_code = http_not_found;
923 goto virt_virt_new_cleanup;
926 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
927 if (unlikely(ret < ret_ok)) {
928 TRACE("virt", "storageVolCreateXML_args; name argument not specified");
929 conn->error_code = http_bad_request;
930 goto virt_virt_new_cleanup;
933 ret = cherokee_avl_get_ptr (conn->arguments, "type", &type);
934 if (unlikely(ret < ret_ok)) {
935 TRACE("virt", "storageVolCreateXML_args; type argument not specified");
936 conn->error_code = http_bad_request;
937 goto virt_virt_new_cleanup;
940 ret = cherokee_avl_get_ptr (conn->arguments, "unit", &unit);
941 if (unlikely(ret < ret_ok)) {
942 TRACE("virt", "storageVolCreateXML_args; unit argument not specified");
943 conn->error_code = http_bad_request;
944 goto virt_virt_new_cleanup;
947 ret = cherokee_avl_get_ptr (conn->arguments, "allocation", &temp);
948 if (unlikely(ret < ret_ok)) {
949 TRACE("virt", "storageVolCreateXML_args; allocation argument not specified");
950 conn->error_code = http_bad_request;
951 goto virt_virt_new_cleanup;
954 allocation = strtoul(temp, NULL, 10);
955 if (errno == ERANGE) {
956 TRACE("virt", "storageVolCreateXML_args; allocation is not a number");
957 conn->error_code = http_bad_request;
958 ret = ret_error;
959 goto virt_virt_new_cleanup;
962 ret = cherokee_avl_get_ptr (conn->arguments, "capacity", &temp);
963 if (unlikely(ret < ret_ok)) {
964 TRACE("virt", "storageVolCreateXML_args; capacity argument not specified");
965 conn->error_code = http_bad_request;
966 goto virt_virt_new_cleanup;
969 capacity = strtoul(temp, NULL, 10);
970 if (errno == ERANGE || capacity == 0) {
971 TRACE("virt", "storageVolCreateXML_args; capacity is not a number");
972 conn->error_code = http_bad_request;
973 ret = ret_error;
974 goto virt_virt_new_cleanup;
977 cherokee_buffer_add_va (&xml, VIRT_STORAGE_XML, type, hdl->user.buf, name, allocation, unit, capacity, hdl->user.buf, name, hdl->user.buf, name);
978 break;
981 case domainDefineXML_args: {
982 ret_t ret;
983 unsigned int i;
984 unsigned long vcpu = 0, interface = 0, memory = 0;
986 void *temp = NULL;
988 ret = cherokee_avl_get_ptr (conn->arguments, "vcpu", &temp);
989 if (ret == ret_ok)
990 vcpu = strtoul(temp, (char **) NULL, 10);
992 if (ret != ret_ok || errno == ERANGE || vcpu == 0) {
993 conn->error_code = http_internal_error;
994 goto virt_virt_new_cleanup;
998 ret = cherokee_avl_get_ptr (conn->arguments, "memory", &temp);
999 if (ret == ret_ok)
1000 memory = strtoul(temp, (char **) NULL, 10);
1002 if (ret != ret_ok || errno == ERANGE || memory == 0) {
1003 conn->error_code = http_internal_error;
1004 goto virt_virt_new_cleanup;
1008 ret = cherokee_avl_get_ptr (conn->arguments, "interface", &temp);
1009 if (ret == ret_ok)
1010 interface = strtoul(temp, (char **) NULL, 10);
1012 if (ret != ret_ok || errno == ERANGE) {
1013 conn->error_code = http_internal_error;
1014 goto virt_virt_new_cleanup;
1017 cherokee_buffer_t cmdline_extra = CHEROKEE_BUF_INIT;
1018 cherokee_buffer_t xml_interfaces = CHEROKEE_BUF_INIT;
1019 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1020 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1022 for (i = 0; i < interface; i++) {
1023 char *mac = NULL;
1024 char *ip = NULL;
1025 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0) {
1026 cherokee_buffer_add_va (&xml_interfaces, VIRT_INTERFACE_XML, mac, ip);
1027 if (i == 0) {
1028 /* TODO: terrible hack */
1029 char gateway[16];
1030 char *temp;
1031 strcpy(gateway, ip);
1032 temp = strchr(gateway, '.');
1033 temp = strchr(++temp, '.');
1034 temp = strchr(++temp, '.');
1035 strcpy(++temp, "254");
1036 cherokee_buffer_add_va (&cmdline_extra, VIRT_DOMAIN_CMD_IP, ip, gateway);
1041 cherokee_buffer_mrproper(&domu);
1043 cherokee_buffer_add_va (&xml, VIRT_DOMAIN_XML,
1044 hdl->user.buf, hdl->vm.buf, cmdline_extra.buf, memory, vcpu, xml_interfaces.buf);
1046 cherokee_buffer_mrproper(&xml_interfaces);
1047 cherokee_buffer_mrproper(&cmdline_extra);
1048 break;
1051 case storageVolCreateXML:
1052 case domainDefineXML: {
1053 off_t postl;
1054 cherokee_post_get_len (&conn->post, &postl);
1055 cherokee_post_walk_read (&conn->post, &xml, (cuint_t) postl);
1056 break;
1060 switch (hdl->action) {
1061 case domainDefineXML_args:
1062 case domainDefineXML: {
1063 virDomainPtr result = virDomainDefineXML(virConn, (const char *) xml.buf);
1065 if (result == NULL) {
1066 /* TODO: vrij maken eventuele uitgegeven macs! */
1067 conn->error_code = http_internal_error;
1068 goto virt_virt_new_cleanup;
1071 save_xml(hdl, result, buf);
1073 virDomainFree(result);
1075 break;
1078 case storageVolCreateXML_args:
1079 case storageVolCreateXML: {
1080 virStorageVolPtr vol = virStorageVolCreateXML(pool, xml.buf, 0);
1082 if (vol == NULL) {
1083 cherokee_buffer_add_long10(buf, -1);
1084 goto virt_virt_new_cleanup;
1087 virStorageVolFree(vol);
1089 cherokee_buffer_add_long10(buf, 0);
1090 break;
1094 virt_virt_new_cleanup:
1095 cherokee_buffer_mrproper(&xml);
1097 if (pool)
1098 virStoragePoolFree(pool);
1100 return ret;
1104 static ret_t
1105 virt_virt_do(cherokee_handler_virt_t *hdl, cherokee_buffer_t *domu, cherokee_buffer_t *uri)
1107 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1109 ret_t ret = ret_error;
1110 virConnectPtr virConn = NULL;
1113 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1114 virConn = virConnectOpen (uri->buf);
1116 if (!virConn && !(virConn = virConnectOpenReadOnly (uri->buf))) {
1117 conn->error_code = http_service_unavailable;
1118 return ret_error;
1121 switch (hdl->action) {
1122 case storageVolDelete_args:
1123 case storageVolSetPassword_args:
1124 case storageVolGetXMLDesc_args:
1125 case storageVolCloneXML_args:
1126 ret = virt_pool_vol(hdl, virConn);
1127 break;
1129 case storageVolCreateXML_args:
1130 case storageVolCreateXML:
1131 case domainDefineXML_args:
1132 case domainDefineXML:
1133 ret = virt_virt_new(hdl, virConn);
1134 break;
1136 default: {
1137 virDomainPtr dom;
1138 if ((dom = virDomainLookupByName(virConn, domu->buf)) == NULL) {
1139 conn->error_code = http_not_found;
1140 } else {
1141 ret = virt_virt_function(hdl, dom, virConn);
1142 virDomainFree(dom);
1147 virConnectClose(virConn);
1148 return ret;
1151 static ret_t
1152 virt_while (cherokee_buffer_t *key, void *value, void *param) {
1153 cherokee_handler_virt_t * hdl = param;
1154 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1155 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1156 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1157 // cherokee_buffer_mrproper(&uri);
1159 cherokee_buffer_add_va (&hdl->buffer, "<domain><name>%s</name></domain>", key->buf);
1161 return ret_ok;
1164 static ret_t
1165 virt_while_user (cherokee_buffer_t *key, void *value, void *param) {
1166 cherokee_handler_virt_t *hdl = param;
1167 if (key->len > hdl->user.len && key->buf[hdl->user.len] == '_' && strncmp(key->buf, hdl->user.buf, hdl->user.len) == 0)
1168 return virt_while (key, value, param);
1170 return ret_ok;
1173 static ret_t
1174 virt_build_page (cherokee_handler_virt_t *hdl)
1176 ret_t ret;
1177 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1178 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1179 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1181 /* We use the webserver methods to parse the querystring */
1182 /* Maybe do something smart with ENUM, begin_args, end_args... */
1183 if ((hdl->action == domainDefineXML_args) ||
1184 (hdl->action == domainAttachDevice_args) ||
1185 (hdl->action == storageVolGetXMLDesc_args) ||
1186 (hdl->action == storageVolDelete_args) ||
1187 (hdl->action == storageVolSetPassword_args) ||
1188 (hdl->action == storageVolCloneXML_args) ||
1189 (hdl->action == storageVolCloneStatus_args) ||
1190 (hdl->action == storageVolCreateXML_args) ||
1191 (hdl->action == graphLoad_args) ||
1192 (hdl->action == graphInterface_args)) {
1193 ret = cherokee_connection_parse_args (conn);
1194 if (unlikely(ret < ret_ok)) {
1195 conn->error_code = http_internal_error;
1196 return ret_error;
1200 switch (hdl->action) {
1201 case graphInterface_args: {
1202 struct stat statbuf;
1203 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1204 void *interface;
1205 if ((ret = cherokee_avl_get_ptr (conn->arguments, "interface", &interface)) != ret_ok)
1206 interface = "eth0";
1208 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/interface_%s.rrd", hdl->user.buf, hdl->vm.buf, interface);
1209 if (stat(path.buf, &statbuf) != 0) {
1210 conn->error_code = http_not_found;
1211 ret = ret_error;
1212 } else {
1213 void *width, *height, *start, *end;
1214 if ((ret = cherokee_avl_get_ptr (conn->arguments, "width", &width)) != ret_ok)
1215 width = "600";
1217 if ((ret = cherokee_avl_get_ptr (conn->arguments, "height", &height)) != ret_ok)
1218 height = "200";
1220 if ((ret = cherokee_avl_get_ptr (conn->arguments, "start", &start)) != ret_ok)
1221 start = "now-1h";
1223 if ((ret = cherokee_avl_get_ptr (conn->arguments, "end", &end)) != ret_ok)
1224 end = "now";
1226 cherokee_buffer_t def1 = CHEROKEE_BUF_INIT;
1227 cherokee_buffer_t def2 = CHEROKEE_BUF_INIT;
1228 cherokee_buffer_add_va (&def1, "DEF:rxbytes=%s:rxbytes:AVERAGE:step=30", path.buf);
1229 cherokee_buffer_add_va (&def2, "DEF:txbytes=%s:txbytes:AVERAGE:step=30", path.buf);
1230 char **calcpr = NULL;
1231 int xsize, ysize;
1232 double ymin, ymax;
1233 char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1234 char *r_graph[] = { "rrdgraph", filename,
1235 "-a", "PNG",
1236 "-w", width,
1237 "-h", height,
1238 "--start", start,
1239 "--end", end,
1240 "--title", interface,
1241 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "bits per second",
1242 def1.buf,
1243 def2.buf,
1244 "CDEF:txbits=txbytes,8,*",
1245 "CDEF:rxbits=rxbytes,8,*",
1246 "AREA:rxbits#00EE00:rxbits",
1247 "LINE:txbits#0000EE:txbits" };
1249 rrd_graph(25, r_graph, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
1250 if ((ret = cherokee_buffer_read_file(&hdl->buffer, filename)) == ret_error) {
1251 hdl->action = http_internal_error;
1254 unlink(filename);
1255 free(filename);
1257 cherokee_buffer_mrproper(&def1);
1258 cherokee_buffer_mrproper(&def2);
1260 cherokee_buffer_mrproper(&path);
1261 goto virt_build_page_cleanup;
1266 case graphLoad_args: {
1267 struct stat statbuf;
1268 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1269 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/cpuTime.rrd", hdl->user.buf, hdl->vm.buf);
1270 if (stat(path.buf, &statbuf) != 0) {
1271 conn->error_code = http_not_found;
1272 ret = ret_error;
1273 } else {
1274 void *width, *height, *start, *end;
1275 if ((ret = cherokee_avl_get_ptr (conn->arguments, "width", &width)) != ret_ok)
1276 width = "600";
1278 if ((ret = cherokee_avl_get_ptr (conn->arguments, "height", &height)) != ret_ok)
1279 height = "200";
1281 if ((ret = cherokee_avl_get_ptr (conn->arguments, "start", &start)) != ret_ok)
1282 start = "now-1h";
1284 if ((ret = cherokee_avl_get_ptr (conn->arguments, "end", &end)) != ret_ok)
1285 end = "now";
1287 /* TODO: wat error checking? */
1289 cherokee_buffer_t def = CHEROKEE_BUF_INIT;
1290 cherokee_buffer_add_va (&def, "DEF:cputime=%s:cpuTime:AVERAGE:step=30", path.buf);
1291 char **calcpr = NULL;
1292 int xsize, ysize;
1293 double ymin, ymax;
1294 char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1295 char *r_graph[] = { "rrdgraph",
1296 filename,
1297 "-a", "PNG",
1298 "-w", width,
1299 "-h", height,
1300 "--start", start,
1301 "--end", end,
1302 "--title", hdl->vm.buf,
1303 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "(used / total) time",
1304 def.buf,
1305 "CDEF:cpuload=cputime,1000000000,/",
1306 "LINE:cpuload#EE0000:cpuLoad" };
1308 rrd_graph(22, r_graph, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
1309 if ((ret = cherokee_buffer_read_file(&hdl->buffer, filename)) == ret_error) {
1310 hdl->action = http_internal_error;
1313 unlink(filename);
1314 free(filename);
1316 cherokee_buffer_mrproper(&def);
1318 cherokee_buffer_mrproper(&path);
1319 goto virt_build_page_cleanup;
1323 if (hdl->action > xml && HDL_VIRT_PROPS(hdl)->xsl.len > 0)
1324 cherokee_buffer_add_va (&hdl->buffer, "<?xml version=\"1.0\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"%s\"?>\n", HDL_VIRT_PROPS(hdl)->xsl.buf);
1327 /* First, block the event loop */
1328 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1329 switch (hdl->action) {
1330 case showall:
1331 cherokee_buffer_add_str (&hdl->buffer, "<domains>");
1332 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl)->entries, virt_while, hdl, NULL, NULL);
1333 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1334 ret = ret_ok;
1335 break;
1337 case showuservms: {
1338 cherokee_buffer_add_str (&hdl->buffer, "<domains>");
1339 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl)->entries, virt_while_user, hdl, NULL, NULL);
1340 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1341 ret = ret_ok;
1342 break;
1345 default: {
1346 cherokee_buffer_t *hostname = NULL;
1347 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1348 ret = cherokee_avl_get_ptr(&HDL_AVAHI_PROPS(hdl)->entries, domu.buf, (void **) &hostname);
1350 if (ret == ret_not_found) {
1351 virDomainPtr virDom;
1352 virConnectPtr virConn;
1353 cherokee_buffer_add_va (&uri, "xen://%s/", HDL_VIRT_PROPS(hdl)->virt); // TODO: change!
1355 /* If we have the read only parameter, we will set up a connection to the
1356 * Hypervisor here. */
1357 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1358 virConn = virConnectOpen (uri.buf);
1360 /* We should already have a connection (read only) or build a new connection
1361 * if this doesn't work, we can safely assume our services is fubar */
1362 if (!virConn && !(virConn = virConnectOpenReadOnly (uri.buf))) {
1363 conn->error_code = http_service_unavailable;
1364 return ret_error;
1367 /* We lookup if there is a domain somewhere with this name */
1368 if ((virDom = virDomainLookupByName(virConn, domu.buf)) == NULL) {
1369 /* If the domain is not found on the network the only possible
1370 * command that is possible would be to Define it */
1371 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1372 ret = ret_ok;
1373 } else {
1374 /* Otherwise we don't have anything to do and we should
1375 * return an error */
1376 hdl->action = nothing;
1377 conn->error_code = http_not_found;
1378 ret = ret_error;
1380 } else {
1381 /* We don't want te recreate things that already found on the network
1382 * first undefine them! */
1383 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1384 TRACE("virt", "domainDefineXML_args/domainDefineXML; domain already exists");
1385 hdl->action = nothing;
1386 conn->error_code = http_bad_request;
1387 ret = ret_error;
1388 } else {
1389 /* Everything is ok, because nothing is found. */
1390 ret = ret_ok;
1393 /* Domain wasn't NULL, so we should free it here */
1394 virDomainFree(virDom);
1396 virConnectClose (virConn);
1397 } else if (ret == ret_ok) {
1398 cherokee_buffer_add_va (&uri, "xen://%s/", hostname->buf);
1399 printf("%s\n", uri.buf);
1400 } else {
1401 hdl->action = http_internal_error;
1402 hdl->action = nothing;
1403 ret = ret_error;
1408 /* Finally, unblock the event loop */
1409 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1411 if (ret == ret_ok && hdl->action != showall && hdl->action != showuservms) {
1412 ret = virt_virt_do(hdl, &domu, &uri);
1415 virt_build_page_cleanup:
1416 cherokee_buffer_mrproper(&domu);
1417 cherokee_buffer_mrproper(&uri);
1419 return ret;
1423 ret_t
1424 cherokee_handler_virt_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
1426 ret_t ret;
1427 CHEROKEE_NEW_STRUCT (n, handler_virt);
1429 /* Init the base class
1432 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(virt));
1434 MODULE(n)->init = (handler_func_init_t) cherokee_handler_virt_init;
1435 MODULE(n)->free = (module_func_free_t) cherokee_handler_virt_free;
1436 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_virt_step;
1437 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_virt_add_headers;
1439 HANDLER(n)->support = hsupport_length | hsupport_range;
1441 ret = cherokee_buffer_init (&n->buffer);
1442 if (unlikely(ret != ret_ok))
1443 return ret;
1445 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
1446 if (unlikely(ret != ret_ok))
1447 return ret;
1449 *hdl = HANDLER(n);
1451 return ret_ok;