1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
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
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'/>" \
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'/>" \
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>" \
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>" \
55 " <memory>%d</memory>" \
57 " <on_poweroff>destroy</on_poweroff>" \
58 " <on_reboot>restart</on_reboot>" \
59 " <on_crash>destroy</on_crash>" \
65 #define VIRT_STORAGE_XML \
66 "<volume type='%s'>" \
67 " <name>%s_%s</name>" \
68 " <allocation>%lu</allocation>" \
69 " <capacity unit='%s'>%lu</capacity>" \
71 " <path>%s_%s</path>" \
73 " <owner>0744</owner>" \
74 " <group>0744</group>" \
75 " <mode>0744</mode>" \
76 " <label>%s_%s</label>" \
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>
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
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
));
128 cherokee_handler_virt_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
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
);
175 return cherokee_handler_clusterstats_configure (conf
, srv
, _props
);
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
;
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
;
212 cherokee_buffer_add (&hdl
->user
, this, len
);
215 if (HDL_VIRT_PROPS(hdl
)->authenticate
) {
216 if (!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
;
228 if (hdl
->action
== showall
) {
230 hdl
->action
= nothing
;
231 conn
->error_code
= http_unauthorized
;
234 return virt_build_page(hdl
);
240 hdl
->action
= showuservms
;
241 return virt_build_page(hdl
);
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
);
256 hdl
->action
= domainGetXMLDesc
;
257 return virt_build_page(hdl
);
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
) {
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
;
292 else if (strcmp(this+9, "Migrate") == 0) hdl
->action
= domainMigrate_args
;
294 else if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice_args
;
296 else if (strcmp(this+9, "DefineXML") == 0) hdl
->action
= domainDefineXML_args
;
297 else if (strcmp(this+9, "Undefine") == 0) hdl
->action
= domainUndefine
;
300 else if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
&& strncmp(this, "virStorage", 10) == 0) {
301 if (strncmp(this+10, "Vol", 3) == 0) {
302 if (strcmp(this+13, "CreateXML") == 0) hdl
->action
= storageVolCreateXML_args
;
303 else if (strcmp(this+13, "Delete") == 0) hdl
->action
= storageVolDelete_args
;
304 else if (strcmp(this+13, "CloneXML") == 0) hdl
->action
= storageVolCloneXML_args
;
305 else if (strcmp(this+13, "CloneStatus") == 0) hdl
->action
= storageVolCloneStatus_args
;
306 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl
->action
= storageVolGetXMLDesc_args
;
307 else if (strcmp(this+13, "SetPassword") == 0) hdl
->action
= storageVolSetPassword_args
;
310 else if (strncmp(this, "virGraph", 8) == 0) {
311 if (strcmp(this+8, "Load") == 0) hdl
->action
= graphLoad_args
;
312 if (strcmp(this+8, "Interface") == 0) hdl
->action
= graphInterface_args
;
318 cherokee_post_get_len (&conn
->post
, &postl
);
320 if (postl
<= 0 || postl
>= (INT_MAX
-1)) {
321 TRACE("virt", "post without post");
322 conn
->error_code
= http_bad_request
;
326 if (strncmp(this, "virDomain", 9) == 0) {
327 if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice
;
328 else if (strcmp(this+9, "DetachDevice") == 0) hdl
->action
= domainDetachDevice
;
329 else if (strcmp(this+9, "DefineXML") == 0) hdl
->action
= domainDefineXML
;
331 else if (strncmp(this, "virStorage", 10) == 0) {
332 if (strncmp(this+10, "Vol", 3) == 0) {
333 if (strcmp(this+13, "CreateXML") == 0) hdl
->action
= storageVolCreateXML
;
344 if (hdl
->action
<= 0) {
345 TRACE("virt", "There was no action specified");
346 conn
->error_code
= http_bad_request
;
350 return virt_build_page(hdl
);
354 cherokee_handler_virt_free (cherokee_handler_virt_t
*hdl
)
356 cherokee_buffer_mrproper (&hdl
->buffer
);
357 cherokee_buffer_mrproper (&hdl
->user
);
358 cherokee_buffer_mrproper (&hdl
->vm
);
364 cherokee_handler_virt_step (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
368 if (cherokee_buffer_is_empty (&hdl
->buffer
))
371 tosend
= (hdl
->buffer
.len
> 1024 ? 1024 : hdl
->buffer
.len
);
373 cherokee_buffer_add (buffer
, hdl
->buffer
.buf
, tosend
);
374 cherokee_buffer_move_to_begin (&hdl
->buffer
, tosend
);
376 if (cherokee_buffer_is_empty (&hdl
->buffer
))
377 return ret_eof_have_data
;
383 cherokee_handler_virt_add_headers (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
385 cherokee_buffer_add_va (buffer
, "Content-Length: %d"CRLF
, hdl
->buffer
.len
);
387 if (hdl
->action
> xml
)
388 cherokee_buffer_add_str (buffer
, "Content-Type: application/xml"CRLF
);
389 else if (hdl
->action
> graph
) {
390 cherokee_buffer_add_str (buffer
, "Content-Type: image/png"CRLF
);
392 cherokee_buffer_add_str (buffer
, "Content-Type: text/plain"CRLF
);
399 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
400 virConnectPtr conn = NULL;
401 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
402 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
404 cherokee_buffer_add_va (&uri, "xen://%s/", value);
406 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
407 if (!(conn = virConnectOpen (uri.buf))) {
412 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
416 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
419 char *xml = virDomainGetXMLDesc(dom, 0);
420 cherokee_buffer_add(buf, xml, strlen(xml));
422 virConnectClose(conn);
425 cherokee_buffer_mrproper(&uri);
430 static ret_t
load_xml(cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*xmlDesc
) {
431 ret_t ret
= ret_error
;
433 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
434 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s", hdl
->user
.buf
);
436 mkdir(path
.buf
, 0755);
437 cherokee_buffer_add_va (&path
, "/%s", hdl
->vm
.buf
);
439 mkdir(path
.buf
, 0755);
440 cherokee_buffer_add_str (&path
, "/index.xml");
442 if ((fd
= fopen(path
.buf
, "r")) != NULL
) {
445 size_t amount
= fread(buf
, sizeof(char), 1024, fd
);
447 cherokee_buffer_add (xmlDesc
, buf
, amount
);
450 if (xmlDesc
->len
> 0)
454 cherokee_buffer_mrproper(&path
);
458 static ret_t
save_xml(cherokee_handler_virt_t
*hdl
, virDomainPtr result
, cherokee_buffer_t
*buf
) {
459 ret_t ret
= ret_error
;
461 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
462 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s", hdl
->user
.buf
);
464 mkdir(path
.buf
, 0755);
465 cherokee_buffer_add_va (&path
, "/%s", hdl
->vm
.buf
);
467 mkdir(path
.buf
, 0755);
468 cherokee_buffer_add_str (&path
, "/index.xml");
470 if ((fd
= fopen(path
.buf
, "w")) == NULL
) {
473 char *output
= virDomainGetXMLDesc(result
, VIR_DOMAIN_XML_INACTIVE
);
475 fwrite(output
, strlen(output
), sizeof(char), fd
);
477 cherokee_buffer_add(buf
, output
, strlen(output
));
483 cherokee_buffer_mrproper(&path
);
489 virt_virt_function(cherokee_handler_virt_t
*hdl
, virDomainPtr dom
, virConnectPtr virConn
) {
490 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
491 cherokee_buffer_t
*buf
= &HDL_VIRT(hdl
)->buffer
;
493 switch (hdl
->action
) {
494 /* Returns the status of a clone copy */
495 case storageVolCloneStatus_args
: {
499 cherokee_buffer_t queue
= CHEROKEE_BUF_INIT
;
501 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
502 if (unlikely(ret
< ret_ok
)) {
503 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
504 conn
->error_code
= http_bad_request
;
508 cherokee_buffer_add_va (&queue
, "/mnt/images/queue/%s_%s.queued", hdl
->user
.buf
, name
);
510 if (stat(queue
.buf
, &statbuf
) != 0) {
511 conn
->error_code
= http_not_found
;
516 if ((namelen
= readlink(queue
.buf
, hardlink
, 1023)) == -1) {
517 conn
->error_code
= http_internal_error
;
520 hardlink
[namelen
] = '\0';
521 if (stat(hardlink
, &statbuf
) != 0) {
522 conn
->error_code
= http_internal_error
;
525 struct stat statbuf2
;
526 cherokee_buffer_t busy
= CHEROKEE_BUF_INIT
;
527 cherokee_buffer_add_va (&busy
, "/mnt/images/queue/%s_%s.busy", hdl
->user
.buf
, name
);
528 if (stat(busy
.buf
, &statbuf2
) != 0) {
529 conn
->error_code
= http_internal_error
;
532 cherokee_buffer_add_va (buf
, "%f", (float)((float)statbuf2
.st_size
/ (float)statbuf
.st_size
));
535 cherokee_buffer_mrproper(&busy
);
540 cherokee_buffer_mrproper(&queue
);
545 /* Save the memory of a domain to a file and suspend the domain */
549 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
550 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/memory", hdl
->user
.buf
, hdl
->vm
.buf
);
551 if ((result
= virDomainSave(dom
, path
.buf
)) != 0) {
552 TRACE("virt", "Saving of %s/%s failed", hdl
->user
.buf
, hdl
->vm
.buf
);
553 conn
->error_code
= http_internal_error
;
556 cherokee_buffer_mrproper(&path
);
558 cherokee_buffer_add_long10(buf
, result
);
563 /* Restore the memory of a domain from a file and resume the domain */
564 case domainRestore
: {
567 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
568 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/memory", hdl
->user
.buf
, hdl
->vm
.buf
);
570 if (stat(path
.buf
, &statbuf
) == 0) {
571 char *destination
= create_tender(HDL_CLUSTERSTATS_PROPS(hdl
)->client
,
572 HDL_CLUSTERSTATS_PROPS(hdl
)->threaded_poll
,
573 virDomainGetName(dom
), virDomainGetMaxMemory(dom
));
575 if (destination
== NULL
) {
576 TRACE("virt", "Nobody wants %s, poor vm!\n", destination
);
577 cherokee_buffer_add_long10(buf
, -1);
579 virConnectPtr virConnNew
;
580 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
582 if (virDomainUndefine(dom
) != 0) {
583 TRACE("virt", "Can't undefine %s, some idiot run it already?\n", destination
);
584 cherokee_buffer_add_long10(buf
, -1);
586 cherokee_buffer_add_va (&uri
, "xen://%s/", destination
);
588 TRACE("virt", "We will transfer to: %s\n", uri
.buf
);
590 virConnNew
= virConnectOpen (uri
.buf
);
592 if (virConnNew
== NULL
) {
593 TRACE("virt", "Can't connect to %s\n", uri
.buf
);
594 cherokee_buffer_add_long10(buf
, -1);
596 cherokee_buffer_add_long10(buf
, virDomainRestore(virConnNew
, path
.buf
));
597 virConnectClose(virConn
);
598 virConn
= virConnNew
;
599 /* TODO: Here I actually want virConnNew to be virConn */
602 cherokee_buffer_mrproper(&uri
);
606 TRACE("virt", "Memory file for %s/%s does not exist", hdl
->user
.buf
, hdl
->vm
.buf
);
607 conn
->error_code
= http_not_found
;
611 cherokee_buffer_mrproper(&path
);
617 case domainMigrate_args
: {
621 ret
= cherokee_avl_get_ptr (conn
->arguments
, "destination", &destination
);
624 destination
= create_tender(HDL_CLUSTERSTATS_PROPS(hdl
)->client
,
625 HDL_CLUSTERSTATS_PROPS(hdl
)->threaded_poll
,
626 virDomainGetName(dom
), virDomainGetMaxMemory(dom
));
629 if (destination
== NULL
) {
630 TRACE("virt", "Nobody wants %s, poor vm!\n", destination
);
631 cherokee_buffer_add_long10(buf
, -1);
633 virConnectPtr virConnNew
;
634 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
635 cherokee_buffer_add_va (&uri
, "xen://%s/", destination
);
636 TRACE("virt", "We will transfer to: %s\n", uri
.buf
);
637 virConnNew
= virConnectOpen (uri
.buf
);
638 if (virConnNew
== NULL
) {
639 TRACE("virt", "Can't connect to %s\n", uri
.buf
);
640 cherokee_buffer_add_long10(buf
, -1);
642 /* TODO: voodoo oplossen, pointers virConnNew/domNew gaat niet werken */
643 virDomainPtr domNew
= virDomainMigrate(dom
, virConnNew
, VIR_MIGRATE_LIVE
, NULL
, NULL
, 0);
649 virConnectClose(virConn
);
650 virConn
= virConnNew
;
652 cherokee_buffer_add_long10(buf
, 0);
654 cherokee_buffer_add_long10(buf
, -1);
657 cherokee_buffer_mrproper(&uri
);
665 case domainUndefine
: {
667 if ((result
= virDomainUndefine(dom
)) != 0) {
668 conn
->error_code
= http_internal_error
; /* TODO */
671 cherokee_buffer_add_long10(buf
, result
);
675 case domainAttachDevice_args
: {
680 ret
= cherokee_avl_get_ptr (conn
->arguments
, "type", &temp
);
683 cherokee_buffer_t xml
= CHEROKEE_BUF_INIT
;
685 if (strcmp(temp
, "disk") == 0) {
687 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "device", &device
)) == ret_ok
) {
689 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "file", &file
)) == ret_ok
) {
690 cherokee_buffer_add_va (&xml
, VIRT_DISK_XML
, file
, device
);
692 virStorageVolPtr volume
= virt_get_vol_by_args(hdl
, virConn
, 1);
694 if (volume
== NULL
) {
698 file
= virStorageVolGetPath(volume
);
699 cherokee_buffer_add_va (&xml
, VIRT_DISK_XML
, file
, device
);
702 virStorageVolFree(volume
);
708 else if (strcmp(temp
, "interface") == 0) {
710 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "mac", &mac
)) == ret_ok
&& (ret
= cherokee_avl_get_ptr (conn
->arguments
, "ip", &ip
)) == ret_ok
) {
711 cherokee_buffer_add_va (&xml
, VIRT_INTERFACE_XML
, mac
, ip
);
715 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
716 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
717 if (getNewMac("dv28", domu
.buf
, &mac
, &ip
) == 0)
718 cherokee_buffer_add_va (&xml
, VIRT_INTERFACE_XML
, mac
, ip
);
719 cherokee_buffer_mrproper(&domu
);
723 if (ret
== ret_ok
&& (result
= virDomainAttachDevice(dom
, (const char *) xml
.buf
)) == 0) {
726 conn
->error_code
= http_internal_error
;
730 cherokee_buffer_add_long10(buf
, result
);
731 cherokee_buffer_mrproper(&xml
);
733 TRACE("virt", "DeviceAttach_args; type was not specified");
734 conn
->error_code
= http_bad_request
;
741 case domainAttachDevice
: {
744 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
745 cherokee_post_get_len (&conn
->post
, &postl
);
746 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
747 if ((result
= virDomainAttachDevice(dom
, (const char *) post
.buf
)) != 0)
748 conn
->error_code
= http_internal_error
;
750 cherokee_buffer_mrproper(&post
);
751 cherokee_buffer_add_long10(buf
, result
);
756 case domainGetXMLDesc
: {
757 char *xml
= virDomainGetXMLDesc(dom
, 0);
758 cherokee_buffer_add(buf
, xml
, strlen(xml
));
763 case domainGetXMLSnapshots
: {
764 /* TODO: maybe in the future one would like to have all snapshots here */
766 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
768 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/memory", hdl
->user
.buf
, hdl
->vm
.buf
);
770 if (stat(path
.buf
, &statbuf
) != 0) {
771 cherokee_buffer_add_str(buf
, "<snapshots />");
773 char *date
= ctime(&(statbuf
.st_ctime
));
774 cherokee_buffer_add_str(buf
, "<snapshots>\n");
775 cherokee_buffer_add_va (buf
, " <snapshot at=\"");
776 cherokee_buffer_add (buf
, date
, strlen(date
)-1);
777 cherokee_buffer_add_va (buf
, "\" />\n");
778 cherokee_buffer_add_str(buf
, "</snapshots>");
781 cherokee_buffer_mrproper(&path
);
785 case domainDetachDevice
: {
789 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
790 cherokee_post_get_len (&conn
->post
, &postl
);
791 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
793 xmlDocPtr doc
= xmlParseMemory((const char *) post
.buf
, post
.len
);
795 TRACE("virt", "DeviceAttach; XML document unparceble");
796 conn
->error_code
= http_bad_request
;
802 if ((result
= virDomainDetachDevice(dom
, (const char *) post
.buf
)) != 0) {
803 conn
->error_code
= http_internal_error
;
804 /* TODO: betere afhandeling */
806 xmlXPathContextPtr context
= xmlXPathNewContext(doc
);
807 if (context
!= NULL
) {
808 xmlXPathObjectPtr obj
= xmlXPathEval("string(//interface/mac/@address)", context
);
809 xmlXPathFreeContext(context
);
810 if ((obj
!= NULL
) && (obj
->type
== XPATH_STRING
) &&
811 (obj
->stringval
!= NULL
) && (obj
->stringval
[0] != 0)) {
812 removeOldMac("dv28", (char *) obj
->stringval
);
814 xmlXPathFreeObject(obj
);
821 cherokee_buffer_mrproper(&post
);
822 cherokee_buffer_add_long10(buf
, result
);
827 cherokee_buffer_add_ulong10(buf
, virDomainGetID(dom
));
830 case domainGetMaxMemory
: {
831 cherokee_buffer_add_ulong10(buf
, virDomainGetMaxMemory (dom
));
834 case domainGetMaxVcpus
: {
835 cherokee_buffer_add_long10(buf
, virDomainGetMaxVcpus (dom
));
838 case domainGetName
: {
839 const char *name
= virDomainGetName (dom
);
840 cherokee_buffer_add(buf
, name
, strlen(name
));
843 case domainGetUUID
: {
844 unsigned char uuid
[VIR_UUID_BUFLEN
];
845 if (virDomainGetUUID(dom
, uuid
) == 0) {
846 cherokee_buffer_add_str(buf
, uuid
);
848 conn
->error_code
= http_internal_error
;
853 case domainGetUUIDString
: {
854 unsigned char uuid
[VIR_UUID_STRING_BUFLEN
];
855 if (virDomainGetUUIDString(dom
, uuid
) == 0) {
856 cherokee_buffer_add_str(buf
, uuid
);
858 conn
->error_code
= http_internal_error
;
866 cherokee_buffer_t xmlDesc
= CHEROKEE_BUF_INIT
;
867 save_xml(hdl
, dom
, &xmlDesc
);
868 destination
= create_tender(HDL_CLUSTERSTATS_PROPS(hdl
)->client
,
869 HDL_CLUSTERSTATS_PROPS(hdl
)->threaded_poll
,
870 virDomainGetName(dom
), virDomainGetMaxMemory(dom
));
872 if (destination
== NULL
) {
873 TRACE("virt", "Nobody wants %s, poor vm!\n", destination
);
874 cherokee_buffer_add_long10(buf
, -1);
876 virConnectPtr virConnNew
;
877 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
879 if (virDomainUndefine(dom
) != 0) {
880 TRACE("virt", "Can't undefine %s, some idiot run it already?\n", destination
);
883 cherokee_buffer_add_va (&uri
, "xen://%s/", destination
);
884 virConnNew
= virConnectOpen (uri
.buf
);
886 if (virConnNew
== NULL
) {
887 TRACE("virt", "Can't connect to %s\n", uri
.buf
);
888 cherokee_buffer_add_long10(buf
, -1);
890 cherokee_buffer_add_long10(buf
,
891 (virDomainCreateLinux(virConnNew
, xmlDesc
.buf
, 0) != NULL
?
893 virConnectClose(virConn
);
895 virConn
= virConnNew
;
896 /* TODO: Here I actually want virConnNew to be virConn */
898 cherokee_buffer_mrproper(&uri
);
902 cherokee_buffer_mrproper(&xmlDesc
);
906 case domainDestroy
: {
907 cherokee_buffer_add_long10(buf
, virDomainDestroy (dom
));
912 cherokee_buffer_add_long10(buf
, virDomainReboot (dom
, 0));
916 case domainShutdown
: {
917 cherokee_buffer_add_long10(buf
, virDomainShutdown (dom
));
922 case domainGetOSType
: {
923 char *ostype
= virDomainGetOSType(dom
);
924 cherokee_buffer_add(buf
, ostype
, strlen(ostype
));
933 if (hdl
->action
== domainUndefine
) {
934 /* Remove VM data from filesystem */
935 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
936 cherokee_buffer_t path2
= CHEROKEE_BUF_INIT
;
937 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/index.xml", hdl
->user
.buf
, hdl
->vm
.buf
);
938 cherokee_buffer_add_buffer (&path2
, &path
);
939 cherokee_buffer_add_str (&path2
, ".deleted");
940 // unlink(path.buf); /* TODO: instead of delet replace */
941 rename(path
.buf
, path2
.buf
);
942 cherokee_buffer_mrproper(&path
);
943 cherokee_buffer_mrproper(&path2
);
944 } else if (hdl
->action
!= domainCreate
) {
945 save_xml(hdl
, dom
, NULL
);
951 static virStoragePoolPtr
952 virt_get_pool_by_args(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
953 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
954 virStoragePoolPtr pool
;
958 ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &temp
);
959 if (unlikely(ret
< ret_ok
)) {
960 TRACE("virt", "virStoragePoolPtr; Pool argument not specified");
961 conn
->error_code
= http_bad_request
;
965 pool
= virStoragePoolLookupByName(virConn
, temp
);
970 static virStorageVolPtr
971 virt_get_vol_by_args(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
, unsigned short int prefix
) {
972 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
973 virStoragePoolPtr pool
;
974 virStorageVolPtr volume
;
978 pool
= virt_get_pool_by_args(hdl
, virConn
);
981 conn
->error_code
= http_not_found
;
985 virStoragePoolRefresh(pool
, 0); /* TODO: might be better to do it outside */
987 ret
= cherokee_avl_get_ptr (conn
->arguments
, "volume", &temp
);
988 if (unlikely(ret
< ret_ok
)) {
989 TRACE("virt", "virStorageVolPtr; Volume argument not specified");
990 conn
->error_code
= http_bad_request
;
995 cherokee_buffer_t fullvol
= CHEROKEE_BUF_INIT
;
996 cherokee_buffer_add_va (&fullvol
, "%s_%s", hdl
->user
.buf
, temp
);
997 volume
= virStorageVolLookupByName(pool
, fullvol
.buf
);
998 cherokee_buffer_mrproper(&fullvol
);
1000 volume
= virStorageVolLookupByName(pool
, temp
);
1004 conn
->error_code
= http_not_found
;
1006 virStoragePoolFree(pool
);
1011 /* This function is the home for all functions that need a working
1012 * pool/volume combination */
1014 virt_pool_vol(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
1015 cherokee_buffer_t
*buf
= &HDL_VIRT(hdl
)->buffer
;
1016 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1017 virStorageVolPtr volume
;
1020 /* We only allow clone to run 'unsafe', others get prefixed */
1021 volume
= virt_get_vol_by_args(hdl
, virConn
, (hdl
->action
!= storageVolCloneXML_args
));
1023 /* If the volume doesn't exist, no point to continue */
1024 if (volume
== NULL
) {
1025 conn
->error_code
= http_not_found
;
1029 switch (hdl
->action
) {
1030 /* Sets the password of a specific volume, requires the password= option */
1031 case storageVolSetPassword_args
: {
1033 ret
= cherokee_avl_get_ptr (conn
->arguments
, "password", &temp
);
1034 if (unlikely(ret
< ret_ok
)) {
1035 TRACE("virt", "storageVolSetPassword_args; password argument not specified");
1036 conn
->error_code
= http_bad_request
;
1038 goto virt_pool_vol_cleanup
;
1040 cherokee_buffer_t cmd_passwd
= CHEROKEE_BUF_INIT
;
1041 cherokee_buffer_add_va (&cmd_passwd
, "/usr/sbin/passwdchanger.sh %s %s\n", virStorageVolGetKey(volume
), temp
);
1042 cherokee_buffer_add_long10(buf
, system(cmd_passwd
.buf
));
1043 cherokee_buffer_mrproper(&cmd_passwd
);
1048 /* Removes a volume */
1049 case storageVolDelete_args
: {
1050 cherokee_buffer_add_long10(buf
, virStorageVolDelete(volume
, 0));
1054 /* Gives a description of a storage volume in XML */
1055 case storageVolGetXMLDesc_args
: {
1056 char *xml
= virStorageVolGetXMLDesc(volume
, 0);
1057 cherokee_buffer_add(buf
, xml
, strlen(xml
));
1062 /* Clones a volume, insecure method! requires a new name= */
1063 case storageVolCloneXML_args
: {
1065 cherokee_buffer_t busy
= CHEROKEE_BUF_INIT
;
1067 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
1068 if (unlikely(ret
< ret_ok
)) {
1069 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
1070 conn
->error_code
= http_bad_request
;
1072 goto virt_pool_vol_cleanup
;
1075 cherokee_buffer_add_va (&busy
, "/mnt/images/queue/%s_%s.queued", hdl
->user
.buf
, name
);
1077 if (unlikely(symlink(virStorageVolGetKey(volume
), busy
.buf
) == 1)) {
1078 conn
->error_code
= http_internal_error
;
1081 cherokee_buffer_add_str(buf
, "QUEUED");
1084 cherokee_buffer_mrproper(&busy
);
1091 virt_pool_vol_cleanup
:
1092 /* And in the end we need to free the volume we have used */
1093 virStorageVolFree(volume
);
1099 virt_virt_new(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
1100 cherokee_buffer_t
*buf
= &HDL_VIRT(hdl
)->buffer
;
1101 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1102 cherokee_buffer_t xml
= CHEROKEE_BUF_INIT
;
1103 virStoragePoolPtr pool
= NULL
;
1106 switch (hdl
->action
) {
1108 case storageVolCreateXML_args
: {
1109 void *temp
, *type
, *name
, *unit
;
1110 unsigned long int capacity
, allocation
;
1112 ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &temp
);
1113 if (unlikely(ret
< ret_ok
)) {
1114 TRACE("virt", "storageVolCreateXML_args; pool argument not specified");
1115 conn
->error_code
= http_bad_request
;
1116 goto virt_virt_new_cleanup
;
1119 TRACE("args", "%s", temp
);
1121 pool
= virStoragePoolLookupByName(virConn
, temp
);
1124 conn
->error_code
= http_not_found
;
1125 goto virt_virt_new_cleanup
;
1128 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
1129 if (unlikely(ret
< ret_ok
)) {
1130 TRACE("virt", "storageVolCreateXML_args; name argument not specified");
1131 conn
->error_code
= http_bad_request
;
1132 goto virt_virt_new_cleanup
;
1135 ret
= cherokee_avl_get_ptr (conn
->arguments
, "type", &type
);
1136 if (unlikely(ret
< ret_ok
)) {
1137 TRACE("virt", "storageVolCreateXML_args; type argument not specified");
1138 conn
->error_code
= http_bad_request
;
1139 goto virt_virt_new_cleanup
;
1142 ret
= cherokee_avl_get_ptr (conn
->arguments
, "unit", &unit
);
1143 if (unlikely(ret
< ret_ok
)) {
1144 TRACE("virt", "storageVolCreateXML_args; unit argument not specified");
1145 conn
->error_code
= http_bad_request
;
1146 goto virt_virt_new_cleanup
;
1149 ret
= cherokee_avl_get_ptr (conn
->arguments
, "allocation", &temp
);
1150 if (unlikely(ret
< ret_ok
)) {
1151 TRACE("virt", "storageVolCreateXML_args; allocation argument not specified");
1152 conn
->error_code
= http_bad_request
;
1153 goto virt_virt_new_cleanup
;
1156 allocation
= strtoul(temp
, NULL
, 10);
1157 if (errno
== ERANGE
) {
1158 TRACE("virt", "storageVolCreateXML_args; allocation is not a number");
1159 conn
->error_code
= http_bad_request
;
1161 goto virt_virt_new_cleanup
;
1164 ret
= cherokee_avl_get_ptr (conn
->arguments
, "capacity", &temp
);
1165 if (unlikely(ret
< ret_ok
)) {
1166 TRACE("virt", "storageVolCreateXML_args; capacity argument not specified");
1167 conn
->error_code
= http_bad_request
;
1168 goto virt_virt_new_cleanup
;
1171 capacity
= strtoul(temp
, NULL
, 10);
1172 if (errno
== ERANGE
|| capacity
== 0) {
1173 TRACE("virt", "storageVolCreateXML_args; capacity is not a number");
1174 conn
->error_code
= http_bad_request
;
1176 goto virt_virt_new_cleanup
;
1179 cherokee_buffer_add_va (&xml
, VIRT_STORAGE_XML
, type
, hdl
->user
.buf
, name
, allocation
, unit
, capacity
, hdl
->user
.buf
, name
, hdl
->user
.buf
, name
);
1183 case domainDefineXML_args
: {
1186 unsigned long vcpu
= 0, interface
= 0, memory
= 0;
1190 ret
= cherokee_avl_get_ptr (conn
->arguments
, "vcpu", &temp
);
1192 vcpu
= strtoul(temp
, (char **) NULL
, 10);
1194 if (ret
!= ret_ok
|| errno
== ERANGE
|| vcpu
== 0) {
1195 conn
->error_code
= http_internal_error
;
1196 goto virt_virt_new_cleanup
;
1200 ret
= cherokee_avl_get_ptr (conn
->arguments
, "memory", &temp
);
1202 memory
= strtoul(temp
, (char **) NULL
, 10);
1204 if (ret
!= ret_ok
|| errno
== ERANGE
|| memory
== 0) {
1205 conn
->error_code
= http_internal_error
;
1206 goto virt_virt_new_cleanup
;
1210 ret
= cherokee_avl_get_ptr (conn
->arguments
, "interface", &temp
);
1212 interface
= strtoul(temp
, (char **) NULL
, 10);
1214 if (ret
!= ret_ok
|| errno
== ERANGE
) {
1215 conn
->error_code
= http_internal_error
;
1216 goto virt_virt_new_cleanup
;
1219 cherokee_buffer_t cmdline_extra
= CHEROKEE_BUF_INIT
;
1220 cherokee_buffer_t xml_interfaces
= CHEROKEE_BUF_INIT
;
1221 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
1222 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
1224 for (i
= 0; i
< interface
; i
++) {
1227 if (getNewMac("dv28", domu
.buf
, &mac
, &ip
) == 0) {
1228 cherokee_buffer_add_va (&xml_interfaces
, VIRT_INTERFACE_XML
, mac
, ip
);
1230 /* TODO: terrible hack */
1233 strcpy(gateway
, ip
);
1234 temp
= strchr(gateway
, '.');
1235 temp
= strchr(++temp
, '.');
1236 temp
= strchr(++temp
, '.');
1237 strcpy(++temp
, "254");
1238 cherokee_buffer_add_va (&cmdline_extra
, VIRT_DOMAIN_CMD_IP
, ip
, gateway
);
1243 cherokee_buffer_mrproper(&domu
);
1245 cherokee_buffer_add_va (&xml
, VIRT_DOMAIN_XML
,
1246 hdl
->user
.buf
, hdl
->vm
.buf
, cmdline_extra
.buf
, memory
, vcpu
, xml_interfaces
.buf
);
1248 cherokee_buffer_mrproper(&xml_interfaces
);
1249 cherokee_buffer_mrproper(&cmdline_extra
);
1253 case storageVolCreateXML
:
1254 case domainDefineXML
: {
1256 cherokee_post_get_len (&conn
->post
, &postl
);
1257 cherokee_post_walk_read (&conn
->post
, &xml
, (cuint_t
) postl
);
1262 switch (hdl
->action
) {
1263 case domainDefineXML_args
:
1264 case domainDefineXML
: {
1265 virDomainPtr result
= virDomainDefineXML(virConn
, (const char *) xml
.buf
);
1267 if (result
== NULL
) {
1268 /* TODO: vrij maken eventuele uitgegeven macs! */
1269 conn
->error_code
= http_internal_error
;
1270 goto virt_virt_new_cleanup
;
1273 save_xml(hdl
, result
, buf
);
1275 virDomainFree(result
);
1280 case storageVolCreateXML_args
:
1281 case storageVolCreateXML
: {
1282 virStorageVolPtr vol
= virStorageVolCreateXML(pool
, xml
.buf
, 0);
1285 cherokee_buffer_add_long10(buf
, -1);
1286 goto virt_virt_new_cleanup
;
1289 virStorageVolFree(vol
);
1291 cherokee_buffer_add_long10(buf
, 0);
1296 virt_virt_new_cleanup
:
1297 cherokee_buffer_mrproper(&xml
);
1300 virStoragePoolFree(pool
);
1307 virt_virt_do(cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*domu
, cherokee_buffer_t
*uri
)
1309 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1311 ret_t ret
= ret_error
;
1312 virConnectPtr virConn
= NULL
;
1315 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
1316 virConn
= virConnectOpen (uri
->buf
);
1318 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
->buf
))) {
1319 conn
->error_code
= http_service_unavailable
;
1323 switch (hdl
->action
) {
1324 case storageVolDelete_args
:
1325 case storageVolSetPassword_args
:
1326 case storageVolGetXMLDesc_args
:
1327 case storageVolCloneXML_args
:
1328 ret
= virt_pool_vol(hdl
, virConn
);
1331 case storageVolCreateXML_args
:
1332 case storageVolCreateXML
:
1333 case domainDefineXML_args
:
1334 case domainDefineXML
:
1335 ret
= virt_virt_new(hdl
, virConn
);
1340 if ((dom
= virDomainLookupByName(virConn
, domu
->buf
)) == NULL
) {
1341 conn
->error_code
= http_not_found
;
1343 ret
= virt_virt_function(hdl
, dom
, virConn
);
1349 virConnectClose(virConn
);
1354 virt_while (cherokee_buffer_t
*key
, void *value
, void *param
) {
1355 cherokee_handler_virt_t
* hdl
= param
;
1356 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1357 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1358 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1359 // cherokee_buffer_mrproper(&uri);
1361 cherokee_buffer_add_va (&hdl
->buffer
, "<domain><name>%s</name></domain>", key
->buf
);
1367 virt_while_user (cherokee_buffer_t
*key
, void *value
, void *param
) {
1368 cherokee_handler_virt_t
*hdl
= param
;
1369 if (key
->len
> hdl
->user
.len
&& key
->buf
[hdl
->user
.len
] == '_' && strncmp(key
->buf
, hdl
->user
.buf
, hdl
->user
.len
) == 0)
1370 return virt_while (key
, value
, param
);
1376 virt_build_page (cherokee_handler_virt_t
*hdl
)
1379 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1380 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
1381 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
1383 /* We use the webserver methods to parse the querystring */
1384 /* Maybe do something smart with ENUM, begin_args, end_args... */
1385 if ((hdl
->action
== domainDefineXML_args
) ||
1386 (hdl
->action
== domainAttachDevice_args
) ||
1387 (hdl
->action
== domainMigrate_args
) ||
1388 (hdl
->action
== storageVolGetXMLDesc_args
) ||
1389 (hdl
->action
== storageVolDelete_args
) ||
1390 (hdl
->action
== storageVolSetPassword_args
) ||
1391 (hdl
->action
== storageVolCloneXML_args
) ||
1392 (hdl
->action
== storageVolCloneStatus_args
) ||
1393 (hdl
->action
== storageVolCreateXML_args
) ||
1394 (hdl
->action
== graphLoad_args
) ||
1395 (hdl
->action
== graphInterface_args
)) {
1396 ret
= cherokee_connection_parse_args (conn
);
1397 if (unlikely(ret
< ret_ok
)) {
1398 conn
->error_code
= http_internal_error
;
1403 switch (hdl
->action
) {
1404 case graphInterface_args
: {
1405 struct stat statbuf
;
1406 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
1408 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "interface", &interface
)) != ret_ok
)
1411 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/interface_%s.rrd", hdl
->user
.buf
, hdl
->vm
.buf
, interface
);
1412 if (stat(path
.buf
, &statbuf
) != 0) {
1413 conn
->error_code
= http_not_found
;
1416 void *width
, *height
, *start
, *end
;
1417 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "width", &width
)) != ret_ok
)
1420 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "height", &height
)) != ret_ok
)
1423 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "start", &start
)) != ret_ok
)
1426 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "end", &end
)) != ret_ok
)
1429 cherokee_buffer_t def1
= CHEROKEE_BUF_INIT
;
1430 cherokee_buffer_t def2
= CHEROKEE_BUF_INIT
;
1431 cherokee_buffer_add_va (&def1
, "DEF:rxbytes=%s:rxbytes:AVERAGE:step=30", path
.buf
);
1432 cherokee_buffer_add_va (&def2
, "DEF:txbytes=%s:txbytes:AVERAGE:step=30", path
.buf
);
1433 char **calcpr
= NULL
;
1436 /* TODO: betere random hier */
1437 char filenametemp
[L_tmpnam
+1];
1438 char *filename
= tmpnam(filenametemp
);
1440 // char *filename = mktemp(strdup("handler_virt_XXXXXX"));
1441 char *r_graph
[] = { "rrdgraph", filename
,
1447 "--title", interface
,
1448 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "bits per second",
1451 "CDEF:txbits=txbytes,8,*",
1452 "CDEF:rxbits=rxbytes,8,*",
1453 "AREA:rxbits#00EE00:rxbits",
1454 "LINE:txbits#0000EE:txbits" };
1456 rrd_graph(25, r_graph
, &calcpr
, &xsize
, &ysize
, NULL
, &ymin
, &ymax
);
1457 if ((ret
= cherokee_buffer_read_file(&hdl
->buffer
, filename
)) == ret_error
) {
1458 hdl
->action
= http_internal_error
;
1463 cherokee_buffer_mrproper(&def1
);
1464 cherokee_buffer_mrproper(&def2
);
1466 cherokee_buffer_mrproper(&path
);
1467 goto virt_build_page_cleanup
;
1472 case graphLoad_args
: {
1473 struct stat statbuf
;
1474 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
1475 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/cpuTime.rrd", hdl
->user
.buf
, hdl
->vm
.buf
);
1476 if (stat(path
.buf
, &statbuf
) != 0) {
1477 conn
->error_code
= http_not_found
;
1480 void *width
, *height
, *start
, *end
;
1481 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "width", &width
)) != ret_ok
)
1484 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "height", &height
)) != ret_ok
)
1487 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "start", &start
)) != ret_ok
)
1490 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "end", &end
)) != ret_ok
)
1493 /* TODO: wat error checking? */
1495 cherokee_buffer_t def
= CHEROKEE_BUF_INIT
;
1496 cherokee_buffer_add_va (&def
, "DEF:cputime=%s:cpuTime:AVERAGE:step=30", path
.buf
);
1497 char **calcpr
= NULL
;
1500 char *filename
= mktemp(strdup("handler_virt_XXXXXX"));
1501 char *r_graph
[] = { "rrdgraph",
1508 "--title", hdl
->vm
.buf
,
1509 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "(used / total) time",
1511 "CDEF:cpuload=cputime,1000000000,/",
1512 "LINE:cpuload#EE0000:cpuLoad" };
1514 rrd_graph(22, r_graph
, &calcpr
, &xsize
, &ysize
, NULL
, &ymin
, &ymax
);
1515 if ((ret
= cherokee_buffer_read_file(&hdl
->buffer
, filename
)) == ret_error
) {
1516 hdl
->action
= http_internal_error
;
1522 cherokee_buffer_mrproper(&def
);
1524 cherokee_buffer_mrproper(&path
);
1525 goto virt_build_page_cleanup
;
1529 if (hdl
->action
> xml
&& HDL_VIRT_PROPS(hdl
)->xsl
.len
> 0)
1530 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
);
1533 switch (hdl
->action
) {
1536 if (cherokee_avl_r_len(&HDL_CLUSTERSTATS_PROPS(hdl
)->entries
, &len
) == ret_ok
&& len
> 0) {
1537 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>\n");
1538 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
);
1539 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
1541 cherokee_buffer_add_str (&hdl
->buffer
, "<domains/>");
1549 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>\n");
1550 get_all_configurations(&HDL_CLUSTERSTATS_PROPS(hdl
)->entries
, &hdl
->user
, &hdl
->buffer
);
1551 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
1557 AvahiStringList
*list
= NULL
;
1558 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
1560 ret
= cherokee_avl_r_get(&HDL_CLUSTERSTATS_PROPS(hdl
)->entries
, &domu
, (void **) &list
);
1562 if (ret
== ret_not_found
) {
1563 virDomainPtr virDom
;
1564 virConnectPtr virConn
;
1565 if (HDL_VIRT_PROPS(hdl
)->virt
.len
> 0)
1566 cherokee_buffer_add_va (&uri
, "xen://%s/", HDL_VIRT_PROPS(hdl
)->virt
); // TODO: change!
1568 /* If we have the read only parameter, we will set up a connection to the
1569 * Hypervisor here. */
1570 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
1571 virConn
= virConnectOpen (uri
.buf
);
1573 /* We should already have a connection (read only) or build a new connection
1574 * if this doesn't work, we can safely assume our services is fubar */
1575 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
.buf
))) {
1576 conn
->error_code
= http_service_unavailable
;
1580 /* We lookup if there is a domain somewhere with this name */
1581 if ((virDom
= virDomainLookupByName(virConn
, domu
.buf
)) == NULL
) {
1582 /* If the domain is not found on the network the only possible
1583 * command that is possible would be to Define it */
1584 if (hdl
->action
== domainDefineXML_args
|| hdl
->action
== domainDefineXML
) {
1587 /* We should also look on disk for defined stuff */
1588 cherokee_buffer_t xmlDesc
= CHEROKEE_BUF_INIT
;
1589 if (load_xml(hdl
, &xmlDesc
) == ret_ok
&& (virDom
= virDomainDefineXML(virConn
, xmlDesc
.buf
)) != NULL
) {
1590 /* The domain existed and is loaded! */
1593 /* Otherwise we don't have anything to do and we should
1594 * return an error */
1595 hdl
->action
= nothing
;
1596 conn
->error_code
= http_not_found
;
1600 cherokee_buffer_mrproper(&xmlDesc
);
1603 /* We don't want te recreate things that already found on the network
1604 * first undefine them! */
1605 if (hdl
->action
== domainDefineXML_args
|| hdl
->action
== domainDefineXML
) {
1606 TRACE("virt", "domainDefineXML_args/domainDefineXML; domain already exists");
1607 hdl
->action
= nothing
;
1608 conn
->error_code
= http_bad_request
;
1611 /* Everything is ok, because nothing is found. */
1615 /* Domain wasn't NULL, so we should free it here */
1616 virDomainFree(virDom
);
1618 virConnectClose (virConn
);
1619 } else if (ret
== ret_ok
) {
1621 avahi_string_list_get_pair(avahi_string_list_find(list
, "dom0"), NULL
, &hostname
, NULL
);
1622 cherokee_buffer_add_va (&uri
, "xen://%s/", hostname
);
1623 printf("%s\n", uri
.buf
);
1624 avahi_free(hostname
);
1626 hdl
->action
= http_internal_error
;
1627 hdl
->action
= nothing
;
1634 if (ret
== ret_ok
&& hdl
->action
!= showall
&& hdl
->action
!= showuservms
) {
1635 ret
= virt_virt_do(hdl
, &domu
, &uri
);
1638 virt_build_page_cleanup
:
1639 cherokee_buffer_mrproper(&domu
);
1640 cherokee_buffer_mrproper(&uri
);
1647 cherokee_handler_virt_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
1650 CHEROKEE_NEW_STRUCT (n
, handler_virt
);
1652 /* Init the base class
1655 cherokee_handler_init_base(HANDLER(n
), cnt
, HANDLER_PROPS(props
), PLUGIN_INFO_HANDLER_PTR(virt
));
1657 MODULE(n
)->init
= (handler_func_init_t
) cherokee_handler_virt_init
;
1658 MODULE(n
)->free
= (module_func_free_t
) cherokee_handler_virt_free
;
1659 HANDLER(n
)->step
= (handler_func_step_t
) cherokee_handler_virt_step
;
1660 HANDLER(n
)->add_headers
= (handler_func_add_headers_t
) cherokee_handler_virt_add_headers
;
1662 HANDLER(n
)->support
= hsupport_length
| hsupport_range
;
1664 ret
= cherokee_buffer_init (&n
->buffer
);
1665 if (unlikely(ret
!= ret_ok
))
1668 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
1669 if (unlikely(ret
!= ret_ok
))