And the files that actually handler the tender phase now.
[handlervirt.git] / handler_virt.c
blob39094053cd0f003b14eb10902d21be6183db4775
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_clusterstats.h"
84 #include "handler_virt_tender.h"
85 #include <cherokee/cherokee.h>
86 #include <libxml/parser.h>
87 #include <libxml/xpath.h>
88 #include <float.h>
90 #include <avahi-client/client.h>
91 #include <avahi-client/publish.h>
92 #include <avahi-client/lookup.h>
94 #include <avahi-common/alternative.h>
95 #include <avahi-common/simple-watch.h>
96 #include <avahi-common/malloc.h>
97 #include <avahi-common/error.h>
98 #include <avahi-common/timeval.h>
102 /* Plug-in initialization
104 * In this function you can use any of these:
105 * http_delete | http_get | http_post | http_put
107 * For a full list: cherokee_http_method_t
109 * It is what your handler to be implements.
112 PLUGIN_INFO_HANDLER_EASIEST_INIT (virt, http_get | http_post);
115 /* Methods implementation
117 static ret_t
118 props_free (cherokee_handler_virt_props_t *props)
120 cherokee_buffer_mrproper(&props->xsl);
121 cherokee_buffer_mrproper(&props->virt);
123 return cherokee_handler_clusterstats_props_free (PROP_CLUSTERSTATS(props));
127 ret_t
128 cherokee_handler_virt_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
130 cherokee_list_t *i;
131 cherokee_handler_virt_props_t *props;
133 /* Instance a new property object
136 if (*_props == NULL) {
137 CHEROKEE_NEW_STRUCT (n, handler_virt_props);
139 cherokee_handler_clusterstats_props_init_base (PROP_CLUSTERSTATS(n), MODULE_PROPS_FREE(props_free));
141 /* Look at handler_virt.h
142 * This is an virt of configuration.
144 n->authenticate = true; /* by default we are secure! */
145 n->read_only = true; /* by default we are secure! */
146 cherokee_buffer_init (&n->xsl); /* we support a custom header */
147 cherokee_buffer_init (&n->virt); /* your first xenserver */
149 *_props = MODULE_PROPS(n);
152 props = PROP_VIRT(*_props);
154 cherokee_config_node_foreach (i, conf) {
155 cherokee_config_node_t *subconf = CONFIG_NODE(i);
157 if (equal_buf_str (&subconf->key, "authenticate")) {
158 props->authenticate = atoi(subconf->val.buf);
160 else if (equal_buf_str (&subconf->key, "read_only")) {
161 props->read_only = atoi(subconf->val.buf);
163 else if (equal_buf_str (&subconf->key, "xsl")) {
164 cherokee_buffer_add_buffer (&props->xsl, &subconf->val);
166 else if (equal_buf_str (&subconf->key, "virt")) {
167 cherokee_buffer_add_buffer (&props->virt, &subconf->val);
172 /* Init base class
175 return cherokee_handler_clusterstats_configure (conf, srv, _props);
178 ret_t
179 cherokee_handler_virt_init (cherokee_handler_virt_t *hdl)
181 cherokee_connection_t *conn = HANDLER_CONN(hdl);
183 /* If someone is posting the server should be in
184 * read/write mode if this is not the case, just
185 * bail out directly */
187 if (conn->header.method == http_post && HDL_VIRT_PROPS(hdl)->read_only == TRUE) {
188 conn->error_code = http_unauthorized;
189 return ret_error;
192 int isroot = false;
193 int len;
194 char *this, *next;
196 cherokee_buffer_init(&hdl->user);
197 cherokee_buffer_init(&hdl->vm);
199 hdl->action = nothing;
201 cherokee_buffer_add (&conn->pathinfo,
202 conn->request.buf + conn->web_directory.len,
203 conn->request.len - conn->web_directory.len);
205 this = conn->pathinfo.buf + 1;
207 next = strchr(this, '/'); /* TODO: this code borks! */
209 if ((!next && (this && (len = strlen(this)) == 0)) || (next && ((len = next - this) == 0)) )
210 hdl->action = showall;
211 else {
212 cherokee_buffer_add (&hdl->user, this, len);
215 if (HDL_VIRT_PROPS(hdl)->authenticate) {
216 if (!conn->validator ||
217 (conn->validator &&
218 (!cherokee_buffer_cmp_buf(&conn->validator->user, &hdl->user) &&
219 !(isroot = cherokee_buffer_cmp (&conn->validator->user, "root", 4))))) {
220 hdl->action = nothing; /* just in case */
221 conn->error_code = http_unauthorized;
222 return ret_error;
224 } else {
225 isroot = true;
228 if (hdl->action == showall) {
229 if (!isroot) {
230 hdl->action = nothing;
231 conn->error_code = http_unauthorized;
232 return ret_error;
233 } else {
234 return virt_build_page(hdl);
239 if (!next) {
240 hdl->action = showuservms;
241 return virt_build_page(hdl);
242 } else {
243 this = next + 1;
244 next = strchr(this, '/');
246 if ( ( !next && (this && (len = strlen(this)) == 0) ) || (next && ((len = next - this) == 0)) ) {
247 //if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
248 hdl->action = showuservms;
249 return virt_build_page(hdl);
253 cherokee_buffer_add (&hdl->vm, this, len);
255 if (!next) {
256 hdl->action = domainGetXMLDesc;
257 return virt_build_page(hdl);
258 } else {
259 this = next + 1;
260 next = strchr(this, '/');
262 if (( !next && (this && (len = strlen(this)) == 0) ) || (next && ((len = next - this) == 0)) ) {
263 hdl->action = domainGetXMLDesc;
264 return virt_build_page(hdl);
268 hdl->action = not_implemented;
269 switch (conn->header.method) {
270 case http_get:
271 if (strncmp(this, "virDomain", 9) == 0) {
272 if (strncmp(this+9, "Get", 3) == 0) {
273 if (strcmp(this+12, "ID") == 0) hdl->action = domainGetID;
274 else if (strcmp(this+12, "Name") == 0) hdl->action = domainGetName;
275 else if (strcmp(this+12, "MaxMemory") == 0) hdl->action = domainGetMaxMemory;
276 else if (strcmp(this+12, "MaxVcpus") == 0) hdl->action = domainGetMaxVcpus;
277 else if (strcmp(this+12, "OSType") == 0) hdl->action = domainGetOSType;
278 else if (strcmp(this+12, "UUID") == 0) hdl->action = domainGetUUID;
279 else if (strcmp(this+12, "UUIDString") == 0) hdl->action = domainGetUUIDString;
280 else if (strcmp(this+12, "XMLDesc") == 0) hdl->action = domainGetXMLDesc;
281 else if (strcmp(this+12, "XMLSnapshots") == 0) hdl->action = domainGetXMLSnapshots;
284 else if (HDL_VIRT_PROPS(hdl)->read_only == FALSE) {
285 if (strcmp(this+9, "Create") == 0) hdl->action = domainCreate;
286 else if (strcmp(this+9, "Destroy") == 0) hdl->action = domainDestroy;
287 else if (strcmp(this+9, "Reboot") == 0) hdl->action = domainReboot;
288 else if (strcmp(this+9, "Shutdown") == 0) hdl->action = domainShutdown;
290 else if (strcmp(this+9, "Save") == 0) hdl->action = domainSave;
291 else if (strcmp(this+9, "Restore") == 0) hdl->action = domainRestore;
293 else if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice_args;
295 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML_args;
296 else if (strcmp(this+9, "Undefine") == 0) hdl->action = domainUndefine;
299 else if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && strncmp(this, "virStorage", 10) == 0) {
300 if (strncmp(this+10, "Vol", 3) == 0) {
301 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML_args;
302 else if (strcmp(this+13, "Delete") == 0) hdl->action = storageVolDelete_args;
303 else if (strcmp(this+13, "CloneXML") == 0) hdl->action = storageVolCloneXML_args;
304 else if (strcmp(this+13, "CloneStatus") == 0) hdl->action = storageVolCloneStatus_args;
305 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl->action = storageVolGetXMLDesc_args;
306 else if (strcmp(this+13, "SetPassword") == 0) hdl->action = storageVolSetPassword_args;
309 else if (strncmp(this, "virGraph", 8) == 0) {
310 if (strcmp(this+8, "Load") == 0) hdl->action = graphLoad_args;
311 if (strcmp(this+8, "Interface") == 0) hdl->action = graphInterface_args;
313 break;
315 case http_post: {
316 off_t postl;
317 cherokee_post_get_len (&conn->post, &postl);
319 if (postl <= 0 || postl >= (INT_MAX-1)) {
320 TRACE("virt", "post without post");
321 conn->error_code = http_bad_request;
322 return ret_error;
325 if (strncmp(this, "virDomain", 9) == 0) {
326 if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice;
327 else if (strcmp(this+9, "DetachDevice") == 0) hdl->action = domainDetachDevice;
328 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML;
330 else if (strncmp(this, "virStorage", 10) == 0) {
331 if (strncmp(this+10, "Vol", 3) == 0) {
332 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML;
336 break;
339 default:
340 return ret_error;
343 if (hdl->action <= 0) {
344 TRACE("virt", "There was no action specified");
345 conn->error_code = http_bad_request;
346 return ret_error;
349 return virt_build_page(hdl);
352 ret_t
353 cherokee_handler_virt_free (cherokee_handler_virt_t *hdl)
355 cherokee_buffer_mrproper (&hdl->buffer);
356 cherokee_buffer_mrproper (&hdl->user);
357 cherokee_buffer_mrproper (&hdl->vm);
359 return ret_ok;
362 ret_t
363 cherokee_handler_virt_step (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
365 cuint_t tosend;
367 if (cherokee_buffer_is_empty (&hdl->buffer))
368 return ret_eof;
370 tosend = (hdl->buffer.len > 1024 ? 1024 : hdl->buffer.len);
372 cherokee_buffer_add (buffer, hdl->buffer.buf, tosend);
373 cherokee_buffer_move_to_begin (&hdl->buffer, tosend);
375 if (cherokee_buffer_is_empty (&hdl->buffer))
376 return ret_eof_have_data;
378 return ret_ok;
381 ret_t
382 cherokee_handler_virt_add_headers (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
384 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
386 if (hdl->action > xml)
387 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
388 else if (hdl->action > graph) {
389 cherokee_buffer_add_str (buffer, "Content-Type: image/png"CRLF);
390 } else
391 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
393 return ret_ok;
397 static ret_t
398 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
399 virConnectPtr conn = NULL;
400 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
401 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
403 cherokee_buffer_add_va (&uri, "xen://%s/", value);
405 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
406 if (!(conn = virConnectOpen (uri.buf))) {
407 return ret_error;
411 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
412 return ret_error;
413 } else {
414 virDomainPtr dom;
415 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
416 return ret_error;
417 } else {
418 char *xml = virDomainGetXMLDesc(dom, 0);
419 cherokee_buffer_add(buf, xml, strlen(xml));
421 virConnectClose(conn);
424 cherokee_buffer_mrproper(&uri);
426 return ret_ok;
429 static ret_t load_xml(cherokee_handler_virt_t *hdl, cherokee_buffer_t *xmlDesc) {
430 ret_t ret = ret_error;
431 FILE *fd;
432 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
433 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s", hdl->user.buf);
435 mkdir(path.buf, 0755);
436 cherokee_buffer_add_va (&path, "/%s", hdl->vm.buf);
438 mkdir(path.buf, 0755);
439 cherokee_buffer_add_str (&path, "/index.xml");
441 if ((fd = fopen(path.buf, "r")) != NULL) {
442 while (!feof(fd)) {
443 char buf[1024];
444 size_t amount = fread(buf, sizeof(char), 1024, fd);
446 cherokee_buffer_add (xmlDesc, buf, amount);
448 fclose(fd);
449 if (xmlDesc->len > 0)
450 ret = ret_ok;
453 cherokee_buffer_mrproper(&path);
454 return ret;
457 static ret_t save_xml(cherokee_handler_virt_t *hdl, virDomainPtr result, cherokee_buffer_t *buf) {
458 ret_t ret = ret_error;
459 FILE *fd;
460 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
461 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s", hdl->user.buf);
463 mkdir(path.buf, 0755);
464 cherokee_buffer_add_va (&path, "/%s", hdl->vm.buf);
466 mkdir(path.buf, 0755);
467 cherokee_buffer_add_str (&path, "/index.xml");
469 if ((fd = fopen(path.buf, "w")) == NULL) {
470 perror(__func__);
471 } else {
472 char *output = virDomainGetXMLDesc(result, VIR_DOMAIN_XML_INACTIVE);
473 if (output) {
474 fwrite(output, strlen(output), sizeof(char), fd);
475 if (buf)
476 cherokee_buffer_add(buf, output, strlen(output));
477 free(output);
479 fclose(fd);
480 ret = ret_ok;
482 cherokee_buffer_mrproper(&path);
483 return ret;
487 static ret_t
488 virt_virt_function(cherokee_handler_virt_t *hdl, virDomainPtr dom, virConnectPtr virConn) {
489 cherokee_connection_t *conn = HANDLER_CONN(hdl);
490 cherokee_buffer_t *buf = &HDL_VIRT(hdl)->buffer;
492 switch (hdl->action) {
493 /* Returns the status of a clone copy */
494 case storageVolCloneStatus_args: {
495 ret_t ret;
496 void *name;
497 struct stat statbuf;
498 cherokee_buffer_t queue = CHEROKEE_BUF_INIT;
500 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
501 if (unlikely(ret < ret_ok)) {
502 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
503 conn->error_code = http_bad_request;
504 return ret_error;
507 cherokee_buffer_add_va (&queue, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
509 if (stat(queue.buf, &statbuf) != 0) {
510 conn->error_code = http_not_found;
511 ret = ret_error;
512 } else {
513 char hardlink[1024];
514 int namelen;
515 if ((namelen = readlink(queue.buf, hardlink, 1023)) == -1) {
516 conn->error_code = http_internal_error;
517 ret = ret_error;
518 } else {
519 hardlink[namelen] = '\0';
520 if (stat(hardlink, &statbuf) != 0) {
521 conn->error_code = http_internal_error;
522 ret = ret_error;
523 } else {
524 struct stat statbuf2;
525 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
526 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.busy", hdl->user.buf, name);
527 if (stat(busy.buf, &statbuf2) != 0) {
528 conn->error_code = http_internal_error;
529 ret = ret_error;
530 } else {
531 cherokee_buffer_add_va (buf, "%f", (float)((float)statbuf2.st_size / (float)statbuf.st_size));
532 ret = ret_ok;
534 cherokee_buffer_mrproper(&busy);
539 cherokee_buffer_mrproper(&queue);
540 return ret;
541 break;
544 /* Save the memory of a domain to a file and suspend the domain */
545 case domainSave: {
546 ret_t ret = ret_ok;
547 int result;
548 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
549 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
550 if ((result = virDomainSave(dom, path.buf)) != 0) {
551 TRACE("virt", "Saving of %s/%s failed", hdl->user.buf, hdl->vm.buf);
552 conn->error_code = http_internal_error;
553 ret = ret_error;
555 cherokee_buffer_mrproper(&path);
557 cherokee_buffer_add_long10(buf, result);
558 return ret;
559 break;
562 /* Restore the memory of a domain from a file and resume the domain */
563 case domainRestore: {
564 ret_t ret = ret_ok;
565 struct stat statbuf;
566 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
567 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
569 if (stat(path.buf, &statbuf) == 0) {
570 char *destination = create_tender(hdl, virDomainGetName(dom), virDomainGetMaxMemory(dom));
572 if (destination == NULL) {
573 TRACE("virt", "Nobody wants %s, poor vm!\n", destination);
574 cherokee_buffer_add_long10(buf, -1);
575 } else {
576 virConnectPtr virConnNew;
577 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
579 if (virDomainUndefine(dom) != 0) {
580 TRACE("virt", "Can't undefine %s, some idiot run it already?\n", destination);
581 cherokee_buffer_add_long10(buf, -1);
582 } else {
583 cherokee_buffer_add_va (&uri, "xen://%s/", destination);
584 virConnNew = virConnectOpen (uri.buf);
586 if (virConnNew == NULL) {
587 TRACE("virt", "Can't connect to %s\n", uri.buf);
588 cherokee_buffer_add_long10(buf, -1);
589 } else {
590 cherokee_buffer_add_long10(buf, virDomainRestore(virConn, path.buf));
591 virConnectClose(virConn);
592 virConn = virConnNew;
593 /* TODO: Here I actually want virConnNew to be virConn */
596 cherokee_buffer_mrproper(&uri);
597 free(destination);
599 } else {
600 TRACE("virt", "Memory file for %s/%s does not exist", hdl->user.buf, hdl->vm.buf);
601 conn->error_code = http_not_found;
602 ret = ret_error;
605 cherokee_buffer_mrproper(&path);
607 return ret;
608 break;
611 case domainUndefine: {
612 int result;
613 if ((result = virDomainUndefine(dom)) != 0) {
614 conn->error_code = http_internal_error; /* TODO */
617 cherokee_buffer_add_long10(buf, result);
618 break;
621 case domainAttachDevice_args: {
622 int result;
623 void *temp;
624 ret_t ret;
626 ret = cherokee_avl_get_ptr (conn->arguments, "type", &temp);
628 if (ret == ret_ok) {
629 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
631 if (strcmp(temp, "disk") == 0) {
632 void *device;
633 if ((ret = cherokee_avl_get_ptr (conn->arguments, "device", &device)) == ret_ok) {
634 void *file;
635 if ((ret = cherokee_avl_get_ptr (conn->arguments, "file", &file)) == ret_ok) {
636 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
637 } else {
638 virStorageVolPtr volume = virt_get_vol_by_args(hdl, virConn, 1);
640 if (volume == NULL) {
641 return ret_error;
644 file = virStorageVolGetPath(volume);
645 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
646 free(file);
648 virStorageVolFree(volume);
649 ret = ret_ok;
654 else if (strcmp(temp, "interface") == 0) {
655 void *mac, *ip;
656 if ((ret = cherokee_avl_get_ptr (conn->arguments, "mac", &mac)) == ret_ok && (ret = cherokee_avl_get_ptr (conn->arguments, "ip", &ip)) == ret_ok) {
657 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
658 } else {
659 char *mac = NULL;
660 char *ip = NULL;
661 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
662 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
663 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0)
664 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
665 cherokee_buffer_mrproper(&domu);
669 if (ret == ret_ok && (result = virDomainAttachDevice(dom, (const char *) xml.buf)) == 0) {
670 ret = ret_ok;
671 } else {
672 conn->error_code = http_internal_error;
673 return ret_error;
676 cherokee_buffer_add_long10(buf, result);
677 cherokee_buffer_mrproper(&xml);
678 } else {
679 TRACE("virt", "DeviceAttach_args; type was not specified");
680 conn->error_code = http_bad_request;
681 return ret_error;
684 break;
687 case domainAttachDevice: {
688 off_t postl;
689 int result;
690 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
691 cherokee_post_get_len (&conn->post, &postl);
692 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
693 if ((result = virDomainAttachDevice(dom, (const char *) post.buf)) != 0)
694 conn->error_code = http_internal_error;
696 cherokee_buffer_mrproper(&post);
697 cherokee_buffer_add_long10(buf, result);
698 break;
702 case domainGetXMLDesc: {
703 char *xml = virDomainGetXMLDesc(dom, 0);
704 cherokee_buffer_add(buf, xml, strlen(xml));
705 free(xml);
706 break;
709 case domainGetXMLSnapshots: {
710 /* TODO: maybe in the future one would like to have all snapshots here */
711 struct stat statbuf;
712 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
714 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
716 if (stat(path.buf, &statbuf) != 0) {
717 cherokee_buffer_add_str(buf, "<snapshots />");
718 } else {
719 char *date = ctime(&(statbuf.st_ctime));
720 cherokee_buffer_add_str(buf, "<snapshots>\n");
721 cherokee_buffer_add_va (buf, " <snapshot at=\"");
722 cherokee_buffer_add (buf, date, strlen(date)-1);
723 cherokee_buffer_add_va (buf, "\" />\n");
724 cherokee_buffer_add_str(buf, "</snapshots>");
727 cherokee_buffer_mrproper(&path);
728 break;
731 case domainDetachDevice: {
732 off_t postl;
733 int result;
734 ret_t ret;
735 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
736 cherokee_post_get_len (&conn->post, &postl);
737 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
739 xmlDocPtr doc = xmlParseMemory((const char *) post.buf, post.len);
740 if (doc == NULL) {
741 TRACE("virt", "DeviceAttach; XML document unparceble");
742 conn->error_code = http_bad_request;
743 ret = ret_error;
744 } else
745 ret = ret_ok;
747 if (ret == ret_ok) {
748 if ((result = virDomainDetachDevice(dom, (const char *) post.buf)) != 0) {
749 conn->error_code = http_internal_error;
750 /* TODO: betere afhandeling */
752 xmlXPathContextPtr context = xmlXPathNewContext(doc);
753 if (context != NULL) {
754 xmlXPathObjectPtr obj = xmlXPathEval("string(//interface/mac/@address)", context);
755 xmlXPathFreeContext(context);
756 if ((obj != NULL) && (obj->type == XPATH_STRING) &&
757 (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
758 removeOldMac("dv28", (char *) obj->stringval);
760 xmlXPathFreeObject(obj);
763 xmlFreeDoc(doc);
764 xmlCleanupParser();
767 cherokee_buffer_mrproper(&post);
768 cherokee_buffer_add_long10(buf, result);
769 break;
772 case domainGetID: {
773 cherokee_buffer_add_ulong10(buf, virDomainGetID(dom));
774 break;
776 case domainGetMaxMemory: {
777 cherokee_buffer_add_ulong10(buf, virDomainGetMaxMemory (dom));
778 break;
780 case domainGetMaxVcpus: {
781 cherokee_buffer_add_long10(buf, virDomainGetMaxVcpus (dom));
782 break;
784 case domainGetName: {
785 const char *name = virDomainGetName (dom);
786 cherokee_buffer_add(buf, name, strlen(name));
787 break;
789 case domainGetUUID: {
790 unsigned char uuid[VIR_UUID_BUFLEN];
791 if (virDomainGetUUID(dom, uuid) == 0) {
792 cherokee_buffer_add_str(buf, uuid);
793 } else {
794 conn->error_code = http_internal_error;
795 return ret_error;
797 break;
799 case domainGetUUIDString: {
800 unsigned char uuid[VIR_UUID_STRING_BUFLEN];
801 if (virDomainGetUUIDString(dom, uuid) == 0) {
802 cherokee_buffer_add_str(buf, uuid);
803 } else {
804 conn->error_code = http_internal_error;
805 return ret_error;
807 break;
810 case domainCreate: {
811 char *destination;
812 cherokee_buffer_t xmlDesc = CHEROKEE_BUF_INIT;
813 save_xml(hdl, dom, &xmlDesc);
815 destination = create_tender(hdl, virDomainGetName(dom), virDomainGetMaxMemory(dom));
817 if (destination == NULL) {
818 TRACE("virt", "Nobody wants %s, poor vm!\n", destination);
819 cherokee_buffer_add_long10(buf, -1);
820 } else {
821 virConnectPtr virConnNew;
822 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
824 if (virDomainUndefine(dom) != 0) {
825 TRACE("virt", "Can't undefine %s, some idiot run it already?\n", destination);
828 cherokee_buffer_add_va (&uri, "xen://%s/", destination);
829 virConnNew = virConnectOpen (uri.buf);
831 if (virConnNew == NULL) {
832 TRACE("virt", "Can't connect to %s\n", uri.buf);
833 cherokee_buffer_add_long10(buf, -1);
834 } else {
835 cherokee_buffer_add_long10(buf,
836 (virDomainCreateLinux(virConnNew, xmlDesc.buf, 0) != NULL ?
837 0 : -1 ));
838 virConnectClose(virConn);
840 virConn = virConnNew;
841 /* TODO: Here I actually want virConnNew to be virConn */
843 cherokee_buffer_mrproper(&uri);
844 free(destination);
847 cherokee_buffer_mrproper(&xmlDesc);
848 break;
851 case domainDestroy: {
852 cherokee_buffer_add_long10(buf, virDomainDestroy (dom));
853 break;
856 case domainReboot: {
857 cherokee_buffer_add_long10(buf, virDomainReboot (dom, 0));
858 break;
861 case domainShutdown: {
862 cherokee_buffer_add_long10(buf, virDomainShutdown (dom));
863 break;
867 case domainGetOSType: {
868 char *ostype = virDomainGetOSType(dom);
869 cherokee_buffer_add(buf, ostype, strlen(ostype));
870 free(ostype);
871 break;
878 if (hdl->action == domainUndefine) {
879 /* Remove VM data from filesystem */
880 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
881 cherokee_buffer_t path2 = CHEROKEE_BUF_INIT;
882 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/index.xml", hdl->user.buf, hdl->vm.buf);
883 cherokee_buffer_add_buffer (&path2, &path);
884 cherokee_buffer_add_str (&path2, ".deleted");
885 // unlink(path.buf); /* TODO: instead of delet replace */
886 rename(path.buf, path2.buf);
887 cherokee_buffer_mrproper(&path);
888 cherokee_buffer_mrproper(&path2);
889 } else if (hdl->action != domainCreate) {
890 save_xml(hdl, dom, NULL);
893 return ret_ok;
896 static virStoragePoolPtr
897 virt_get_pool_by_args(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
898 cherokee_connection_t *conn = HANDLER_CONN(hdl);
899 virStoragePoolPtr pool;
900 void *temp;
901 ret_t ret;
903 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
904 if (unlikely(ret < ret_ok)) {
905 TRACE("virt", "virStoragePoolPtr; Pool argument not specified");
906 conn->error_code = http_bad_request;
907 return NULL;
910 pool = virStoragePoolLookupByName(virConn, temp);
912 return pool;
915 static virStorageVolPtr
916 virt_get_vol_by_args(cherokee_handler_virt_t *hdl, virConnectPtr virConn, unsigned short int prefix) {
917 cherokee_connection_t *conn = HANDLER_CONN(hdl);
918 virStoragePoolPtr pool;
919 virStorageVolPtr volume;
920 void *temp;
921 ret_t ret;
923 pool = virt_get_pool_by_args(hdl, virConn);
925 if (pool == NULL) {
926 conn->error_code = http_not_found;
927 return NULL;
930 virStoragePoolRefresh(pool, 0); /* TODO: might be better to do it outside */
932 ret = cherokee_avl_get_ptr (conn->arguments, "volume", &temp);
933 if (unlikely(ret < ret_ok)) {
934 TRACE("virt", "virStorageVolPtr; Volume argument not specified");
935 conn->error_code = http_bad_request;
936 return NULL;
939 if (prefix == 1) {
940 cherokee_buffer_t fullvol = CHEROKEE_BUF_INIT;
941 cherokee_buffer_add_va (&fullvol, "%s_%s", hdl->user.buf, temp);
942 volume = virStorageVolLookupByName(pool, fullvol.buf);
943 cherokee_buffer_mrproper(&fullvol);
944 } else {
945 volume = virStorageVolLookupByName(pool, temp);
948 if (volume == NULL)
949 conn->error_code = http_not_found;
951 virStoragePoolFree(pool);
953 return volume;
956 /* This function is the home for all functions that need a working
957 * pool/volume combination */
958 static ret_t
959 virt_pool_vol(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
960 cherokee_buffer_t *buf = &HDL_VIRT(hdl)->buffer;
961 cherokee_connection_t *conn = HANDLER_CONN(hdl);
962 virStorageVolPtr volume;
963 ret_t ret = ret_ok;
965 /* We only allow clone to run 'unsafe', others get prefixed */
966 volume = virt_get_vol_by_args(hdl, virConn, (hdl->action != storageVolCloneXML_args));
968 /* If the volume doesn't exist, no point to continue */
969 if (volume == NULL) {
970 conn->error_code = http_not_found;
971 return ret_error;
974 switch (hdl->action) {
975 /* Sets the password of a specific volume, requires the password= option */
976 case storageVolSetPassword_args: {
977 void *temp;
978 ret = cherokee_avl_get_ptr (conn->arguments, "password", &temp);
979 if (unlikely(ret < ret_ok)) {
980 TRACE("virt", "storageVolSetPassword_args; password argument not specified");
981 conn->error_code = http_bad_request;
982 ret = ret_error;
983 goto virt_pool_vol_cleanup;
984 } else {
985 cherokee_buffer_t cmd_passwd = CHEROKEE_BUF_INIT;
986 cherokee_buffer_add_va (&cmd_passwd, "/usr/sbin/passwdchanger.sh %s %s\n", virStorageVolGetKey(volume), temp);
987 cherokee_buffer_add_long10(buf, system(cmd_passwd.buf));
988 cherokee_buffer_mrproper(&cmd_passwd);
990 break;
993 /* Removes a volume */
994 case storageVolDelete_args: {
995 cherokee_buffer_add_long10(buf, virStorageVolDelete(volume, 0));
996 break;
999 /* Gives a description of a storage volume in XML */
1000 case storageVolGetXMLDesc_args: {
1001 char *xml = virStorageVolGetXMLDesc(volume, 0);
1002 cherokee_buffer_add(buf, xml, strlen(xml));
1003 free(xml);
1004 break;
1007 /* Clones a volume, insecure method! requires a new name= */
1008 case storageVolCloneXML_args: {
1009 void *name;
1010 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
1012 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
1013 if (unlikely(ret < ret_ok)) {
1014 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
1015 conn->error_code = http_bad_request;
1016 ret = ret_error;
1017 goto virt_pool_vol_cleanup;
1020 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
1022 if (unlikely(symlink(virStorageVolGetKey(volume), busy.buf) == 1)) {
1023 conn->error_code = http_internal_error;
1024 ret = ret_error;
1025 } else {
1026 cherokee_buffer_add_str(buf, "QUEUED");
1029 cherokee_buffer_mrproper(&busy);
1031 break;
1036 virt_pool_vol_cleanup:
1037 /* And in the end we need to free the volume we have used */
1038 virStorageVolFree(volume);
1040 return ret;
1043 static ret_t
1044 virt_virt_new(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
1045 cherokee_buffer_t *buf = &HDL_VIRT(hdl)->buffer;
1046 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1047 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
1048 virStoragePoolPtr pool = NULL;
1049 ret_t ret = ret_ok;
1051 switch (hdl->action) {
1053 case storageVolCreateXML_args: {
1054 void *temp, *type, *name, *unit;
1055 unsigned long int capacity, allocation;
1057 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
1058 if (unlikely(ret < ret_ok)) {
1059 TRACE("virt", "storageVolCreateXML_args; pool argument not specified");
1060 conn->error_code = http_bad_request;
1061 goto virt_virt_new_cleanup;
1064 TRACE("args", "%s", temp);
1066 pool = virStoragePoolLookupByName(virConn, temp);
1068 if (pool == NULL) {
1069 conn->error_code = http_not_found;
1070 goto virt_virt_new_cleanup;
1073 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
1074 if (unlikely(ret < ret_ok)) {
1075 TRACE("virt", "storageVolCreateXML_args; name argument not specified");
1076 conn->error_code = http_bad_request;
1077 goto virt_virt_new_cleanup;
1080 ret = cherokee_avl_get_ptr (conn->arguments, "type", &type);
1081 if (unlikely(ret < ret_ok)) {
1082 TRACE("virt", "storageVolCreateXML_args; type argument not specified");
1083 conn->error_code = http_bad_request;
1084 goto virt_virt_new_cleanup;
1087 ret = cherokee_avl_get_ptr (conn->arguments, "unit", &unit);
1088 if (unlikely(ret < ret_ok)) {
1089 TRACE("virt", "storageVolCreateXML_args; unit argument not specified");
1090 conn->error_code = http_bad_request;
1091 goto virt_virt_new_cleanup;
1094 ret = cherokee_avl_get_ptr (conn->arguments, "allocation", &temp);
1095 if (unlikely(ret < ret_ok)) {
1096 TRACE("virt", "storageVolCreateXML_args; allocation argument not specified");
1097 conn->error_code = http_bad_request;
1098 goto virt_virt_new_cleanup;
1101 allocation = strtoul(temp, NULL, 10);
1102 if (errno == ERANGE) {
1103 TRACE("virt", "storageVolCreateXML_args; allocation is not a number");
1104 conn->error_code = http_bad_request;
1105 ret = ret_error;
1106 goto virt_virt_new_cleanup;
1109 ret = cherokee_avl_get_ptr (conn->arguments, "capacity", &temp);
1110 if (unlikely(ret < ret_ok)) {
1111 TRACE("virt", "storageVolCreateXML_args; capacity argument not specified");
1112 conn->error_code = http_bad_request;
1113 goto virt_virt_new_cleanup;
1116 capacity = strtoul(temp, NULL, 10);
1117 if (errno == ERANGE || capacity == 0) {
1118 TRACE("virt", "storageVolCreateXML_args; capacity is not a number");
1119 conn->error_code = http_bad_request;
1120 ret = ret_error;
1121 goto virt_virt_new_cleanup;
1124 cherokee_buffer_add_va (&xml, VIRT_STORAGE_XML, type, hdl->user.buf, name, allocation, unit, capacity, hdl->user.buf, name, hdl->user.buf, name);
1125 break;
1128 case domainDefineXML_args: {
1129 ret_t ret;
1130 unsigned int i;
1131 unsigned long vcpu = 0, interface = 0, memory = 0;
1133 void *temp = NULL;
1135 ret = cherokee_avl_get_ptr (conn->arguments, "vcpu", &temp);
1136 if (ret == ret_ok)
1137 vcpu = strtoul(temp, (char **) NULL, 10);
1139 if (ret != ret_ok || errno == ERANGE || vcpu == 0) {
1140 conn->error_code = http_internal_error;
1141 goto virt_virt_new_cleanup;
1145 ret = cherokee_avl_get_ptr (conn->arguments, "memory", &temp);
1146 if (ret == ret_ok)
1147 memory = strtoul(temp, (char **) NULL, 10);
1149 if (ret != ret_ok || errno == ERANGE || memory == 0) {
1150 conn->error_code = http_internal_error;
1151 goto virt_virt_new_cleanup;
1155 ret = cherokee_avl_get_ptr (conn->arguments, "interface", &temp);
1156 if (ret == ret_ok)
1157 interface = strtoul(temp, (char **) NULL, 10);
1159 if (ret != ret_ok || errno == ERANGE) {
1160 conn->error_code = http_internal_error;
1161 goto virt_virt_new_cleanup;
1164 cherokee_buffer_t cmdline_extra = CHEROKEE_BUF_INIT;
1165 cherokee_buffer_t xml_interfaces = CHEROKEE_BUF_INIT;
1166 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1167 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1169 for (i = 0; i < interface; i++) {
1170 char *mac = NULL;
1171 char *ip = NULL;
1172 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0) {
1173 cherokee_buffer_add_va (&xml_interfaces, VIRT_INTERFACE_XML, mac, ip);
1174 if (i == 0) {
1175 /* TODO: terrible hack */
1176 char gateway[16];
1177 char *temp;
1178 strcpy(gateway, ip);
1179 temp = strchr(gateway, '.');
1180 temp = strchr(++temp, '.');
1181 temp = strchr(++temp, '.');
1182 strcpy(++temp, "254");
1183 cherokee_buffer_add_va (&cmdline_extra, VIRT_DOMAIN_CMD_IP, ip, gateway);
1188 cherokee_buffer_mrproper(&domu);
1190 cherokee_buffer_add_va (&xml, VIRT_DOMAIN_XML,
1191 hdl->user.buf, hdl->vm.buf, cmdline_extra.buf, memory, vcpu, xml_interfaces.buf);
1193 cherokee_buffer_mrproper(&xml_interfaces);
1194 cherokee_buffer_mrproper(&cmdline_extra);
1195 break;
1198 case storageVolCreateXML:
1199 case domainDefineXML: {
1200 off_t postl;
1201 cherokee_post_get_len (&conn->post, &postl);
1202 cherokee_post_walk_read (&conn->post, &xml, (cuint_t) postl);
1203 break;
1207 switch (hdl->action) {
1208 case domainDefineXML_args:
1209 case domainDefineXML: {
1210 virDomainPtr result = virDomainDefineXML(virConn, (const char *) xml.buf);
1212 if (result == NULL) {
1213 /* TODO: vrij maken eventuele uitgegeven macs! */
1214 conn->error_code = http_internal_error;
1215 goto virt_virt_new_cleanup;
1218 save_xml(hdl, result, buf);
1220 virDomainFree(result);
1222 break;
1225 case storageVolCreateXML_args:
1226 case storageVolCreateXML: {
1227 virStorageVolPtr vol = virStorageVolCreateXML(pool, xml.buf, 0);
1229 if (vol == NULL) {
1230 cherokee_buffer_add_long10(buf, -1);
1231 goto virt_virt_new_cleanup;
1234 virStorageVolFree(vol);
1236 cherokee_buffer_add_long10(buf, 0);
1237 break;
1241 virt_virt_new_cleanup:
1242 cherokee_buffer_mrproper(&xml);
1244 if (pool)
1245 virStoragePoolFree(pool);
1247 return ret;
1251 static ret_t
1252 virt_virt_do(cherokee_handler_virt_t *hdl, cherokee_buffer_t *domu, cherokee_buffer_t *uri)
1254 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1256 ret_t ret = ret_error;
1257 virConnectPtr virConn = NULL;
1260 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1261 virConn = virConnectOpen (uri->buf);
1263 if (!virConn && !(virConn = virConnectOpenReadOnly (uri->buf))) {
1264 conn->error_code = http_service_unavailable;
1265 return ret_error;
1268 switch (hdl->action) {
1269 case storageVolDelete_args:
1270 case storageVolSetPassword_args:
1271 case storageVolGetXMLDesc_args:
1272 case storageVolCloneXML_args:
1273 ret = virt_pool_vol(hdl, virConn);
1274 break;
1276 case storageVolCreateXML_args:
1277 case storageVolCreateXML:
1278 case domainDefineXML_args:
1279 case domainDefineXML:
1280 ret = virt_virt_new(hdl, virConn);
1281 break;
1283 default: {
1284 virDomainPtr dom;
1285 if ((dom = virDomainLookupByName(virConn, domu->buf)) == NULL) {
1286 conn->error_code = http_not_found;
1287 } else {
1288 ret = virt_virt_function(hdl, dom, virConn);
1289 virDomainFree(dom);
1294 virConnectClose(virConn);
1295 return ret;
1298 static ret_t
1299 virt_while (cherokee_buffer_t *key, void *value, void *param) {
1300 cherokee_handler_virt_t * hdl = param;
1301 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1302 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1303 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1304 // cherokee_buffer_mrproper(&uri);
1306 cherokee_buffer_add_va (&hdl->buffer, "<domain><name>%s</name></domain>", key->buf);
1308 return ret_ok;
1311 static ret_t
1312 virt_while_user (cherokee_buffer_t *key, void *value, void *param) {
1313 cherokee_handler_virt_t *hdl = param;
1314 if (key->len > hdl->user.len && key->buf[hdl->user.len] == '_' && strncmp(key->buf, hdl->user.buf, hdl->user.len) == 0)
1315 return virt_while (key, value, param);
1317 return ret_ok;
1320 static ret_t
1321 virt_build_page (cherokee_handler_virt_t *hdl)
1323 ret_t ret;
1324 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1325 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1326 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1328 /* We use the webserver methods to parse the querystring */
1329 /* Maybe do something smart with ENUM, begin_args, end_args... */
1330 if ((hdl->action == domainDefineXML_args) ||
1331 (hdl->action == domainAttachDevice_args) ||
1332 (hdl->action == storageVolGetXMLDesc_args) ||
1333 (hdl->action == storageVolDelete_args) ||
1334 (hdl->action == storageVolSetPassword_args) ||
1335 (hdl->action == storageVolCloneXML_args) ||
1336 (hdl->action == storageVolCloneStatus_args) ||
1337 (hdl->action == storageVolCreateXML_args) ||
1338 (hdl->action == graphLoad_args) ||
1339 (hdl->action == graphInterface_args)) {
1340 ret = cherokee_connection_parse_args (conn);
1341 if (unlikely(ret < ret_ok)) {
1342 conn->error_code = http_internal_error;
1343 return ret_error;
1347 switch (hdl->action) {
1348 case graphInterface_args: {
1349 struct stat statbuf;
1350 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1351 void *interface;
1352 if ((ret = cherokee_avl_get_ptr (conn->arguments, "interface", &interface)) != ret_ok)
1353 interface = "eth0";
1355 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/interface_%s.rrd", hdl->user.buf, hdl->vm.buf, interface);
1356 if (stat(path.buf, &statbuf) != 0) {
1357 conn->error_code = http_not_found;
1358 ret = ret_error;
1359 } else {
1360 void *width, *height, *start, *end;
1361 if ((ret = cherokee_avl_get_ptr (conn->arguments, "width", &width)) != ret_ok)
1362 width = "600";
1364 if ((ret = cherokee_avl_get_ptr (conn->arguments, "height", &height)) != ret_ok)
1365 height = "200";
1367 if ((ret = cherokee_avl_get_ptr (conn->arguments, "start", &start)) != ret_ok)
1368 start = "now-1h";
1370 if ((ret = cherokee_avl_get_ptr (conn->arguments, "end", &end)) != ret_ok)
1371 end = "now";
1373 cherokee_buffer_t def1 = CHEROKEE_BUF_INIT;
1374 cherokee_buffer_t def2 = CHEROKEE_BUF_INIT;
1375 cherokee_buffer_add_va (&def1, "DEF:rxbytes=%s:rxbytes:AVERAGE:step=30", path.buf);
1376 cherokee_buffer_add_va (&def2, "DEF:txbytes=%s:txbytes:AVERAGE:step=30", path.buf);
1377 char **calcpr = NULL;
1378 int xsize, ysize;
1379 double ymin, ymax;
1380 /* TODO: betere random hier */
1381 char filenametemp[L_tmpnam+1];
1382 char *filename = tmpnam(filenametemp);
1384 // char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1385 char *r_graph[] = { "rrdgraph", filename,
1386 "-a", "PNG",
1387 "-w", width,
1388 "-h", height,
1389 "--start", start,
1390 "--end", end,
1391 "--title", interface,
1392 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "bits per second",
1393 def1.buf,
1394 def2.buf,
1395 "CDEF:txbits=txbytes,8,*",
1396 "CDEF:rxbits=rxbytes,8,*",
1397 "AREA:rxbits#00EE00:rxbits",
1398 "LINE:txbits#0000EE:txbits" };
1400 rrd_graph(25, r_graph, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
1401 if ((ret = cherokee_buffer_read_file(&hdl->buffer, filename)) == ret_error) {
1402 hdl->action = http_internal_error;
1405 unlink(filename);
1407 cherokee_buffer_mrproper(&def1);
1408 cherokee_buffer_mrproper(&def2);
1410 cherokee_buffer_mrproper(&path);
1411 goto virt_build_page_cleanup;
1416 case graphLoad_args: {
1417 struct stat statbuf;
1418 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1419 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/cpuTime.rrd", hdl->user.buf, hdl->vm.buf);
1420 if (stat(path.buf, &statbuf) != 0) {
1421 conn->error_code = http_not_found;
1422 ret = ret_error;
1423 } else {
1424 void *width, *height, *start, *end;
1425 if ((ret = cherokee_avl_get_ptr (conn->arguments, "width", &width)) != ret_ok)
1426 width = "600";
1428 if ((ret = cherokee_avl_get_ptr (conn->arguments, "height", &height)) != ret_ok)
1429 height = "200";
1431 if ((ret = cherokee_avl_get_ptr (conn->arguments, "start", &start)) != ret_ok)
1432 start = "now-1h";
1434 if ((ret = cherokee_avl_get_ptr (conn->arguments, "end", &end)) != ret_ok)
1435 end = "now";
1437 /* TODO: wat error checking? */
1439 cherokee_buffer_t def = CHEROKEE_BUF_INIT;
1440 cherokee_buffer_add_va (&def, "DEF:cputime=%s:cpuTime:AVERAGE:step=30", path.buf);
1441 char **calcpr = NULL;
1442 int xsize, ysize;
1443 double ymin, ymax;
1444 char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1445 char *r_graph[] = { "rrdgraph",
1446 filename,
1447 "-a", "PNG",
1448 "-w", width,
1449 "-h", height,
1450 "--start", start,
1451 "--end", end,
1452 "--title", hdl->vm.buf,
1453 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "(used / total) time",
1454 def.buf,
1455 "CDEF:cpuload=cputime,1000000000,/",
1456 "LINE:cpuload#EE0000:cpuLoad" };
1458 rrd_graph(22, r_graph, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
1459 if ((ret = cherokee_buffer_read_file(&hdl->buffer, filename)) == ret_error) {
1460 hdl->action = http_internal_error;
1463 unlink(filename);
1464 free(filename);
1466 cherokee_buffer_mrproper(&def);
1468 cherokee_buffer_mrproper(&path);
1469 goto virt_build_page_cleanup;
1473 if (hdl->action > xml && HDL_VIRT_PROPS(hdl)->xsl.len > 0)
1474 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);
1477 switch (hdl->action) {
1478 case showall: {
1479 size_t len;
1480 if (cherokee_avl_r_len(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &len) == ret_ok && len > 0) {
1481 cherokee_buffer_add_str (&hdl->buffer, "<domains>\n");
1482 cherokee_avl_r_while (&HDL_CLUSTERSTATS_PROPS(hdl)->entries, (cherokee_avl_while_func_t) cherokee_handler_clusterstats_while_func_entries, (void *) &hdl->buffer, NULL, NULL);
1483 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1484 } else {
1485 cherokee_buffer_add_str (&hdl->buffer, "<domains/>");
1488 ret = ret_ok;
1489 break;
1492 case showuservms: {
1493 cherokee_buffer_add_str (&hdl->buffer, "<domains>\n");
1494 get_all_configurations(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &hdl->user, &hdl->buffer);
1495 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1496 ret = ret_ok;
1497 break;
1500 default: {
1501 AvahiStringList *list = NULL;
1502 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1504 ret = cherokee_avl_r_get(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &domu, (void **) &list);
1506 if (ret == ret_not_found) {
1507 virDomainPtr virDom;
1508 virConnectPtr virConn;
1509 if (HDL_VIRT_PROPS(hdl)->virt.len > 0)
1510 cherokee_buffer_add_va (&uri, "xen://%s/", HDL_VIRT_PROPS(hdl)->virt); // TODO: change!
1512 /* If we have the read only parameter, we will set up a connection to the
1513 * Hypervisor here. */
1514 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1515 virConn = virConnectOpen (uri.buf);
1517 /* We should already have a connection (read only) or build a new connection
1518 * if this doesn't work, we can safely assume our services is fubar */
1519 if (!virConn && !(virConn = virConnectOpenReadOnly (uri.buf))) {
1520 conn->error_code = http_service_unavailable;
1521 return ret_error;
1524 /* We lookup if there is a domain somewhere with this name */
1525 if ((virDom = virDomainLookupByName(virConn, domu.buf)) == NULL) {
1526 /* If the domain is not found on the network the only possible
1527 * command that is possible would be to Define it */
1528 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1529 ret = ret_ok;
1530 } else {
1531 /* We should also look on disk for defined stuff */
1532 cherokee_buffer_t xmlDesc = CHEROKEE_BUF_INIT;
1533 if (load_xml(hdl, &xmlDesc) == ret_ok && (virDom = virDomainDefineXML(virConn, xmlDesc.buf)) != NULL) {
1534 /* The domain existed and is loaded! */
1535 ret = ret_ok;
1536 } else {
1537 /* Otherwise we don't have anything to do and we should
1538 * return an error */
1539 hdl->action = nothing;
1540 conn->error_code = http_not_found;
1541 ret = ret_error;
1544 cherokee_buffer_mrproper(&xmlDesc);
1546 } else {
1547 /* We don't want te recreate things that already found on the network
1548 * first undefine them! */
1549 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1550 TRACE("virt", "domainDefineXML_args/domainDefineXML; domain already exists");
1551 hdl->action = nothing;
1552 conn->error_code = http_bad_request;
1553 ret = ret_error;
1554 } else {
1555 /* Everything is ok, because nothing is found. */
1556 ret = ret_ok;
1559 /* Domain wasn't NULL, so we should free it here */
1560 virDomainFree(virDom);
1562 virConnectClose (virConn);
1563 } else if (ret == ret_ok) {
1564 char *hostname;
1565 avahi_string_list_get_pair(avahi_string_list_find(list, "dom0"), NULL, &hostname, NULL);
1566 cherokee_buffer_add_va (&uri, "xen://%s/", hostname);
1567 printf("%s\n", uri.buf);
1568 avahi_free(hostname);
1569 } else {
1570 hdl->action = http_internal_error;
1571 hdl->action = nothing;
1572 ret = ret_error;
1578 if (ret == ret_ok && hdl->action != showall && hdl->action != showuservms) {
1579 ret = virt_virt_do(hdl, &domu, &uri);
1582 virt_build_page_cleanup:
1583 cherokee_buffer_mrproper(&domu);
1584 cherokee_buffer_mrproper(&uri);
1586 return ret;
1590 ret_t
1591 cherokee_handler_virt_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
1593 ret_t ret;
1594 CHEROKEE_NEW_STRUCT (n, handler_virt);
1596 /* Init the base class
1599 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(virt));
1601 MODULE(n)->init = (handler_func_init_t) cherokee_handler_virt_init;
1602 MODULE(n)->free = (module_func_free_t) cherokee_handler_virt_free;
1603 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_virt_step;
1604 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_virt_add_headers;
1606 HANDLER(n)->support = hsupport_length | hsupport_range;
1608 ret = cherokee_buffer_init (&n->buffer);
1609 if (unlikely(ret != ret_ok))
1610 return ret;
1612 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
1613 if (unlikely(ret != ret_ok))
1614 return ret;
1616 *hdl = HANDLER(n);
1618 return ret_ok;