Update before major change
[handlervirt.git] / handler_virt.c
blobf3ac5f13372836565ec45d084aee6173182dd76f
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 cherokee_connection_t *conn = HANDLER_CONN(hdl);
171 /* If someone is posting the server should be in
172 * read/write mode if this is not the case, just
173 * bail out directly */
175 if (conn->header.method == http_post && HDL_VIRT_PROPS(hdl)->read_only == TRUE) {
176 conn->error_code = http_unauthorized;
177 return ret_error;
180 int isroot = false;
181 int len;
182 char *this, *next;
184 cherokee_buffer_init(&hdl->user);
185 cherokee_buffer_init(&hdl->vm);
187 hdl->action = nothing;
189 cherokee_buffer_add (&conn->pathinfo,
190 conn->request.buf + conn->web_directory.len,
191 conn->request.len - conn->web_directory.len);
193 this = conn->pathinfo.buf + 1;
194 next = strchr(this, '/');
197 if ((!next && (this && (len = strlen(this)) == 0)) || (next && ((len = next - this) == 0)) )
198 hdl->action = showall;
199 else {
200 cherokee_buffer_add (&hdl->user, this, len);
203 if (HDL_VIRT_PROPS(hdl)->authenticate) {
204 if (!conn->validator ||
205 (conn->validator &&
206 (!cherokee_buffer_cmp_buf(&conn->validator->user, &hdl->user) &&
207 !(isroot = cherokee_buffer_cmp (&conn->validator->user, "root", 4))))) {
208 hdl->action = nothing; /* just in case */
209 conn->error_code = http_unauthorized;
210 return ret_error;
212 } else {
213 isroot = true;
216 if (hdl->action == showall) {
217 if (!isroot) {
218 hdl->action = nothing;
219 conn->error_code = http_unauthorized;
220 return ret_error;
221 } else {
222 return virt_build_page(hdl);
227 if (!next) {
228 hdl->action = showuservms;
229 return virt_build_page(hdl);
230 } else {
231 this = next + 1;
232 next = strchr(this, '/');
234 if ( ( !next && (this && (len = strlen(this)) == 0) ) || (next && ((len = next - this) == 0)) ) {
235 //if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
236 hdl->action = showuservms;
237 return virt_build_page(hdl);
241 cherokee_buffer_add (&hdl->vm, this, len);
243 if (!next) {
244 hdl->action = domainGetXMLDesc;
245 return virt_build_page(hdl);
246 } else {
247 this = next + 1;
248 next = strchr(this, '/');
250 if (( !next && (this && (len = strlen(this)) == 0) ) || (next && ((len = next - this) == 0)) ) {
251 hdl->action = domainGetXMLDesc;
252 return virt_build_page(hdl);
256 hdl->action = not_implemented;
257 switch (conn->header.method) {
258 case http_get:
259 if (strncmp(this, "virDomain", 9) == 0) {
260 if (strncmp(this+9, "Get", 3) == 0) {
261 if (strcmp(this+12, "ID") == 0) hdl->action = domainGetID;
262 else if (strcmp(this+12, "Name") == 0) hdl->action = domainGetName;
263 else if (strcmp(this+12, "MaxMemory") == 0) hdl->action = domainGetMaxMemory;
264 else if (strcmp(this+12, "MaxVcpus") == 0) hdl->action = domainGetMaxVcpus;
265 else if (strcmp(this+12, "OSType") == 0) hdl->action = domainGetOSType;
266 else if (strcmp(this+12, "UUID") == 0) hdl->action = domainGetUUID;
267 else if (strcmp(this+12, "UUIDString") == 0) hdl->action = domainGetUUIDString;
268 else if (strcmp(this+12, "XMLDesc") == 0) hdl->action = domainGetXMLDesc;
271 else if (HDL_VIRT_PROPS(hdl)->read_only == FALSE) {
272 if (strcmp(this+9, "Create") == 0) hdl->action = domainCreate;
273 else if (strcmp(this+9, "Destroy") == 0) hdl->action = domainDestroy;
274 else if (strcmp(this+9, "Reboot") == 0) hdl->action = domainReboot;
275 else if (strcmp(this+9, "Shutdown") == 0) hdl->action = domainShutdown;
277 else if (strcmp(this+9, "Save") == 0) hdl->action = domainSave;
278 else if (strcmp(this+9, "Restore") == 0) hdl->action = domainRestore;
280 else if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice_args;
282 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML_args;
283 else if (strcmp(this+9, "Undefine") == 0) hdl->action = domainUndefine;
286 else if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && strncmp(this, "virStorage", 10) == 0) {
287 if (strncmp(this+10, "Vol", 3) == 0) {
288 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML_args;
289 else if (strcmp(this+13, "Delete") == 0) hdl->action = storageVolDelete_args;
290 else if (strcmp(this+13, "CloneXML") == 0) hdl->action = storageVolCloneXML_args;
291 else if (strcmp(this+13, "CloneStatus") == 0) hdl->action = storageVolCloneStatus_args;
292 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl->action = storageVolGetXMLDesc_args;
293 else if (strcmp(this+13, "SetPassword") == 0) hdl->action = storageVolSetPassword_args;
296 else if (strncmp(this, "virGraph", 8) == 0) {
297 if (strcmp(this+8, "Load") == 0) hdl->action = graphLoad_args;
298 if (strcmp(this+8, "Interface") == 0) hdl->action = graphInterface_args;
300 break;
302 case http_post: {
303 off_t postl;
304 cherokee_post_get_len (&conn->post, &postl);
306 if (postl <= 0 || postl >= (INT_MAX-1)) {
307 TRACE("virt", "post without post");
308 conn->error_code = http_bad_request;
309 return ret_error;
312 if (strncmp(this, "virDomain", 9) == 0) {
313 if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice;
314 else if (strcmp(this+9, "DetachDevice") == 0) hdl->action = domainDetachDevice;
315 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML;
317 else if (strncmp(this, "virStorage", 10) == 0) {
318 if (strncmp(this+10, "Vol", 3) == 0) {
319 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML;
323 break;
326 default:
327 return ret_error;
330 if (hdl->action <= 0) {
331 TRACE("virt", "There was no action specified");
332 conn->error_code = http_bad_request;
333 return ret_error;
337 return virt_build_page(hdl);
340 ret_t
341 cherokee_handler_virt_free (cherokee_handler_virt_t *hdl)
343 cherokee_buffer_mrproper (&hdl->buffer);
344 cherokee_buffer_mrproper (&hdl->user);
345 cherokee_buffer_mrproper (&hdl->vm);
347 return ret_ok;
350 ret_t
351 cherokee_handler_virt_step (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
353 cuint_t tosend;
355 if (cherokee_buffer_is_empty (&hdl->buffer))
356 return ret_eof;
358 tosend = (hdl->buffer.len > 1024 ? 1024 : hdl->buffer.len);
360 cherokee_buffer_add (buffer, hdl->buffer.buf, tosend);
361 cherokee_buffer_move_to_begin (&hdl->buffer, tosend);
363 if (cherokee_buffer_is_empty (&hdl->buffer))
364 return ret_eof_have_data;
366 return ret_ok;
369 ret_t
370 cherokee_handler_virt_add_headers (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
372 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
374 if (hdl->action > xml)
375 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
376 else if (hdl->action > graph) {
377 cherokee_buffer_add_str (buffer, "Content-Type: image/png"CRLF);
378 } else
379 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
381 return ret_ok;
385 static ret_t
386 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
387 virConnectPtr conn = NULL;
388 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
389 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
391 cherokee_buffer_add_va (&uri, "xen://%s/", value);
393 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
394 if (!(conn = virConnectOpen (uri.buf))) {
395 return ret_error;
399 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
400 return ret_error;
401 } else {
402 virDomainPtr dom;
403 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
404 return ret_error;
405 } else {
406 char *xml = virDomainGetXMLDesc(dom, 0);
407 cherokee_buffer_add(buf, xml, strlen(xml));
409 virConnectClose(conn);
412 cherokee_buffer_mrproper(&uri);
414 return ret_ok;
417 static ret_t load_xml(cherokee_handler_virt_t *hdl, cherokee_buffer_t *xmlDesc) {
418 ret_t ret = ret_error;
419 FILE *fd;
420 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
421 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s", hdl->user.buf);
423 mkdir(path.buf, 0755);
424 cherokee_buffer_add_va (&path, "/%s", hdl->vm.buf);
426 mkdir(path.buf, 0755);
427 cherokee_buffer_add_str (&path, "/index.xml");
429 if ((fd = fopen(path.buf, "r")) != NULL) {
430 while (!feof(fd)) {
431 char buf[1024];
432 size_t amount = fread(buf, sizeof(char), 1024, fd);
434 cherokee_buffer_add (xmlDesc, buf, amount);
436 fclose(fd);
437 if (xmlDesc->len > 0)
438 ret = ret_ok;
441 cherokee_buffer_mrproper(&path);
442 return ret;
445 static ret_t save_xml(cherokee_handler_virt_t *hdl, virDomainPtr result, cherokee_buffer_t *buf) {
446 ret_t ret = ret_error;
447 FILE *fd;
448 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
449 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s", hdl->user.buf);
451 mkdir(path.buf, 0755);
452 cherokee_buffer_add_va (&path, "/%s", hdl->vm.buf);
454 mkdir(path.buf, 0755);
455 cherokee_buffer_add_str (&path, "/index.xml");
457 if ((fd = fopen(path.buf, "w")) == NULL) {
458 perror(__func__);
459 } else {
460 char *output = virDomainGetXMLDesc(result, VIR_DOMAIN_XML_INACTIVE);
461 fwrite(output, strlen(output), sizeof(char), fd);
462 fclose(fd);
463 if (buf)
464 cherokee_buffer_add(buf, output, strlen(output));
465 free(output);
466 ret = ret_ok;
468 cherokee_buffer_mrproper(&path);
469 return ret;
473 static ret_t
474 virt_virt_function(cherokee_handler_virt_t *hdl, virDomainPtr dom, virConnectPtr virConn) {
475 cherokee_connection_t *conn = HANDLER_CONN(hdl);
476 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
478 switch (hdl->action) {
479 /* Returns the status of a clone copy */
480 case storageVolCloneStatus_args: {
481 ret_t ret;
482 void *name;
483 struct stat statbuf;
484 cherokee_buffer_t queue = CHEROKEE_BUF_INIT;
486 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
487 if (unlikely(ret < ret_ok)) {
488 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
489 conn->error_code = http_bad_request;
490 return ret_error;
493 cherokee_buffer_add_va (&queue, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
495 if (stat(queue.buf, &statbuf) != 0) {
496 conn->error_code = http_not_found;
497 ret = ret_error;
498 } else {
499 char hardlink[1024];
500 int namelen;
501 if ((namelen = readlink(queue.buf, hardlink, 1023)) == -1) {
502 conn->error_code = http_internal_error;
503 ret = ret_error;
504 } else {
505 hardlink[namelen] = '\0';
506 if (stat(hardlink, &statbuf) != 0) {
507 conn->error_code = http_internal_error;
508 ret = ret_error;
509 } else {
510 struct stat statbuf2;
511 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
512 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.busy", hdl->user.buf, name);
513 if (stat(busy.buf, &statbuf2) != 0) {
514 conn->error_code = http_internal_error;
515 ret = ret_error;
516 } else {
517 cherokee_buffer_add_va (buf, "%f", (float)((float)statbuf2.st_size / (float)statbuf.st_size));
518 ret = ret_ok;
520 cherokee_buffer_mrproper(&busy);
525 cherokee_buffer_mrproper(&queue);
526 return ret;
527 break;
530 /* Save the memory of a domain to a file and suspend the domain */
531 case domainSave: {
532 ret_t ret = ret_ok;
533 int result;
534 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
535 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
536 if ((result = virDomainSave(dom, path.buf)) != 0) {
537 TRACE("virt", "Saving of %s/%s failed", hdl->user.buf, hdl->vm.buf);
538 conn->error_code = http_internal_error;
539 ret = ret_error;
541 cherokee_buffer_mrproper(&path);
543 cherokee_buffer_add_long10(buf, result);
544 return ret;
545 break;
548 /* Restore the memory of a domain from a file and resume the domain */
549 case domainRestore: {
550 ret_t ret = ret_ok;
551 struct stat statbuf;
552 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
553 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
555 if (stat(path.buf, &statbuf) == 0) {
556 int result;
557 if ((result = virDomainRestore(virConn, path.buf)) != 0) {
558 TRACE("virt", "Restoring of %s/%s failed", hdl->user.buf, hdl->vm.buf);
559 conn->error_code = http_internal_error;
560 ret = ret_error;
562 cherokee_buffer_add_long10(buf, result);
563 } else {
564 TRACE("virt", "Memory file for %s/%s does not exist", hdl->user.buf, hdl->vm.buf);
565 conn->error_code = http_not_found;
566 ret = ret_error;
569 cherokee_buffer_mrproper(&path);
570 return ret;
571 break;
574 case domainUndefine: {
575 int result;
576 if ((result = virDomainUndefine(dom)) != 0) {
577 conn->error_code = http_internal_error; /* TODO */
580 cherokee_buffer_add_long10(buf, result);
581 break;
584 case domainAttachDevice_args: {
585 int result;
586 void *temp;
587 ret_t ret;
589 ret = cherokee_avl_get_ptr (conn->arguments, "type", &temp);
591 if (ret == ret_ok) {
592 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
594 if (strcmp(temp, "disk") == 0) {
595 void *device;
596 if ((ret = cherokee_avl_get_ptr (conn->arguments, "device", &device)) == ret_ok) {
597 void *file;
598 if ((ret = cherokee_avl_get_ptr (conn->arguments, "file", &file)) == ret_ok) {
599 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
600 } else {
601 virStorageVolPtr volume = virt_get_vol_by_args(hdl, virConn, 1);
603 if (volume == NULL) {
604 return ret_error;
607 file = virStorageVolGetPath(volume);
608 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
609 free(file);
611 virStorageVolFree(volume);
612 ret = ret_ok;
617 else if (strcmp(temp, "interface") == 0) {
618 void *mac, *ip;
619 if ((ret = cherokee_avl_get_ptr (conn->arguments, "mac", &mac)) == ret_ok && (ret = cherokee_avl_get_ptr (conn->arguments, "ip", &ip)) == ret_ok) {
620 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
621 } else {
622 char *mac = NULL;
623 char *ip = NULL;
624 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
625 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
626 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0)
627 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
628 cherokee_buffer_mrproper(&domu);
632 if (ret == ret_ok && (result = virDomainAttachDevice(dom, (const char *) xml.buf)) == 0) {
633 ret = ret_ok;
634 } else {
635 conn->error_code = http_internal_error;
636 return ret_error;
639 cherokee_buffer_add_long10(buf, result);
640 cherokee_buffer_mrproper(&xml);
641 } else {
642 TRACE("virt", "DeviceAttach_args; type was not specified");
643 conn->error_code = http_bad_request;
644 return ret_error;
647 break;
650 case domainAttachDevice: {
651 off_t postl;
652 int result;
653 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
654 cherokee_post_get_len (&conn->post, &postl);
655 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
656 if ((result = virDomainAttachDevice(dom, (const char *) post.buf)) != 0)
657 conn->error_code = http_internal_error;
659 cherokee_buffer_mrproper(&post);
660 cherokee_buffer_add_long10(buf, result);
661 break;
665 case domainGetXMLDesc: {
666 char *xml = virDomainGetXMLDesc(dom, 0);
667 cherokee_buffer_add(buf, xml, strlen(xml));
668 free(xml);
669 break;
673 case domainDetachDevice: {
674 off_t postl;
675 int result;
676 ret_t ret;
677 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
678 cherokee_post_get_len (&conn->post, &postl);
679 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
681 xmlDocPtr doc = xmlParseMemory((const char *) post.buf, post.len);
682 if (doc == NULL) {
683 TRACE("virt", "DeviceAttach; XML document unparceble");
684 conn->error_code = http_bad_request;
685 ret = ret_error;
686 } else
687 ret = ret_ok;
689 if (ret == ret_ok) {
690 if ((result = virDomainDetachDevice(dom, (const char *) post.buf)) != 0) {
691 conn->error_code = http_internal_error;
692 /* TODO: betere afhandeling */
694 xmlXPathContextPtr context = xmlXPathNewContext(doc);
695 if (context != NULL) {
696 xmlXPathObjectPtr obj = xmlXPathEval("string(//interface/mac/@address)", context);
697 xmlXPathFreeContext(context);
698 if ((obj != NULL) && (obj->type == XPATH_STRING) &&
699 (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
700 removeOldMac("dv28", (char *) obj->stringval);
702 xmlXPathFreeObject(obj);
705 xmlFreeDoc(doc);
706 xmlCleanupParser();
709 cherokee_buffer_mrproper(&post);
710 cherokee_buffer_add_long10(buf, result);
711 break;
714 case domainGetID: {
715 cherokee_buffer_add_ulong10(buf, virDomainGetID(dom));
716 break;
718 case domainGetMaxMemory: {
719 cherokee_buffer_add_ulong10(buf, virDomainGetMaxMemory (dom));
720 break;
722 case domainGetMaxVcpus: {
723 cherokee_buffer_add_long10(buf, virDomainGetMaxVcpus (dom));
724 break;
726 case domainGetName: {
727 const char *name = virDomainGetName (dom);
728 cherokee_buffer_add(buf, name, strlen(name));
729 break;
731 case domainGetUUID: {
732 unsigned char uuid[VIR_UUID_BUFLEN];
733 if (virDomainGetUUID(dom, uuid) == 0) {
734 cherokee_buffer_add_str(buf, uuid);
735 } else {
736 conn->error_code = http_internal_error;
737 return ret_error;
739 break;
741 case domainGetUUIDString: {
742 unsigned char uuid[VIR_UUID_STRING_BUFLEN];
743 if (virDomainGetUUIDString(dom, uuid) == 0) {
744 cherokee_buffer_add_str(buf, uuid);
745 } else {
746 conn->error_code = http_internal_error;
747 return ret_error;
749 break;
752 case domainCreate: {
753 cherokee_buffer_t xmlDesc = CHEROKEE_BUF_INIT;
754 save_xml(hdl, dom, &xmlDesc);
755 // TODO: conn = waar moet ik van avahi naar toe
757 cherokee_buffer_add_long10(buf, (virDomainUndefine(dom) == 0 &&
758 (dom = virDomainCreateLinux(virConn, xmlDesc.buf, 0)) != NULL ? 0 : -1) );
759 cherokee_buffer_mrproper(&xmlDesc);
760 break;
763 case domainDestroy: {
764 cherokee_buffer_add_long10(buf, virDomainDestroy (dom));
765 break;
768 case domainReboot: {
769 cherokee_buffer_add_long10(buf, virDomainReboot (dom, 0));
770 break;
773 case domainShutdown: {
774 cherokee_buffer_add_long10(buf, virDomainShutdown (dom));
775 break;
779 case domainGetOSType: {
780 char *ostype = virDomainGetOSType(dom);
781 cherokee_buffer_add(buf, ostype, strlen(ostype));
782 free(ostype);
783 break;
790 if (hdl->action == domainUndefine) {
791 /* Remove VM data from filesystem */
792 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
793 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/index.xml", hdl->user.buf, hdl->vm.buf);
794 unlink(path.buf); /* TODO: instead of delet replace */
795 cherokee_buffer_mrproper(&path);
796 } else if (hdl->action != domainCreate) {
797 save_xml(hdl, dom, NULL);
800 return ret_ok;
803 static virStoragePoolPtr
804 virt_get_pool_by_args(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
805 cherokee_connection_t *conn = HANDLER_CONN(hdl);
806 virStoragePoolPtr pool;
807 void *temp;
808 ret_t ret;
810 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
811 if (unlikely(ret < ret_ok)) {
812 TRACE("virt", "virStoragePoolPtr; Pool argument not specified");
813 conn->error_code = http_bad_request;
814 return NULL;
817 pool = virStoragePoolLookupByName(virConn, temp);
819 return pool;
822 static virStorageVolPtr
823 virt_get_vol_by_args(cherokee_handler_virt_t *hdl, virConnectPtr virConn, unsigned short int prefix) {
824 cherokee_connection_t *conn = HANDLER_CONN(hdl);
825 virStoragePoolPtr pool;
826 virStorageVolPtr volume;
827 void *temp;
828 ret_t ret;
830 pool = virt_get_pool_by_args(hdl, virConn);
832 if (pool == NULL) {
833 conn->error_code = http_not_found;
834 return NULL;
837 virStoragePoolRefresh(pool, 0); /* TODO: might be better to do it outside */
839 ret = cherokee_avl_get_ptr (conn->arguments, "volume", &temp);
840 if (unlikely(ret < ret_ok)) {
841 TRACE("virt", "virStorageVolPtr; Volume argument not specified");
842 conn->error_code = http_bad_request;
843 return NULL;
846 if (prefix == 1) {
847 cherokee_buffer_t fullvol = CHEROKEE_BUF_INIT;
848 cherokee_buffer_add_va (&fullvol, "%s_%s", hdl->user.buf, temp);
849 volume = virStorageVolLookupByName(pool, fullvol.buf);
850 cherokee_buffer_mrproper(&fullvol);
851 } else {
852 volume = virStorageVolLookupByName(pool, temp);
855 if (volume == NULL)
856 conn->error_code = http_not_found;
858 virStoragePoolFree(pool);
860 return volume;
863 /* This function is the home for all functions that need a working
864 * pool/volume combination */
865 static ret_t
866 virt_pool_vol(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
867 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
868 cherokee_connection_t *conn = HANDLER_CONN(hdl);
869 virStorageVolPtr volume;
870 ret_t ret = ret_ok;
872 /* We only allow clone to run 'unsafe', others get prefixed */
873 volume = virt_get_vol_by_args(hdl, virConn, (hdl->action != storageVolCloneXML_args));
875 /* If the volume doesn't exist, no point to continue */
876 if (volume == NULL)
877 return ret_error;
879 switch (hdl->action) {
880 /* Sets the password of a specific volume, requires the password= option */
881 case storageVolSetPassword_args: {
882 void *temp;
883 ret = cherokee_avl_get_ptr (conn->arguments, "password", &temp);
884 if (unlikely(ret < ret_ok)) {
885 TRACE("virt", "storageVolSetPassword_args; password argument not specified");
886 conn->error_code = http_bad_request;
887 goto virt_pool_vol_cleanup;
888 } else {
889 cherokee_buffer_t cmd_passwd = CHEROKEE_BUF_INIT;
890 cherokee_buffer_add_va (&cmd_passwd, "/usr/sbin/passwdchanger.sh %s %s\n", virStorageVolGetKey(volume), temp);
891 cherokee_buffer_add_long10(buf, system(cmd_passwd.buf));
892 cherokee_buffer_mrproper(&cmd_passwd);
894 break;
897 /* Removes a volume */
898 case storageVolDelete_args: {
899 cherokee_buffer_add_long10(buf, virStorageVolDelete(volume, 0));
900 break;
903 /* Gives a description of a storage volume in XML */
904 case storageVolGetXMLDesc_args: {
905 char *xml = virStorageVolGetXMLDesc(volume, 0);
906 cherokee_buffer_add(buf, xml, strlen(xml));
907 free(xml);
908 break;
911 /* Clones a volume, insecure method! requires a new name= */
912 case storageVolCloneXML_args: {
913 void *name;
914 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
916 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
917 if (unlikely(ret < ret_ok)) {
918 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
919 conn->error_code = http_bad_request;
920 goto virt_pool_vol_cleanup;
923 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
925 if (unlikely(symlink(virStorageVolGetKey(volume), busy.buf) == 1)) {
926 conn->error_code = http_internal_error;
927 ret = ret_error;
928 } else {
929 cherokee_buffer_add_str(buf, "QUEUED");
932 cherokee_buffer_mrproper(&busy);
934 break;
939 virt_pool_vol_cleanup:
940 /* And in the end we need to free the volume we have used */
941 virStorageVolFree(volume);
943 return ret;
946 static ret_t
947 virt_virt_new(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
948 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
949 cherokee_connection_t *conn = HANDLER_CONN(hdl);
950 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
951 virStoragePoolPtr pool = NULL;
952 ret_t ret = ret_ok;
954 switch (hdl->action) {
956 case storageVolCreateXML_args: {
957 void *temp, *type, *name, *unit;
958 unsigned long int capacity, allocation;
960 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
961 if (unlikely(ret < ret_ok)) {
962 TRACE("virt", "storageVolCreateXML_args; pool argument not specified");
963 conn->error_code = http_bad_request;
964 goto virt_virt_new_cleanup;
967 TRACE("args", "%s", temp);
969 pool = virStoragePoolLookupByName(virConn, temp);
971 if (pool == NULL) {
972 conn->error_code = http_not_found;
973 goto virt_virt_new_cleanup;
976 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
977 if (unlikely(ret < ret_ok)) {
978 TRACE("virt", "storageVolCreateXML_args; name argument not specified");
979 conn->error_code = http_bad_request;
980 goto virt_virt_new_cleanup;
983 ret = cherokee_avl_get_ptr (conn->arguments, "type", &type);
984 if (unlikely(ret < ret_ok)) {
985 TRACE("virt", "storageVolCreateXML_args; type argument not specified");
986 conn->error_code = http_bad_request;
987 goto virt_virt_new_cleanup;
990 ret = cherokee_avl_get_ptr (conn->arguments, "unit", &unit);
991 if (unlikely(ret < ret_ok)) {
992 TRACE("virt", "storageVolCreateXML_args; unit argument not specified");
993 conn->error_code = http_bad_request;
994 goto virt_virt_new_cleanup;
997 ret = cherokee_avl_get_ptr (conn->arguments, "allocation", &temp);
998 if (unlikely(ret < ret_ok)) {
999 TRACE("virt", "storageVolCreateXML_args; allocation argument not specified");
1000 conn->error_code = http_bad_request;
1001 goto virt_virt_new_cleanup;
1004 allocation = strtoul(temp, NULL, 10);
1005 if (errno == ERANGE) {
1006 TRACE("virt", "storageVolCreateXML_args; allocation is not a number");
1007 conn->error_code = http_bad_request;
1008 ret = ret_error;
1009 goto virt_virt_new_cleanup;
1012 ret = cherokee_avl_get_ptr (conn->arguments, "capacity", &temp);
1013 if (unlikely(ret < ret_ok)) {
1014 TRACE("virt", "storageVolCreateXML_args; capacity argument not specified");
1015 conn->error_code = http_bad_request;
1016 goto virt_virt_new_cleanup;
1019 capacity = strtoul(temp, NULL, 10);
1020 if (errno == ERANGE || capacity == 0) {
1021 TRACE("virt", "storageVolCreateXML_args; capacity is not a number");
1022 conn->error_code = http_bad_request;
1023 ret = ret_error;
1024 goto virt_virt_new_cleanup;
1027 cherokee_buffer_add_va (&xml, VIRT_STORAGE_XML, type, hdl->user.buf, name, allocation, unit, capacity, hdl->user.buf, name, hdl->user.buf, name);
1028 break;
1031 case domainDefineXML_args: {
1032 ret_t ret;
1033 unsigned int i;
1034 unsigned long vcpu = 0, interface = 0, memory = 0;
1036 void *temp = NULL;
1038 ret = cherokee_avl_get_ptr (conn->arguments, "vcpu", &temp);
1039 if (ret == ret_ok)
1040 vcpu = strtoul(temp, (char **) NULL, 10);
1042 if (ret != ret_ok || errno == ERANGE || vcpu == 0) {
1043 conn->error_code = http_internal_error;
1044 goto virt_virt_new_cleanup;
1048 ret = cherokee_avl_get_ptr (conn->arguments, "memory", &temp);
1049 if (ret == ret_ok)
1050 memory = strtoul(temp, (char **) NULL, 10);
1052 if (ret != ret_ok || errno == ERANGE || memory == 0) {
1053 conn->error_code = http_internal_error;
1054 goto virt_virt_new_cleanup;
1058 ret = cherokee_avl_get_ptr (conn->arguments, "interface", &temp);
1059 if (ret == ret_ok)
1060 interface = strtoul(temp, (char **) NULL, 10);
1062 if (ret != ret_ok || errno == ERANGE) {
1063 conn->error_code = http_internal_error;
1064 goto virt_virt_new_cleanup;
1067 cherokee_buffer_t cmdline_extra = CHEROKEE_BUF_INIT;
1068 cherokee_buffer_t xml_interfaces = CHEROKEE_BUF_INIT;
1069 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1070 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1072 for (i = 0; i < interface; i++) {
1073 char *mac = NULL;
1074 char *ip = NULL;
1075 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0) {
1076 cherokee_buffer_add_va (&xml_interfaces, VIRT_INTERFACE_XML, mac, ip);
1077 if (i == 0) {
1078 /* TODO: terrible hack */
1079 char gateway[16];
1080 char *temp;
1081 strcpy(gateway, ip);
1082 temp = strchr(gateway, '.');
1083 temp = strchr(++temp, '.');
1084 temp = strchr(++temp, '.');
1085 strcpy(++temp, "254");
1086 cherokee_buffer_add_va (&cmdline_extra, VIRT_DOMAIN_CMD_IP, ip, gateway);
1091 cherokee_buffer_mrproper(&domu);
1093 cherokee_buffer_add_va (&xml, VIRT_DOMAIN_XML,
1094 hdl->user.buf, hdl->vm.buf, cmdline_extra.buf, memory, vcpu, xml_interfaces.buf);
1096 cherokee_buffer_mrproper(&xml_interfaces);
1097 cherokee_buffer_mrproper(&cmdline_extra);
1098 break;
1101 case storageVolCreateXML:
1102 case domainDefineXML: {
1103 off_t postl;
1104 cherokee_post_get_len (&conn->post, &postl);
1105 cherokee_post_walk_read (&conn->post, &xml, (cuint_t) postl);
1106 break;
1110 switch (hdl->action) {
1111 case domainDefineXML_args:
1112 case domainDefineXML: {
1113 virDomainPtr result = virDomainDefineXML(virConn, (const char *) xml.buf);
1115 if (result == NULL) {
1116 /* TODO: vrij maken eventuele uitgegeven macs! */
1117 conn->error_code = http_internal_error;
1118 goto virt_virt_new_cleanup;
1121 save_xml(hdl, result, buf);
1123 virDomainFree(result);
1125 break;
1128 case storageVolCreateXML_args:
1129 case storageVolCreateXML: {
1130 virStorageVolPtr vol = virStorageVolCreateXML(pool, xml.buf, 0);
1132 if (vol == NULL) {
1133 cherokee_buffer_add_long10(buf, -1);
1134 goto virt_virt_new_cleanup;
1137 virStorageVolFree(vol);
1139 cherokee_buffer_add_long10(buf, 0);
1140 break;
1144 virt_virt_new_cleanup:
1145 cherokee_buffer_mrproper(&xml);
1147 if (pool)
1148 virStoragePoolFree(pool);
1150 return ret;
1154 static ret_t
1155 virt_virt_do(cherokee_handler_virt_t *hdl, cherokee_buffer_t *domu, cherokee_buffer_t *uri)
1157 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1159 ret_t ret = ret_error;
1160 virConnectPtr virConn = NULL;
1163 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1164 virConn = virConnectOpen (uri->buf);
1166 if (!virConn && !(virConn = virConnectOpenReadOnly (uri->buf))) {
1167 conn->error_code = http_service_unavailable;
1168 return ret_error;
1171 switch (hdl->action) {
1172 case storageVolDelete_args:
1173 case storageVolSetPassword_args:
1174 case storageVolGetXMLDesc_args:
1175 case storageVolCloneXML_args:
1176 ret = virt_pool_vol(hdl, virConn);
1177 break;
1179 case storageVolCreateXML_args:
1180 case storageVolCreateXML:
1181 case domainDefineXML_args:
1182 case domainDefineXML:
1183 ret = virt_virt_new(hdl, virConn);
1184 break;
1186 default: {
1187 virDomainPtr dom;
1188 if ((dom = virDomainLookupByName(virConn, domu->buf)) == NULL) {
1189 conn->error_code = http_not_found;
1190 } else {
1191 ret = virt_virt_function(hdl, dom, virConn);
1192 virDomainFree(dom);
1197 virConnectClose(virConn);
1198 return ret;
1201 static ret_t
1202 virt_while (cherokee_buffer_t *key, void *value, void *param) {
1203 cherokee_handler_virt_t * hdl = param;
1204 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1205 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1206 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1207 // cherokee_buffer_mrproper(&uri);
1209 cherokee_buffer_add_va (&hdl->buffer, "<domain><name>%s</name></domain>", key->buf);
1211 return ret_ok;
1214 static ret_t
1215 virt_while_user (cherokee_buffer_t *key, void *value, void *param) {
1216 cherokee_handler_virt_t *hdl = param;
1217 if (key->len > hdl->user.len && key->buf[hdl->user.len] == '_' && strncmp(key->buf, hdl->user.buf, hdl->user.len) == 0)
1218 return virt_while (key, value, param);
1220 return ret_ok;
1223 static ret_t
1224 virt_build_page (cherokee_handler_virt_t *hdl)
1226 ret_t ret;
1227 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1228 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1229 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1231 /* We use the webserver methods to parse the querystring */
1232 /* Maybe do something smart with ENUM, begin_args, end_args... */
1233 if ((hdl->action == domainDefineXML_args) ||
1234 (hdl->action == domainAttachDevice_args) ||
1235 (hdl->action == storageVolGetXMLDesc_args) ||
1236 (hdl->action == storageVolDelete_args) ||
1237 (hdl->action == storageVolSetPassword_args) ||
1238 (hdl->action == storageVolCloneXML_args) ||
1239 (hdl->action == storageVolCloneStatus_args) ||
1240 (hdl->action == storageVolCreateXML_args) ||
1241 (hdl->action == graphLoad_args) ||
1242 (hdl->action == graphInterface_args)) {
1243 ret = cherokee_connection_parse_args (conn);
1244 if (unlikely(ret < ret_ok)) {
1245 conn->error_code = http_internal_error;
1246 return ret_error;
1250 switch (hdl->action) {
1251 case graphInterface_args: {
1252 struct stat statbuf;
1253 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1254 void *interface;
1255 if ((ret = cherokee_avl_get_ptr (conn->arguments, "interface", &interface)) != ret_ok)
1256 interface = "eth0";
1258 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/interface_%s.rrd", hdl->user.buf, hdl->vm.buf, interface);
1259 if (stat(path.buf, &statbuf) != 0) {
1260 conn->error_code = http_not_found;
1261 ret = ret_error;
1262 } else {
1263 void *width, *height, *start, *end;
1264 if ((ret = cherokee_avl_get_ptr (conn->arguments, "width", &width)) != ret_ok)
1265 width = "600";
1267 if ((ret = cherokee_avl_get_ptr (conn->arguments, "height", &height)) != ret_ok)
1268 height = "200";
1270 if ((ret = cherokee_avl_get_ptr (conn->arguments, "start", &start)) != ret_ok)
1271 start = "now-1h";
1273 if ((ret = cherokee_avl_get_ptr (conn->arguments, "end", &end)) != ret_ok)
1274 end = "now";
1276 cherokee_buffer_t def1 = CHEROKEE_BUF_INIT;
1277 cherokee_buffer_t def2 = CHEROKEE_BUF_INIT;
1278 cherokee_buffer_add_va (&def1, "DEF:rxbytes=%s:rxbytes:AVERAGE:step=30", path.buf);
1279 cherokee_buffer_add_va (&def2, "DEF:txbytes=%s:txbytes:AVERAGE:step=30", path.buf);
1280 char **calcpr = NULL;
1281 int xsize, ysize;
1282 double ymin, ymax;
1283 char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1284 char *r_graph[] = { "rrdgraph", filename,
1285 "-a", "PNG",
1286 "-w", width,
1287 "-h", height,
1288 "--start", start,
1289 "--end", end,
1290 "--title", interface,
1291 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "bits per second",
1292 def1.buf,
1293 def2.buf,
1294 "CDEF:txbits=txbytes,8,*",
1295 "CDEF:rxbits=rxbytes,8,*",
1296 "AREA:rxbits#00EE00:rxbits",
1297 "LINE:txbits#0000EE:txbits" };
1299 rrd_graph(25, r_graph, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
1300 if ((ret = cherokee_buffer_read_file(&hdl->buffer, filename)) == ret_error) {
1301 hdl->action = http_internal_error;
1304 unlink(filename);
1305 free(filename);
1307 cherokee_buffer_mrproper(&def1);
1308 cherokee_buffer_mrproper(&def2);
1310 cherokee_buffer_mrproper(&path);
1311 goto virt_build_page_cleanup;
1316 case graphLoad_args: {
1317 struct stat statbuf;
1318 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1319 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/cpuTime.rrd", hdl->user.buf, hdl->vm.buf);
1320 if (stat(path.buf, &statbuf) != 0) {
1321 conn->error_code = http_not_found;
1322 ret = ret_error;
1323 } else {
1324 void *width, *height, *start, *end;
1325 if ((ret = cherokee_avl_get_ptr (conn->arguments, "width", &width)) != ret_ok)
1326 width = "600";
1328 if ((ret = cherokee_avl_get_ptr (conn->arguments, "height", &height)) != ret_ok)
1329 height = "200";
1331 if ((ret = cherokee_avl_get_ptr (conn->arguments, "start", &start)) != ret_ok)
1332 start = "now-1h";
1334 if ((ret = cherokee_avl_get_ptr (conn->arguments, "end", &end)) != ret_ok)
1335 end = "now";
1337 /* TODO: wat error checking? */
1339 cherokee_buffer_t def = CHEROKEE_BUF_INIT;
1340 cherokee_buffer_add_va (&def, "DEF:cputime=%s:cpuTime:AVERAGE:step=30", path.buf);
1341 char **calcpr = NULL;
1342 int xsize, ysize;
1343 double ymin, ymax;
1344 char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1345 char *r_graph[] = { "rrdgraph",
1346 filename,
1347 "-a", "PNG",
1348 "-w", width,
1349 "-h", height,
1350 "--start", start,
1351 "--end", end,
1352 "--title", hdl->vm.buf,
1353 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "(used / total) time",
1354 def.buf,
1355 "CDEF:cpuload=cputime,1000000000,/",
1356 "LINE:cpuload#EE0000:cpuLoad" };
1358 rrd_graph(22, r_graph, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
1359 if ((ret = cherokee_buffer_read_file(&hdl->buffer, filename)) == ret_error) {
1360 hdl->action = http_internal_error;
1363 unlink(filename);
1364 free(filename);
1366 cherokee_buffer_mrproper(&def);
1368 cherokee_buffer_mrproper(&path);
1369 goto virt_build_page_cleanup;
1373 if (hdl->action > xml && HDL_VIRT_PROPS(hdl)->xsl.len > 0)
1374 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);
1377 /* First, block the event loop */
1378 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1379 switch (hdl->action) {
1380 case showall:
1381 cherokee_buffer_add_str (&hdl->buffer, "<domains>");
1382 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl)->entries, virt_while, hdl, NULL, NULL);
1383 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1384 ret = ret_ok;
1385 break;
1387 case showuservms: {
1388 cherokee_buffer_add_str (&hdl->buffer, "<domains>");
1389 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl)->entries, virt_while_user, hdl, NULL, NULL);
1390 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1391 ret = ret_ok;
1392 break;
1395 default: {
1396 cherokee_buffer_t *hostname = NULL;
1397 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1398 ret = cherokee_avl_get_ptr(&HDL_AVAHI_PROPS(hdl)->entries, domu.buf, (void **) &hostname);
1400 if (ret == ret_not_found) {
1401 virDomainPtr virDom;
1402 virConnectPtr virConn;
1403 cherokee_buffer_add_va (&uri, "xen://%s/", HDL_VIRT_PROPS(hdl)->virt); // TODO: change!
1405 /* If we have the read only parameter, we will set up a connection to the
1406 * Hypervisor here. */
1407 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1408 virConn = virConnectOpen (uri.buf);
1410 /* We should already have a connection (read only) or build a new connection
1411 * if this doesn't work, we can safely assume our services is fubar */
1412 if (!virConn && !(virConn = virConnectOpenReadOnly (uri.buf))) {
1413 conn->error_code = http_service_unavailable;
1414 return ret_error;
1417 /* We lookup if there is a domain somewhere with this name */
1418 if ((virDom = virDomainLookupByName(virConn, domu.buf)) == NULL) {
1419 /* If the domain is not found on the network the only possible
1420 * command that is possible would be to Define it */
1421 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1422 ret = ret_ok;
1423 } else {
1424 /* We should also look on disk for defined stuff */
1425 cherokee_buffer_t xmlDesc = CHEROKEE_BUF_INIT;
1426 if (load_xml(hdl, &xmlDesc) == ret_ok && (virDom = virDomainDefineXML(virConn, xmlDesc.buf)) != NULL) {
1427 /* The domain existed and is loaded! */
1428 ret = ret_ok;
1429 } else {
1430 /* Otherwise we don't have anything to do and we should
1431 * return an error */
1432 hdl->action = nothing;
1433 conn->error_code = http_not_found;
1434 ret = ret_error;
1437 cherokee_buffer_mrproper(&xmlDesc);
1439 } else {
1440 /* We don't want te recreate things that already found on the network
1441 * first undefine them! */
1442 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1443 TRACE("virt", "domainDefineXML_args/domainDefineXML; domain already exists");
1444 hdl->action = nothing;
1445 conn->error_code = http_bad_request;
1446 ret = ret_error;
1447 } else {
1448 /* Everything is ok, because nothing is found. */
1449 ret = ret_ok;
1452 /* Domain wasn't NULL, so we should free it here */
1453 virDomainFree(virDom);
1455 virConnectClose (virConn);
1456 } else if (ret == ret_ok) {
1457 cherokee_buffer_add_va (&uri, "xen://%s/", hostname->buf);
1458 printf("%s\n", uri.buf);
1459 } else {
1460 hdl->action = http_internal_error;
1461 hdl->action = nothing;
1462 ret = ret_error;
1467 /* Finally, unblock the event loop */
1468 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1470 if (ret == ret_ok && hdl->action != showall && hdl->action != showuservms) {
1471 ret = virt_virt_do(hdl, &domu, &uri);
1474 virt_build_page_cleanup:
1475 cherokee_buffer_mrproper(&domu);
1476 cherokee_buffer_mrproper(&uri);
1478 return ret;
1482 ret_t
1483 cherokee_handler_virt_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
1485 ret_t ret;
1486 CHEROKEE_NEW_STRUCT (n, handler_virt);
1488 /* Init the base class
1491 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(virt));
1493 MODULE(n)->init = (handler_func_init_t) cherokee_handler_virt_init;
1494 MODULE(n)->free = (module_func_free_t) cherokee_handler_virt_free;
1495 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_virt_step;
1496 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_virt_add_headers;
1498 HANDLER(n)->support = hsupport_length | hsupport_range;
1500 ret = cherokee_buffer_init (&n->buffer);
1501 if (unlikely(ret != ret_ok))
1502 return ret;
1504 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
1505 if (unlikely(ret != ret_ok))
1506 return ret;
1508 *hdl = HANDLER(n);
1510 return ret_ok;