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 avahi_service_resolver_free(r
);
224 case AVAHI_RESOLVER_FOUND
: {
225 char a
[AVAHI_ADDRESS_STR_MAX
], *t
;
226 AvahiStringList
*needle
;
228 fprintf(stderr
, "(Resolver) Service '%s' of type '%s' in domain '%s':\n", name
, type
, domain
);
230 avahi_address_snprint(a
, sizeof(a
), address
);
231 t
= avahi_string_list_to_string(txt
);
243 avahi_string_list_get_service_cookie(txt
),
244 !!(flags
& AVAHI_LOOKUP_RESULT_LOCAL
),
245 !!(flags
& AVAHI_LOOKUP_RESULT_OUR_OWN
),
246 !!(flags
& AVAHI_LOOKUP_RESULT_WIDE_AREA
),
247 !!(flags
& AVAHI_LOOKUP_RESULT_MULTICAST
),
248 !!(flags
& AVAHI_LOOKUP_RESULT_CACHED
));
253 unsigned int len
= strlen(tender
->name
);
255 if (strlen(name
) > len
&& name
[len
] == '.' && strncmp(tender
->name
, name
, len
) == 0) {
256 if ((needle
= avahi_string_list_find (txt
, "cost")) != NULL
) {
260 avahi_string_list_get_pair (needle
, NULL
, &cost
, NULL
);
263 TRACE("tender", "%s will run %s for the cost of L$W %f\n", host_name
, tender
->name
, amount
);
264 if (amount
< tender
->cost
) {
266 tender
->cost
= amount
;
267 tender
->dom
= strdup(host_name
);
268 TRACE("tender", "We will consider his offer!");
280 static void tender_browse_callback(
281 AvahiServiceBrowser
*b
,
282 AvahiIfIndex interface
,
283 AvahiProtocol protocol
,
284 AvahiBrowserEvent event
,
288 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags
,
292 AvahiClient
*c
= avahi_service_browser_get_client(b
);
294 /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
297 case AVAHI_BROWSER_FAILURE
:
298 fprintf(stderr
, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b
))));
301 case AVAHI_BROWSER_NEW
:
302 fprintf(stderr
, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
304 /* We ignore the returned resolver object. In the callback
305 function we free it. If the server is terminated before
306 the callback function is called the server will free
307 the resolver for us. */
309 if (!(avahi_service_resolver_new(c
, interface
, protocol
, name
, type
, domain
, AVAHI_PROTO_UNSPEC
, 0, tender_resolve_callback
, userdata
)))
310 fprintf(stderr
, "Failed to resolve service '%s': %s\n", name
, avahi_strerror(avahi_client_errno(c
)));
314 case AVAHI_BROWSER_REMOVE
:
315 fprintf(stderr
, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name
, type
, domain
);
318 case AVAHI_BROWSER_ALL_FOR_NOW
:
319 case AVAHI_BROWSER_CACHE_EXHAUSTED
:
320 fprintf(stderr
, "(Browser) %s\n", event
== AVAHI_BROWSER_CACHE_EXHAUSTED
? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
326 cherokee_handler_virt_init (cherokee_handler_virt_t
*hdl
)
328 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
330 /* If someone is posting the server should be in
331 * read/write mode if this is not the case, just
332 * bail out directly */
334 if (conn
->header
.method
== http_post
&& HDL_VIRT_PROPS(hdl
)->read_only
== TRUE
) {
335 conn
->error_code
= http_unauthorized
;
343 cherokee_buffer_init(&hdl
->user
);
344 cherokee_buffer_init(&hdl
->vm
);
346 hdl
->action
= nothing
;
348 cherokee_buffer_add (&conn
->pathinfo
,
349 conn
->request
.buf
+ conn
->web_directory
.len
,
350 conn
->request
.len
- conn
->web_directory
.len
);
352 this = conn
->pathinfo
.buf
+ 1;
353 next
= strchr(this, '/');
356 if ((!next
&& (this && (len
= strlen(this)) == 0)) || (next
&& ((len
= next
- this) == 0)) )
357 hdl
->action
= showall
;
359 cherokee_buffer_add (&hdl
->user
, this, len
);
362 if (HDL_VIRT_PROPS(hdl
)->authenticate
) {
363 if (!conn
->validator
||
365 (!cherokee_buffer_cmp_buf(&conn
->validator
->user
, &hdl
->user
) &&
366 !(isroot
= cherokee_buffer_cmp (&conn
->validator
->user
, "root", 4))))) {
367 hdl
->action
= nothing
; /* just in case */
368 conn
->error_code
= http_unauthorized
;
375 if (hdl
->action
== showall
) {
377 hdl
->action
= nothing
;
378 conn
->error_code
= http_unauthorized
;
381 return virt_build_page(hdl
);
387 hdl
->action
= showuservms
;
388 return virt_build_page(hdl
);
391 next
= strchr(this, '/');
393 if ( ( !next
&& (this && (len
= strlen(this)) == 0) ) || (next
&& ((len
= next
- this) == 0)) ) {
394 //if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
395 hdl
->action
= showuservms
;
396 return virt_build_page(hdl
);
400 cherokee_buffer_add (&hdl
->vm
, this, len
);
403 hdl
->action
= domainGetXMLDesc
;
404 return virt_build_page(hdl
);
407 next
= strchr(this, '/');
409 if (( !next
&& (this && (len
= strlen(this)) == 0) ) || (next
&& ((len
= next
- this) == 0)) ) {
410 hdl
->action
= domainGetXMLDesc
;
411 return virt_build_page(hdl
);
415 hdl
->action
= not_implemented
;
416 switch (conn
->header
.method
) {
418 if (strncmp(this, "virDomain", 9) == 0) {
419 if (strncmp(this+9, "Get", 3) == 0) {
420 if (strcmp(this+12, "ID") == 0) hdl
->action
= domainGetID
;
421 else if (strcmp(this+12, "Name") == 0) hdl
->action
= domainGetName
;
422 else if (strcmp(this+12, "MaxMemory") == 0) hdl
->action
= domainGetMaxMemory
;
423 else if (strcmp(this+12, "MaxVcpus") == 0) hdl
->action
= domainGetMaxVcpus
;
424 else if (strcmp(this+12, "OSType") == 0) hdl
->action
= domainGetOSType
;
425 else if (strcmp(this+12, "UUID") == 0) hdl
->action
= domainGetUUID
;
426 else if (strcmp(this+12, "UUIDString") == 0) hdl
->action
= domainGetUUIDString
;
427 else if (strcmp(this+12, "XMLDesc") == 0) hdl
->action
= domainGetXMLDesc
;
430 else if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
) {
431 if (strcmp(this+9, "Create") == 0) hdl
->action
= domainCreate
;
432 else if (strcmp(this+9, "Destroy") == 0) hdl
->action
= domainDestroy
;
433 else if (strcmp(this+9, "Reboot") == 0) hdl
->action
= domainReboot
;
434 else if (strcmp(this+9, "Shutdown") == 0) hdl
->action
= domainShutdown
;
436 else if (strcmp(this+9, "Save") == 0) hdl
->action
= domainSave
;
437 else if (strcmp(this+9, "Restore") == 0) hdl
->action
= domainRestore
;
439 else if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice_args
;
441 else if (strcmp(this+9, "DefineXML") == 0) hdl
->action
= domainDefineXML_args
;
442 else if (strcmp(this+9, "Undefine") == 0) hdl
->action
= domainUndefine
;
445 else if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
&& strncmp(this, "virStorage", 10) == 0) {
446 if (strncmp(this+10, "Vol", 3) == 0) {
447 if (strcmp(this+13, "CreateXML") == 0) hdl
->action
= storageVolCreateXML_args
;
448 else if (strcmp(this+13, "Delete") == 0) hdl
->action
= storageVolDelete_args
;
449 else if (strcmp(this+13, "CloneXML") == 0) hdl
->action
= storageVolCloneXML_args
;
450 else if (strcmp(this+13, "CloneStatus") == 0) hdl
->action
= storageVolCloneStatus_args
;
451 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl
->action
= storageVolGetXMLDesc_args
;
452 else if (strcmp(this+13, "SetPassword") == 0) hdl
->action
= storageVolSetPassword_args
;
455 else if (strncmp(this, "virGraph", 8) == 0) {
456 if (strcmp(this+8, "Load") == 0) hdl
->action
= graphLoad_args
;
457 if (strcmp(this+8, "Interface") == 0) hdl
->action
= graphInterface_args
;
463 cherokee_post_get_len (&conn
->post
, &postl
);
465 if (postl
<= 0 || postl
>= (INT_MAX
-1)) {
466 TRACE("virt", "post without post");
467 conn
->error_code
= http_bad_request
;
471 if (strncmp(this, "virDomain", 9) == 0) {
472 if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice
;
473 else if (strcmp(this+9, "DetachDevice") == 0) hdl
->action
= domainDetachDevice
;
474 else if (strcmp(this+9, "DefineXML") == 0) hdl
->action
= domainDefineXML
;
476 else if (strncmp(this, "virStorage", 10) == 0) {
477 if (strncmp(this+10, "Vol", 3) == 0) {
478 if (strcmp(this+13, "CreateXML") == 0) hdl
->action
= storageVolCreateXML
;
489 if (hdl
->action
<= 0) {
490 TRACE("virt", "There was no action specified");
491 conn
->error_code
= http_bad_request
;
496 return virt_build_page(hdl
);
500 cherokee_handler_virt_free (cherokee_handler_virt_t
*hdl
)
502 cherokee_buffer_mrproper (&hdl
->buffer
);
503 cherokee_buffer_mrproper (&hdl
->user
);
504 cherokee_buffer_mrproper (&hdl
->vm
);
510 cherokee_handler_virt_step (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
514 if (cherokee_buffer_is_empty (&hdl
->buffer
))
517 tosend
= (hdl
->buffer
.len
> 1024 ? 1024 : hdl
->buffer
.len
);
519 cherokee_buffer_add (buffer
, hdl
->buffer
.buf
, tosend
);
520 cherokee_buffer_move_to_begin (&hdl
->buffer
, tosend
);
522 if (cherokee_buffer_is_empty (&hdl
->buffer
))
523 return ret_eof_have_data
;
529 cherokee_handler_virt_add_headers (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
531 cherokee_buffer_add_va (buffer
, "Content-Length: %d"CRLF
, hdl
->buffer
.len
);
533 if (hdl
->action
> xml
)
534 cherokee_buffer_add_str (buffer
, "Content-Type: application/xml"CRLF
);
535 else if (hdl
->action
> graph
) {
536 cherokee_buffer_add_str (buffer
, "Content-Type: image/png"CRLF
);
538 cherokee_buffer_add_str (buffer
, "Content-Type: text/plain"CRLF
);
545 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
546 virConnectPtr conn = NULL;
547 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
548 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
550 cherokee_buffer_add_va (&uri, "xen://%s/", value);
552 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
553 if (!(conn = virConnectOpen (uri.buf))) {
558 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
562 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
565 char *xml = virDomainGetXMLDesc(dom, 0);
566 cherokee_buffer_add(buf, xml, strlen(xml));
568 virConnectClose(conn);
571 cherokee_buffer_mrproper(&uri);
576 static ret_t
load_xml(cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*xmlDesc
) {
577 ret_t ret
= ret_error
;
579 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
580 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s", hdl
->user
.buf
);
582 mkdir(path
.buf
, 0755);
583 cherokee_buffer_add_va (&path
, "/%s", hdl
->vm
.buf
);
585 mkdir(path
.buf
, 0755);
586 cherokee_buffer_add_str (&path
, "/index.xml");
588 if ((fd
= fopen(path
.buf
, "r")) != NULL
) {
591 size_t amount
= fread(buf
, sizeof(char), 1024, fd
);
593 cherokee_buffer_add (xmlDesc
, buf
, amount
);
596 if (xmlDesc
->len
> 0)
600 cherokee_buffer_mrproper(&path
);
604 static ret_t
save_xml(cherokee_handler_virt_t
*hdl
, virDomainPtr result
, cherokee_buffer_t
*buf
) {
605 ret_t ret
= ret_error
;
607 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
608 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s", hdl
->user
.buf
);
610 mkdir(path
.buf
, 0755);
611 cherokee_buffer_add_va (&path
, "/%s", hdl
->vm
.buf
);
613 mkdir(path
.buf
, 0755);
614 cherokee_buffer_add_str (&path
, "/index.xml");
616 if ((fd
= fopen(path
.buf
, "w")) == NULL
) {
619 char *output
= virDomainGetXMLDesc(result
, VIR_DOMAIN_XML_INACTIVE
);
620 fwrite(output
, strlen(output
), sizeof(char), fd
);
623 cherokee_buffer_add(buf
, output
, strlen(output
));
627 cherokee_buffer_mrproper(&path
);
633 virt_virt_function(cherokee_handler_virt_t
*hdl
, virDomainPtr dom
, virConnectPtr virConn
) {
634 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
635 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
637 switch (hdl
->action
) {
638 /* Returns the status of a clone copy */
639 case storageVolCloneStatus_args
: {
643 cherokee_buffer_t queue
= CHEROKEE_BUF_INIT
;
645 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
646 if (unlikely(ret
< ret_ok
)) {
647 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
648 conn
->error_code
= http_bad_request
;
652 cherokee_buffer_add_va (&queue
, "/mnt/images/queue/%s_%s.queued", hdl
->user
.buf
, name
);
654 if (stat(queue
.buf
, &statbuf
) != 0) {
655 conn
->error_code
= http_not_found
;
660 if ((namelen
= readlink(queue
.buf
, hardlink
, 1023)) == -1) {
661 conn
->error_code
= http_internal_error
;
664 hardlink
[namelen
] = '\0';
665 if (stat(hardlink
, &statbuf
) != 0) {
666 conn
->error_code
= http_internal_error
;
669 struct stat statbuf2
;
670 cherokee_buffer_t busy
= CHEROKEE_BUF_INIT
;
671 cherokee_buffer_add_va (&busy
, "/mnt/images/queue/%s_%s.busy", hdl
->user
.buf
, name
);
672 if (stat(busy
.buf
, &statbuf2
) != 0) {
673 conn
->error_code
= http_internal_error
;
676 cherokee_buffer_add_va (buf
, "%f", (float)((float)statbuf2
.st_size
/ (float)statbuf
.st_size
));
679 cherokee_buffer_mrproper(&busy
);
684 cherokee_buffer_mrproper(&queue
);
689 /* Save the memory of a domain to a file and suspend the domain */
693 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
694 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/memory", hdl
->user
.buf
, hdl
->vm
.buf
);
695 if ((result
= virDomainSave(dom
, path
.buf
)) != 0) {
696 TRACE("virt", "Saving of %s/%s failed", hdl
->user
.buf
, hdl
->vm
.buf
);
697 conn
->error_code
= http_internal_error
;
700 cherokee_buffer_mrproper(&path
);
702 cherokee_buffer_add_long10(buf
, result
);
707 /* Restore the memory of a domain from a file and resume the domain */
708 case domainRestore
: {
711 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
712 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/memory", hdl
->user
.buf
, hdl
->vm
.buf
);
714 if (stat(path
.buf
, &statbuf
) == 0) {
716 if ((result
= virDomainRestore(virConn
, path
.buf
)) != 0) {
717 TRACE("virt", "Restoring of %s/%s failed", hdl
->user
.buf
, hdl
->vm
.buf
);
718 conn
->error_code
= http_internal_error
;
721 cherokee_buffer_add_long10(buf
, result
);
723 TRACE("virt", "Memory file for %s/%s does not exist", hdl
->user
.buf
, hdl
->vm
.buf
);
724 conn
->error_code
= http_not_found
;
728 cherokee_buffer_mrproper(&path
);
733 case domainUndefine
: {
735 if ((result
= virDomainUndefine(dom
)) != 0) {
736 conn
->error_code
= http_internal_error
; /* TODO */
739 cherokee_buffer_add_long10(buf
, result
);
743 case domainAttachDevice_args
: {
748 ret
= cherokee_avl_get_ptr (conn
->arguments
, "type", &temp
);
751 cherokee_buffer_t xml
= CHEROKEE_BUF_INIT
;
753 if (strcmp(temp
, "disk") == 0) {
755 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "device", &device
)) == ret_ok
) {
757 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "file", &file
)) == ret_ok
) {
758 cherokee_buffer_add_va (&xml
, VIRT_DISK_XML
, file
, device
);
760 virStorageVolPtr volume
= virt_get_vol_by_args(hdl
, virConn
, 1);
762 if (volume
== NULL
) {
766 file
= virStorageVolGetPath(volume
);
767 cherokee_buffer_add_va (&xml
, VIRT_DISK_XML
, file
, device
);
770 virStorageVolFree(volume
);
776 else if (strcmp(temp
, "interface") == 0) {
778 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "mac", &mac
)) == ret_ok
&& (ret
= cherokee_avl_get_ptr (conn
->arguments
, "ip", &ip
)) == ret_ok
) {
779 cherokee_buffer_add_va (&xml
, VIRT_INTERFACE_XML
, mac
, ip
);
783 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
784 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
785 if (getNewMac("dv28", domu
.buf
, &mac
, &ip
) == 0)
786 cherokee_buffer_add_va (&xml
, VIRT_INTERFACE_XML
, mac
, ip
);
787 cherokee_buffer_mrproper(&domu
);
791 if (ret
== ret_ok
&& (result
= virDomainAttachDevice(dom
, (const char *) xml
.buf
)) == 0) {
794 conn
->error_code
= http_internal_error
;
798 cherokee_buffer_add_long10(buf
, result
);
799 cherokee_buffer_mrproper(&xml
);
801 TRACE("virt", "DeviceAttach_args; type was not specified");
802 conn
->error_code
= http_bad_request
;
809 case domainAttachDevice
: {
812 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
813 cherokee_post_get_len (&conn
->post
, &postl
);
814 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
815 if ((result
= virDomainAttachDevice(dom
, (const char *) post
.buf
)) != 0)
816 conn
->error_code
= http_internal_error
;
818 cherokee_buffer_mrproper(&post
);
819 cherokee_buffer_add_long10(buf
, result
);
824 case domainGetXMLDesc
: {
825 char *xml
= virDomainGetXMLDesc(dom
, 0);
826 cherokee_buffer_add(buf
, xml
, strlen(xml
));
832 case domainDetachDevice
: {
836 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
837 cherokee_post_get_len (&conn
->post
, &postl
);
838 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
840 xmlDocPtr doc
= xmlParseMemory((const char *) post
.buf
, post
.len
);
842 TRACE("virt", "DeviceAttach; XML document unparceble");
843 conn
->error_code
= http_bad_request
;
849 if ((result
= virDomainDetachDevice(dom
, (const char *) post
.buf
)) != 0) {
850 conn
->error_code
= http_internal_error
;
851 /* TODO: betere afhandeling */
853 xmlXPathContextPtr context
= xmlXPathNewContext(doc
);
854 if (context
!= NULL
) {
855 xmlXPathObjectPtr obj
= xmlXPathEval("string(//interface/mac/@address)", context
);
856 xmlXPathFreeContext(context
);
857 if ((obj
!= NULL
) && (obj
->type
== XPATH_STRING
) &&
858 (obj
->stringval
!= NULL
) && (obj
->stringval
[0] != 0)) {
859 removeOldMac("dv28", (char *) obj
->stringval
);
861 xmlXPathFreeObject(obj
);
868 cherokee_buffer_mrproper(&post
);
869 cherokee_buffer_add_long10(buf
, result
);
874 cherokee_buffer_add_ulong10(buf
, virDomainGetID(dom
));
877 case domainGetMaxMemory
: {
878 cherokee_buffer_add_ulong10(buf
, virDomainGetMaxMemory (dom
));
881 case domainGetMaxVcpus
: {
882 cherokee_buffer_add_long10(buf
, virDomainGetMaxVcpus (dom
));
885 case domainGetName
: {
886 const char *name
= virDomainGetName (dom
);
887 cherokee_buffer_add(buf
, name
, strlen(name
));
890 case domainGetUUID
: {
891 unsigned char uuid
[VIR_UUID_BUFLEN
];
892 if (virDomainGetUUID(dom
, uuid
) == 0) {
893 cherokee_buffer_add_str(buf
, uuid
);
895 conn
->error_code
= http_internal_error
;
900 case domainGetUUIDString
: {
901 unsigned char uuid
[VIR_UUID_STRING_BUFLEN
];
902 if (virDomainGetUUIDString(dom
, uuid
) == 0) {
903 cherokee_buffer_add_str(buf
, uuid
);
905 conn
->error_code
= http_internal_error
;
912 cherokee_buffer_t xmlDesc
= CHEROKEE_BUF_INIT
;
914 save_xml(hdl
, dom
, &xmlDesc
);
915 tender_t best_tender
;
916 snprintf(txt
, 254, "memory=%lu", virDomainGetMaxMemory(dom
));
919 best_tender
.name
= virDomainGetName(dom
);
920 best_tender
.cost
= FLT_MAX
;
921 best_tender
.dom
= NULL
;
923 AvahiServiceBrowser
*sb
= avahi_service_browser_new(HDL_AVAHI_PROPS(hdl
)->client
, AVAHI_IF_UNSPEC
,
924 AVAHI_PROTO_UNSPEC
, "_tender._tcp",
925 NULL
, 0, tender_browse_callback
, &best_tender
);
928 TRACE("avahi", "For whatever reason the sb is NULL\n");
931 AvahiEntryGroup
*group
= avahi_entry_group_new(HDL_AVAHI_PROPS(hdl
)->client
, entry_group_callback
, NULL
);
934 TRACE("avahi", "For whatever reason the group is NULL\n");
936 avahi_entry_group_add_service(group
, AVAHI_IF_UNSPEC
, AVAHI_PROTO_UNSPEC
, 0,
937 best_tender
.name
, "_offer._tcp", NULL
, NULL
, 651, txt
, NULL
, NULL
);
938 avahi_entry_group_commit(group
);
940 sleep(3); /* we are for quick bidding ;) */
942 avahi_entry_group_free(group
);
945 avahi_service_browser_free(sb
);
947 if (best_tender
.dom
== NULL
) {
948 TRACE("virt", "Nobody wants %s, poor vm!\n", best_tender
.name
);
949 cherokee_buffer_add_long10(buf
, -1);
951 if (virDomainUndefine(dom
) != 0) {
952 TRACE("virt", "Can't undefine %s, some idiot run it already?\n", best_tender
.name
);
953 cherokee_buffer_add_long10(buf
, -1);
955 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
956 virConnectClose(virConn
);
957 cherokee_buffer_add_va (&uri
, "xen://%s/", best_tender
.dom
);
958 virConn
= virConnectOpen (uri
.buf
);
959 if (virConn
== NULL
) {
960 TRACE("virt", "Can't connect to %s\n", uri
.buf
);
961 cherokee_buffer_add_long10(buf
, -1);
963 cherokee_buffer_add_long10(buf
,
964 (virDomainCreateLinux(virConn
, xmlDesc
.buf
, 0) != NULL
?
967 cherokee_buffer_mrproper(&uri
);
969 TRACE("virt", "going to free\n");
970 free(best_tender
.dom
);
975 cherokee_buffer_mrproper(&xmlDesc
);
979 case domainDestroy
: {
980 cherokee_buffer_add_long10(buf
, virDomainDestroy (dom
));
985 cherokee_buffer_add_long10(buf
, virDomainReboot (dom
, 0));
989 case domainShutdown
: {
990 cherokee_buffer_add_long10(buf
, virDomainShutdown (dom
));
995 case domainGetOSType
: {
996 char *ostype
= virDomainGetOSType(dom
);
997 cherokee_buffer_add(buf
, ostype
, strlen(ostype
));
1006 if (hdl
->action
== domainUndefine
) {
1007 /* Remove VM data from filesystem */
1008 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
1009 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/index.xml", hdl
->user
.buf
, hdl
->vm
.buf
);
1010 unlink(path
.buf
); /* TODO: instead of delet replace */
1011 cherokee_buffer_mrproper(&path
);
1012 } else if (hdl
->action
!= domainCreate
) {
1013 save_xml(hdl
, dom
, NULL
);
1019 static virStoragePoolPtr
1020 virt_get_pool_by_args(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
1021 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1022 virStoragePoolPtr pool
;
1026 ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &temp
);
1027 if (unlikely(ret
< ret_ok
)) {
1028 TRACE("virt", "virStoragePoolPtr; Pool argument not specified");
1029 conn
->error_code
= http_bad_request
;
1033 pool
= virStoragePoolLookupByName(virConn
, temp
);
1038 static virStorageVolPtr
1039 virt_get_vol_by_args(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
, unsigned short int prefix
) {
1040 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1041 virStoragePoolPtr pool
;
1042 virStorageVolPtr volume
;
1046 pool
= virt_get_pool_by_args(hdl
, virConn
);
1049 conn
->error_code
= http_not_found
;
1053 virStoragePoolRefresh(pool
, 0); /* TODO: might be better to do it outside */
1055 ret
= cherokee_avl_get_ptr (conn
->arguments
, "volume", &temp
);
1056 if (unlikely(ret
< ret_ok
)) {
1057 TRACE("virt", "virStorageVolPtr; Volume argument not specified");
1058 conn
->error_code
= http_bad_request
;
1063 cherokee_buffer_t fullvol
= CHEROKEE_BUF_INIT
;
1064 cherokee_buffer_add_va (&fullvol
, "%s_%s", hdl
->user
.buf
, temp
);
1065 volume
= virStorageVolLookupByName(pool
, fullvol
.buf
);
1066 cherokee_buffer_mrproper(&fullvol
);
1068 volume
= virStorageVolLookupByName(pool
, temp
);
1072 conn
->error_code
= http_not_found
;
1074 virStoragePoolFree(pool
);
1079 /* This function is the home for all functions that need a working
1080 * pool/volume combination */
1082 virt_pool_vol(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
1083 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
1084 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1085 virStorageVolPtr volume
;
1088 /* We only allow clone to run 'unsafe', others get prefixed */
1089 volume
= virt_get_vol_by_args(hdl
, virConn
, (hdl
->action
!= storageVolCloneXML_args
));
1091 /* If the volume doesn't exist, no point to continue */
1095 switch (hdl
->action
) {
1096 /* Sets the password of a specific volume, requires the password= option */
1097 case storageVolSetPassword_args
: {
1099 ret
= cherokee_avl_get_ptr (conn
->arguments
, "password", &temp
);
1100 if (unlikely(ret
< ret_ok
)) {
1101 TRACE("virt", "storageVolSetPassword_args; password argument not specified");
1102 conn
->error_code
= http_bad_request
;
1103 goto virt_pool_vol_cleanup
;
1105 cherokee_buffer_t cmd_passwd
= CHEROKEE_BUF_INIT
;
1106 cherokee_buffer_add_va (&cmd_passwd
, "/usr/sbin/passwdchanger.sh %s %s\n", virStorageVolGetKey(volume
), temp
);
1107 cherokee_buffer_add_long10(buf
, system(cmd_passwd
.buf
));
1108 cherokee_buffer_mrproper(&cmd_passwd
);
1113 /* Removes a volume */
1114 case storageVolDelete_args
: {
1115 cherokee_buffer_add_long10(buf
, virStorageVolDelete(volume
, 0));
1119 /* Gives a description of a storage volume in XML */
1120 case storageVolGetXMLDesc_args
: {
1121 char *xml
= virStorageVolGetXMLDesc(volume
, 0);
1122 cherokee_buffer_add(buf
, xml
, strlen(xml
));
1127 /* Clones a volume, insecure method! requires a new name= */
1128 case storageVolCloneXML_args
: {
1130 cherokee_buffer_t busy
= CHEROKEE_BUF_INIT
;
1132 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
1133 if (unlikely(ret
< ret_ok
)) {
1134 TRACE("virt", "storageVolCloneXML_args; name argument not specified");
1135 conn
->error_code
= http_bad_request
;
1136 goto virt_pool_vol_cleanup
;
1139 cherokee_buffer_add_va (&busy
, "/mnt/images/queue/%s_%s.queued", hdl
->user
.buf
, name
);
1141 if (unlikely(symlink(virStorageVolGetKey(volume
), busy
.buf
) == 1)) {
1142 conn
->error_code
= http_internal_error
;
1145 cherokee_buffer_add_str(buf
, "QUEUED");
1148 cherokee_buffer_mrproper(&busy
);
1155 virt_pool_vol_cleanup
:
1156 /* And in the end we need to free the volume we have used */
1157 virStorageVolFree(volume
);
1163 virt_virt_new(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
1164 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
1165 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1166 cherokee_buffer_t xml
= CHEROKEE_BUF_INIT
;
1167 virStoragePoolPtr pool
= NULL
;
1170 switch (hdl
->action
) {
1172 case storageVolCreateXML_args
: {
1173 void *temp
, *type
, *name
, *unit
;
1174 unsigned long int capacity
, allocation
;
1176 ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &temp
);
1177 if (unlikely(ret
< ret_ok
)) {
1178 TRACE("virt", "storageVolCreateXML_args; pool argument not specified");
1179 conn
->error_code
= http_bad_request
;
1180 goto virt_virt_new_cleanup
;
1183 TRACE("args", "%s", temp
);
1185 pool
= virStoragePoolLookupByName(virConn
, temp
);
1188 conn
->error_code
= http_not_found
;
1189 goto virt_virt_new_cleanup
;
1192 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
1193 if (unlikely(ret
< ret_ok
)) {
1194 TRACE("virt", "storageVolCreateXML_args; name argument not specified");
1195 conn
->error_code
= http_bad_request
;
1196 goto virt_virt_new_cleanup
;
1199 ret
= cherokee_avl_get_ptr (conn
->arguments
, "type", &type
);
1200 if (unlikely(ret
< ret_ok
)) {
1201 TRACE("virt", "storageVolCreateXML_args; type argument not specified");
1202 conn
->error_code
= http_bad_request
;
1203 goto virt_virt_new_cleanup
;
1206 ret
= cherokee_avl_get_ptr (conn
->arguments
, "unit", &unit
);
1207 if (unlikely(ret
< ret_ok
)) {
1208 TRACE("virt", "storageVolCreateXML_args; unit argument not specified");
1209 conn
->error_code
= http_bad_request
;
1210 goto virt_virt_new_cleanup
;
1213 ret
= cherokee_avl_get_ptr (conn
->arguments
, "allocation", &temp
);
1214 if (unlikely(ret
< ret_ok
)) {
1215 TRACE("virt", "storageVolCreateXML_args; allocation argument not specified");
1216 conn
->error_code
= http_bad_request
;
1217 goto virt_virt_new_cleanup
;
1220 allocation
= strtoul(temp
, NULL
, 10);
1221 if (errno
== ERANGE
) {
1222 TRACE("virt", "storageVolCreateXML_args; allocation is not a number");
1223 conn
->error_code
= http_bad_request
;
1225 goto virt_virt_new_cleanup
;
1228 ret
= cherokee_avl_get_ptr (conn
->arguments
, "capacity", &temp
);
1229 if (unlikely(ret
< ret_ok
)) {
1230 TRACE("virt", "storageVolCreateXML_args; capacity argument not specified");
1231 conn
->error_code
= http_bad_request
;
1232 goto virt_virt_new_cleanup
;
1235 capacity
= strtoul(temp
, NULL
, 10);
1236 if (errno
== ERANGE
|| capacity
== 0) {
1237 TRACE("virt", "storageVolCreateXML_args; capacity is not a number");
1238 conn
->error_code
= http_bad_request
;
1240 goto virt_virt_new_cleanup
;
1243 cherokee_buffer_add_va (&xml
, VIRT_STORAGE_XML
, type
, hdl
->user
.buf
, name
, allocation
, unit
, capacity
, hdl
->user
.buf
, name
, hdl
->user
.buf
, name
);
1247 case domainDefineXML_args
: {
1250 unsigned long vcpu
= 0, interface
= 0, memory
= 0;
1254 ret
= cherokee_avl_get_ptr (conn
->arguments
, "vcpu", &temp
);
1256 vcpu
= strtoul(temp
, (char **) NULL
, 10);
1258 if (ret
!= ret_ok
|| errno
== ERANGE
|| vcpu
== 0) {
1259 conn
->error_code
= http_internal_error
;
1260 goto virt_virt_new_cleanup
;
1264 ret
= cherokee_avl_get_ptr (conn
->arguments
, "memory", &temp
);
1266 memory
= strtoul(temp
, (char **) NULL
, 10);
1268 if (ret
!= ret_ok
|| errno
== ERANGE
|| memory
== 0) {
1269 conn
->error_code
= http_internal_error
;
1270 goto virt_virt_new_cleanup
;
1274 ret
= cherokee_avl_get_ptr (conn
->arguments
, "interface", &temp
);
1276 interface
= strtoul(temp
, (char **) NULL
, 10);
1278 if (ret
!= ret_ok
|| errno
== ERANGE
) {
1279 conn
->error_code
= http_internal_error
;
1280 goto virt_virt_new_cleanup
;
1283 cherokee_buffer_t cmdline_extra
= CHEROKEE_BUF_INIT
;
1284 cherokee_buffer_t xml_interfaces
= CHEROKEE_BUF_INIT
;
1285 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
1286 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
1288 for (i
= 0; i
< interface
; i
++) {
1291 if (getNewMac("dv28", domu
.buf
, &mac
, &ip
) == 0) {
1292 cherokee_buffer_add_va (&xml_interfaces
, VIRT_INTERFACE_XML
, mac
, ip
);
1294 /* TODO: terrible hack */
1297 strcpy(gateway
, ip
);
1298 temp
= strchr(gateway
, '.');
1299 temp
= strchr(++temp
, '.');
1300 temp
= strchr(++temp
, '.');
1301 strcpy(++temp
, "254");
1302 cherokee_buffer_add_va (&cmdline_extra
, VIRT_DOMAIN_CMD_IP
, ip
, gateway
);
1307 cherokee_buffer_mrproper(&domu
);
1309 cherokee_buffer_add_va (&xml
, VIRT_DOMAIN_XML
,
1310 hdl
->user
.buf
, hdl
->vm
.buf
, cmdline_extra
.buf
, memory
, vcpu
, xml_interfaces
.buf
);
1312 cherokee_buffer_mrproper(&xml_interfaces
);
1313 cherokee_buffer_mrproper(&cmdline_extra
);
1317 case storageVolCreateXML
:
1318 case domainDefineXML
: {
1320 cherokee_post_get_len (&conn
->post
, &postl
);
1321 cherokee_post_walk_read (&conn
->post
, &xml
, (cuint_t
) postl
);
1326 switch (hdl
->action
) {
1327 case domainDefineXML_args
:
1328 case domainDefineXML
: {
1329 virDomainPtr result
= virDomainDefineXML(virConn
, (const char *) xml
.buf
);
1331 if (result
== NULL
) {
1332 /* TODO: vrij maken eventuele uitgegeven macs! */
1333 conn
->error_code
= http_internal_error
;
1334 goto virt_virt_new_cleanup
;
1337 save_xml(hdl
, result
, buf
);
1339 virDomainFree(result
);
1344 case storageVolCreateXML_args
:
1345 case storageVolCreateXML
: {
1346 virStorageVolPtr vol
= virStorageVolCreateXML(pool
, xml
.buf
, 0);
1349 cherokee_buffer_add_long10(buf
, -1);
1350 goto virt_virt_new_cleanup
;
1353 virStorageVolFree(vol
);
1355 cherokee_buffer_add_long10(buf
, 0);
1360 virt_virt_new_cleanup
:
1361 cherokee_buffer_mrproper(&xml
);
1364 virStoragePoolFree(pool
);
1371 virt_virt_do(cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*domu
, cherokee_buffer_t
*uri
)
1373 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1375 ret_t ret
= ret_error
;
1376 virConnectPtr virConn
= NULL
;
1379 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
1380 virConn
= virConnectOpen (uri
->buf
);
1382 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
->buf
))) {
1383 conn
->error_code
= http_service_unavailable
;
1387 switch (hdl
->action
) {
1388 case storageVolDelete_args
:
1389 case storageVolSetPassword_args
:
1390 case storageVolGetXMLDesc_args
:
1391 case storageVolCloneXML_args
:
1392 ret
= virt_pool_vol(hdl
, virConn
);
1395 case storageVolCreateXML_args
:
1396 case storageVolCreateXML
:
1397 case domainDefineXML_args
:
1398 case domainDefineXML
:
1399 ret
= virt_virt_new(hdl
, virConn
);
1404 if ((dom
= virDomainLookupByName(virConn
, domu
->buf
)) == NULL
) {
1405 conn
->error_code
= http_not_found
;
1407 ret
= virt_virt_function(hdl
, dom
, virConn
);
1413 virConnectClose(virConn
);
1418 virt_while (cherokee_buffer_t
*key
, void *value
, void *param
) {
1419 cherokee_handler_virt_t
* hdl
= param
;
1420 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1421 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1422 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1423 // cherokee_buffer_mrproper(&uri);
1425 cherokee_buffer_add_va (&hdl
->buffer
, "<domain><name>%s</name></domain>", key
->buf
);
1431 virt_while_user (cherokee_buffer_t
*key
, void *value
, void *param
) {
1432 cherokee_handler_virt_t
*hdl
= param
;
1433 if (key
->len
> hdl
->user
.len
&& key
->buf
[hdl
->user
.len
] == '_' && strncmp(key
->buf
, hdl
->user
.buf
, hdl
->user
.len
) == 0)
1434 return virt_while (key
, value
, param
);
1440 virt_build_page (cherokee_handler_virt_t
*hdl
)
1443 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1444 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
1445 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
1447 /* We use the webserver methods to parse the querystring */
1448 /* Maybe do something smart with ENUM, begin_args, end_args... */
1449 if ((hdl
->action
== domainDefineXML_args
) ||
1450 (hdl
->action
== domainAttachDevice_args
) ||
1451 (hdl
->action
== storageVolGetXMLDesc_args
) ||
1452 (hdl
->action
== storageVolDelete_args
) ||
1453 (hdl
->action
== storageVolSetPassword_args
) ||
1454 (hdl
->action
== storageVolCloneXML_args
) ||
1455 (hdl
->action
== storageVolCloneStatus_args
) ||
1456 (hdl
->action
== storageVolCreateXML_args
) ||
1457 (hdl
->action
== graphLoad_args
) ||
1458 (hdl
->action
== graphInterface_args
)) {
1459 ret
= cherokee_connection_parse_args (conn
);
1460 if (unlikely(ret
< ret_ok
)) {
1461 conn
->error_code
= http_internal_error
;
1466 switch (hdl
->action
) {
1467 case graphInterface_args
: {
1468 struct stat statbuf
;
1469 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
1471 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "interface", &interface
)) != ret_ok
)
1474 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/interface_%s.rrd", hdl
->user
.buf
, hdl
->vm
.buf
, interface
);
1475 if (stat(path
.buf
, &statbuf
) != 0) {
1476 conn
->error_code
= http_not_found
;
1479 void *width
, *height
, *start
, *end
;
1480 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "width", &width
)) != ret_ok
)
1483 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "height", &height
)) != ret_ok
)
1486 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "start", &start
)) != ret_ok
)
1489 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "end", &end
)) != ret_ok
)
1492 cherokee_buffer_t def1
= CHEROKEE_BUF_INIT
;
1493 cherokee_buffer_t def2
= CHEROKEE_BUF_INIT
;
1494 cherokee_buffer_add_va (&def1
, "DEF:rxbytes=%s:rxbytes:AVERAGE:step=30", path
.buf
);
1495 cherokee_buffer_add_va (&def2
, "DEF:txbytes=%s:txbytes:AVERAGE:step=30", path
.buf
);
1496 char **calcpr
= NULL
;
1499 char *filename
= mktemp(strdup("handler_virt_XXXXXX"));
1500 char *r_graph
[] = { "rrdgraph", filename
,
1506 "--title", interface
,
1507 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "bits per second",
1510 "CDEF:txbits=txbytes,8,*",
1511 "CDEF:rxbits=rxbytes,8,*",
1512 "AREA:rxbits#00EE00:rxbits",
1513 "LINE:txbits#0000EE:txbits" };
1515 rrd_graph(25, r_graph
, &calcpr
, &xsize
, &ysize
, NULL
, &ymin
, &ymax
);
1516 if ((ret
= cherokee_buffer_read_file(&hdl
->buffer
, filename
)) == ret_error
) {
1517 hdl
->action
= http_internal_error
;
1523 cherokee_buffer_mrproper(&def1
);
1524 cherokee_buffer_mrproper(&def2
);
1526 cherokee_buffer_mrproper(&path
);
1527 goto virt_build_page_cleanup
;
1532 case graphLoad_args
: {
1533 struct stat statbuf
;
1534 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
1535 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/cpuTime.rrd", hdl
->user
.buf
, hdl
->vm
.buf
);
1536 if (stat(path
.buf
, &statbuf
) != 0) {
1537 conn
->error_code
= http_not_found
;
1540 void *width
, *height
, *start
, *end
;
1541 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "width", &width
)) != ret_ok
)
1544 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "height", &height
)) != ret_ok
)
1547 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "start", &start
)) != ret_ok
)
1550 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "end", &end
)) != ret_ok
)
1553 /* TODO: wat error checking? */
1555 cherokee_buffer_t def
= CHEROKEE_BUF_INIT
;
1556 cherokee_buffer_add_va (&def
, "DEF:cputime=%s:cpuTime:AVERAGE:step=30", path
.buf
);
1557 char **calcpr
= NULL
;
1560 char *filename
= mktemp(strdup("handler_virt_XXXXXX"));
1561 char *r_graph
[] = { "rrdgraph",
1568 "--title", hdl
->vm
.buf
,
1569 "--lower-limit", "0", "--alt-autoscale-max", "--vertical-label", "(used / total) time",
1571 "CDEF:cpuload=cputime,1000000000,/",
1572 "LINE:cpuload#EE0000:cpuLoad" };
1574 rrd_graph(22, r_graph
, &calcpr
, &xsize
, &ysize
, NULL
, &ymin
, &ymax
);
1575 if ((ret
= cherokee_buffer_read_file(&hdl
->buffer
, filename
)) == ret_error
) {
1576 hdl
->action
= http_internal_error
;
1582 cherokee_buffer_mrproper(&def
);
1584 cherokee_buffer_mrproper(&path
);
1585 goto virt_build_page_cleanup
;
1589 if (hdl
->action
> xml
&& HDL_VIRT_PROPS(hdl
)->xsl
.len
> 0)
1590 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
);
1593 switch (hdl
->action
) {
1595 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>");
1596 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
1597 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl
)->entries
, virt_while
, hdl
, NULL
, NULL
);
1598 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
1599 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
1604 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>");
1605 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
1606 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl
)->entries
, virt_while_user
, hdl
, NULL
, NULL
);
1607 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
1608 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
1614 cherokee_buffer_t
*hostname
= NULL
;
1615 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
1617 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
1618 ret
= cherokee_avl_get_ptr(&HDL_AVAHI_PROPS(hdl
)->entries
, domu
.buf
, (void **) &hostname
);
1619 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
1621 if (ret
== ret_not_found
) {
1622 virDomainPtr virDom
;
1623 virConnectPtr virConn
;
1624 cherokee_buffer_add_va (&uri
, "xen://%s/", HDL_VIRT_PROPS(hdl
)->virt
); // TODO: change!
1626 /* If we have the read only parameter, we will set up a connection to the
1627 * Hypervisor here. */
1628 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
1629 virConn
= virConnectOpen (uri
.buf
);
1631 /* We should already have a connection (read only) or build a new connection
1632 * if this doesn't work, we can safely assume our services is fubar */
1633 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
.buf
))) {
1634 conn
->error_code
= http_service_unavailable
;
1638 /* We lookup if there is a domain somewhere with this name */
1639 if ((virDom
= virDomainLookupByName(virConn
, domu
.buf
)) == NULL
) {
1640 /* If the domain is not found on the network the only possible
1641 * command that is possible would be to Define it */
1642 if (hdl
->action
== domainDefineXML_args
|| hdl
->action
== domainDefineXML
) {
1645 /* We should also look on disk for defined stuff */
1646 cherokee_buffer_t xmlDesc
= CHEROKEE_BUF_INIT
;
1647 if (load_xml(hdl
, &xmlDesc
) == ret_ok
&& (virDom
= virDomainDefineXML(virConn
, xmlDesc
.buf
)) != NULL
) {
1648 /* The domain existed and is loaded! */
1651 /* Otherwise we don't have anything to do and we should
1652 * return an error */
1653 hdl
->action
= nothing
;
1654 conn
->error_code
= http_not_found
;
1658 cherokee_buffer_mrproper(&xmlDesc
);
1661 /* We don't want te recreate things that already found on the network
1662 * first undefine them! */
1663 if (hdl
->action
== domainDefineXML_args
|| hdl
->action
== domainDefineXML
) {
1664 TRACE("virt", "domainDefineXML_args/domainDefineXML; domain already exists");
1665 hdl
->action
= nothing
;
1666 conn
->error_code
= http_bad_request
;
1669 /* Everything is ok, because nothing is found. */
1673 /* Domain wasn't NULL, so we should free it here */
1674 virDomainFree(virDom
);
1676 virConnectClose (virConn
);
1677 } else if (ret
== ret_ok
) {
1678 cherokee_buffer_add_va (&uri
, "xen://%s/", hostname
->buf
);
1679 printf("%s\n", uri
.buf
);
1681 hdl
->action
= http_internal_error
;
1682 hdl
->action
= nothing
;
1689 if (ret
== ret_ok
&& hdl
->action
!= showall
&& hdl
->action
!= showuservms
) {
1690 ret
= virt_virt_do(hdl
, &domu
, &uri
);
1693 virt_build_page_cleanup
:
1694 cherokee_buffer_mrproper(&domu
);
1695 cherokee_buffer_mrproper(&uri
);
1702 cherokee_handler_virt_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
1705 CHEROKEE_NEW_STRUCT (n
, handler_virt
);
1707 /* Init the base class
1710 cherokee_handler_init_base(HANDLER(n
), cnt
, HANDLER_PROPS(props
), PLUGIN_INFO_HANDLER_PTR(virt
));
1712 MODULE(n
)->init
= (handler_func_init_t
) cherokee_handler_virt_init
;
1713 MODULE(n
)->free
= (module_func_free_t
) cherokee_handler_virt_free
;
1714 HANDLER(n
)->step
= (handler_func_step_t
) cherokee_handler_virt_step
;
1715 HANDLER(n
)->add_headers
= (handler_func_add_headers_t
) cherokee_handler_virt_add_headers
;
1717 HANDLER(n
)->support
= hsupport_length
| hsupport_range
;
1719 ret
= cherokee_buffer_init (&n
->buffer
);
1720 if (unlikely(ret
!= ret_ok
))
1723 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
1724 if (unlikely(ret
!= ret_ok
))