Something that should look as if it did locking...
[handlervirt.git] / handler_virt.c
blobea789f1085ca629a4fce403b1ddcec84be3f2088
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 " <target dev='vif1.0' />" \
31 " <source bridge='xenbr0'/>" \
32 " <mac address='%s'/>" \
33 " <ip address='%s' />" \
34 " <script path='vif-bridge'/>" \
35 " </interface>"
37 //" <target dev='vif1.0'/>" \
39 #define VIRT_DISK_XML \
40 " <disk type='file' device='disk'>" \
41 " <driver name='tap' type='aio' />" \
42 " <source file='%s'/>" \
43 " <target dev='%s' bus='xen'/>" \
44 " </disk>"
48 #define VIRT_DOMAIN_XML \
49 "<domain type='xen'>" \
50 " <name>%s_%s</name>" \
51 " <os>" \
52 " <type>linux</type>" \
53 " <kernel>/usr/lib/xen/boot/linux-2.6.20-xen-r6</kernel>" \
54 " <cmdline> root=/dev/xvda ro</cmdline>" \
55 " </os>" \
56 " <memory>%d</memory>" \
57 " <vcpu>%d</vcpu>" \
58 " <on_poweroff>destroy</on_poweroff>" \
59 " <on_reboot>restart</on_reboot>" \
60 " <on_crash>destroy</on_crash>" \
61 " <devices>" \
62 " %s" \
63 " </devices>" \
64 "</domain>"
66 #define VIRT_STORAGE_XML \
67 "<volume type='%s'>" \
68 " <name>%s_%s</name>" \
69 " <allocation>%lu</allocation>" \
70 " <capacity unit='%s'>%lu</capacity>" \
71 " <target>" \
72 " <path>%s_%s</path>" \
73 " <permissions>" \
74 " <owner>0744</owner>" \
75 " <group>0744</group>" \
76 " <mode>0744</mode>" \
77 " <label>%s_%s</label>" \
78 " </permissions>" \
79 " </target>" \
80 "</volume>"
83 #include "handler_virt.h"
84 #include "handler_avahi.h"
85 #include <cherokee/cherokee.h>
87 /* Plug-in initialization
89 * In this function you can use any of these:
90 * http_delete | http_get | http_post | http_put
92 * For a full list: cherokee_http_method_t
94 * It is what your handler to be implements.
97 PLUGIN_INFO_HANDLER_EASIEST_INIT (virt, http_get | http_post);
100 /* Methods implementation
102 static ret_t
103 props_free (cherokee_handler_virt_props_t *props)
106 cherokee_buffer_mrproper(&props->xsl);
107 cherokee_buffer_mrproper(&props->virt);
108 return cherokee_module_props_free_base (MODULE_PROPS(props));
112 ret_t
113 cherokee_handler_virt_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
115 cherokee_list_t *i;
116 cherokee_handler_virt_props_t *props;
118 /* Instance a new property object
121 if (*_props == NULL) {
122 CHEROKEE_NEW_STRUCT (n, handler_virt_props);
124 cherokee_handler_avahi_props_init_base (PROP_AVAHI(n), MODULE_PROPS_FREE(props_free));
126 /* Look at handler_virt.h
127 * This is an virt of configuration.
129 n->authenticate = true; /* by default we are secure! */
130 n->read_only = true; /* by default we are secure! */
131 cherokee_buffer_init (&n->xsl); /* we support a custom header */
132 cherokee_buffer_init (&n->virt); /* your first xenserver */
134 *_props = MODULE_PROPS(n);
137 props = PROP_VIRT(*_props);
139 cherokee_config_node_foreach (i, conf) {
140 cherokee_config_node_t *subconf = CONFIG_NODE(i);
142 if (equal_buf_str (&subconf->key, "authenticate")) {
143 props->authenticate = atoi(subconf->val.buf);
145 else if (equal_buf_str (&subconf->key, "read_only")) {
146 props->read_only = atoi(subconf->val.buf);
148 else if (equal_buf_str (&subconf->key, "xsl")) {
149 cherokee_buffer_add_buffer (&props->xsl, &subconf->val);
151 else if (equal_buf_str (&subconf->key, "virt")) {
152 cherokee_buffer_add_buffer (&props->virt, &subconf->val);
157 /* Init base class
160 return cherokee_handler_avahi_configure (conf, srv, _props);
164 ret_t
165 cherokee_handler_virt_init (cherokee_handler_virt_t *hdl)
167 int isroot = false;
168 int len;
169 char *this, *next;
171 cherokee_connection_t *conn = HANDLER_CONN(hdl);
172 cherokee_buffer_init(&hdl->user);
173 cherokee_buffer_init(&hdl->vm);
175 hdl->action = nothing;
177 cherokee_buffer_add (&conn->pathinfo,
178 conn->request.buf + conn->web_directory.len,
179 conn->request.len - conn->web_directory.len);
181 this = conn->pathinfo.buf + 1;
182 next = strchr(this, '/');
185 if ((!next && (this && (len = strlen(this)) == 0)) || (next && ((len = next - this) == 0)) )
186 hdl->action = showall;
187 else {
188 cherokee_buffer_add (&hdl->user, this, len);
191 if (HDL_VIRT_PROPS(hdl)->authenticate) {
192 if (!conn->validator ||
193 (conn->validator &&
194 (!cherokee_buffer_cmp_buf(&conn->validator->user, &hdl->user) &&
195 !(isroot = cherokee_buffer_cmp (&conn->validator->user, "root", 4))))) {
196 hdl->action = nothing; /* just in case */
197 conn->error_code = http_unauthorized;
198 return ret_error;
200 } else {
201 isroot = true;
204 if (hdl->action == showall) {
205 if (!isroot) {
206 hdl->action = nothing;
207 conn->error_code = http_unauthorized;
208 return ret_error;
209 } else {
210 return virt_build_page(hdl);
215 if (!next) {
216 hdl->action = showuservms;
217 return virt_build_page(hdl);
218 } else {
219 this = next + 1;
220 next = strchr(this, '/');
222 if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
223 hdl->action = showuservms;
224 return virt_build_page(hdl);
228 cherokee_buffer_add (&hdl->vm, this, len);
230 if (!next) {
231 hdl->action = domainGetXMLDesc;
232 return virt_build_page(hdl);
233 } else {
234 this = next + 1;
235 next = strchr(this, '/');
237 if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
238 hdl->action = domainGetXMLDesc;
239 return virt_build_page(hdl);
243 /* TODO: it would be nice to filter read_only methods already on this point */
244 hdl->action = not_implemented;
245 switch (conn->header.method) {
246 case http_get:
247 if (strncmp(this, "virDomain", 9) == 0) {
248 if (strncmp(this+9, "Get", 3) == 0) {
249 if (strcmp(this+12, "ID") == 0) hdl->action = domainGetID;
250 else if (strcmp(this+12, "Name") == 0) hdl->action = domainGetName;
251 else if (strcmp(this+12, "MaxMemory") == 0) hdl->action = domainGetMaxMemory;
252 else if (strcmp(this+12, "MaxVcpus") == 0) hdl->action = domainGetMaxVcpus;
253 else if (strcmp(this+12, "OSType") == 0) hdl->action = domainGetOSType;
254 else if (strcmp(this+12, "UUID") == 0) hdl->action = domainGetUUID;
255 else if (strcmp(this+12, "UUIDString") == 0) hdl->action = domainGetUUIDString;
256 else if (strcmp(this+12, "XMLDesc") == 0) hdl->action = domainGetXMLDesc;
258 else if (strcmp(this+9, "Create") == 0) hdl->action = domainCreate;
259 else if (strcmp(this+9, "Destroy") == 0) hdl->action = domainDestroy;
260 else if (strcmp(this+9, "Reboot") == 0) hdl->action = domainReboot;
261 else if (strcmp(this+9, "Shutdown") == 0) hdl->action = domainShutdown;
263 else if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice_args;
265 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML_args;
266 else if (strcmp(this+9, "Undefine") == 0) hdl->action = domainUndefine;
268 else if (strncmp(this, "virStorage", 10) == 0) {
269 if (strncmp(this+10, "Vol", 3) == 0) {
270 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML_args;
271 else if (strcmp(this+13, "Delete") == 0) hdl->action = storageVolDelete_args;
272 else if (strcmp(this+13, "CloneXML") == 0) hdl->action = storageVolCloneXML_args;
273 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl->action = storageVolGetXMLDesc;
276 break;
278 case http_post: {
279 off_t postl;
280 cherokee_post_get_len (&conn->post, &postl);
282 if (postl <= 0 || postl >= (INT_MAX-1)) {
283 conn->error_code = http_bad_request;
284 return ret_error;
287 if (strncmp(this, "virDomain", 9) == 0) {
288 if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice;
289 else if (strcmp(this+9, "DetachDevice") == 0) hdl->action = domainDetachDevice;
290 else if (strcmp(this+9, "DefineXML") == 0) hdl->action = domainDefineXML;
292 else if (strncmp(this, "virStorage", 10) == 0) {
293 if (strncmp(this+10, "Vol", 3) == 0) {
294 if (strcmp(this+13, "CreateXML") == 0) hdl->action = storageVolCreateXML;
298 break;
301 default:
302 return ret_error;
305 if (hdl->action <= 0) {
306 conn->error_code = http_bad_request;
307 return ret_error;
311 return virt_build_page(hdl);
314 ret_t
315 cherokee_handler_virt_free (cherokee_handler_virt_t *hdl)
317 cherokee_buffer_mrproper (&hdl->buffer);
318 cherokee_buffer_mrproper (&hdl->user);
319 cherokee_buffer_mrproper (&hdl->vm);
321 return ret_ok;
324 ret_t
325 cherokee_handler_virt_step (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
327 cherokee_buffer_add_buffer (buffer, &hdl->buffer);
328 return ret_eof_have_data;
331 ret_t
332 cherokee_handler_virt_add_headers (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
334 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
336 if (hdl->action > xml)
337 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
338 else
339 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
341 return ret_ok;
345 static ret_t
346 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
347 virConnectPtr conn = NULL;
348 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
349 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
351 cherokee_buffer_add_va (&uri, "xen://%s/", value);
353 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
354 if (!(conn = virConnectOpen (uri.buf))) {
355 return ret_error;
359 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
360 return ret_error;
361 } else {
362 virDomainPtr dom;
363 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
364 return ret_error;
365 } else {
366 char *xml = virDomainGetXMLDesc(dom, 0);
367 cherokee_buffer_add(buf, xml, strlen(xml));
369 virConnectClose(conn);
372 cherokee_buffer_mrproper(&uri);
374 return ret_ok;
377 static ret_t save_xml(cherokee_handler_virt_t *hdl, virDomainPtr result, cherokee_buffer_t *buf) {
378 ret_t ret = ret_error;
379 FILE *fd;
380 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
381 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s", hdl->user.buf);
383 mkdir(path.buf, 0755);
384 cherokee_buffer_add_va (&path, "/%s", hdl->vm.buf);
386 mkdir(path.buf, 0755);
387 cherokee_buffer_add_str (&path, "/index.xml");
389 if ((fd = fopen(path.buf, "w")) == NULL) {
390 perror(__func__);
391 } else {
392 char *output = virDomainGetXMLDesc(result, 0);
393 fwrite(output, strlen(output), sizeof(char), fd);
394 fclose(fd);
395 if (buf)
396 cherokee_buffer_add(buf, output, strlen(output));
397 free(output);
398 ret = ret_ok;
400 cherokee_buffer_mrproper(&path);
401 return ret;
405 static ret_t
406 virt_virt_function(cherokee_handler_virt_t *hdl, virDomainPtr dom, virConnectPtr virConn) {
407 cherokee_connection_t *conn = HANDLER_CONN(hdl);
408 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
410 switch (hdl->action) {
412 case domainUndefine: {
413 int result;
414 if ((result = virDomainUndefine(dom)) != 0) {
415 conn->error_code = http_internal_error;
418 cherokee_buffer_add_long10(buf, result);
419 break;
422 case domainAttachDevice_args: {
423 int result;
424 void *temp;
425 ret_t ret;
426 ret = cherokee_connection_parse_args (conn);
427 if (unlikely(ret < ret_ok))
428 return ret;
430 ret = cherokee_avl_get_ptr (conn->arguments, "type", &temp);
432 if (ret == ret_ok) {
433 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
435 if (strcmp(temp, "disk") == 0) {
436 void *device;
437 if ((ret = cherokee_avl_get_ptr (conn->arguments, "device", &device)) == ret_ok) {
438 void *file;
439 if ((ret = cherokee_avl_get_ptr (conn->arguments, "file", &file)) == ret_ok) {
440 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
441 } else {
442 void *poolstr, *volumestr;
443 if ((ret = cherokee_avl_get_ptr (conn->arguments, "pool", &poolstr)) == ret_ok &&
444 (ret = cherokee_avl_get_ptr (conn->arguments, "volume", &volumestr)) == ret_ok) {
445 cherokee_buffer_t fullvol = CHEROKEE_BUF_INIT;
446 virStoragePoolPtr pool;
447 virStorageVolPtr volume;
449 pool = virStoragePoolLookupByName(virConn, poolstr);
450 if (pool == NULL) {
451 conn->error_code = http_not_found;
452 return ret_error;
455 cherokee_buffer_add_va (&fullvol, "%s_%s", hdl->user.buf, volumestr);
456 volume = virStorageVolLookupByName(pool, fullvol.buf);
458 cherokee_buffer_mrproper(&fullvol);
459 virStoragePoolFree(pool);
461 if (volume == NULL) {
462 conn->error_code = http_not_found;
463 return ret_error;
465 file = virStorageVolGetPath(volume);
466 cherokee_buffer_add_va (&xml, VIRT_DISK_XML, file, device);
467 free(file);
469 virStorageVolFree(volume);
470 ret = ret_ok;
471 } else {
472 conn->error_code = http_bad_request;
473 return ret_error;
479 else if (strcmp(temp, "interface") == 0) {
480 void *mac, *ip;
481 if ((ret = cherokee_avl_get_ptr (conn->arguments, "mac", &mac)) == ret_ok && (ret = cherokee_avl_get_ptr (conn->arguments, "ip", &ip)) == ret_ok) {
482 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
483 } else {
484 char *mac = NULL;
485 char *ip = NULL;
486 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
487 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
488 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0)
489 cherokee_buffer_add_va (&xml, VIRT_INTERFACE_XML, mac, ip);
490 cherokee_buffer_mrproper(&domu);
494 if (ret == ret_ok && (result = virDomainAttachDevice(dom, (const char *) xml.buf)) == 0) {
495 ret = ret_ok;
496 } else {
497 conn->error_code = http_internal_error;
498 return ret_error;
501 cherokee_buffer_add_long10(buf, result);
502 cherokee_buffer_mrproper(&xml);
503 } else {
504 conn->error_code = http_bad_request;
505 return ret_error;
508 break;
511 case domainAttachDevice: {
512 off_t postl;
513 int result;
514 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
515 cherokee_post_get_len (&conn->post, &postl);
516 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
517 if ((result = virDomainAttachDevice(dom, (const char *) post.buf)) != 0)
518 conn->error_code = http_internal_error;
520 cherokee_buffer_mrproper(&post);
521 cherokee_buffer_add_long10(buf, result);
522 break;
526 case domainGetXMLDesc: {
527 char *xml = virDomainGetXMLDesc(dom, 0);
528 cherokee_buffer_add(buf, xml, strlen(xml));
529 free(xml);
530 break;
534 case domainDetachDevice: {
535 off_t postl;
536 int result;
537 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
538 cherokee_post_get_len (&conn->post, &postl);
539 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
540 if ((result = virDomainDetachDevice(dom, (const char *) post.buf)) != 0) {
541 conn->error_code = http_internal_error;
543 cherokee_buffer_mrproper(&post);
544 cherokee_buffer_add_long10(buf, result);
545 break;
548 case domainGetID: {
549 cherokee_buffer_add_ulong10(buf, virDomainGetID(dom));
550 break;
552 case domainGetMaxMemory: {
553 cherokee_buffer_add_ulong10(buf, virDomainGetMaxMemory (dom));
554 break;
556 case domainGetMaxVcpus: {
557 cherokee_buffer_add_long10(buf, virDomainGetMaxVcpus (dom));
558 break;
560 case domainGetName: {
561 const char *name = virDomainGetName (dom);
562 cherokee_buffer_add(buf, name, strlen(name));
563 break;
565 case domainGetUUID: {
566 unsigned char uuid[VIR_UUID_BUFLEN];
567 if (virDomainGetUUID(dom, uuid) == 0) {
568 cherokee_buffer_add_str(buf, uuid);
569 } else {
570 conn->error_code = http_internal_error;
571 return ret_error;
573 break;
575 case domainGetUUIDString: {
576 unsigned char uuid[VIR_UUID_STRING_BUFLEN];
577 if (virDomainGetUUIDString(dom, uuid) == 0) {
578 cherokee_buffer_add_str(buf, uuid);
579 } else {
580 conn->error_code = http_internal_error;
581 return ret_error;
583 break;
586 case domainCreate: {
587 cherokee_buffer_add_long10(buf, virDomainCreate (dom));
588 break;
591 case domainDestroy: {
592 cherokee_buffer_add_long10(buf, virDomainDestroy (dom));
593 break;
596 case domainReboot: {
597 cherokee_buffer_add_long10(buf, virDomainReboot (dom, 0));
598 break;
601 case domainShutdown: {
602 cherokee_buffer_add_long10(buf, virDomainShutdown (dom));
603 break;
607 case domainGetOSType: {
608 char *ostype = virDomainGetOSType(dom);
609 cherokee_buffer_add(buf, ostype, strlen(ostype));
610 free(ostype);
611 break;
618 if (hdl->action == domainUndefine) {
619 /* Remove VM data from filesystem */
620 cherokee_buffer_t path = CHEROKEE_BUF_INIT;
621 cherokee_buffer_add_va (&path, "/mnt/netapp/users/%s/%s/index.xml", hdl->user.buf, hdl->vm.buf);
622 unlink(path.buf); /* TODO: instead of delet replace */
623 cherokee_buffer_mrproper(&path);
624 } else {
625 save_xml(hdl, dom, NULL);
628 return ret_ok;
634 static ret_t
635 virt_virt_new(cherokee_handler_virt_t *hdl, virConnectPtr virConn)
637 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
638 cherokee_connection_t *conn = HANDLER_CONN(hdl);
639 cherokee_buffer_t xml = CHEROKEE_BUF_INIT;
640 virDomainPtr result;
641 virStoragePoolPtr pool;
642 virStorageVolPtr volume;
644 switch (hdl->action) {
645 case storageVolDelete_args: {
646 cherokee_buffer_t fullvol = CHEROKEE_BUF_INIT;
647 void *temp;
648 ret_t ret;
649 ret = cherokee_connection_parse_args (conn);
651 if (unlikely(ret < ret_ok)) {
652 conn->error_code = http_internal_error;
653 return ret_error;
656 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
657 if (unlikely(ret < ret_ok)) {
658 conn->error_code = http_bad_request;
659 return ret;
662 pool = virStoragePoolLookupByName(virConn, temp);
664 if (pool == NULL) {
665 conn->error_code = http_not_found;
666 return ret_error;
669 ret = cherokee_avl_get_ptr (conn->arguments, "volume", &temp);
670 if (unlikely(ret < ret_ok)) {
671 conn->error_code = http_bad_request;
672 return ret;
675 cherokee_buffer_add_va (&fullvol, "%s_%s", hdl->user.buf, temp);
676 printf("%s\n", fullvol.buf);
677 volume = virStorageVolLookupByName(pool, fullvol.buf);
679 cherokee_buffer_mrproper(&fullvol);
680 virStoragePoolFree(pool);
682 if (volume == NULL) {
683 conn->error_code = http_not_found;
684 return ret_error;
687 cherokee_buffer_add_long10(buf, virStorageVolDelete(volume, 0));
689 ret = ret_ok;
691 virStorageVolFree(volume);
693 break;
696 case storageVolGetXMLDesc: {
697 cherokee_buffer_t fullvol = CHEROKEE_BUF_INIT;
698 void *temp;
699 ret_t ret;
700 ret = cherokee_connection_parse_args (conn);
702 if (unlikely(ret < ret_ok)) {
703 conn->error_code = http_internal_error;
704 return ret_error;
707 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
708 if (unlikely(ret < ret_ok)) {
709 conn->error_code = http_bad_request;
710 return ret;
713 pool = virStoragePoolLookupByName(virConn, temp);
715 if (pool == NULL) {
716 conn->error_code = http_not_found;
717 return ret_error;
720 virStoragePoolRefresh(pool, 0); /* TODO: might be better to do it outside */
722 ret = cherokee_avl_get_ptr (conn->arguments, "volume", &temp);
723 if (unlikely(ret < ret_ok)) {
724 conn->error_code = http_bad_request;
725 return ret;
728 cherokee_buffer_add_va (&fullvol, "%s_%s", hdl->user.buf, temp);
729 printf("%s\n", fullvol.buf);
730 volume = virStorageVolLookupByName(pool, fullvol.buf);
732 cherokee_buffer_mrproper(&fullvol);
733 virStoragePoolFree(pool);
735 if (volume == NULL) {
736 conn->error_code = http_not_found;
737 return ret_error;
740 char *xml = virStorageVolGetXMLDesc(volume, 0);
741 virStorageVolFree(volume);
742 cherokee_buffer_add(buf, xml, strlen(xml));
743 free(xml);
745 break;
748 case storageVolCloneXML_args: {
749 void *temp, *name;
750 const char *source;
751 ret_t ret;
752 ret = cherokee_connection_parse_args (conn);
753 if (unlikely(ret < ret_ok)) {
754 conn->error_code = http_internal_error;
755 return ret_error;
758 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
759 if (unlikely(ret < ret_ok)) {
760 conn->error_code = http_bad_request;
761 return ret;
764 pool = virStoragePoolLookupByName(virConn, temp);
766 if (pool == NULL) {
767 conn->error_code = http_not_found;
768 return ret_error;
771 ret = cherokee_avl_get_ptr (conn->arguments, "volume", &temp);
772 if (unlikely(ret < ret_ok)) {
773 conn->error_code = http_bad_request;
774 return ret;
777 volume = virStorageVolLookupByName(pool, temp);
779 if (volume == NULL) {
780 conn->error_code = http_not_found;
781 return ret_error;
784 source = virStorageVolGetKey(volume);
786 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
787 if (unlikely(ret < ret_ok)) {
788 virStorageVolFree(volume);
789 virStoragePoolFree(pool);
790 conn->error_code = http_bad_request;
791 return ret;
794 cherokee_buffer_t busy = CHEROKEE_BUF_INIT;
795 cherokee_buffer_add_va (&busy, "/mnt/images/queue/%s_%s.queued", hdl->user.buf, name);
797 if (unlikely(symlink(source, busy.buf) == 1)) {
798 virStorageVolFree(volume);
799 virStoragePoolFree(pool);
800 conn->error_code = http_internal_error;
801 return ret_error;
804 cherokee_buffer_mrproper(&busy);
805 cherokee_buffer_add_str(buf, "QUEUED");
807 break;
810 case storageVolCreateXML_args: {
811 void *temp, *type, *name, *unit;
812 unsigned long int capacity, allocation;
814 ret_t ret;
815 ret = cherokee_connection_parse_args (conn);
816 if (unlikely(ret < ret_ok)) {
817 conn->error_code = http_internal_error;
818 return ret;
821 ret = cherokee_avl_get_ptr (conn->arguments, "pool", &temp);
822 if (unlikely(ret < ret_ok)) {
823 conn->error_code = http_bad_request;
824 return ret;
827 pool = virStoragePoolLookupByName(virConn, temp);
829 if (pool == NULL) {
830 conn->error_code = http_not_found;
831 return ret_error;
834 ret = cherokee_avl_get_ptr (conn->arguments, "name", &name);
835 if (unlikely(ret < ret_ok)) {
836 conn->error_code = http_bad_request;
837 return ret;
840 ret = cherokee_avl_get_ptr (conn->arguments, "type", &type);
841 if (unlikely(ret < ret_ok)) {
842 conn->error_code = http_bad_request;
843 return ret;
846 ret = cherokee_avl_get_ptr (conn->arguments, "unit", &unit);
847 if (unlikely(ret < ret_ok)) {
848 conn->error_code = http_bad_request;
849 return ret;
852 ret = cherokee_avl_get_ptr (conn->arguments, "allocation", &temp);
853 if (unlikely(ret < ret_ok)) {
854 conn->error_code = http_bad_request;
855 return ret;
859 allocation = strtoul(temp, NULL, 10);
860 /* TODO: errno check */
862 ret = cherokee_avl_get_ptr (conn->arguments, "capacity", &temp);
863 if (unlikely(ret < ret_ok)) {
864 conn->error_code = http_bad_request;
865 return ret;
868 capacity = strtoul(temp, NULL, 10);
869 /* TODO: errno check */
871 cherokee_buffer_add_va (&xml, VIRT_STORAGE_XML, type, hdl->user.buf, name, allocation, unit, capacity, hdl->user.buf, name, hdl->user.buf, name);
872 printf("%s", xml.buf);
874 break;
877 case domainDefineXML_args: {
878 ret_t ret;
879 unsigned int i;
880 unsigned long vcpu = 0, interface = 0, memory = 0;
882 cherokee_buffer_t xml_interfaces = CHEROKEE_BUF_INIT;
883 void *temp = NULL;
885 ret = cherokee_connection_parse_args (conn);
886 if (unlikely(ret < ret_ok))
887 return ret;
889 ret = cherokee_avl_get_ptr (conn->arguments, "vcpu", &temp);
890 if (ret == ret_ok)
891 vcpu = strtoul(temp, (char **) NULL, 10);
893 if (ret != ret_ok || errno == ERANGE || vcpu == 0) {
894 conn->error_code = http_internal_error;
895 return ret_error;
899 ret = cherokee_avl_get_ptr (conn->arguments, "memory", &temp);
900 if (ret == ret_ok)
901 memory = strtoul(temp, (char **) NULL, 10);
903 if (ret != ret_ok || errno == ERANGE || memory == 0) {
904 conn->error_code = http_internal_error;
905 return ret_error;
909 ret = cherokee_avl_get_ptr (conn->arguments, "interface", &temp);
910 if (ret == ret_ok)
911 interface = strtoul(temp, (char **) NULL, 10);
913 if (ret != ret_ok || errno == ERANGE) {
914 conn->error_code = http_internal_error;
915 return ret_error;
918 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
919 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
921 for (i = 0; i < interface; i++) {
922 char *mac = NULL;
923 char *ip = NULL;
924 if (getNewMac("dv28", domu.buf, &mac, &ip) == 0)
925 cherokee_buffer_add_va (&xml_interfaces, VIRT_INTERFACE_XML, mac, ip);
928 cherokee_buffer_mrproper(&domu);
930 cherokee_buffer_add_va (&xml, VIRT_DOMAIN_XML,
931 hdl->user.buf, hdl->vm.buf, memory, vcpu, xml_interfaces.buf);
933 cherokee_buffer_mrproper(&xml_interfaces);
934 break;
937 case storageVolCreateXML:
938 case domainDefineXML: {
939 off_t postl;
940 cherokee_post_get_len (&conn->post, &postl);
941 cherokee_post_walk_read (&conn->post, &xml, (cuint_t) postl);
942 break;
946 switch (hdl->action) {
947 case domainDefineXML_args:
948 case domainDefineXML: {
949 result = virDomainDefineXML(virConn, (const char *) xml.buf);
950 // printf("%s\n", xml.buf);
951 cherokee_buffer_mrproper(&xml);
953 if (result == NULL) {
954 /* TODO: vrij maken eventuele uitgegeven macs! */
955 conn->error_code = http_internal_error;
956 return ret_error;
959 save_xml(hdl, result, buf);
961 break;
964 case storageVolCreateXML_args:
965 case storageVolCreateXML: {
966 virStorageVolPtr vol = virStorageVolCreateXML(pool, xml.buf, 0);
967 virStoragePoolFree(pool);
968 cherokee_buffer_mrproper(&xml);
970 if (vol == NULL) {
971 cherokee_buffer_add_long10(buf, -1);
972 return ret_error;
975 cherokee_buffer_add_long10(buf, 0);
976 break;
980 return ret_ok;
984 static ret_t
985 virt_virt_do(cherokee_handler_virt_t *hdl, cherokee_buffer_t *domu, cherokee_buffer_t *uri)
987 cherokee_connection_t *conn = HANDLER_CONN(hdl);
989 ret_t ret = ret_error;
990 virConnectPtr virConn = NULL;
993 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
994 virConn = virConnectOpen (uri->buf);
996 if (!virConn && !(virConn = virConnectOpenReadOnly (uri->buf))) {
997 conn->error_code = http_service_unavailable;
998 return ret_error;
1001 switch (hdl->action) {
1002 case storageVolDelete_args:
1003 case storageVolGetXMLDesc:
1004 case storageVolCloneXML_args:
1005 case storageVolCreateXML_args:
1006 case storageVolCreateXML:
1007 case domainDefineXML_args:
1008 case domainDefineXML: {
1009 ret = virt_virt_new(hdl, virConn);
1010 break;
1013 default: {
1014 virDomainPtr dom;
1015 if ((dom = virDomainLookupByName(virConn, domu->buf)) == NULL) {
1016 conn->error_code = http_not_found;
1017 } else {
1018 ret = virt_virt_function(hdl, dom, virConn);
1019 virDomainFree(dom);
1024 virConnectClose(virConn);
1025 return ret;
1028 static ret_t
1029 virt_while (cherokee_buffer_t *key, void *value, void *param) {
1030 cherokee_handler_virt_t * hdl = param;
1031 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1032 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1033 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1034 // cherokee_buffer_mrproper(&uri);
1036 cherokee_buffer_add_va (&hdl->buffer, "<domain><name>%s</name></domain>", key->buf);
1038 return ret_ok;
1041 static ret_t
1042 virt_while_user (cherokee_buffer_t *key, void *value, void *param) {
1043 cherokee_handler_virt_t *hdl = param;
1044 if (key->len > hdl->user.len && key->buf[hdl->user.len] == '_' && strncmp(key->buf, hdl->user.buf, hdl->user.len) == 0)
1045 return virt_while (key, value, param);
1047 return ret_ok;
1050 static ret_t
1051 virt_build_page (cherokee_handler_virt_t *hdl)
1053 ret_t ret;
1054 cherokee_connection_t *conn = HANDLER_CONN(hdl);
1055 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1056 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
1058 if (hdl->action > xml && HDL_VIRT_PROPS(hdl)->xsl.len > 0)
1059 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);
1062 /* First, block the event loop */
1063 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1064 switch (hdl->action) {
1065 case showall:
1066 cherokee_buffer_add_str (&hdl->buffer, "<domains>");
1067 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl)->entries, virt_while, hdl, NULL, NULL);
1068 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1069 ret = ret_ok;
1070 break;
1072 case showuservms: {
1073 void *param[3];
1074 cherokee_buffer_add_str (&hdl->buffer, "<domains>");
1075 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl)->entries, virt_while_user, hdl, NULL, NULL);
1076 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
1077 ret = ret_ok;
1078 break;
1081 default: {
1082 cherokee_buffer_t *hostname = NULL;
1083 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
1084 ret = cherokee_avl_get_ptr(&HDL_AVAHI_PROPS(hdl)->entries, domu.buf, (void **) &hostname);
1086 if (ret == ret_not_found) {
1087 virDomainPtr virDom;
1088 virConnectPtr virConn;
1089 cherokee_buffer_add_va (&uri, "xen://%s/", HDL_VIRT_PROPS(hdl)->virt); // TODO: change!
1091 /* If we have the read only parameter, we will set up a connection to the
1092 * Hypervisor here. */
1093 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
1094 virConn = virConnectOpen (uri.buf);
1096 /* We should already have a connection (read only) or build a new connection
1097 * if this doesn't work, we can safely assume our services is fubar */
1098 if (!virConn && !(virConn = virConnectOpenReadOnly (uri.buf))) {
1099 conn->error_code = http_service_unavailable;
1100 return ret_error;
1103 /* We lookup if there is a domain somewhere with this name */
1104 if ((virDom = virDomainLookupByName(virConn, domu.buf)) == NULL) {
1105 /* If the domain is not found on the network the only possible
1106 * command that is possible would be to Define it */
1107 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1108 ret = ret_ok;
1109 } else {
1110 /* Otherwise we don't have anything to do and we should
1111 * return an error */
1112 hdl->action = nothing;
1113 conn->error_code = http_not_found;
1114 ret = ret_error;
1116 } else {
1117 /* We don't want te recreate things that already found on the network
1118 * first undefine them! */
1119 if (hdl->action == domainDefineXML_args || hdl->action == domainDefineXML) {
1120 hdl->action = nothing;
1121 conn->error_code = http_bad_request;
1122 ret = ret_error;
1123 } else {
1124 /* Everything is ok, because nothing is found. */
1125 ret = ret_ok;
1128 /* Domain wasn't NULL, so we should free it here */
1129 virDomainFree(virDom);
1131 virConnectClose (virConn);
1132 } else if (ret == ret_ok) {
1133 cherokee_buffer_add_va (&uri, "xen://%s/", hostname->buf);
1134 printf("%s\n", uri.buf);
1135 } else {
1136 hdl->action = http_internal_error;
1137 hdl->action = nothing;
1138 ret = ret_error;
1143 /* Finally, unblock the event loop */
1144 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1146 if (ret == ret_ok && hdl->action != showall && hdl->action != showuservms) {
1147 ret = virt_virt_do(hdl, &domu, &uri);
1150 cherokee_buffer_mrproper(&domu);
1151 cherokee_buffer_mrproper(&uri);
1154 return ret;
1158 ret_t
1159 cherokee_handler_virt_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
1161 ret_t ret;
1162 CHEROKEE_NEW_STRUCT (n, handler_virt);
1164 /* Init the base class
1167 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(virt));
1169 MODULE(n)->init = (handler_func_init_t) cherokee_handler_virt_init;
1170 MODULE(n)->free = (module_func_free_t) cherokee_handler_virt_free;
1171 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_virt_step;
1172 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_virt_add_headers;
1174 HANDLER(n)->support = hsupport_length | hsupport_range;
1176 ret = cherokee_buffer_init (&n->buffer);
1177 if (unlikely(ret != ret_ok))
1178 return ret;
1180 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
1181 if (unlikely(ret != ret_ok))
1182 return ret;
1184 *hdl = HANDLER(n);
1186 return ret_ok;