Second problem;
[handlervirt.git] / handler_virt.c
blob5a02560b0222faf3fc0a21d7726cac603702f049
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 <cherokee/cherokee.h>
85 #include <libxml/parser.h>
86 #include <libxml/xpath.h>
87 #include <float.h>
89 #include <avahi-client/client.h>
90 #include <avahi-client/publish.h>
91 #include <avahi-client/lookup.h>
93 #include <avahi-common/alternative.h>
94 #include <avahi-common/simple-watch.h>
95 #include <avahi-common/malloc.h>
96 #include <avahi-common/error.h>
97 #include <avahi-common/timeval.h>
100 /* Plug-in initialization
102 * In this function you can use any of these:
103 * http_delete | http_get | http_post | http_put
105 * For a full list: cherokee_http_method_t
107 * It is what your handler to be implements.
110 PLUGIN_INFO_HANDLER_EASIEST_INIT (virt, http_get | http_post);
113 /* Methods implementation
115 static ret_t
116 props_free (cherokee_handler_virt_props_t *props)
118 cherokee_buffer_mrproper(&props->xsl);
119 cherokee_buffer_mrproper(&props->virt);
121 return cherokee_handler_clusterstats_props_free (PROP_CLUSTERSTATS(props));
125 ret_t
126 cherokee_handler_virt_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
128 cherokee_list_t *i;
129 cherokee_handler_virt_props_t *props;
131 /* Instance a new property object
134 if (*_props == NULL) {
135 CHEROKEE_NEW_STRUCT (n, handler_virt_props);
137 cherokee_handler_clusterstats_props_init_base (PROP_CLUSTERSTATS(n), MODULE_PROPS_FREE(props_free));
139 /* Look at handler_virt.h
140 * This is an virt of configuration.
142 n->authenticate = true; /* by default we are secure! */
143 n->read_only = true; /* by default we are secure! */
144 cherokee_buffer_init (&n->xsl); /* we support a custom header */
145 cherokee_buffer_init (&n->virt); /* your first xenserver */
147 *_props = MODULE_PROPS(n);
150 props = PROP_VIRT(*_props);
152 cherokee_config_node_foreach (i, conf) {
153 cherokee_config_node_t *subconf = CONFIG_NODE(i);
155 if (equal_buf_str (&subconf->key, "authenticate")) {
156 props->authenticate = atoi(subconf->val.buf);
158 else if (equal_buf_str (&subconf->key, "read_only")) {
159 props->read_only = atoi(subconf->val.buf);
161 else if (equal_buf_str (&subconf->key, "xsl")) {
162 cherokee_buffer_add_buffer (&props->xsl, &subconf->val);
164 else if (equal_buf_str (&subconf->key, "virt")) {
165 cherokee_buffer_add_buffer (&props->virt, &subconf->val);
170 /* Init base class
173 return cherokee_handler_clusterstats_configure (conf, srv, _props);
176 static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) {
177 switch (state) {
178 case AVAHI_ENTRY_GROUP_ESTABLISHED :
179 /* The entry group has been established successfully */
180 break;
182 case AVAHI_ENTRY_GROUP_COLLISION : {
183 /* A service name collision with a remote service
184 * happened. */
185 break;
188 case AVAHI_ENTRY_GROUP_FAILURE :
189 /* Some kind of failure happened while we were registering our services */
190 break;
192 case AVAHI_ENTRY_GROUP_UNCOMMITED:
193 case AVAHI_ENTRY_GROUP_REGISTERING:
198 static void tender_resolve_callback(
199 AvahiServiceResolver *r,
200 AVAHI_GCC_UNUSED AvahiIfIndex interface,
201 AVAHI_GCC_UNUSED AvahiProtocol protocol,
202 AvahiResolverEvent event,
203 const char *name,
204 const char *type,
205 const char *domain,
206 const char *host_name,
207 const AvahiAddress *address,
208 uint16_t port,
209 AvahiStringList *txt,
210 AvahiLookupResultFlags flags,
211 void* userdata) {
213 tender_t *tender = userdata;
215 assert(r);
217 /* Called whenever a service has been resolved successfully or timed out */
219 switch (event) {
220 case AVAHI_RESOLVER_FAILURE:
221 fprintf(stderr, "(Resolver) FAILURE!\n");
222 avahi_service_resolver_free(r);
223 break;
225 case AVAHI_RESOLVER_FOUND: {
226 char a[AVAHI_ADDRESS_STR_MAX], *t;
227 AvahiStringList *needle;
229 fprintf(stderr, "(Resolver) Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
231 avahi_address_snprint(a, sizeof(a), address);
232 t = avahi_string_list_to_string(txt);
233 fprintf(stderr,
234 "\t%s:%u (%s)\n"
235 "\tTXT=%s\n"
236 "\tcookie is %u\n"
237 "\tis_local: %i\n"
238 "\tour_own: %i\n"
239 "\twide_area: %i\n"
240 "\tmulticast: %i\n"
241 "\tcached: %i\n",
242 host_name, port, a,
244 avahi_string_list_get_service_cookie(txt),
245 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
246 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
247 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
248 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
249 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
252 avahi_free(t);
254 unsigned int len = strlen(tender->name);
256 if (strlen(name) > len && name[len] == '.' && strncmp(tender->name, name, len) == 0) {
257 if ((needle = avahi_string_list_find (txt, "cost")) != NULL) {
259 float amount;
260 char *cost;
261 avahi_string_list_get_pair (needle, NULL, &cost, NULL);
262 amount = atof(cost);
264 TRACE("tender", "%s will run %s for the cost of L$W %f\n", host_name, tender->name, amount);
265 if (amount < tender->cost) {
266 /* TODO: LOCK */
267 tender->cost = amount;
268 tender->dom = strdup(host_name);
269 TRACE("tender", "We will consider his offer!");
272 avahi_free(cost);
274 break;
281 static void tender_browse_callback(
282 AvahiServiceBrowser *b,
283 AvahiIfIndex interface,
284 AvahiProtocol protocol,
285 AvahiBrowserEvent event,
286 const char *name,
287 const char *type,
288 const char *domain,
289 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
290 void* userdata) {
291 AvahiClient *c;
292 assert(b);
294 c = avahi_service_browser_get_client(b);
296 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
298 switch (event) {
299 case AVAHI_BROWSER_FAILURE:
300 fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(c)));
301 return;
303 case AVAHI_BROWSER_NEW:
304 fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
306 /* We ignore the returned resolver object. In the callback
307 function we free it. If the server is terminated before
308 the callback function is called the server will free
309 the resolver for us. */
311 if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, tender_resolve_callback, userdata)))
312 fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
314 break;
316 case AVAHI_BROWSER_REMOVE:
317 fprintf(stderr, "%s, (Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", __func__, name, type, domain);
318 break;
320 case AVAHI_BROWSER_ALL_FOR_NOW:
321 case AVAHI_BROWSER_CACHE_EXHAUSTED:
322 fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
323 break;
327 ret_t
328 cherokee_handler_virt_init (cherokee_handler_virt_t *hdl)
330 cherokee_connection_t *conn = HANDLER_CONN(hdl);
332 /* If someone is posting the server should be in
333 * read/write mode if this is not the case, just
334 * bail out directly */
336 if (conn->header.method == http_post && HDL_VIRT_PROPS(hdl)->read_only == TRUE) {
337 conn->error_code = http_unauthorized;
338 return ret_error;
341 int isroot = false;
342 int len;
343 char *this, *next;
345 cherokee_buffer_init(&hdl->user);
346 cherokee_buffer_init(&hdl->vm);
348 hdl->action = nothing;
350 cherokee_buffer_add (&conn->pathinfo,
351 conn->request.buf + conn->web_directory.len,
352 conn->request.len - conn->web_directory.len);
354 this = conn->pathinfo.buf + 1;
356 next = strchr(this, '/'); /* TODO: this code borks! */
358 if ((!next && (this && (len = strlen(this)) == 0)) || (next && ((len = next - this) == 0)) )
359 hdl->action = showall;
360 else {
361 cherokee_buffer_add (&hdl->user, this, len);
364 if (HDL_VIRT_PROPS(hdl)->authenticate) {
365 if (!conn->validator ||
366 (conn->validator &&
367 (!cherokee_buffer_cmp_buf(&conn->validator->user, &hdl->user) &&
368 !(isroot = cherokee_buffer_cmp (&conn->validator->user, "root", 4))))) {
369 hdl->action = nothing; /* just in case */
370 conn->error_code = http_unauthorized;
371 return ret_error;
373 } else {
374 isroot = true;
377 if (hdl->action == showall) {
378 if (!isroot) {
379 hdl->action = nothing;
380 conn->error_code = http_unauthorized;
381 return ret_error;
382 } else {
383 return virt_build_page(hdl);
388 if (!next) {
389 hdl->action = showuservms;
390 return virt_build_page(hdl);
391 } else {
392 this = next + 1;
393 next = strchr(this, '/');
395 if ( ( !next && (this && (len = strlen(this)) == 0) ) || (next && ((len = next - this) == 0)) ) {
396 //if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
397 hdl->action = showuservms;
398 return virt_build_page(hdl);
402 cherokee_buffer_add (&hdl->vm, this, len);
404 if (!next) {
405 hdl->action = domainGetXMLDesc;
406 return virt_build_page(hdl);
407 } else {
408 this = next + 1;
409 next = strchr(this, '/');
411 if (( !next && (this && (len = strlen(this)) == 0) ) || (next && ((len = next - this) == 0)) ) {
412 hdl->action = domainGetXMLDesc;
413 return virt_build_page(hdl);
417 hdl->action = not_implemented;
418 switch (conn->header.method) {
419 case http_get:
420 if (strncmp(this, "virDomain", 9) == 0) {
421 if (strncmp(this+9, "Get", 3) == 0) {
422 if (strcmp(this+12, "ID") == 0) hdl->action = domainGetID;
423 else if (strcmp(this+12, "Name") == 0) hdl->action = domainGetName;
424 else if (strcmp(this+12, "MaxMemory") == 0) hdl->action = domainGetMaxMemory;
425 else if (strcmp(this+12, "MaxVcpus") == 0) hdl->action = domainGetMaxVcpus;
426 else if (strcmp(this+12, "OSType") == 0) hdl->action = domainGetOSType;
427 else if (strcmp(this+12, "UUID") == 0) hdl->action = domainGetUUID;
428 else if (strcmp(this+12, "UUIDString") == 0) hdl->action = domainGetUUIDString;
429 else if (strcmp(this+12, "XMLDesc") == 0) hdl->action = domainGetXMLDesc;
432 else if (HDL_VIRT_PROPS(hdl)->read_only == FALSE) {
433 if (strcmp(this+9, "Create") == 0) hdl->action = domainCreate;
434 else if (strcmp(this+9, "Destroy") == 0) hdl->action = domainDestroy;
435 else if (strcmp(this+9, "Reboot") == 0) hdl->action = domainReboot;
436 else if (strcmp(this+9, "Shutdown") == 0) hdl->action = domainShutdown;
438 else if (strcmp(this+9, "Save") == 0) hdl->action = domainSave;
439 else if (strcmp(this+9, "Restore") == 0) hdl->action = domainRestore;
441 else if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice_args;
443 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML_args;
444 else if (strcmp(this+9, "Undefine") == 0) hdl->action = domainUndefine;
447 else if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && strncmp(this, "virStorage", 10) == 0) {
448 if (strncmp(this+10, "Vol", 3) == 0) {
449 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML_args;
450 else if (strcmp(this+13, "Delete") == 0) hdl->action = storageVolDelete_args;
451 else if (strcmp(this+13, "CloneXML") == 0) hdl->action = storageVolCloneXML_args;
452 else if (strcmp(this+13, "CloneStatus") == 0) hdl->action = storageVolCloneStatus_args;
453 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl->action = storageVolGetXMLDesc_args;
454 else if (strcmp(this+13, "SetPassword") == 0) hdl->action = storageVolSetPassword_args;
457 else if (strncmp(this, "virGraph", 8) == 0) {
458 if (strcmp(this+8, "Load") == 0) hdl->action = graphLoad_args;
459 if (strcmp(this+8, "Interface") == 0) hdl->action = graphInterface_args;
461 break;
463 case http_post: {
464 off_t postl;
465 cherokee_post_get_len (&conn->post, &postl);
467 if (postl <= 0 || postl >= (INT_MAX-1)) {
468 TRACE("virt", "post without post");
469 conn->error_code = http_bad_request;
470 return ret_error;
473 if (strncmp(this, "virDomain", 9) == 0) {
474 if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice;
475 else if (strcmp(this+9, "DetachDevice") == 0) hdl->action = domainDetachDevice;
476 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML;
478 else if (strncmp(this, "virStorage", 10) == 0) {
479 if (strncmp(this+10, "Vol", 3) == 0) {
480 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML;
484 break;
487 default:
488 return ret_error;
491 if (hdl->action <= 0) {
492 TRACE("virt", "There was no action specified");
493 conn->error_code = http_bad_request;
494 return ret_error;
497 return virt_build_page(hdl);
500 ret_t
501 cherokee_handler_virt_free (cherokee_handler_virt_t *hdl)
503 cherokee_buffer_mrproper (&hdl->buffer);
504 cherokee_buffer_mrproper (&hdl->user);
505 cherokee_buffer_mrproper (&hdl->vm);
507 return ret_ok;
510 ret_t
511 cherokee_handler_virt_step (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
513 cuint_t tosend;
515 if (cherokee_buffer_is_empty (&hdl->buffer))
516 return ret_eof;
518 tosend = (hdl->buffer.len > 1024 ? 1024 : hdl->buffer.len);
520 cherokee_buffer_add (buffer, hdl->buffer.buf, tosend);
521 cherokee_buffer_move_to_begin (&hdl->buffer, tosend);
523 if (cherokee_buffer_is_empty (&hdl->buffer))
524 return ret_eof_have_data;
526 return ret_ok;
529 ret_t
530 cherokee_handler_virt_add_headers (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
532 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
534 if (hdl->action > xml)
535 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
536 else if (hdl->action > graph) {
537 cherokee_buffer_add_str (buffer, "Content-Type: image/png"CRLF);
538 } else
539 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
541 return ret_ok;
545 static ret_t
546 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
547 virConnectPtr conn = NULL;
548 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
549 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
551 cherokee_buffer_add_va (&uri, "xen://%s/", value);
553 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
554 if (!(conn = virConnectOpen (uri.buf))) {
555 return ret_error;
559 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
560 return ret_error;
561 } else {
562 virDomainPtr dom;
563 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
564 return ret_error;
565 } else {
566 char *xml = virDomainGetXMLDesc(dom, 0);
567 cherokee_buffer_add(buf, xml, strlen(xml));
569 virConnectClose(conn);
572 cherokee_buffer_mrproper(&uri);
574 return ret_ok;
577 static ret_t load_xml(cherokee_handler_virt_t *hdl, cherokee_buffer_t *xmlDesc) {
578 ret_t ret = ret_error;
579 FILE *fd;
580 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
581 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s", hdl->user.buf);
583 mkdir(path.buf, 0755);
584 cherokee_buffer_add_va (&path, "/%s", hdl->vm.buf);
586 mkdir(path.buf, 0755);
587 cherokee_buffer_add_str (&path, "/index.xml");
589 if ((fd = fopen(path.buf, "r")) != NULL) {
590 while (!feof(fd)) {
591 char buf[1024];
592 size_t amount = fread(buf, sizeof(char), 1024, fd);
594 cherokee_buffer_add (xmlDesc, buf, amount);
596 fclose(fd);
597 if (xmlDesc->len > 0)
598 ret = ret_ok;
601 cherokee_buffer_mrproper(&path);
602 return ret;
605 static ret_t save_xml(cherokee_handler_virt_t *hdl, virDomainPtr result, cherokee_buffer_t *buf) {
606 ret_t ret = ret_error;
607 FILE *fd;
608 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
609 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s", hdl->user.buf);
611 mkdir(path.buf, 0755);
612 cherokee_buffer_add_va (&path, "/%s", hdl->vm.buf);
614 mkdir(path.buf, 0755);
615 cherokee_buffer_add_str (&path, "/index.xml");
617 if ((fd = fopen(path.buf, "w")) == NULL) {
618 perror(__func__);
619 } else {
620 char *output = virDomainGetXMLDesc(result, VIR_DOMAIN_XML_INACTIVE);
621 if (output) {
622 fwrite(output, strlen(output), sizeof(char), fd);
623 if (buf)
624 cherokee_buffer_add(buf, output, strlen(output));
625 free(output);
627 fclose(fd);
628 ret = ret_ok;
630 cherokee_buffer_mrproper(&path);
631 return ret;
635 static ret_t
636 virt_virt_function(cherokee_handler_virt_t *hdl, virDomainPtr dom, virConnectPtr virConn) {
637 cherokee_connection_t *conn = HANDLER_CONN(hdl);
638 cherokee_buffer_t *buf = &HDL_VIRT(hdl)->buffer;
640 switch (hdl->action) {
641 /* Returns the status of a clone copy */
642 case storageVolCloneStatus_args: {
643 ret_t ret;
644 void *name;
645 struct stat statbuf;
646 cherokee_buffer_t queue = CHEROKEE_BUF_INIT;
648 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
649 if (unlikely(ret < ret_ok)) {
650 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
651 conn->error_code = http_bad_request;
652 return ret_error;
655 cherokee_buffer_add_va (&queue, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
657 if (stat(queue.buf, &statbuf) != 0) {
658 conn->error_code = http_not_found;
659 ret = ret_error;
660 } else {
661 char hardlink[1024];
662 int namelen;
663 if ((namelen = readlink(queue.buf, hardlink, 1023)) == -1) {
664 conn->error_code = http_internal_error;
665 ret = ret_error;
666 } else {
667 hardlink[namelen] = '\0';
668 if (stat(hardlink, &statbuf) != 0) {
669 conn->error_code = http_internal_error;
670 ret = ret_error;
671 } else {
672 struct stat statbuf2;
673 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
674 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.busy", hdl->user.buf, name);
675 if (stat(busy.buf, &statbuf2) != 0) {
676 conn->error_code = http_internal_error;
677 ret = ret_error;
678 } else {
679 cherokee_buffer_add_va (buf, "%f", (float)((float)statbuf2.st_size / (float)statbuf.st_size));
680 ret = ret_ok;
682 cherokee_buffer_mrproper(&busy);
687 cherokee_buffer_mrproper(&queue);
688 return ret;
689 break;
692 /* Save the memory of a domain to a file and suspend the domain */
693 case domainSave: {
694 ret_t ret = ret_ok;
695 int result;
696 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
697 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
698 if ((result = virDomainSave(dom, path.buf)) != 0) {
699 TRACE("virt", "Saving of %s/%s failed", hdl->user.buf, hdl->vm.buf);
700 conn->error_code = http_internal_error;
701 ret = ret_error;
703 cherokee_buffer_mrproper(&path);
705 cherokee_buffer_add_long10(buf, result);
706 return ret;
707 break;
710 /* Restore the memory of a domain from a file and resume the domain */
711 case domainRestore: {
712 ret_t ret = ret_ok;
713 struct stat statbuf;
714 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
715 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/memory", hdl->user.buf, hdl->vm.buf);
717 if (stat(path.buf, &statbuf) == 0) {
718 int result;
719 if ((result = virDomainRestore(virConn, path.buf)) != 0) {
720 TRACE("virt", "Restoring of %s/%s failed", hdl->user.buf, hdl->vm.buf);
721 conn->error_code = http_internal_error;
722 ret = ret_error;
724 cherokee_buffer_add_long10(buf, result);
725 } else {
726 TRACE("virt", "Memory file for %s/%s does not exist", hdl->user.buf, hdl->vm.buf);
727 conn->error_code = http_not_found;
728 ret = ret_error;
731 cherokee_buffer_mrproper(&path);
732 return ret;
733 break;
736 case domainUndefine: {
737 int result;
738 if ((result = virDomainUndefine(dom)) != 0) {
739 conn->error_code = http_internal_error; /* TODO */
742 cherokee_buffer_add_long10(buf, result);
743 break;
746 case domainAttachDevice_args: {
747 int result;
748 void *temp;
749 ret_t ret;
751 ret = cherokee_avl_get_ptr (conn->arguments, "type", &temp);
753 if (ret == ret_ok) {
754 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
756 if (strcmp(temp, "disk") == 0) {
757 void *device;
758 if ((ret = cherokee_avl_get_ptr (conn->arguments, "device", &device)) == ret_ok) {
759 void *file;
760 if ((ret = cherokee_avl_get_ptr (conn->arguments, "file", &file)) == ret_ok) {
761 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
762 } else {
763 virStorageVolPtr volume = virt_get_vol_by_args(hdl, virConn, 1);
765 if (volume == NULL) {
766 return ret_error;
769 file = virStorageVolGetPath(volume);
770 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
771 free(file);
773 virStorageVolFree(volume);
774 ret = ret_ok;
779 else if (strcmp(temp, "interface") == 0) {
780 void *mac, *ip;
781 if ((ret = cherokee_avl_get_ptr (conn->arguments, "mac", &mac)) == ret_ok && (ret = cherokee_avl_get_ptr (conn->arguments, "ip", &ip)) == ret_ok) {
782 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
783 } else {
784 char *mac = NULL;
785 char *ip = NULL;
786 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
787 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
788 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0)
789 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
790 cherokee_buffer_mrproper(&domu);
794 if (ret == ret_ok && (result = virDomainAttachDevice(dom, (const char *) xml.buf)) == 0) {
795 ret = ret_ok;
796 } else {
797 conn->error_code = http_internal_error;
798 return ret_error;
801 cherokee_buffer_add_long10(buf, result);
802 cherokee_buffer_mrproper(&xml);
803 } else {
804 TRACE("virt", "DeviceAttach_args; type was not specified");
805 conn->error_code = http_bad_request;
806 return ret_error;
809 break;
812 case domainAttachDevice: {
813 off_t postl;
814 int result;
815 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
816 cherokee_post_get_len (&conn->post, &postl);
817 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
818 if ((result = virDomainAttachDevice(dom, (const char *) post.buf)) != 0)
819 conn->error_code = http_internal_error;
821 cherokee_buffer_mrproper(&post);
822 cherokee_buffer_add_long10(buf, result);
823 break;
827 case domainGetXMLDesc: {
828 char *xml = virDomainGetXMLDesc(dom, 0);
829 cherokee_buffer_add(buf, xml, strlen(xml));
830 free(xml);
831 break;
835 case domainDetachDevice: {
836 off_t postl;
837 int result;
838 ret_t ret;
839 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
840 cherokee_post_get_len (&conn->post, &postl);
841 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
843 xmlDocPtr doc = xmlParseMemory((const char *) post.buf, post.len);
844 if (doc == NULL) {
845 TRACE("virt", "DeviceAttach; XML document unparceble");
846 conn->error_code = http_bad_request;
847 ret = ret_error;
848 } else
849 ret = ret_ok;
851 if (ret == ret_ok) {
852 if ((result = virDomainDetachDevice(dom, (const char *) post.buf)) != 0) {
853 conn->error_code = http_internal_error;
854 /* TODO: betere afhandeling */
856 xmlXPathContextPtr context = xmlXPathNewContext(doc);
857 if (context != NULL) {
858 xmlXPathObjectPtr obj = xmlXPathEval("string(//interface/mac/@address)", context);
859 xmlXPathFreeContext(context);
860 if ((obj != NULL) && (obj->type == XPATH_STRING) &&
861 (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
862 removeOldMac("dv28", (char *) obj->stringval);
864 xmlXPathFreeObject(obj);
867 xmlFreeDoc(doc);
868 xmlCleanupParser();
871 cherokee_buffer_mrproper(&post);
872 cherokee_buffer_add_long10(buf, result);
873 break;
876 case domainGetID: {
877 cherokee_buffer_add_ulong10(buf, virDomainGetID(dom));
878 break;
880 case domainGetMaxMemory: {
881 cherokee_buffer_add_ulong10(buf, virDomainGetMaxMemory (dom));
882 break;
884 case domainGetMaxVcpus: {
885 cherokee_buffer_add_long10(buf, virDomainGetMaxVcpus (dom));
886 break;
888 case domainGetName: {
889 const char *name = virDomainGetName (dom);
890 cherokee_buffer_add(buf, name, strlen(name));
891 break;
893 case domainGetUUID: {
894 unsigned char uuid[VIR_UUID_BUFLEN];
895 if (virDomainGetUUID(dom, uuid) == 0) {
896 cherokee_buffer_add_str(buf, uuid);
897 } else {
898 conn->error_code = http_internal_error;
899 return ret_error;
901 break;
903 case domainGetUUIDString: {
904 unsigned char uuid[VIR_UUID_STRING_BUFLEN];
905 if (virDomainGetUUIDString(dom, uuid) == 0) {
906 cherokee_buffer_add_str(buf, uuid);
907 } else {
908 conn->error_code = http_internal_error;
909 return ret_error;
911 break;
914 case domainCreate: {
915 cherokee_buffer_t xmlDesc = CHEROKEE_BUF_INIT;
916 char txt[254];
917 save_xml(hdl, dom, &xmlDesc);
918 tender_t best_tender;
919 snprintf(txt, 252, "memory=%lu", virDomainGetMaxMemory(dom));
920 txt[253] = '\0';
922 best_tender.name = virDomainGetName(dom);
923 best_tender.cost = FLT_MAX;
924 best_tender.dom = NULL;
926 avahi_threaded_poll_lock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
927 AvahiServiceBrowser *sb = avahi_service_browser_new(HDL_CLUSTERSTATS_PROPS(hdl)->client, AVAHI_IF_UNSPEC,
928 AVAHI_PROTO_UNSPEC, "_tender._tcp",
929 NULL, 0, tender_browse_callback, &best_tender);
931 if (sb == NULL) {
932 TRACE("avahi", "For whatever reason the sb is NULL\n");
933 } else {
934 AvahiEntryGroup *group = avahi_entry_group_new(HDL_CLUSTERSTATS_PROPS(hdl)->client, entry_group_callback, NULL);
936 if (group == NULL) {
937 TRACE("avahi", "For whatever reason the group is NULL\n");
938 } else {
939 avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0,
940 best_tender.name, "_offer._tcp", NULL, NULL, 651, txt, NULL, NULL);
941 avahi_entry_group_commit(group);
942 avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
944 sleep(3); /* we are for quick bidding ;) */
946 avahi_threaded_poll_lock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
947 avahi_entry_group_free(group);
950 avahi_service_browser_free(sb);
951 avahi_threaded_poll_unlock(HDL_CLUSTERSTATS_PROPS(hdl)->threaded_poll);
953 if (best_tender.dom == NULL) {
954 TRACE("virt", "Nobody wants %s, poor vm!\n", best_tender.name);
955 cherokee_buffer_add_long10(buf, -1);
956 } else {
957 if (virDomainUndefine(dom) != 0) {
958 TRACE("virt", "Can't undefine %s, some idiot run it already?\n", best_tender.name);
959 cherokee_buffer_add_long10(buf, -1);
960 } else {
961 virConnectPtr virConnNew;
962 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
963 // virConnectClose(virConn);
964 cherokee_buffer_add_va (&uri, "xen://%s/", best_tender.dom);
965 virConnNew = virConnectOpen (uri.buf);
966 if (virConnNew == NULL) {
967 TRACE("virt", "Can't connect to %s\n", uri.buf);
968 cherokee_buffer_add_long10(buf, -1);
969 } else {
970 cherokee_buffer_add_long10(buf,
971 (virDomainCreateLinux(virConnNew, xmlDesc.buf, 0) != NULL ?
972 0 : -1 ));
973 virConnectClose(virConn);
975 virConn = virConnNew;
976 /* TODO: Here I actually want virConnNew to be virConn */
978 cherokee_buffer_mrproper(&uri);
980 TRACE("virt", "going to free\n");
981 free(best_tender.dom);
986 cherokee_buffer_mrproper(&xmlDesc);
987 break;
990 case domainDestroy: {
991 cherokee_buffer_add_long10(buf, virDomainDestroy (dom));
992 break;
995 case domainReboot: {
996 cherokee_buffer_add_long10(buf, virDomainReboot (dom, 0));
997 break;
1000 case domainShutdown: {
1001 cherokee_buffer_add_long10(buf, virDomainShutdown (dom));
1002 break;
1006 case domainGetOSType: {
1007 char *ostype = virDomainGetOSType(dom);
1008 cherokee_buffer_add(buf, ostype, strlen(ostype));
1009 free(ostype);
1010 break;
1017 if (hdl->action == domainUndefine) {
1018 /* Remove VM data from filesystem */
1019 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1020 cherokee_buffer_t path2 = CHEROKEE_BUF_INIT;
1021 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/index.xml", hdl->user.buf, hdl->vm.buf);
1022 cherokee_buffer_add_buffer (&path2, &path);
1023 cherokee_buffer_add_str (&path2, ".deleted");
1024 // unlink(path.buf); /* TODO: instead of delet replace */
1025 rename(path.buf, path2.buf);
1026 cherokee_buffer_mrproper(&path);
1027 cherokee_buffer_mrproper(&path2);
1028 } else if (hdl->action != domainCreate) {
1029 save_xml(hdl, dom, NULL);
1032 return ret_ok;
1035 static virStoragePoolPtr
1036 virt_get_pool_by_args(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
1037 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1038 virStoragePoolPtr pool;
1039 void *temp;
1040 ret_t ret;
1042 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
1043 if (unlikely(ret < ret_ok)) {
1044 TRACE("virt", "virStoragePoolPtr; Pool argument not specified");
1045 conn->error_code = http_bad_request;
1046 return NULL;
1049 pool = virStoragePoolLookupByName(virConn, temp);
1051 return pool;
1054 static virStorageVolPtr
1055 virt_get_vol_by_args(cherokee_handler_virt_t *hdl, virConnectPtr virConn, unsigned short int prefix) {
1056 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1057 virStoragePoolPtr pool;
1058 virStorageVolPtr volume;
1059 void *temp;
1060 ret_t ret;
1062 pool = virt_get_pool_by_args(hdl, virConn);
1064 if (pool == NULL) {
1065 conn->error_code = http_not_found;
1066 return NULL;
1069 virStoragePoolRefresh(pool, 0); /* TODO: might be better to do it outside */
1071 ret = cherokee_avl_get_ptr (conn->arguments, "volume", &temp);
1072 if (unlikely(ret < ret_ok)) {
1073 TRACE("virt", "virStorageVolPtr; Volume argument not specified");
1074 conn->error_code = http_bad_request;
1075 return NULL;
1078 if (prefix == 1) {
1079 cherokee_buffer_t fullvol = CHEROKEE_BUF_INIT;
1080 cherokee_buffer_add_va (&fullvol, "%s_%s", hdl->user.buf, temp);
1081 volume = virStorageVolLookupByName(pool, fullvol.buf);
1082 cherokee_buffer_mrproper(&fullvol);
1083 } else {
1084 volume = virStorageVolLookupByName(pool, temp);
1087 if (volume == NULL)
1088 conn->error_code = http_not_found;
1090 virStoragePoolFree(pool);
1092 return volume;
1095 /* This function is the home for all functions that need a working
1096 * pool/volume combination */
1097 static ret_t
1098 virt_pool_vol(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
1099 cherokee_buffer_t *buf = &HDL_VIRT(hdl)->buffer;
1100 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1101 virStorageVolPtr volume;
1102 ret_t ret = ret_ok;
1104 /* We only allow clone to run 'unsafe', others get prefixed */
1105 volume = virt_get_vol_by_args(hdl, virConn, (hdl->action != storageVolCloneXML_args));
1107 /* If the volume doesn't exist, no point to continue */
1108 if (volume == NULL) {
1109 conn->error_code = http_not_found;
1110 return ret_error;
1113 switch (hdl->action) {
1114 /* Sets the password of a specific volume, requires the password= option */
1115 case storageVolSetPassword_args: {
1116 void *temp;
1117 ret = cherokee_avl_get_ptr (conn->arguments, "password", &temp);
1118 if (unlikely(ret < ret_ok)) {
1119 TRACE("virt", "storageVolSetPassword_args; password argument not specified");
1120 conn->error_code = http_bad_request;
1121 ret = ret_error;
1122 goto virt_pool_vol_cleanup;
1123 } else {
1124 cherokee_buffer_t cmd_passwd = CHEROKEE_BUF_INIT;
1125 cherokee_buffer_add_va (&cmd_passwd, "/usr/sbin/passwdchanger.sh %s %s\n", virStorageVolGetKey(volume), temp);
1126 cherokee_buffer_add_long10(buf, system(cmd_passwd.buf));
1127 cherokee_buffer_mrproper(&cmd_passwd);
1129 break;
1132 /* Removes a volume */
1133 case storageVolDelete_args: {
1134 cherokee_buffer_add_long10(buf, virStorageVolDelete(volume, 0));
1135 break;
1138 /* Gives a description of a storage volume in XML */
1139 case storageVolGetXMLDesc_args: {
1140 char *xml = virStorageVolGetXMLDesc(volume, 0);
1141 cherokee_buffer_add(buf, xml, strlen(xml));
1142 free(xml);
1143 break;
1146 /* Clones a volume, insecure method! requires a new name= */
1147 case storageVolCloneXML_args: {
1148 void *name;
1149 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
1151 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
1152 if (unlikely(ret < ret_ok)) {
1153 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
1154 conn->error_code = http_bad_request;
1155 ret = ret_error;
1156 goto virt_pool_vol_cleanup;
1159 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
1161 if (unlikely(symlink(virStorageVolGetKey(volume), busy.buf) == 1)) {
1162 conn->error_code = http_internal_error;
1163 ret = ret_error;
1164 } else {
1165 cherokee_buffer_add_str(buf, "QUEUED");
1168 cherokee_buffer_mrproper(&busy);
1170 break;
1175 virt_pool_vol_cleanup:
1176 /* And in the end we need to free the volume we have used */
1177 virStorageVolFree(volume);
1179 return ret;
1182 static ret_t
1183 virt_virt_new(cherokee_handler_virt_t *hdl, virConnectPtr virConn) {
1184 cherokee_buffer_t *buf = &HDL_VIRT(hdl)->buffer;
1185 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1186 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
1187 virStoragePoolPtr pool = NULL;
1188 ret_t ret = ret_ok;
1190 switch (hdl->action) {
1192 case storageVolCreateXML_args: {
1193 void *temp, *type, *name, *unit;
1194 unsigned long int capacity, allocation;
1196 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
1197 if (unlikely(ret < ret_ok)) {
1198 TRACE("virt", "storageVolCreateXML_args; pool argument not specified");
1199 conn->error_code = http_bad_request;
1200 goto virt_virt_new_cleanup;
1203 TRACE("args", "%s", temp);
1205 pool = virStoragePoolLookupByName(virConn, temp);
1207 if (pool == NULL) {
1208 conn->error_code = http_not_found;
1209 goto virt_virt_new_cleanup;
1212 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
1213 if (unlikely(ret < ret_ok)) {
1214 TRACE("virt", "storageVolCreateXML_args; name argument not specified");
1215 conn->error_code = http_bad_request;
1216 goto virt_virt_new_cleanup;
1219 ret = cherokee_avl_get_ptr (conn->arguments, "type", &type);
1220 if (unlikely(ret < ret_ok)) {
1221 TRACE("virt", "storageVolCreateXML_args; type argument not specified");
1222 conn->error_code = http_bad_request;
1223 goto virt_virt_new_cleanup;
1226 ret = cherokee_avl_get_ptr (conn->arguments, "unit", &unit);
1227 if (unlikely(ret < ret_ok)) {
1228 TRACE("virt", "storageVolCreateXML_args; unit argument not specified");
1229 conn->error_code = http_bad_request;
1230 goto virt_virt_new_cleanup;
1233 ret = cherokee_avl_get_ptr (conn->arguments, "allocation", &temp);
1234 if (unlikely(ret < ret_ok)) {
1235 TRACE("virt", "storageVolCreateXML_args; allocation argument not specified");
1236 conn->error_code = http_bad_request;
1237 goto virt_virt_new_cleanup;
1240 allocation = strtoul(temp, NULL, 10);
1241 if (errno == ERANGE) {
1242 TRACE("virt", "storageVolCreateXML_args; allocation is not a number");
1243 conn->error_code = http_bad_request;
1244 ret = ret_error;
1245 goto virt_virt_new_cleanup;
1248 ret = cherokee_avl_get_ptr (conn->arguments, "capacity", &temp);
1249 if (unlikely(ret < ret_ok)) {
1250 TRACE("virt", "storageVolCreateXML_args; capacity argument not specified");
1251 conn->error_code = http_bad_request;
1252 goto virt_virt_new_cleanup;
1255 capacity = strtoul(temp, NULL, 10);
1256 if (errno == ERANGE || capacity == 0) {
1257 TRACE("virt", "storageVolCreateXML_args; capacity is not a number");
1258 conn->error_code = http_bad_request;
1259 ret = ret_error;
1260 goto virt_virt_new_cleanup;
1263 cherokee_buffer_add_va (&xml, VIRT_STORAGE_XML, type, hdl->user.buf, name, allocation, unit, capacity, hdl->user.buf, name, hdl->user.buf, name);
1264 break;
1267 case domainDefineXML_args: {
1268 ret_t ret;
1269 unsigned int i;
1270 unsigned long vcpu = 0, interface = 0, memory = 0;
1272 void *temp = NULL;
1274 ret = cherokee_avl_get_ptr (conn->arguments, "vcpu", &temp);
1275 if (ret == ret_ok)
1276 vcpu = strtoul(temp, (char **) NULL, 10);
1278 if (ret != ret_ok || errno == ERANGE || vcpu == 0) {
1279 conn->error_code = http_internal_error;
1280 goto virt_virt_new_cleanup;
1284 ret = cherokee_avl_get_ptr (conn->arguments, "memory", &temp);
1285 if (ret == ret_ok)
1286 memory = strtoul(temp, (char **) NULL, 10);
1288 if (ret != ret_ok || errno == ERANGE || memory == 0) {
1289 conn->error_code = http_internal_error;
1290 goto virt_virt_new_cleanup;
1294 ret = cherokee_avl_get_ptr (conn->arguments, "interface", &temp);
1295 if (ret == ret_ok)
1296 interface = strtoul(temp, (char **) NULL, 10);
1298 if (ret != ret_ok || errno == ERANGE) {
1299 conn->error_code = http_internal_error;
1300 goto virt_virt_new_cleanup;
1303 cherokee_buffer_t cmdline_extra = CHEROKEE_BUF_INIT;
1304 cherokee_buffer_t xml_interfaces = CHEROKEE_BUF_INIT;
1305 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1306 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1308 for (i = 0; i < interface; i++) {
1309 char *mac = NULL;
1310 char *ip = NULL;
1311 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0) {
1312 cherokee_buffer_add_va (&xml_interfaces, VIRT_INTERFACE_XML, mac, ip);
1313 if (i == 0) {
1314 /* TODO: terrible hack */
1315 char gateway[16];
1316 char *temp;
1317 strcpy(gateway, ip);
1318 temp = strchr(gateway, '.');
1319 temp = strchr(++temp, '.');
1320 temp = strchr(++temp, '.');
1321 strcpy(++temp, "254");
1322 cherokee_buffer_add_va (&cmdline_extra, VIRT_DOMAIN_CMD_IP, ip, gateway);
1327 cherokee_buffer_mrproper(&domu);
1329 cherokee_buffer_add_va (&xml, VIRT_DOMAIN_XML,
1330 hdl->user.buf, hdl->vm.buf, cmdline_extra.buf, memory, vcpu, xml_interfaces.buf);
1332 cherokee_buffer_mrproper(&xml_interfaces);
1333 cherokee_buffer_mrproper(&cmdline_extra);
1334 break;
1337 case storageVolCreateXML:
1338 case domainDefineXML: {
1339 off_t postl;
1340 cherokee_post_get_len (&conn->post, &postl);
1341 cherokee_post_walk_read (&conn->post, &xml, (cuint_t) postl);
1342 break;
1346 switch (hdl->action) {
1347 case domainDefineXML_args:
1348 case domainDefineXML: {
1349 virDomainPtr result = virDomainDefineXML(virConn, (const char *) xml.buf);
1351 if (result == NULL) {
1352 /* TODO: vrij maken eventuele uitgegeven macs! */
1353 conn->error_code = http_internal_error;
1354 goto virt_virt_new_cleanup;
1357 save_xml(hdl, result, buf);
1359 virDomainFree(result);
1361 break;
1364 case storageVolCreateXML_args:
1365 case storageVolCreateXML: {
1366 virStorageVolPtr vol = virStorageVolCreateXML(pool, xml.buf, 0);
1368 if (vol == NULL) {
1369 cherokee_buffer_add_long10(buf, -1);
1370 goto virt_virt_new_cleanup;
1373 virStorageVolFree(vol);
1375 cherokee_buffer_add_long10(buf, 0);
1376 break;
1380 virt_virt_new_cleanup:
1381 cherokee_buffer_mrproper(&xml);
1383 if (pool)
1384 virStoragePoolFree(pool);
1386 return ret;
1390 static ret_t
1391 virt_virt_do(cherokee_handler_virt_t *hdl, cherokee_buffer_t *domu, cherokee_buffer_t *uri)
1393 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1395 ret_t ret = ret_error;
1396 virConnectPtr virConn = NULL;
1399 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1400 virConn = virConnectOpen (uri->buf);
1402 if (!virConn && !(virConn = virConnectOpenReadOnly (uri->buf))) {
1403 conn->error_code = http_service_unavailable;
1404 return ret_error;
1407 switch (hdl->action) {
1408 case storageVolDelete_args:
1409 case storageVolSetPassword_args:
1410 case storageVolGetXMLDesc_args:
1411 case storageVolCloneXML_args:
1412 ret = virt_pool_vol(hdl, virConn);
1413 break;
1415 case storageVolCreateXML_args:
1416 case storageVolCreateXML:
1417 case domainDefineXML_args:
1418 case domainDefineXML:
1419 ret = virt_virt_new(hdl, virConn);
1420 break;
1422 default: {
1423 virDomainPtr dom;
1424 if ((dom = virDomainLookupByName(virConn, domu->buf)) == NULL) {
1425 conn->error_code = http_not_found;
1426 } else {
1427 ret = virt_virt_function(hdl, dom, virConn);
1428 virDomainFree(dom);
1433 virConnectClose(virConn);
1434 return ret;
1437 static ret_t
1438 virt_while (cherokee_buffer_t *key, void *value, void *param) {
1439 cherokee_handler_virt_t * hdl = param;
1440 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1441 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1442 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1443 // cherokee_buffer_mrproper(&uri);
1445 cherokee_buffer_add_va (&hdl->buffer, "<domain><name>%s</name></domain>", key->buf);
1447 return ret_ok;
1450 static ret_t
1451 virt_while_user (cherokee_buffer_t *key, void *value, void *param) {
1452 cherokee_handler_virt_t *hdl = param;
1453 if (key->len > hdl->user.len && key->buf[hdl->user.len] == '_' && strncmp(key->buf, hdl->user.buf, hdl->user.len) == 0)
1454 return virt_while (key, value, param);
1456 return ret_ok;
1459 static ret_t
1460 virt_build_page (cherokee_handler_virt_t *hdl)
1462 ret_t ret;
1463 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1464 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1465 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1467 /* We use the webserver methods to parse the querystring */
1468 /* Maybe do something smart with ENUM, begin_args, end_args... */
1469 if ((hdl->action == domainDefineXML_args) ||
1470 (hdl->action == domainAttachDevice_args) ||
1471 (hdl->action == storageVolGetXMLDesc_args) ||
1472 (hdl->action == storageVolDelete_args) ||
1473 (hdl->action == storageVolSetPassword_args) ||
1474 (hdl->action == storageVolCloneXML_args) ||
1475 (hdl->action == storageVolCloneStatus_args) ||
1476 (hdl->action == storageVolCreateXML_args) ||
1477 (hdl->action == graphLoad_args) ||
1478 (hdl->action == graphInterface_args)) {
1479 ret = cherokee_connection_parse_args (conn);
1480 if (unlikely(ret < ret_ok)) {
1481 conn->error_code = http_internal_error;
1482 return ret_error;
1486 switch (hdl->action) {
1487 case graphInterface_args: {
1488 struct stat statbuf;
1489 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1490 void *interface;
1491 if ((ret = cherokee_avl_get_ptr (conn->arguments, "interface", &interface)) != ret_ok)
1492 interface = "eth0";
1494 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/interface_%s.rrd", hdl->user.buf, hdl->vm.buf, interface);
1495 if (stat(path.buf, &statbuf) != 0) {
1496 conn->error_code = http_not_found;
1497 ret = ret_error;
1498 } else {
1499 void *width, *height, *start, *end;
1500 if ((ret = cherokee_avl_get_ptr (conn->arguments, "width", &width)) != ret_ok)
1501 width = "600";
1503 if ((ret = cherokee_avl_get_ptr (conn->arguments, "height", &height)) != ret_ok)
1504 height = "200";
1506 if ((ret = cherokee_avl_get_ptr (conn->arguments, "start", &start)) != ret_ok)
1507 start = "now-1h";
1509 if ((ret = cherokee_avl_get_ptr (conn->arguments, "end", &end)) != ret_ok)
1510 end = "now";
1512 cherokee_buffer_t def1 = CHEROKEE_BUF_INIT;
1513 cherokee_buffer_t def2 = CHEROKEE_BUF_INIT;
1514 cherokee_buffer_add_va (&def1, "DEF:rxbytes=%s:rxbytes:AVERAGE:step=30", path.buf);
1515 cherokee_buffer_add_va (&def2, "DEF:txbytes=%s:txbytes:AVERAGE:step=30", path.buf);
1516 char **calcpr = NULL;
1517 int xsize, ysize;
1518 double ymin, ymax;
1519 /* TODO: betere random hier */
1520 char filenametemp[L_tmpnam+1];
1521 char *filename = tmpnam(filenametemp);
1523 // char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1524 char *r_graph[] = { "rrdgraph", filename,
1525 "-a", "PNG",
1526 "-w", width,
1527 "-h", height,
1528 "--start", start,
1529 "--end", end,
1530 "--title", interface,
1531 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "bits per second",
1532 def1.buf,
1533 def2.buf,
1534 "CDEF:txbits=txbytes,8,*",
1535 "CDEF:rxbits=rxbytes,8,*",
1536 "AREA:rxbits#00EE00:rxbits",
1537 "LINE:txbits#0000EE:txbits" };
1539 rrd_graph(25, r_graph, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
1540 if ((ret = cherokee_buffer_read_file(&hdl->buffer, filename)) == ret_error) {
1541 hdl->action = http_internal_error;
1544 unlink(filename);
1546 cherokee_buffer_mrproper(&def1);
1547 cherokee_buffer_mrproper(&def2);
1549 cherokee_buffer_mrproper(&path);
1550 goto virt_build_page_cleanup;
1555 case graphLoad_args: {
1556 struct stat statbuf;
1557 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
1558 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/cpuTime.rrd", hdl->user.buf, hdl->vm.buf);
1559 if (stat(path.buf, &statbuf) != 0) {
1560 conn->error_code = http_not_found;
1561 ret = ret_error;
1562 } else {
1563 void *width, *height, *start, *end;
1564 if ((ret = cherokee_avl_get_ptr (conn->arguments, "width", &width)) != ret_ok)
1565 width = "600";
1567 if ((ret = cherokee_avl_get_ptr (conn->arguments, "height", &height)) != ret_ok)
1568 height = "200";
1570 if ((ret = cherokee_avl_get_ptr (conn->arguments, "start", &start)) != ret_ok)
1571 start = "now-1h";
1573 if ((ret = cherokee_avl_get_ptr (conn->arguments, "end", &end)) != ret_ok)
1574 end = "now";
1576 /* TODO: wat error checking? */
1578 cherokee_buffer_t def = CHEROKEE_BUF_INIT;
1579 cherokee_buffer_add_va (&def, "DEF:cputime=%s:cpuTime:AVERAGE:step=30", path.buf);
1580 char **calcpr = NULL;
1581 int xsize, ysize;
1582 double ymin, ymax;
1583 char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1584 char *r_graph[] = { "rrdgraph",
1585 filename,
1586 "-a", "PNG",
1587 "-w", width,
1588 "-h", height,
1589 "--start", start,
1590 "--end", end,
1591 "--title", hdl->vm.buf,
1592 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "(used / total) time",
1593 def.buf,
1594 "CDEF:cpuload=cputime,1000000000,/",
1595 "LINE:cpuload#EE0000:cpuLoad" };
1597 rrd_graph(22, r_graph, &calcpr, &xsize, &ysize, NULL, &ymin, &ymax);
1598 if ((ret = cherokee_buffer_read_file(&hdl->buffer, filename)) == ret_error) {
1599 hdl->action = http_internal_error;
1602 unlink(filename);
1603 free(filename);
1605 cherokee_buffer_mrproper(&def);
1607 cherokee_buffer_mrproper(&path);
1608 goto virt_build_page_cleanup;
1612 if (hdl->action > xml && HDL_VIRT_PROPS(hdl)->xsl.len > 0)
1613 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);
1616 switch (hdl->action) {
1617 case showall: {
1618 size_t len;
1619 if (cherokee_avl_r_len(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &len) == ret_ok && len > 0) {
1620 cherokee_buffer_add_str (&hdl->buffer, "<domains>\n");
1621 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);
1622 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1623 } else {
1624 cherokee_buffer_add_str (&hdl->buffer, "<domains/>");
1627 ret = ret_ok;
1628 break;
1631 case showuservms: {
1632 cherokee_buffer_add_str (&hdl->buffer, "<domains>\n");
1633 get_all_configurations(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &hdl->user, &hdl->buffer);
1634 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1635 ret = ret_ok;
1636 break;
1639 default: {
1640 AvahiStringList *list = NULL;
1641 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1643 ret = cherokee_avl_r_get(&HDL_CLUSTERSTATS_PROPS(hdl)->entries, &domu, (void **) &list);
1645 if (ret == ret_not_found) {
1646 virDomainPtr virDom;
1647 virConnectPtr virConn;
1648 if (HDL_VIRT_PROPS(hdl)->virt.len > 0)
1649 cherokee_buffer_add_va (&uri, "xen://%s/", HDL_VIRT_PROPS(hdl)->virt); // TODO: change!
1651 /* If we have the read only parameter, we will set up a connection to the
1652 * Hypervisor here. */
1653 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1654 virConn = virConnectOpen (uri.buf);
1656 /* We should already have a connection (read only) or build a new connection
1657 * if this doesn't work, we can safely assume our services is fubar */
1658 if (!virConn && !(virConn = virConnectOpenReadOnly (uri.buf))) {
1659 conn->error_code = http_service_unavailable;
1660 return ret_error;
1663 /* We lookup if there is a domain somewhere with this name */
1664 if ((virDom = virDomainLookupByName(virConn, domu.buf)) == NULL) {
1665 /* If the domain is not found on the network the only possible
1666 * command that is possible would be to Define it */
1667 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1668 ret = ret_ok;
1669 } else {
1670 /* We should also look on disk for defined stuff */
1671 cherokee_buffer_t xmlDesc = CHEROKEE_BUF_INIT;
1672 if (load_xml(hdl, &xmlDesc) == ret_ok && (virDom = virDomainDefineXML(virConn, xmlDesc.buf)) != NULL) {
1673 /* The domain existed and is loaded! */
1674 ret = ret_ok;
1675 } else {
1676 /* Otherwise we don't have anything to do and we should
1677 * return an error */
1678 hdl->action = nothing;
1679 conn->error_code = http_not_found;
1680 ret = ret_error;
1683 cherokee_buffer_mrproper(&xmlDesc);
1685 } else {
1686 /* We don't want te recreate things that already found on the network
1687 * first undefine them! */
1688 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1689 TRACE("virt", "domainDefineXML_args/domainDefineXML; domain already exists");
1690 hdl->action = nothing;
1691 conn->error_code = http_bad_request;
1692 ret = ret_error;
1693 } else {
1694 /* Everything is ok, because nothing is found. */
1695 ret = ret_ok;
1698 /* Domain wasn't NULL, so we should free it here */
1699 virDomainFree(virDom);
1701 virConnectClose (virConn);
1702 } else if (ret == ret_ok) {
1703 char *hostname;
1704 avahi_string_list_get_pair(avahi_string_list_find(list, "dom0"), NULL, &hostname, NULL);
1705 cherokee_buffer_add_va (&uri, "xen://%s/", hostname);
1706 printf("%s\n", uri.buf);
1707 avahi_free(hostname);
1708 } else {
1709 hdl->action = http_internal_error;
1710 hdl->action = nothing;
1711 ret = ret_error;
1717 if (ret == ret_ok && hdl->action != showall && hdl->action != showuservms) {
1718 ret = virt_virt_do(hdl, &domu, &uri);
1721 virt_build_page_cleanup:
1722 cherokee_buffer_mrproper(&domu);
1723 cherokee_buffer_mrproper(&uri);
1725 return ret;
1729 ret_t
1730 cherokee_handler_virt_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
1732 ret_t ret;
1733 CHEROKEE_NEW_STRUCT (n, handler_virt);
1735 /* Init the base class
1738 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(virt));
1740 MODULE(n)->init = (handler_func_init_t) cherokee_handler_virt_init;
1741 MODULE(n)->free = (module_func_free_t) cherokee_handler_virt_free;
1742 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_virt_step;
1743 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_virt_add_headers;
1745 HANDLER(n)->support = hsupport_length | hsupport_range;
1747 ret = cherokee_buffer_init (&n->buffer);
1748 if (unlikely(ret != ret_ok))
1749 return ret;
1751 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
1752 if (unlikely(ret != ret_ok))
1753 return ret;
1755 *hdl = HANDLER(n);
1757 return ret_ok;