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 " <target dev='vif1.0' />" \
31 " <source bridge='xenbr0'/>" \
32 " <mac address='%s'/>" \
33 " <ip address='%s' />" \
34 " <script path='vif-bridge'/>" \
37 //" <target dev='vif1.0'/>" \
39 #define VIRT_DISK_XML \
40 " <disk type='file' device='disk'>" \
41 " <driver name='tap' type='aio' />" \
42 " <source file='%s'/>" \
43 " <target dev='%s' bus='xen'/>" \
48 #define VIRT_DOMAIN_XML \
49 "<domain type='xen'>" \
50 " <name>%s_%s</name>" \
52 " <type>linux</type>" \
53 " <kernel>/usr/lib/xen/boot/linux-2.6.20-xen-r6</kernel>" \
54 " <cmdline> root=/dev/xvda ro</cmdline>" \
56 " <memory>%d</memory>" \
58 " <on_poweroff>destroy</on_poweroff>" \
59 " <on_reboot>restart</on_reboot>" \
60 " <on_crash>destroy</on_crash>" \
66 #define VIRT_STORAGE_XML \
67 "<volume type='%s'>" \
68 " <name>%s_%s</name>" \
69 " <allocation>%lu</allocation>" \
70 " <capacity unit='%s'>%lu</capacity>" \
72 " <path>%s_%s</path>" \
74 " <owner>0744</owner>" \
75 " <group>0744</group>" \
76 " <mode>0744</mode>" \
77 " <label>%s_%s</label>" \
83 #include "handler_virt.h"
84 #include "handler_avahi.h"
85 #include <cherokee/cherokee.h>
86 #include <libxml/parser.h>
87 #include <libxml/xpath.h>
90 /* Plug-in initialization
92 * In this function you can use any of these:
93 * http_delete | http_get | http_post | http_put
95 * For a full list: cherokee_http_method_t
97 * It is what your handler to be implements.
100 PLUGIN_INFO_HANDLER_EASIEST_INIT (virt
, http_get
| http_post
);
103 /* Methods implementation
106 props_free (cherokee_handler_virt_props_t
*props
)
109 cherokee_buffer_mrproper(&props
->xsl
);
110 cherokee_buffer_mrproper(&props
->virt
);
111 return cherokee_module_props_free_base (MODULE_PROPS(props
));
116 cherokee_handler_virt_configure (cherokee_config_node_t
*conf
, cherokee_server_t
*srv
, cherokee_module_props_t
**_props
)
119 cherokee_handler_virt_props_t
*props
;
121 /* Instance a new property object
124 if (*_props
== NULL
) {
125 CHEROKEE_NEW_STRUCT (n
, handler_virt_props
);
127 cherokee_handler_avahi_props_init_base (PROP_AVAHI(n
), MODULE_PROPS_FREE(props_free
));
129 /* Look at handler_virt.h
130 * This is an virt of configuration.
132 n
->authenticate
= true; /* by default we are secure! */
133 n
->read_only
= true; /* by default we are secure! */
134 cherokee_buffer_init (&n
->xsl
); /* we support a custom header */
135 cherokee_buffer_init (&n
->virt
); /* your first xenserver */
137 *_props
= MODULE_PROPS(n
);
140 props
= PROP_VIRT(*_props
);
142 cherokee_config_node_foreach (i
, conf
) {
143 cherokee_config_node_t
*subconf
= CONFIG_NODE(i
);
145 if (equal_buf_str (&subconf
->key
, "authenticate")) {
146 props
->authenticate
= atoi(subconf
->val
.buf
);
148 else if (equal_buf_str (&subconf
->key
, "read_only")) {
149 props
->read_only
= atoi(subconf
->val
.buf
);
151 else if (equal_buf_str (&subconf
->key
, "xsl")) {
152 cherokee_buffer_add_buffer (&props
->xsl
, &subconf
->val
);
154 else if (equal_buf_str (&subconf
->key
, "virt")) {
155 cherokee_buffer_add_buffer (&props
->virt
, &subconf
->val
);
163 return cherokee_handler_avahi_configure (conf
, srv
, _props
);
168 cherokee_handler_virt_init (cherokee_handler_virt_t
*hdl
)
174 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
175 cherokee_buffer_init(&hdl
->user
);
176 cherokee_buffer_init(&hdl
->vm
);
178 hdl
->action
= nothing
;
180 cherokee_buffer_add (&conn
->pathinfo
,
181 conn
->request
.buf
+ conn
->web_directory
.len
,
182 conn
->request
.len
- conn
->web_directory
.len
);
184 this = conn
->pathinfo
.buf
+ 1;
185 next
= strchr(this, '/');
188 if ((!next
&& (this && (len
= strlen(this)) == 0)) || (next
&& ((len
= next
- this) == 0)) )
189 hdl
->action
= showall
;
191 cherokee_buffer_add (&hdl
->user
, this, len
);
194 if (HDL_VIRT_PROPS(hdl
)->authenticate
) {
195 if (!conn
->validator
||
197 (!cherokee_buffer_cmp_buf(&conn
->validator
->user
, &hdl
->user
) &&
198 !(isroot
= cherokee_buffer_cmp (&conn
->validator
->user
, "root", 4))))) {
199 hdl
->action
= nothing
; /* just in case */
200 conn
->error_code
= http_unauthorized
;
207 if (hdl
->action
== showall
) {
209 hdl
->action
= nothing
;
210 conn
->error_code
= http_unauthorized
;
213 return virt_build_page(hdl
);
219 hdl
->action
= showuservms
;
220 return virt_build_page(hdl
);
223 next
= strchr(this, '/');
225 if (!next
&& (this && ( (len
= strlen(this)) == 0) || (next
&& ((len
= next
- this) == 0)) ) ) {
226 hdl
->action
= showuservms
;
227 return virt_build_page(hdl
);
231 cherokee_buffer_add (&hdl
->vm
, this, len
);
234 hdl
->action
= domainGetXMLDesc
;
235 return virt_build_page(hdl
);
238 next
= strchr(this, '/');
240 if (!next
&& (this && (len
= strlen(this)) == 0) || (next
&& ((len
= next
- this) == 0)) ) {
241 hdl
->action
= domainGetXMLDesc
;
242 return virt_build_page(hdl
);
246 /* TODO: it would be nice to filter read_only methods already on this point */
247 hdl
->action
= not_implemented
;
248 switch (conn
->header
.method
) {
250 if (strncmp(this, "virDomain", 9) == 0) {
251 if (strncmp(this+9, "Get", 3) == 0) {
252 if (strcmp(this+12, "ID") == 0) hdl
->action
= domainGetID
;
253 else if (strcmp(this+12, "Name") == 0) hdl
->action
= domainGetName
;
254 else if (strcmp(this+12, "MaxMemory") == 0) hdl
->action
= domainGetMaxMemory
;
255 else if (strcmp(this+12, "MaxVcpus") == 0) hdl
->action
= domainGetMaxVcpus
;
256 else if (strcmp(this+12, "OSType") == 0) hdl
->action
= domainGetOSType
;
257 else if (strcmp(this+12, "UUID") == 0) hdl
->action
= domainGetUUID
;
258 else if (strcmp(this+12, "UUIDString") == 0) hdl
->action
= domainGetUUIDString
;
259 else if (strcmp(this+12, "XMLDesc") == 0) hdl
->action
= domainGetXMLDesc
;
261 else if (strcmp(this+9, "Create") == 0) hdl
->action
= domainCreate
;
262 else if (strcmp(this+9, "Destroy") == 0) hdl
->action
= domainDestroy
;
263 else if (strcmp(this+9, "Reboot") == 0) hdl
->action
= domainReboot
;
264 else if (strcmp(this+9, "Shutdown") == 0) hdl
->action
= domainShutdown
;
266 else if (strcmp(this+9, "Save") == 0) hdl
->action
= domainSave_args
;
267 else if (strcmp(this+9, "Restore") == 0) hdl
->action
= domainRestore_args
;
269 else if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice_args
;
271 else if (strcmp(this+9, "DefineXML") == 0) hdl
->action
= domainDefineXML_args
;
272 else if (strcmp(this+9, "Undefine") == 0) hdl
->action
= domainUndefine
;
274 else if (strncmp(this, "virStorage", 10) == 0) {
275 if (strncmp(this+10, "Vol", 3) == 0) {
276 if (strcmp(this+13, "CreateXML") == 0) hdl
->action
= storageVolCreateXML_args
;
277 else if (strcmp(this+13, "Delete") == 0) hdl
->action
= storageVolDelete_args
;
278 else if (strcmp(this+13, "CloneXML") == 0) hdl
->action
= storageVolCloneXML_args
;
279 else if (strcmp(this+13, "GetXMLDesc") == 0) hdl
->action
= storageVolGetXMLDesc_args
;
280 else if (strcmp(this+13, "SetPassword") == 0) hdl
->action
= storageVolSetPassword_args
;
287 cherokee_post_get_len (&conn
->post
, &postl
);
289 if (postl
<= 0 || postl
>= (INT_MAX
-1)) {
290 conn
->error_code
= http_bad_request
;
294 if (strncmp(this, "virDomain", 9) == 0) {
295 if (strcmp(this+9, "AttachDevice") == 0) hdl
->action
= domainAttachDevice
;
296 else if (strcmp(this+9, "DetachDevice") == 0) hdl
->action
= domainDetachDevice
;
297 else if (strcmp(this+9, "DefineXML") == 0) hdl
->action
= domainDefineXML
;
299 else if (strncmp(this, "virStorage", 10) == 0) {
300 if (strncmp(this+10, "Vol", 3) == 0) {
301 if (strcmp(this+13, "CreateXML") == 0) hdl
->action
= storageVolCreateXML
;
312 if (hdl
->action
<= 0) {
313 conn
->error_code
= http_bad_request
;
318 return virt_build_page(hdl
);
322 cherokee_handler_virt_free (cherokee_handler_virt_t
*hdl
)
324 cherokee_buffer_mrproper (&hdl
->buffer
);
325 cherokee_buffer_mrproper (&hdl
->user
);
326 cherokee_buffer_mrproper (&hdl
->vm
);
332 cherokee_handler_virt_step (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
334 cherokee_buffer_add_buffer (buffer
, &hdl
->buffer
);
335 return ret_eof_have_data
;
339 cherokee_handler_virt_add_headers (cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*buffer
)
341 cherokee_buffer_add_va (buffer
, "Content-Length: %d"CRLF
, hdl
->buffer
.len
);
343 if (hdl
->action
> xml
)
344 cherokee_buffer_add_str (buffer
, "Content-Type: application/xml"CRLF
);
346 cherokee_buffer_add_str (buffer
, "Content-Type: text/plain"CRLF
);
353 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
354 virConnectPtr conn = NULL;
355 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
356 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
358 cherokee_buffer_add_va (&uri, "xen://%s/", value);
360 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
361 if (!(conn = virConnectOpen (uri.buf))) {
366 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
370 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
373 char *xml = virDomainGetXMLDesc(dom, 0);
374 cherokee_buffer_add(buf, xml, strlen(xml));
376 virConnectClose(conn);
379 cherokee_buffer_mrproper(&uri);
384 static ret_t
save_xml(cherokee_handler_virt_t
*hdl
, virDomainPtr result
, cherokee_buffer_t
*buf
) {
385 ret_t ret
= ret_error
;
387 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
388 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s", hdl
->user
.buf
);
390 mkdir(path
.buf
, 0755);
391 cherokee_buffer_add_va (&path
, "/%s", hdl
->vm
.buf
);
393 mkdir(path
.buf
, 0755);
394 cherokee_buffer_add_str (&path
, "/index.xml");
396 if ((fd
= fopen(path
.buf
, "w")) == NULL
) {
399 char *output
= virDomainGetXMLDesc(result
, 0);
400 fwrite(output
, strlen(output
), sizeof(char), fd
);
403 cherokee_buffer_add(buf
, output
, strlen(output
));
407 cherokee_buffer_mrproper(&path
);
413 virt_virt_function(cherokee_handler_virt_t
*hdl
, virDomainPtr dom
, virConnectPtr virConn
) {
414 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
415 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
417 switch (hdl
->action
) {
419 case domainUndefine
: {
421 if ((result
= virDomainUndefine(dom
)) != 0) {
422 conn
->error_code
= http_internal_error
;
425 cherokee_buffer_add_long10(buf
, result
);
429 case domainAttachDevice_args
: {
433 ret
= cherokee_connection_parse_args (conn
);
434 if (unlikely(ret
< ret_ok
))
437 ret
= cherokee_avl_get_ptr (conn
->arguments
, "type", &temp
);
440 cherokee_buffer_t xml
= CHEROKEE_BUF_INIT
;
442 if (strcmp(temp
, "disk") == 0) {
444 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "device", &device
)) == ret_ok
) {
446 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "file", &file
)) == ret_ok
) {
447 cherokee_buffer_add_va (&xml
, VIRT_DISK_XML
, file
, device
);
449 void *poolstr
, *volumestr
;
450 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &poolstr
)) == ret_ok
&&
451 (ret
= cherokee_avl_get_ptr (conn
->arguments
, "volume", &volumestr
)) == ret_ok
) {
452 cherokee_buffer_t fullvol
= CHEROKEE_BUF_INIT
;
453 virStoragePoolPtr pool
;
454 virStorageVolPtr volume
;
456 pool
= virStoragePoolLookupByName(virConn
, poolstr
);
458 conn
->error_code
= http_not_found
;
462 cherokee_buffer_add_va (&fullvol
, "%s_%s", hdl
->user
.buf
, volumestr
);
463 volume
= virStorageVolLookupByName(pool
, fullvol
.buf
);
465 cherokee_buffer_mrproper(&fullvol
);
466 virStoragePoolFree(pool
);
468 if (volume
== NULL
) {
469 conn
->error_code
= http_not_found
;
472 file
= virStorageVolGetPath(volume
);
473 cherokee_buffer_add_va (&xml
, VIRT_DISK_XML
, file
, device
);
476 virStorageVolFree(volume
);
479 conn
->error_code
= http_bad_request
;
486 else if (strcmp(temp
, "interface") == 0) {
488 if ((ret
= cherokee_avl_get_ptr (conn
->arguments
, "mac", &mac
)) == ret_ok
&& (ret
= cherokee_avl_get_ptr (conn
->arguments
, "ip", &ip
)) == ret_ok
) {
489 cherokee_buffer_add_va (&xml
, VIRT_INTERFACE_XML
, mac
, ip
);
493 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
494 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
495 if (getNewMac("dv28", domu
.buf
, &mac
, &ip
) == 0)
496 cherokee_buffer_add_va (&xml
, VIRT_INTERFACE_XML
, mac
, ip
);
497 cherokee_buffer_mrproper(&domu
);
501 if (ret
== ret_ok
&& (result
= virDomainAttachDevice(dom
, (const char *) xml
.buf
)) == 0) {
504 conn
->error_code
= http_internal_error
;
508 cherokee_buffer_add_long10(buf
, result
);
509 cherokee_buffer_mrproper(&xml
);
511 conn
->error_code
= http_bad_request
;
518 case domainAttachDevice
: {
521 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
522 cherokee_post_get_len (&conn
->post
, &postl
);
523 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
524 if ((result
= virDomainAttachDevice(dom
, (const char *) post
.buf
)) != 0)
525 conn
->error_code
= http_internal_error
;
527 cherokee_buffer_mrproper(&post
);
528 cherokee_buffer_add_long10(buf
, result
);
533 case domainGetXMLDesc
: {
534 char *xml
= virDomainGetXMLDesc(dom
, 0);
535 cherokee_buffer_add(buf
, xml
, strlen(xml
));
541 case domainDetachDevice
: {
545 cherokee_buffer_t post
= CHEROKEE_BUF_INIT
;
546 cherokee_post_get_len (&conn
->post
, &postl
);
547 cherokee_post_walk_read (&conn
->post
, &post
, (cuint_t
) postl
);
549 xmlDocPtr doc
= xmlParseMemory((const char *) post
.buf
, post
.len
);
551 conn
->error_code
= http_bad_request
;
557 if ((result
= virDomainDetachDevice(dom
, (const char *) post
.buf
)) != 0) {
558 conn
->error_code
= http_internal_error
;
559 /* TODO: betere afhandeling */
561 xmlXPathContextPtr context
= xmlXPathNewContext(doc
);
562 if (context
!= NULL
) {
563 xmlXPathObjectPtr obj
= xmlXPathEval("string(//interface/mac/@address)", context
);
564 xmlXPathFreeContext(context
);
565 if ((obj
!= NULL
) && (obj
->type
== XPATH_STRING
) &&
566 (obj
->stringval
!= NULL
) && (obj
->stringval
[0] != 0)) {
567 removeOldMac("dv28", (char *) obj
->stringval
);
569 xmlXPathFreeObject(obj
);
576 cherokee_buffer_mrproper(&post
);
577 cherokee_buffer_add_long10(buf
, result
);
582 cherokee_buffer_add_ulong10(buf
, virDomainGetID(dom
));
585 case domainGetMaxMemory
: {
586 cherokee_buffer_add_ulong10(buf
, virDomainGetMaxMemory (dom
));
589 case domainGetMaxVcpus
: {
590 cherokee_buffer_add_long10(buf
, virDomainGetMaxVcpus (dom
));
593 case domainGetName
: {
594 const char *name
= virDomainGetName (dom
);
595 cherokee_buffer_add(buf
, name
, strlen(name
));
598 case domainGetUUID
: {
599 unsigned char uuid
[VIR_UUID_BUFLEN
];
600 if (virDomainGetUUID(dom
, uuid
) == 0) {
601 cherokee_buffer_add_str(buf
, uuid
);
603 conn
->error_code
= http_internal_error
;
608 case domainGetUUIDString
: {
609 unsigned char uuid
[VIR_UUID_STRING_BUFLEN
];
610 if (virDomainGetUUIDString(dom
, uuid
) == 0) {
611 cherokee_buffer_add_str(buf
, uuid
);
613 conn
->error_code
= http_internal_error
;
620 cherokee_buffer_add_long10(buf
, virDomainCreate (dom
));
624 case domainDestroy
: {
625 cherokee_buffer_add_long10(buf
, virDomainDestroy (dom
));
630 cherokee_buffer_add_long10(buf
, virDomainReboot (dom
, 0));
634 case domainShutdown
: {
635 cherokee_buffer_add_long10(buf
, virDomainShutdown (dom
));
640 case domainGetOSType
: {
641 char *ostype
= virDomainGetOSType(dom
);
642 cherokee_buffer_add(buf
, ostype
, strlen(ostype
));
651 if (hdl
->action
== domainUndefine
) {
652 /* Remove VM data from filesystem */
653 cherokee_buffer_t path
= CHEROKEE_BUF_INIT
;
654 cherokee_buffer_add_va (&path
, "/mnt/netapp/users/%s/%s/index.xml", hdl
->user
.buf
, hdl
->vm
.buf
);
655 unlink(path
.buf
); /* TODO: instead of delet replace */
656 cherokee_buffer_mrproper(&path
);
658 save_xml(hdl
, dom
, NULL
);
665 static virStorageVolPtr
666 virt_get_vol_by_args(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
, unsigned short int prefix
) {
667 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
668 virStoragePoolPtr pool
;
669 virStorageVolPtr volume
;
673 ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &temp
);
674 if (unlikely(ret
< ret_ok
)) {
675 conn
->error_code
= http_bad_request
;
679 pool
= virStoragePoolLookupByName(virConn
, temp
);
682 conn
->error_code
= http_not_found
;
686 virStoragePoolRefresh(pool
, 0); /* TODO: might be better to do it outside */
688 ret
= cherokee_avl_get_ptr (conn
->arguments
, "volume", &temp
);
689 if (unlikely(ret
< ret_ok
)) {
690 conn
->error_code
= http_bad_request
;
695 cherokee_buffer_t fullvol
= CHEROKEE_BUF_INIT
;
696 cherokee_buffer_add_va (&fullvol
, "%s_%s", hdl
->user
.buf
, temp
);
697 volume
= virStorageVolLookupByName(pool
, fullvol
.buf
);
698 cherokee_buffer_mrproper(&fullvol
);
700 volume
= virStorageVolLookupByName(pool
, temp
);
704 conn
->error_code
= http_not_found
;
706 virStoragePoolFree(pool
);
711 /* This function is the home for all functions that need a working
712 * pool/volume combination */
714 virt_pool_vol(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
715 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
716 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
717 virStorageVolPtr volume
;
720 /* We only allow clone to run 'unsafe', others get prefixed */
721 volume
= virt_get_vol_by_args(hdl
, virConn
, (hdl
->action
!= storageVolCloneXML_args
));
723 /* If the volume doesn't exist, no point to continue */
727 switch (hdl
->action
) {
728 /* Sets the password of a specific volume, requires the password= option */
729 case storageVolSetPassword_args
: {
731 ret
= cherokee_avl_get_ptr (conn
->arguments
, "password", &temp
);
732 if (unlikely(ret
< ret_ok
)) {
733 conn
->error_code
= http_bad_request
;
734 goto virt_pool_vol_cleanup
;
737 cherokee_buffer_add_long10(buf
, execl("/usr/sbin/passwdchanger.sh", virStorageVolGetKey(volume
), temp
, NULL
));
741 /* Removes a volume */
742 case storageVolDelete_args
: {
743 cherokee_buffer_add_long10(buf
, virStorageVolDelete(volume
, 0));
747 /* Gives a description of a storage volume in XML */
748 case storageVolGetXMLDesc_args
: {
749 char *xml
= virStorageVolGetXMLDesc(volume
, 0);
750 cherokee_buffer_add(buf
, xml
, strlen(xml
));
755 /* Clones a volume, insecure method! requires a new name=*/
756 case storageVolCloneXML_args
: {
758 cherokee_buffer_t busy
= CHEROKEE_BUF_INIT
;
760 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
761 if (unlikely(ret
< ret_ok
)) {
762 conn
->error_code
= http_bad_request
;
763 goto virt_pool_vol_cleanup
;
766 cherokee_buffer_add_va (&busy
, "/mnt/images/queue/%s_%s.queued", hdl
->user
.buf
, name
);
768 if (unlikely(symlink(virStorageVolGetKey(volume
), busy
.buf
) == 1)) {
769 conn
->error_code
= http_internal_error
;
770 goto virt_pool_vol_cleanup
;
773 cherokee_buffer_mrproper(&busy
);
774 cherokee_buffer_add_str(buf
, "QUEUED");
780 virt_pool_vol_cleanup
:
781 /* And in the end we need to free the volume we have used */
782 virStorageVolFree(volume
);
788 virt_virt_new(cherokee_handler_virt_t
*hdl
, virConnectPtr virConn
) {
789 cherokee_buffer_t
*buf
= &HDL_AVAHI(hdl
)->buffer
;
790 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
791 cherokee_buffer_t xml
= CHEROKEE_BUF_INIT
;
792 virStoragePoolPtr pool
= NULL
;
795 switch (hdl
->action
) {
796 case storageVolCreateXML_args
: {
797 void *temp
, *type
, *name
, *unit
;
798 unsigned long int capacity
, allocation
;
800 ret
= cherokee_avl_get_ptr (conn
->arguments
, "pool", &temp
);
801 if (unlikely(ret
< ret_ok
)) {
802 conn
->error_code
= http_bad_request
;
803 goto virt_virt_new_cleanup
;
806 pool
= virStoragePoolLookupByName(virConn
, temp
);
809 conn
->error_code
= http_not_found
;
810 goto virt_virt_new_cleanup
;
813 ret
= cherokee_avl_get_ptr (conn
->arguments
, "name", &name
);
814 if (unlikely(ret
< ret_ok
)) {
815 conn
->error_code
= http_bad_request
;
816 goto virt_virt_new_cleanup
;
819 ret
= cherokee_avl_get_ptr (conn
->arguments
, "type", &type
);
820 if (unlikely(ret
< ret_ok
)) {
821 conn
->error_code
= http_bad_request
;
822 goto virt_virt_new_cleanup
;
825 ret
= cherokee_avl_get_ptr (conn
->arguments
, "unit", &unit
);
826 if (unlikely(ret
< ret_ok
)) {
827 conn
->error_code
= http_bad_request
;
828 goto virt_virt_new_cleanup
;
831 ret
= cherokee_avl_get_ptr (conn
->arguments
, "allocation", &temp
);
832 if (unlikely(ret
< ret_ok
)) {
833 conn
->error_code
= http_bad_request
;
834 goto virt_virt_new_cleanup
;
837 allocation
= strtoul(temp
, NULL
, 10);
838 if (errno
== ERANGE
) {
839 conn
->error_code
= http_bad_request
;
841 goto virt_virt_new_cleanup
;
844 ret
= cherokee_avl_get_ptr (conn
->arguments
, "capacity", &temp
);
845 if (unlikely(ret
< ret_ok
)) {
846 conn
->error_code
= http_bad_request
;
847 goto virt_virt_new_cleanup
;
850 capacity
= strtoul(temp
, NULL
, 10);
851 if (errno
== ERANGE
|| capacity
== 0) {
852 conn
->error_code
= http_bad_request
;
854 goto virt_virt_new_cleanup
;
857 cherokee_buffer_add_va (&xml
, VIRT_STORAGE_XML
, type
, hdl
->user
.buf
, name
, allocation
, unit
, capacity
, hdl
->user
.buf
, name
, hdl
->user
.buf
, name
);
861 case domainDefineXML_args
: {
864 unsigned long vcpu
= 0, interface
= 0, memory
= 0;
868 ret
= cherokee_avl_get_ptr (conn
->arguments
, "vcpu", &temp
);
870 vcpu
= strtoul(temp
, (char **) NULL
, 10);
872 if (ret
!= ret_ok
|| errno
== ERANGE
|| vcpu
== 0) {
873 conn
->error_code
= http_internal_error
;
874 goto virt_virt_new_cleanup
;
878 ret
= cherokee_avl_get_ptr (conn
->arguments
, "memory", &temp
);
880 memory
= strtoul(temp
, (char **) NULL
, 10);
882 if (ret
!= ret_ok
|| errno
== ERANGE
|| memory
== 0) {
883 conn
->error_code
= http_internal_error
;
884 goto virt_virt_new_cleanup
;
888 ret
= cherokee_avl_get_ptr (conn
->arguments
, "interface", &temp
);
890 interface
= strtoul(temp
, (char **) NULL
, 10);
892 if (ret
!= ret_ok
|| errno
== ERANGE
) {
893 conn
->error_code
= http_internal_error
;
894 goto virt_virt_new_cleanup
;
897 cherokee_buffer_t xml_interfaces
= CHEROKEE_BUF_INIT
;
898 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
899 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
901 for (i
= 0; i
< interface
; i
++) {
904 if (getNewMac("dv28", domu
.buf
, &mac
, &ip
) == 0)
905 cherokee_buffer_add_va (&xml_interfaces
, VIRT_INTERFACE_XML
, mac
, ip
);
908 cherokee_buffer_mrproper(&domu
);
910 cherokee_buffer_add_va (&xml
, VIRT_DOMAIN_XML
,
911 hdl
->user
.buf
, hdl
->vm
.buf
, memory
, vcpu
, xml_interfaces
.buf
);
913 cherokee_buffer_mrproper(&xml_interfaces
);
917 case storageVolCreateXML
:
918 case domainDefineXML
: {
920 cherokee_post_get_len (&conn
->post
, &postl
);
921 cherokee_post_walk_read (&conn
->post
, &xml
, (cuint_t
) postl
);
926 switch (hdl
->action
) {
927 case domainDefineXML_args
:
928 case domainDefineXML
: {
929 virDomainPtr result
= virDomainDefineXML(virConn
, (const char *) xml
.buf
);
931 if (result
== NULL
) {
932 /* TODO: vrij maken eventuele uitgegeven macs! */
933 conn
->error_code
= http_internal_error
;
934 goto virt_virt_new_cleanup
;
937 save_xml(hdl
, result
, buf
);
939 virDomainFree(result
);
944 case storageVolCreateXML_args
:
945 case storageVolCreateXML
: {
946 virStorageVolPtr vol
= virStorageVolCreateXML(pool
, xml
.buf
, 0);
949 cherokee_buffer_add_long10(buf
, -1);
950 goto virt_virt_new_cleanup
;
953 virStorageVolFree(vol
);
955 cherokee_buffer_add_long10(buf
, 0);
960 virt_virt_new_cleanup
:
961 cherokee_buffer_mrproper(&xml
);
964 virStoragePoolFree(pool
);
971 virt_virt_do(cherokee_handler_virt_t
*hdl
, cherokee_buffer_t
*domu
, cherokee_buffer_t
*uri
)
973 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
975 ret_t ret
= ret_error
;
976 virConnectPtr virConn
= NULL
;
979 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
980 virConn
= virConnectOpen (uri
->buf
);
982 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
->buf
))) {
983 conn
->error_code
= http_service_unavailable
;
987 /* We use the webserver methods to parse the querystring */
988 /* Maybe do something smart with ENUM, begin_args, end_args... */
989 if ((hdl
->action
== domainDefineXML_args
) ||
990 (hdl
->action
== domainSave_args
) ||
991 (hdl
->action
== domainRestore_args
) ||
992 (hdl
->action
== storageVolGetXMLDesc_args
) ||
993 (hdl
->action
== storageVolDelete_args
) ||
994 (hdl
->action
== storageVolSetPassword_args
) ||
995 (hdl
->action
== storageVolCloneXML_args
) ||
996 (hdl
->action
== storageVolCreateXML_args
)) {
997 ret
= cherokee_connection_parse_args (conn
);
998 if (unlikely(ret
< ret_ok
)) {
999 conn
->error_code
= http_internal_error
;
1004 switch (hdl
->action
) {
1005 case domainSave_args
:
1006 case domainRestore_args
:
1007 case storageVolDelete_args
:
1008 case storageVolSetPassword_args
:
1009 case storageVolGetXMLDesc_args
:
1010 case storageVolCloneXML_args
:
1011 ret
= virt_pool_vol(hdl
, virConn
);
1014 case storageVolCreateXML_args
:
1015 case storageVolCreateXML
:
1016 case domainDefineXML_args
:
1017 case domainDefineXML
:
1018 ret
= virt_virt_new(hdl
, virConn
);
1023 if ((dom
= virDomainLookupByName(virConn
, domu
->buf
)) == NULL
) {
1024 conn
->error_code
= http_not_found
;
1026 ret
= virt_virt_function(hdl
, dom
, virConn
);
1032 virConnectClose(virConn
);
1037 virt_while (cherokee_buffer_t
*key
, void *value
, void *param
) {
1038 cherokee_handler_virt_t
* hdl
= param
;
1039 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
1040 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
1041 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
1042 // cherokee_buffer_mrproper(&uri);
1044 cherokee_buffer_add_va (&hdl
->buffer
, "<domain><name>%s</name></domain>", key
->buf
);
1050 virt_while_user (cherokee_buffer_t
*key
, void *value
, void *param
) {
1051 cherokee_handler_virt_t
*hdl
= param
;
1052 if (key
->len
> hdl
->user
.len
&& key
->buf
[hdl
->user
.len
] == '_' && strncmp(key
->buf
, hdl
->user
.buf
, hdl
->user
.len
) == 0)
1053 return virt_while (key
, value
, param
);
1059 virt_build_page (cherokee_handler_virt_t
*hdl
)
1062 cherokee_connection_t
*conn
= HANDLER_CONN(hdl
);
1063 cherokee_buffer_t uri
= CHEROKEE_BUF_INIT
;
1064 cherokee_buffer_t domu
= CHEROKEE_BUF_INIT
;
1066 if (hdl
->action
> xml
&& HDL_VIRT_PROPS(hdl
)->xsl
.len
> 0)
1067 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
);
1070 /* First, block the event loop */
1071 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
1072 switch (hdl
->action
) {
1074 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>");
1075 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl
)->entries
, virt_while
, hdl
, NULL
, NULL
);
1076 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
1081 cherokee_buffer_add_str (&hdl
->buffer
, "<domains>");
1082 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl
)->entries
, virt_while_user
, hdl
, NULL
, NULL
);
1083 cherokee_buffer_add_str (&hdl
->buffer
, "</domains>");
1089 cherokee_buffer_t
*hostname
= NULL
;
1090 cherokee_buffer_add_va (&domu
, "%s_%s", hdl
->user
.buf
, hdl
->vm
.buf
);
1091 ret
= cherokee_avl_get_ptr(&HDL_AVAHI_PROPS(hdl
)->entries
, domu
.buf
, (void **) &hostname
);
1093 if (ret
== ret_not_found
) {
1094 virDomainPtr virDom
;
1095 virConnectPtr virConn
;
1096 cherokee_buffer_add_va (&uri
, "xen://%s/", HDL_VIRT_PROPS(hdl
)->virt
); // TODO: change!
1098 /* If we have the read only parameter, we will set up a connection to the
1099 * Hypervisor here. */
1100 if (HDL_VIRT_PROPS(hdl
)->read_only
== FALSE
)
1101 virConn
= virConnectOpen (uri
.buf
);
1103 /* We should already have a connection (read only) or build a new connection
1104 * if this doesn't work, we can safely assume our services is fubar */
1105 if (!virConn
&& !(virConn
= virConnectOpenReadOnly (uri
.buf
))) {
1106 conn
->error_code
= http_service_unavailable
;
1110 /* We lookup if there is a domain somewhere with this name */
1111 if ((virDom
= virDomainLookupByName(virConn
, domu
.buf
)) == NULL
) {
1112 /* If the domain is not found on the network the only possible
1113 * command that is possible would be to Define it */
1114 if (hdl
->action
== domainDefineXML_args
|| hdl
->action
== domainDefineXML
) {
1117 /* Otherwise we don't have anything to do and we should
1118 * return an error */
1119 hdl
->action
= nothing
;
1120 conn
->error_code
= http_not_found
;
1124 /* We don't want te recreate things that already found on the network
1125 * first undefine them! */
1126 if (hdl
->action
== domainDefineXML_args
|| hdl
->action
== domainDefineXML
) {
1127 hdl
->action
= nothing
;
1128 conn
->error_code
= http_bad_request
;
1131 /* Everything is ok, because nothing is found. */
1135 /* Domain wasn't NULL, so we should free it here */
1136 virDomainFree(virDom
);
1138 virConnectClose (virConn
);
1139 } else if (ret
== ret_ok
) {
1140 cherokee_buffer_add_va (&uri
, "xen://%s/", hostname
->buf
);
1141 printf("%s\n", uri
.buf
);
1143 hdl
->action
= http_internal_error
;
1144 hdl
->action
= nothing
;
1150 /* Finally, unblock the event loop */
1151 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl
)->threaded_poll
);
1153 if (ret
== ret_ok
&& hdl
->action
!= showall
&& hdl
->action
!= showuservms
) {
1154 ret
= virt_virt_do(hdl
, &domu
, &uri
);
1157 cherokee_buffer_mrproper(&domu
);
1158 cherokee_buffer_mrproper(&uri
);
1166 cherokee_handler_virt_new (cherokee_handler_t
**hdl
, cherokee_connection_t
*cnt
, cherokee_module_props_t
*props
)
1169 CHEROKEE_NEW_STRUCT (n
, handler_virt
);
1171 /* Init the base class
1174 cherokee_handler_init_base(HANDLER(n
), cnt
, HANDLER_PROPS(props
), PLUGIN_INFO_HANDLER_PTR(virt
));
1176 MODULE(n
)->init
= (handler_func_init_t
) cherokee_handler_virt_init
;
1177 MODULE(n
)->free
= (module_func_free_t
) cherokee_handler_virt_free
;
1178 HANDLER(n
)->step
= (handler_func_step_t
) cherokee_handler_virt_step
;
1179 HANDLER(n
)->add_headers
= (handler_func_add_headers_t
) cherokee_handler_virt_add_headers
;
1181 HANDLER(n
)->support
= hsupport_length
| hsupport_range
;
1183 ret
= cherokee_buffer_init (&n
->buffer
);
1184 if (unlikely(ret
!= ret_ok
))
1187 ret
= cherokee_buffer_ensure_size (&n
->buffer
, 4*1024);
1188 if (unlikely(ret
!= ret_ok
))