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_avahi.h"
84 #include <cherokee/cherokee.h>
85 #include <libxml/parser.h>
86 #include <libxml/xpath.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
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_avahi_props_free (PROP_AVAHI(props
));
126 cherokee_handler_virt_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
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_avahi_props_init_base (PROP_AVAHI(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
);
173 return cherokee_handler_avahi_configure (conf
, srv
, _props
);
176 static void entry_group_callback(AvahiEntryGroup
*g
, AvahiEntryGroupState state
, AVAHI_GCC_UNUSED
void *userdata
) {
178 case AVAHI_ENTRY_GROUP_ESTABLISHED
:
179 /* The entry group has been established successfully */
182 case AVAHI_ENTRY_GROUP_COLLISION
: {
183 /* A service name collision with a remote service
188 case AVAHI_ENTRY_GROUP_FAILURE
:
189 /* Some kind of failure happened while we were registering our services */
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
,
206 const char *host_name
,
207 const AvahiAddress
*address
,
209 AvahiStringList
*txt
,
210 AvahiLookupResultFlags flags
,
213 tender_t
*tender
= userdata
;
217 /* Called whenever a service has been resolved successfully or timed out */
220 case AVAHI_RESOLVER_FAILURE
:
221 fprintf(stderr
, "(Resolver) FAILURE!\n");
222 avahi_service_resolver_free(r
);
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
);
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
));
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
) {
261 avahi_string_list_get_pair (needle
, NULL
, &cost
, NULL
);
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
) {
267 tender
->cost
= amount
;
268 tender
->dom
= strdup(host_name
);
269 TRACE("tender", "We will consider his offer!");
281 static void tender_browse_callback(
282 AvahiServiceBrowser
*b
,
283 AvahiIfIndex interface
,
284 AvahiProtocol protocol
,
285 AvahiBrowserEvent event
,
289 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
293 AvahiClient
*c
= avahi_service_browser_get_client(b
);
295 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
298 case AVAHI_BROWSER_FAILURE
:
299 fprintf(stderr
, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))));
302 case AVAHI_BROWSER_NEW
:
303 fprintf(stderr
, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
305 /* We ignore the returned resolver object. In the callback
306 function we free it. If the server is terminated before
307 the callback function is called the server will free
308 the resolver for us. */
310 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
, AVAHI_PROTO_UNSPEC
, 0, tender_resolve_callback
, userdata
)))
311 fprintf(stderr
, "Failed to resolve service '%s': %s\n", name
, avahi_strerror(avahi_client_errno(c
)));
315 case AVAHI_BROWSER_REMOVE
:
316 fprintf(stderr
, "%s, (Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", __func__
, name
, type
, domain
);
319 case AVAHI_BROWSER_ALL_FOR_NOW
:
320 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
321 fprintf(stderr
, "(Browser) %s\n", event
== AVAHI_BROWSER_CACHE_EXHAUSTED
? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
327 cherokee_handler_virt_init (cherokee_handler_virt_t
*hdl
)
329 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
331 /* If someone is posting the server should be in
332 * read/write mode if this is not the case, just
333 * bail out directly */
335 if (conn
->header
.method
== http_post
&& HDL_VIRT_PROPS(hdl
)->read_only
== TRUE
) {
336 conn
->error_code
= http_unauthorized
;
344 cherokee_buffer_init(&hdl
->user
);
345 cherokee_buffer_init(&hdl
->vm
);
347 hdl
->action
= nothing
;
349 cherokee_buffer_add (&conn
->pathinfo
,
350 conn
->request
.buf
+ conn
->web_directory
.len
,
351 conn
->request
.len
- conn
->web_directory
.len
);
353 this = conn
->pathinfo
.buf
+ 1;
355 next
= strchr(this, '/'); /* TODO: this code borks! */
357 if ((!next
&& (this && (len
= strlen(this)) == 0)) || (next
&& ((len
= next
- this) == 0)) )
358 hdl
->action
= showall
;
360 cherokee_buffer_add (&hdl
->user
, this, len
);
363 if (HDL_VIRT_PROPS(hdl
)->authenticate
) {
364 if (!conn
->validator
||
366 (!cherokee_buffer_cmp_buf(&conn
->validator
->user
, &hdl
->user
) &&
367 !(isroot
= cherokee_buffer_cmp (&conn
->validator
->user
, "root", 4))))) {
368 hdl
->action
= nothing
; /* just in case */
369 conn
->error_code
= http_unauthorized
;
376 if (hdl
->action
== showall
) {
378 hdl
->action
= nothing
;
379 conn
->error_code
= http_unauthorized
;
382 return virt_build_page(hdl
);
388 hdl
->action
= showuservms
;
389 return virt_build_page(hdl
);
392 next
= strchr(this, '/');
394 if ( ( !next
&& (this && (len
= strlen(this)) == 0) ) || (next
&& ((len
= next
- this) == 0)) ) {
395 //if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
396 hdl
->action
= showuservms
;
397 return virt_build_page(hdl
);
401 cherokee_buffer_add (&hdl
->vm
, this, len
);
404 hdl
->action
= domainGetXMLDesc
;
405 return virt_build_page(hdl
);
408 next
= strchr(this, '/');
410 if (( !next
&& (this && (len
= strlen(this)) == 0) ) || (next
&& ((len
= next
- this) == 0)) ) {
411 hdl
->action
= domainGetXMLDesc
;
412 return virt_build_page(hdl
);
416 hdl
->action
= not_implemented
;
417 switch (conn
->header
.method
) {
419 if (strncmp(this, "virDomain", 9) == 0) {
420 if (strncmp(this+9, "Get", 3) == 0) {
421 if (strcmp(this+12, "ID") == 0) hdl
->action
= domainGetID
;
422 else if (strcmp(this+12, "Name") == 0) hdl
->action
= domainGetName
;
423 else if (strcmp(this+12, "MaxMemory") == 0) hdl
->action
= domainGetMaxMemory
;
424 else if (strcmp(this+12, "MaxVcpus") == 0) hdl
->action
= domainGetMaxVcpus
;
425 else if (strcmp(this+12, "OSType") == 0) hdl
->action
= domainGetOSType
;
426 else if (strcmp(this+12, "UUID") == 0) hdl
->action
= domainGetUUID
;
427 else if (strcmp(this+12, "UUIDString") == 0) hdl
->action
= domainGetUUIDString
;
428 else if (strcmp(this+12, "XMLDesc") == 0) hdl
->action
= domainGetXMLDesc
;
431 else if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
) {
432 if (strcmp(this+9, "Create") == 0) hdl
->action
= domainCreate
;
433 else if (strcmp(this+9, "Destroy") == 0) hdl
->action
= domainDestroy
;
434 else if (strcmp(this+9, "Reboot") == 0) hdl
->action
= domainReboot
;
435 else if (strcmp(this+9, "Shutdown") == 0) hdl
->action
= domainShutdown
;
437 else if (strcmp(this+9, "Save") == 0) hdl
->action
= domainSave
;
438 else if (strcmp(this+9, "Restore") == 0) hdl
->action
= domainRestore
;
440 else if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice_args
;
442 else if (strcmp(this+9, "DefineXML") == 0) hdl
->action
= domainDefineXML_args
;
443 else if (strcmp(this+9, "Undefine") == 0) hdl
->action
= domainUndefine
;
446 else if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
&& strncmp(this, "virStorage", 10) == 0) {
447 if (strncmp(this+10, "Vol", 3) == 0) {
448 if (strcmp(this+13, "CreateXML") == 0) hdl
->action
= storageVolCreateXML_args
;
449 else if (strcmp(this+13, "Delete") == 0) hdl
->action
= storageVolDelete_args
;
450 else if (strcmp(this+13, "CloneXML") == 0) hdl
->action
= storageVolCloneXML_args
;
451 else if (strcmp(this+13, "CloneStatus") == 0) hdl
->action
= storageVolCloneStatus_args
;
452 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl
->action
= storageVolGetXMLDesc_args
;
453 else if (strcmp(this+13, "SetPassword") == 0) hdl
->action
= storageVolSetPassword_args
;
456 else if (strncmp(this, "virGraph", 8) == 0) {
457 if (strcmp(this+8, "Load") == 0) hdl
->action
= graphLoad_args
;
458 if (strcmp(this+8, "Interface") == 0) hdl
->action
= graphInterface_args
;
464 cherokee_post_get_len (&conn
->post
, &postl
);
466 if (postl
<= 0 || postl
>= (INT_MAX
-1)) {
467 TRACE("virt", "post without post");
468 conn
->error_code
= http_bad_request
;
472 if (strncmp(this, "virDomain", 9) == 0) {
473 if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice
;
474 else if (strcmp(this+9, "DetachDevice") == 0) hdl
->action
= domainDetachDevice
;
475 else if (strcmp(this+9, "DefineXML") == 0) hdl
->action
= domainDefineXML
;
477 else if (strncmp(this, "virStorage", 10) == 0) {
478 if (strncmp(this+10, "Vol", 3) == 0) {
479 if (strcmp(this+13, "CreateXML") == 0) hdl
->action
= storageVolCreateXML
;
490 if (hdl
->action
<= 0) {
491 TRACE("virt", "There was no action specified");
492 conn
->error_code
= http_bad_request
;
497 return virt_build_page(hdl
);
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
);
511 cherokee_handler_virt_step (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
515 if (cherokee_buffer_is_empty (&hdl
->buffer
))
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
;
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
);
539 cherokee_buffer_add_str (buffer
, "Content-Type: text/plain"CRLF
);
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))) {
559 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
563 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
566 char *xml = virDomainGetXMLDesc(dom, 0);
567 cherokee_buffer_add(buf, xml, strlen(xml));
569 virConnectClose(conn);
572 cherokee_buffer_mrproper(&uri);
577 static ret_t
load_xml(cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*xmlDesc
) {
578 ret_t ret
= ret_error
;
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
) {
592 size_t amount
= fread(buf
, sizeof(char), 1024, fd
);
594 cherokee_buffer_add (xmlDesc
, buf
, amount
);
597 if (xmlDesc
->len
> 0)
601 cherokee_buffer_mrproper(&path
);
605 static ret_t
save_xml(cherokee_handler_virt_t
*hdl
, virDomainPtr result
, cherokee_buffer_t
*buf
) {
606 ret_t ret
= ret_error
;
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
) {
620 char *output
= virDomainGetXMLDesc(result
, VIR_DOMAIN_XML_INACTIVE
);
621 fwrite(output
, strlen(output
), sizeof(char), fd
);
624 cherokee_buffer_add(buf
, output
, strlen(output
));
628 cherokee_buffer_mrproper(&path
);
634 virt_virt_function(cherokee_handler_virt_t
*hdl
, virDomainPtr dom
, virConnectPtr virConn
) {
635 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
636 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
638 switch (hdl
->action
) {
639 /* Returns the status of a clone copy */
640 case storageVolCloneStatus_args
: {
644 cherokee_buffer_t queue
= CHEROKEE_BUF_INIT
;
646 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
647 if (unlikely(ret
< ret_ok
)) {
648 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
649 conn
->error_code
= http_bad_request
;
653 cherokee_buffer_add_va (&queue
, "/mnt/images/queue/%s_%s.queued", hdl
->user
.buf
, name
);
655 if (stat(queue
.buf
, &statbuf
) != 0) {
656 conn
->error_code
= http_not_found
;
661 if ((namelen
= readlink(queue
.buf
, hardlink
, 1023)) == -1) {
662 conn
->error_code
= http_internal_error
;
665 hardlink
[namelen
] = '\0';
666 if (stat(hardlink
, &statbuf
) != 0) {
667 conn
->error_code
= http_internal_error
;
670 struct stat statbuf2
;
671 cherokee_buffer_t busy
= CHEROKEE_BUF_INIT
;
672 cherokee_buffer_add_va (&busy
, "/mnt/images/queue/%s_%s.busy", hdl
->user
.buf
, name
);
673 if (stat(busy
.buf
, &statbuf2
) != 0) {
674 conn
->error_code
= http_internal_error
;
677 cherokee_buffer_add_va (buf
, "%f", (float)((float)statbuf2
.st_size
/ (float)statbuf
.st_size
));
680 cherokee_buffer_mrproper(&busy
);
685 cherokee_buffer_mrproper(&queue
);
690 /* Save the memory of a domain to a file and suspend the domain */
694 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
695 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/memory", hdl
->user
.buf
, hdl
->vm
.buf
);
696 if ((result
= virDomainSave(dom
, path
.buf
)) != 0) {
697 TRACE("virt", "Saving of %s/%s failed", hdl
->user
.buf
, hdl
->vm
.buf
);
698 conn
->error_code
= http_internal_error
;
701 cherokee_buffer_mrproper(&path
);
703 cherokee_buffer_add_long10(buf
, result
);
708 /* Restore the memory of a domain from a file and resume the domain */
709 case domainRestore
: {
712 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
713 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/memory", hdl
->user
.buf
, hdl
->vm
.buf
);
715 if (stat(path
.buf
, &statbuf
) == 0) {
717 if ((result
= virDomainRestore(virConn
, path
.buf
)) != 0) {
718 TRACE("virt", "Restoring of %s/%s failed", hdl
->user
.buf
, hdl
->vm
.buf
);
719 conn
->error_code
= http_internal_error
;
722 cherokee_buffer_add_long10(buf
, result
);
724 TRACE("virt", "Memory file for %s/%s does not exist", hdl
->user
.buf
, hdl
->vm
.buf
);
725 conn
->error_code
= http_not_found
;
729 cherokee_buffer_mrproper(&path
);
734 case domainUndefine
: {
736 if ((result
= virDomainUndefine(dom
)) != 0) {
737 conn
->error_code
= http_internal_error
; /* TODO */
740 cherokee_buffer_add_long10(buf
, result
);
744 case domainAttachDevice_args
: {
749 ret
= cherokee_avl_get_ptr (conn
->arguments
, "type", &temp
);
752 cherokee_buffer_t xml
= CHEROKEE_BUF_INIT
;
754 if (strcmp(temp
, "disk") == 0) {
756 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "device", &device
)) == ret_ok
) {
758 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "file", &file
)) == ret_ok
) {
759 cherokee_buffer_add_va (&xml
, VIRT_DISK_XML
, file
, device
);
761 virStorageVolPtr volume
= virt_get_vol_by_args(hdl
, virConn
, 1);
763 if (volume
== NULL
) {
767 file
= virStorageVolGetPath(volume
);
768 cherokee_buffer_add_va (&xml
, VIRT_DISK_XML
, file
, device
);
771 virStorageVolFree(volume
);
777 else if (strcmp(temp
, "interface") == 0) {
779 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "mac", &mac
)) == ret_ok
&& (ret
= cherokee_avl_get_ptr (conn
->arguments
, "ip", &ip
)) == ret_ok
) {
780 cherokee_buffer_add_va (&xml
, VIRT_INTERFACE_XML
, mac
, ip
);
784 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
785 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
786 if (getNewMac("dv28", domu
.buf
, &mac
, &ip
) == 0)
787 cherokee_buffer_add_va (&xml
, VIRT_INTERFACE_XML
, mac
, ip
);
788 cherokee_buffer_mrproper(&domu
);
792 if (ret
== ret_ok
&& (result
= virDomainAttachDevice(dom
, (const char *) xml
.buf
)) == 0) {
795 conn
->error_code
= http_internal_error
;
799 cherokee_buffer_add_long10(buf
, result
);
800 cherokee_buffer_mrproper(&xml
);
802 TRACE("virt", "DeviceAttach_args; type was not specified");
803 conn
->error_code
= http_bad_request
;
810 case domainAttachDevice
: {
813 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
814 cherokee_post_get_len (&conn
->post
, &postl
);
815 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
816 if ((result
= virDomainAttachDevice(dom
, (const char *) post
.buf
)) != 0)
817 conn
->error_code
= http_internal_error
;
819 cherokee_buffer_mrproper(&post
);
820 cherokee_buffer_add_long10(buf
, result
);
825 case domainGetXMLDesc
: {
826 char *xml
= virDomainGetXMLDesc(dom
, 0);
827 cherokee_buffer_add(buf
, xml
, strlen(xml
));
833 case domainDetachDevice
: {
837 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
838 cherokee_post_get_len (&conn
->post
, &postl
);
839 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
841 xmlDocPtr doc
= xmlParseMemory((const char *) post
.buf
, post
.len
);
843 TRACE("virt", "DeviceAttach; XML document unparceble");
844 conn
->error_code
= http_bad_request
;
850 if ((result
= virDomainDetachDevice(dom
, (const char *) post
.buf
)) != 0) {
851 conn
->error_code
= http_internal_error
;
852 /* TODO: betere afhandeling */
854 xmlXPathContextPtr context
= xmlXPathNewContext(doc
);
855 if (context
!= NULL
) {
856 xmlXPathObjectPtr obj
= xmlXPathEval("string(//interface/mac/@address)", context
);
857 xmlXPathFreeContext(context
);
858 if ((obj
!= NULL
) && (obj
->type
== XPATH_STRING
) &&
859 (obj
->stringval
!= NULL
) && (obj
->stringval
[0] != 0)) {
860 removeOldMac("dv28", (char *) obj
->stringval
);
862 xmlXPathFreeObject(obj
);
869 cherokee_buffer_mrproper(&post
);
870 cherokee_buffer_add_long10(buf
, result
);
875 cherokee_buffer_add_ulong10(buf
, virDomainGetID(dom
));
878 case domainGetMaxMemory
: {
879 cherokee_buffer_add_ulong10(buf
, virDomainGetMaxMemory (dom
));
882 case domainGetMaxVcpus
: {
883 cherokee_buffer_add_long10(buf
, virDomainGetMaxVcpus (dom
));
886 case domainGetName
: {
887 const char *name
= virDomainGetName (dom
);
888 cherokee_buffer_add(buf
, name
, strlen(name
));
891 case domainGetUUID
: {
892 unsigned char uuid
[VIR_UUID_BUFLEN
];
893 if (virDomainGetUUID(dom
, uuid
) == 0) {
894 cherokee_buffer_add_str(buf
, uuid
);
896 conn
->error_code
= http_internal_error
;
901 case domainGetUUIDString
: {
902 unsigned char uuid
[VIR_UUID_STRING_BUFLEN
];
903 if (virDomainGetUUIDString(dom
, uuid
) == 0) {
904 cherokee_buffer_add_str(buf
, uuid
);
906 conn
->error_code
= http_internal_error
;
913 cherokee_buffer_t xmlDesc
= CHEROKEE_BUF_INIT
;
915 save_xml(hdl
, dom
, &xmlDesc
);
916 tender_t best_tender
;
917 snprintf(txt
, 252, "memory=%lu", virDomainGetMaxMemory(dom
));
920 best_tender
.name
= virDomainGetName(dom
);
921 best_tender
.cost
= FLT_MAX
;
922 best_tender
.dom
= NULL
;
924 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
925 AvahiServiceBrowser
*sb
= avahi_service_browser_new(HDL_AVAHI_PROPS(hdl
)->client
, AVAHI_IF_UNSPEC
,
926 AVAHI_PROTO_UNSPEC
, "_tender._tcp",
927 NULL
, 0, tender_browse_callback
, &best_tender
);
930 TRACE("avahi", "For whatever reason the sb is NULL\n");
933 AvahiEntryGroup
*group
= avahi_entry_group_new(HDL_AVAHI_PROPS(hdl
)->client
, entry_group_callback
, NULL
);
936 TRACE("avahi", "For whatever reason the group is NULL\n");
938 avahi_entry_group_add_service(group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0,
939 best_tender
.name
, "_offer._tcp", NULL
, NULL
, 651, txt
, NULL
, NULL
);
940 avahi_entry_group_commit(group
);
941 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
943 sleep(3); /* we are for quick bidding ;) */
945 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
946 avahi_entry_group_free(group
);
949 avahi_service_browser_free(sb
);
950 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
952 if (best_tender
.dom
== NULL
) {
953 TRACE("virt", "Nobody wants %s, poor vm!\n", best_tender
.name
);
954 cherokee_buffer_add_long10(buf
, -1);
956 if (virDomainUndefine(dom
) != 0) {
957 TRACE("virt", "Can't undefine %s, some idiot run it already?\n", best_tender
.name
);
958 cherokee_buffer_add_long10(buf
, -1);
960 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
961 virConnectClose(virConn
);
962 cherokee_buffer_add_va (&uri
, "xen://%s/", best_tender
.dom
);
963 virConn
= virConnectOpen (uri
.buf
);
964 if (virConn
== NULL
) {
965 TRACE("virt", "Can't connect to %s\n", uri
.buf
);
966 cherokee_buffer_add_long10(buf
, -1);
968 cherokee_buffer_add_long10(buf
,
969 (virDomainCreateLinux(virConn
, xmlDesc
.buf
, 0) != NULL
?
972 cherokee_buffer_mrproper(&uri
);
974 TRACE("virt", "going to free\n");
975 free(best_tender
.dom
);
980 cherokee_buffer_mrproper(&xmlDesc
);
984 case domainDestroy
: {
985 cherokee_buffer_add_long10(buf
, virDomainDestroy (dom
));
990 cherokee_buffer_add_long10(buf
, virDomainReboot (dom
, 0));
994 case domainShutdown
: {
995 cherokee_buffer_add_long10(buf
, virDomainShutdown (dom
));
1000 case domainGetOSType
: {
1001 char *ostype
= virDomainGetOSType(dom
);
1002 cherokee_buffer_add(buf
, ostype
, strlen(ostype
));
1011 if (hdl
->action
== domainUndefine
) {
1012 /* Remove VM data from filesystem */
1013 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
1014 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/index.xml", hdl
->user
.buf
, hdl
->vm
.buf
);
1015 unlink(path
.buf
); /* TODO: instead of delet replace */
1016 cherokee_buffer_mrproper(&path
);
1017 } else if (hdl
->action
!= domainCreate
) {
1018 save_xml(hdl
, dom
, NULL
);
1024 static virStoragePoolPtr
1025 virt_get_pool_by_args(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
1026 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1027 virStoragePoolPtr pool
;
1031 ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &temp
);
1032 if (unlikely(ret
< ret_ok
)) {
1033 TRACE("virt", "virStoragePoolPtr; Pool argument not specified");
1034 conn
->error_code
= http_bad_request
;
1038 pool
= virStoragePoolLookupByName(virConn
, temp
);
1043 static virStorageVolPtr
1044 virt_get_vol_by_args(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
, unsigned short int prefix
) {
1045 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1046 virStoragePoolPtr pool
;
1047 virStorageVolPtr volume
;
1051 pool
= virt_get_pool_by_args(hdl
, virConn
);
1054 conn
->error_code
= http_not_found
;
1058 virStoragePoolRefresh(pool
, 0); /* TODO: might be better to do it outside */
1060 ret
= cherokee_avl_get_ptr (conn
->arguments
, "volume", &temp
);
1061 if (unlikely(ret
< ret_ok
)) {
1062 TRACE("virt", "virStorageVolPtr; Volume argument not specified");
1063 conn
->error_code
= http_bad_request
;
1068 cherokee_buffer_t fullvol
= CHEROKEE_BUF_INIT
;
1069 cherokee_buffer_add_va (&fullvol
, "%s_%s", hdl
->user
.buf
, temp
);
1070 volume
= virStorageVolLookupByName(pool
, fullvol
.buf
);
1071 cherokee_buffer_mrproper(&fullvol
);
1073 volume
= virStorageVolLookupByName(pool
, temp
);
1077 conn
->error_code
= http_not_found
;
1079 virStoragePoolFree(pool
);
1084 /* This function is the home for all functions that need a working
1085 * pool/volume combination */
1087 virt_pool_vol(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
1088 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
1089 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1090 virStorageVolPtr volume
;
1093 /* We only allow clone to run 'unsafe', others get prefixed */
1094 volume
= virt_get_vol_by_args(hdl
, virConn
, (hdl
->action
!= storageVolCloneXML_args
));
1096 /* If the volume doesn't exist, no point to continue */
1100 switch (hdl
->action
) {
1101 /* Sets the password of a specific volume, requires the password= option */
1102 case storageVolSetPassword_args
: {
1104 ret
= cherokee_avl_get_ptr (conn
->arguments
, "password", &temp
);
1105 if (unlikely(ret
< ret_ok
)) {
1106 TRACE("virt", "storageVolSetPassword_args; password argument not specified");
1107 conn
->error_code
= http_bad_request
;
1108 goto virt_pool_vol_cleanup
;
1110 cherokee_buffer_t cmd_passwd
= CHEROKEE_BUF_INIT
;
1111 cherokee_buffer_add_va (&cmd_passwd
, "/usr/sbin/passwdchanger.sh %s %s\n", virStorageVolGetKey(volume
), temp
);
1112 cherokee_buffer_add_long10(buf
, system(cmd_passwd
.buf
));
1113 cherokee_buffer_mrproper(&cmd_passwd
);
1118 /* Removes a volume */
1119 case storageVolDelete_args
: {
1120 cherokee_buffer_add_long10(buf
, virStorageVolDelete(volume
, 0));
1124 /* Gives a description of a storage volume in XML */
1125 case storageVolGetXMLDesc_args
: {
1126 char *xml
= virStorageVolGetXMLDesc(volume
, 0);
1127 cherokee_buffer_add(buf
, xml
, strlen(xml
));
1132 /* Clones a volume, insecure method! requires a new name= */
1133 case storageVolCloneXML_args
: {
1135 cherokee_buffer_t busy
= CHEROKEE_BUF_INIT
;
1137 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
1138 if (unlikely(ret
< ret_ok
)) {
1139 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
1140 conn
->error_code
= http_bad_request
;
1141 goto virt_pool_vol_cleanup
;
1144 cherokee_buffer_add_va (&busy
, "/mnt/images/queue/%s_%s.queued", hdl
->user
.buf
, name
);
1146 if (unlikely(symlink(virStorageVolGetKey(volume
), busy
.buf
) == 1)) {
1147 conn
->error_code
= http_internal_error
;
1150 cherokee_buffer_add_str(buf
, "QUEUED");
1153 cherokee_buffer_mrproper(&busy
);
1160 virt_pool_vol_cleanup
:
1161 /* And in the end we need to free the volume we have used */
1162 virStorageVolFree(volume
);
1168 virt_virt_new(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
1169 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
1170 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1171 cherokee_buffer_t xml
= CHEROKEE_BUF_INIT
;
1172 virStoragePoolPtr pool
= NULL
;
1175 switch (hdl
->action
) {
1177 case storageVolCreateXML_args
: {
1178 void *temp
, *type
, *name
, *unit
;
1179 unsigned long int capacity
, allocation
;
1181 ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &temp
);
1182 if (unlikely(ret
< ret_ok
)) {
1183 TRACE("virt", "storageVolCreateXML_args; pool argument not specified");
1184 conn
->error_code
= http_bad_request
;
1185 goto virt_virt_new_cleanup
;
1188 TRACE("args", "%s", temp
);
1190 pool
= virStoragePoolLookupByName(virConn
, temp
);
1193 conn
->error_code
= http_not_found
;
1194 goto virt_virt_new_cleanup
;
1197 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
1198 if (unlikely(ret
< ret_ok
)) {
1199 TRACE("virt", "storageVolCreateXML_args; name argument not specified");
1200 conn
->error_code
= http_bad_request
;
1201 goto virt_virt_new_cleanup
;
1204 ret
= cherokee_avl_get_ptr (conn
->arguments
, "type", &type
);
1205 if (unlikely(ret
< ret_ok
)) {
1206 TRACE("virt", "storageVolCreateXML_args; type argument not specified");
1207 conn
->error_code
= http_bad_request
;
1208 goto virt_virt_new_cleanup
;
1211 ret
= cherokee_avl_get_ptr (conn
->arguments
, "unit", &unit
);
1212 if (unlikely(ret
< ret_ok
)) {
1213 TRACE("virt", "storageVolCreateXML_args; unit argument not specified");
1214 conn
->error_code
= http_bad_request
;
1215 goto virt_virt_new_cleanup
;
1218 ret
= cherokee_avl_get_ptr (conn
->arguments
, "allocation", &temp
);
1219 if (unlikely(ret
< ret_ok
)) {
1220 TRACE("virt", "storageVolCreateXML_args; allocation argument not specified");
1221 conn
->error_code
= http_bad_request
;
1222 goto virt_virt_new_cleanup
;
1225 allocation
= strtoul(temp
, NULL
, 10);
1226 if (errno
== ERANGE
) {
1227 TRACE("virt", "storageVolCreateXML_args; allocation is not a number");
1228 conn
->error_code
= http_bad_request
;
1230 goto virt_virt_new_cleanup
;
1233 ret
= cherokee_avl_get_ptr (conn
->arguments
, "capacity", &temp
);
1234 if (unlikely(ret
< ret_ok
)) {
1235 TRACE("virt", "storageVolCreateXML_args; capacity argument not specified");
1236 conn
->error_code
= http_bad_request
;
1237 goto virt_virt_new_cleanup
;
1240 capacity
= strtoul(temp
, NULL
, 10);
1241 if (errno
== ERANGE
|| capacity
== 0) {
1242 TRACE("virt", "storageVolCreateXML_args; capacity is not a number");
1243 conn
->error_code
= http_bad_request
;
1245 goto virt_virt_new_cleanup
;
1248 cherokee_buffer_add_va (&xml
, VIRT_STORAGE_XML
, type
, hdl
->user
.buf
, name
, allocation
, unit
, capacity
, hdl
->user
.buf
, name
, hdl
->user
.buf
, name
);
1252 case domainDefineXML_args
: {
1255 unsigned long vcpu
= 0, interface
= 0, memory
= 0;
1259 ret
= cherokee_avl_get_ptr (conn
->arguments
, "vcpu", &temp
);
1261 vcpu
= strtoul(temp
, (char **) NULL
, 10);
1263 if (ret
!= ret_ok
|| errno
== ERANGE
|| vcpu
== 0) {
1264 conn
->error_code
= http_internal_error
;
1265 goto virt_virt_new_cleanup
;
1269 ret
= cherokee_avl_get_ptr (conn
->arguments
, "memory", &temp
);
1271 memory
= strtoul(temp
, (char **) NULL
, 10);
1273 if (ret
!= ret_ok
|| errno
== ERANGE
|| memory
== 0) {
1274 conn
->error_code
= http_internal_error
;
1275 goto virt_virt_new_cleanup
;
1279 ret
= cherokee_avl_get_ptr (conn
->arguments
, "interface", &temp
);
1281 interface
= strtoul(temp
, (char **) NULL
, 10);
1283 if (ret
!= ret_ok
|| errno
== ERANGE
) {
1284 conn
->error_code
= http_internal_error
;
1285 goto virt_virt_new_cleanup
;
1288 cherokee_buffer_t cmdline_extra
= CHEROKEE_BUF_INIT
;
1289 cherokee_buffer_t xml_interfaces
= CHEROKEE_BUF_INIT
;
1290 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
1291 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
1293 for (i
= 0; i
< interface
; i
++) {
1296 if (getNewMac("dv28", domu
.buf
, &mac
, &ip
) == 0) {
1297 cherokee_buffer_add_va (&xml_interfaces
, VIRT_INTERFACE_XML
, mac
, ip
);
1299 /* TODO: terrible hack */
1302 strcpy(gateway
, ip
);
1303 temp
= strchr(gateway
, '.');
1304 temp
= strchr(++temp
, '.');
1305 temp
= strchr(++temp
, '.');
1306 strcpy(++temp
, "254");
1307 cherokee_buffer_add_va (&cmdline_extra
, VIRT_DOMAIN_CMD_IP
, ip
, gateway
);
1312 cherokee_buffer_mrproper(&domu
);
1314 cherokee_buffer_add_va (&xml
, VIRT_DOMAIN_XML
,
1315 hdl
->user
.buf
, hdl
->vm
.buf
, cmdline_extra
.buf
, memory
, vcpu
, xml_interfaces
.buf
);
1317 cherokee_buffer_mrproper(&xml_interfaces
);
1318 cherokee_buffer_mrproper(&cmdline_extra
);
1322 case storageVolCreateXML
:
1323 case domainDefineXML
: {
1325 cherokee_post_get_len (&conn
->post
, &postl
);
1326 cherokee_post_walk_read (&conn
->post
, &xml
, (cuint_t
) postl
);
1331 switch (hdl
->action
) {
1332 case domainDefineXML_args
:
1333 case domainDefineXML
: {
1334 virDomainPtr result
= virDomainDefineXML(virConn
, (const char *) xml
.buf
);
1336 if (result
== NULL
) {
1337 /* TODO: vrij maken eventuele uitgegeven macs! */
1338 conn
->error_code
= http_internal_error
;
1339 goto virt_virt_new_cleanup
;
1342 save_xml(hdl
, result
, buf
);
1344 virDomainFree(result
);
1349 case storageVolCreateXML_args
:
1350 case storageVolCreateXML
: {
1351 virStorageVolPtr vol
= virStorageVolCreateXML(pool
, xml
.buf
, 0);
1354 cherokee_buffer_add_long10(buf
, -1);
1355 goto virt_virt_new_cleanup
;
1358 virStorageVolFree(vol
);
1360 cherokee_buffer_add_long10(buf
, 0);
1365 virt_virt_new_cleanup
:
1366 cherokee_buffer_mrproper(&xml
);
1369 virStoragePoolFree(pool
);
1376 virt_virt_do(cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*domu
, cherokee_buffer_t
*uri
)
1378 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1380 ret_t ret
= ret_error
;
1381 virConnectPtr virConn
= NULL
;
1384 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
1385 virConn
= virConnectOpen (uri
->buf
);
1387 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
->buf
))) {
1388 conn
->error_code
= http_service_unavailable
;
1392 switch (hdl
->action
) {
1393 case storageVolDelete_args
:
1394 case storageVolSetPassword_args
:
1395 case storageVolGetXMLDesc_args
:
1396 case storageVolCloneXML_args
:
1397 ret
= virt_pool_vol(hdl
, virConn
);
1400 case storageVolCreateXML_args
:
1401 case storageVolCreateXML
:
1402 case domainDefineXML_args
:
1403 case domainDefineXML
:
1404 ret
= virt_virt_new(hdl
, virConn
);
1409 if ((dom
= virDomainLookupByName(virConn
, domu
->buf
)) == NULL
) {
1410 conn
->error_code
= http_not_found
;
1412 ret
= virt_virt_function(hdl
, dom
, virConn
);
1418 virConnectClose(virConn
);
1423 virt_while (cherokee_buffer_t
*key
, void *value
, void *param
) {
1424 cherokee_handler_virt_t
* hdl
= param
;
1425 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1426 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1427 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1428 // cherokee_buffer_mrproper(&uri);
1430 cherokee_buffer_add_va (&hdl
->buffer
, "<domain><name>%s</name></domain>", key
->buf
);
1436 virt_while_user (cherokee_buffer_t
*key
, void *value
, void *param
) {
1437 cherokee_handler_virt_t
*hdl
= param
;
1438 if (key
->len
> hdl
->user
.len
&& key
->buf
[hdl
->user
.len
] == '_' && strncmp(key
->buf
, hdl
->user
.buf
, hdl
->user
.len
) == 0)
1439 return virt_while (key
, value
, param
);
1445 virt_build_page (cherokee_handler_virt_t
*hdl
)
1448 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1449 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
1450 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
1452 /* We use the webserver methods to parse the querystring */
1453 /* Maybe do something smart with ENUM, begin_args, end_args... */
1454 if ((hdl
->action
== domainDefineXML_args
) ||
1455 (hdl
->action
== domainAttachDevice_args
) ||
1456 (hdl
->action
== storageVolGetXMLDesc_args
) ||
1457 (hdl
->action
== storageVolDelete_args
) ||
1458 (hdl
->action
== storageVolSetPassword_args
) ||
1459 (hdl
->action
== storageVolCloneXML_args
) ||
1460 (hdl
->action
== storageVolCloneStatus_args
) ||
1461 (hdl
->action
== storageVolCreateXML_args
) ||
1462 (hdl
->action
== graphLoad_args
) ||
1463 (hdl
->action
== graphInterface_args
)) {
1464 ret
= cherokee_connection_parse_args (conn
);
1465 if (unlikely(ret
< ret_ok
)) {
1466 conn
->error_code
= http_internal_error
;
1471 switch (hdl
->action
) {
1472 case graphInterface_args
: {
1473 struct stat statbuf
;
1474 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
1476 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "interface", &interface
)) != ret_ok
)
1479 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/interface_%s.rrd", hdl
->user
.buf
, hdl
->vm
.buf
, interface
);
1480 if (stat(path
.buf
, &statbuf
) != 0) {
1481 conn
->error_code
= http_not_found
;
1484 void *width
, *height
, *start
, *end
;
1485 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "width", &width
)) != ret_ok
)
1488 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "height", &height
)) != ret_ok
)
1491 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "start", &start
)) != ret_ok
)
1494 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "end", &end
)) != ret_ok
)
1497 cherokee_buffer_t def1
= CHEROKEE_BUF_INIT
;
1498 cherokee_buffer_t def2
= CHEROKEE_BUF_INIT
;
1499 cherokee_buffer_add_va (&def1
, "DEF:rxbytes=%s:rxbytes:AVERAGE:step=30", path
.buf
);
1500 cherokee_buffer_add_va (&def2
, "DEF:txbytes=%s:txbytes:AVERAGE:step=30", path
.buf
);
1501 char **calcpr
= NULL
;
1504 char *filename
= mktemp(strdup("handler_virt_XXXXXX"));
1505 char *r_graph
[] = { "rrdgraph", filename
,
1511 "--title", interface
,
1512 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "bits per second",
1515 "CDEF:txbits=txbytes,8,*",
1516 "CDEF:rxbits=rxbytes,8,*",
1517 "AREA:rxbits#00EE00:rxbits",
1518 "LINE:txbits#0000EE:txbits" };
1520 rrd_graph(25, r_graph
, &calcpr
, &xsize
, &ysize
, NULL
, &ymin
, &ymax
);
1521 if ((ret
= cherokee_buffer_read_file(&hdl
->buffer
, filename
)) == ret_error
) {
1522 hdl
->action
= http_internal_error
;
1528 cherokee_buffer_mrproper(&def1
);
1529 cherokee_buffer_mrproper(&def2
);
1531 cherokee_buffer_mrproper(&path
);
1532 goto virt_build_page_cleanup
;
1537 case graphLoad_args
: {
1538 struct stat statbuf
;
1539 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
1540 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/cpuTime.rrd", hdl
->user
.buf
, hdl
->vm
.buf
);
1541 if (stat(path
.buf
, &statbuf
) != 0) {
1542 conn
->error_code
= http_not_found
;
1545 void *width
, *height
, *start
, *end
;
1546 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "width", &width
)) != ret_ok
)
1549 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "height", &height
)) != ret_ok
)
1552 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "start", &start
)) != ret_ok
)
1555 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "end", &end
)) != ret_ok
)
1558 /* TODO: wat error checking? */
1560 cherokee_buffer_t def
= CHEROKEE_BUF_INIT
;
1561 cherokee_buffer_add_va (&def
, "DEF:cputime=%s:cpuTime:AVERAGE:step=30", path
.buf
);
1562 char **calcpr
= NULL
;
1565 char *filename
= mktemp(strdup("handler_virt_XXXXXX"));
1566 char *r_graph
[] = { "rrdgraph",
1573 "--title", hdl
->vm
.buf
,
1574 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "(used / total) time",
1576 "CDEF:cpuload=cputime,1000000000,/",
1577 "LINE:cpuload#EE0000:cpuLoad" };
1579 rrd_graph(22, r_graph
, &calcpr
, &xsize
, &ysize
, NULL
, &ymin
, &ymax
);
1580 if ((ret
= cherokee_buffer_read_file(&hdl
->buffer
, filename
)) == ret_error
) {
1581 hdl
->action
= http_internal_error
;
1587 cherokee_buffer_mrproper(&def
);
1589 cherokee_buffer_mrproper(&path
);
1590 goto virt_build_page_cleanup
;
1594 if (hdl
->action
> xml
&& HDL_VIRT_PROPS(hdl
)->xsl
.len
> 0)
1595 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
);
1598 switch (hdl
->action
) {
1600 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>");
1601 // avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1602 cherokee_avl_r_while(&HDL_AVAHI_PROPS(hdl
)->entries
, virt_while
, hdl
, NULL
, NULL
);
1603 // avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1604 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
1609 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>");
1610 // avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1611 cherokee_avl_r_while(&HDL_AVAHI_PROPS(hdl
)->entries
, virt_while_user
, hdl
, NULL
, NULL
);
1612 // avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1613 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
1619 cherokee_buffer_t
*hostname
= NULL
;
1620 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
1622 // avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1623 ret
= cherokee_avl_r_get(&HDL_AVAHI_PROPS(hdl
)->entries
, &domu
, (void **) &hostname
);
1624 // avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
1626 if (ret
== ret_not_found
) {
1627 virDomainPtr virDom
;
1628 virConnectPtr virConn
;
1629 cherokee_buffer_add_va (&uri
, "xen://%s/", HDL_VIRT_PROPS(hdl
)->virt
); // TODO: change!
1631 /* If we have the read only parameter, we will set up a connection to the
1632 * Hypervisor here. */
1633 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
1634 virConn
= virConnectOpen (uri
.buf
);
1636 /* We should already have a connection (read only) or build a new connection
1637 * if this doesn't work, we can safely assume our services is fubar */
1638 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
.buf
))) {
1639 conn
->error_code
= http_service_unavailable
;
1643 /* We lookup if there is a domain somewhere with this name */
1644 if ((virDom
= virDomainLookupByName(virConn
, domu
.buf
)) == NULL
) {
1645 /* If the domain is not found on the network the only possible
1646 * command that is possible would be to Define it */
1647 if (hdl
->action
== domainDefineXML_args
|| hdl
->action
== domainDefineXML
) {
1650 /* We should also look on disk for defined stuff */
1651 cherokee_buffer_t xmlDesc
= CHEROKEE_BUF_INIT
;
1652 if (load_xml(hdl
, &xmlDesc
) == ret_ok
&& (virDom
= virDomainDefineXML(virConn
, xmlDesc
.buf
)) != NULL
) {
1653 /* The domain existed and is loaded! */
1656 /* Otherwise we don't have anything to do and we should
1657 * return an error */
1658 hdl
->action
= nothing
;
1659 conn
->error_code
= http_not_found
;
1663 cherokee_buffer_mrproper(&xmlDesc
);
1666 /* We don't want te recreate things that already found on the network
1667 * first undefine them! */
1668 if (hdl
->action
== domainDefineXML_args
|| hdl
->action
== domainDefineXML
) {
1669 TRACE("virt", "domainDefineXML_args/domainDefineXML; domain already exists");
1670 hdl
->action
= nothing
;
1671 conn
->error_code
= http_bad_request
;
1674 /* Everything is ok, because nothing is found. */
1678 /* Domain wasn't NULL, so we should free it here */
1679 virDomainFree(virDom
);
1681 virConnectClose (virConn
);
1682 } else if (ret
== ret_ok
) {
1683 cherokee_buffer_add_va (&uri
, "xen://%s/", hostname
->buf
);
1684 printf("%s\n", uri
.buf
);
1686 hdl
->action
= http_internal_error
;
1687 hdl
->action
= nothing
;
1694 if (ret
== ret_ok
&& hdl
->action
!= showall
&& hdl
->action
!= showuservms
) {
1695 ret
= virt_virt_do(hdl
, &domu
, &uri
);
1698 virt_build_page_cleanup
:
1699 cherokee_buffer_mrproper(&domu
);
1700 cherokee_buffer_mrproper(&uri
);
1707 cherokee_handler_virt_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
1710 CHEROKEE_NEW_STRUCT (n
, handler_virt
);
1712 /* Init the base class
1715 cherokee_handler_init_base(HANDLER(n
), cnt
, HANDLER_PROPS(props
), PLUGIN_INFO_HANDLER_PTR(virt
));
1717 MODULE(n
)->init
= (handler_func_init_t
) cherokee_handler_virt_init
;
1718 MODULE(n
)->free
= (module_func_free_t
) cherokee_handler_virt_free
;
1719 HANDLER(n
)->step
= (handler_func_step_t
) cherokee_handler_virt_step
;
1720 HANDLER(n
)->add_headers
= (handler_func_add_headers_t
) cherokee_handler_virt_add_headers
;
1722 HANDLER(n
)->support
= hsupport_length
| hsupport_range
;
1724 ret
= cherokee_buffer_init (&n
->buffer
);
1725 if (unlikely(ret
!= ret_ok
))
1728 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
1729 if (unlikely(ret
!= ret_ok
))