Added installation of ModuleVirt.py, added an option to configure the XSL document.
[handlervirt.git] / handler_virt.c
blob7ff80e6946bcf8bbd9abac40cd6f672141428a85
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 /* Cherokee
5 * Authors:
6 * Alvaro Lopez Ortega <alvaro@alobbs.com>
7 * Stefan de Konink <stefan@konink.de>
9 * Copyright (C) 2001-2008 Alvaro Lopez Ortega
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
26 #include "handler_virt.h"
27 #include "handler_avahi.h"
28 #include <cherokee/cherokee.h>
30 /* Plug-in initialization
32 * In this function you can use any of these:
33 * http_delete | http_get | http_post | http_put
35 * For a full list: cherokee_http_method_t
37 * It is what your handler to be implements.
40 PLUGIN_INFO_HANDLER_EASIEST_INIT (virt, http_get | http_post);
43 /* Methods implementation
45 static ret_t
46 props_free (cherokee_handler_virt_props_t *props)
48 return cherokee_module_props_free_base (MODULE_PROPS(props));
52 ret_t
53 cherokee_handler_virt_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
55 cherokee_list_t *i;
56 cherokee_handler_virt_props_t *props;
58 /* Instance a new property object
61 if (*_props == NULL) {
62 CHEROKEE_NEW_STRUCT (n, handler_virt_props);
64 cherokee_handler_avahi_props_init_base (PROP_AVAHI(n), MODULE_PROPS_FREE(props_free));
66 /* Look at handler_virt.h
67 * This is an virt of configuration.
69 n->authenticate = true; /* by default we are secure! */
70 n->read_only = true; /* by default we are secure! */
71 cherokee_buffer_init (&n->xsl); /* we support a custom header */
73 *_props = MODULE_PROPS(n);
76 props = PROP_VIRT(*_props);
78 cherokee_config_node_foreach (i, conf) {
79 cherokee_config_node_t *subconf = CONFIG_NODE(i);
81 if (equal_buf_str (&subconf->key, "authenticate")) {
82 props->authenticate = atoi(subconf->val.buf);
84 else if (equal_buf_str (&subconf->key, "read_only")) {
85 props->read_only = atoi(subconf->val.buf);
87 else if (equal_buf_str (&subconf->key, "xsl")) {
88 cherokee_buffer_add_buffer (&props->xsl, &subconf->val);
92 /* Init base class
95 return cherokee_handler_avahi_configure (conf, srv, _props);
99 ret_t
100 cherokee_handler_virt_init (cherokee_handler_virt_t *hdl)
102 int isroot = false;
103 int len;
104 char *this, *next;
106 cherokee_connection_t *conn = HANDLER_CONN(hdl);
107 cherokee_buffer_init(&hdl->user);
108 cherokee_buffer_init(&hdl->vm);
110 hdl->action = nothing;
112 cherokee_buffer_add (&conn->pathinfo,
113 conn->request.buf + conn->web_directory.len,
114 conn->request.len - conn->web_directory.len);
116 this = conn->pathinfo.buf + 1;
117 next = strchr(this, '/');
120 if ((!next && (this && (len = strlen(this)) == 0)) || (next && ((len = next - this) == 0)) )
121 hdl->action = showall;
122 else {
123 cherokee_buffer_add (&hdl->user, this, len);
126 if (HDL_VIRT_PROPS(hdl)->authenticate) {
127 if (!conn->validator ||
128 (conn->validator &&
129 (!cherokee_buffer_cmp_buf(&conn->validator->user, &hdl->user) &&
130 !(isroot = cherokee_buffer_cmp (&conn->validator->user, "root", 4))))) {
131 hdl->action = nothing; /* just in case */
132 conn->error_code = http_unauthorized;
133 return ret_error;
135 } else {
136 isroot = true;
139 if (hdl->action == showall) {
140 if (!isroot) {
141 hdl->action = nothing;
142 conn->error_code = http_unauthorized;
143 return ret_error;
144 } else {
145 return virt_build_page(hdl);
150 if (!next) {
151 hdl->action = showuservms;
152 return virt_build_page(hdl);
153 } else {
154 this = next + 1;
155 next = strchr(this, '/');
157 if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
158 hdl->action = showuservms;
159 return virt_build_page(hdl);
163 cherokee_buffer_add (&hdl->vm, this, len);
165 if (!next) {
166 hdl->action = domainGetXMLDesc;
167 return virt_build_page(hdl);
168 } else {
169 this = next + 1;
170 next = strchr(this, '/');
172 if (!next && (this && (len = strlen(this)) == 0) || (next && ((len = next - this) == 0)) ) {
173 hdl->action = domainGetXMLDesc;
174 return virt_build_page(hdl);
178 hdl->action = not_implemented;
179 switch (conn->header.method) {
180 case http_get:
181 if (strncmp(this, "virDomain", 9) == 0) {
182 if (strncmp(this+9, "Get", 3) == 0) {
183 if (strcmp(this+12, "ID") == 0) hdl->action = domainGetID;
184 else if (strcmp(this+12, "Name") == 0) hdl->action = domainGetName;
185 else if (strcmp(this+12, "MaxMemory") == 0) hdl->action = domainGetMaxMemory;
186 else if (strcmp(this+12, "MaxVcpus") == 0) hdl->action = domainGetMaxVcpus;
187 else if (strcmp(this+12, "OSType") == 0) hdl->action = domainGetOSType;
188 else if (strcmp(this+12, "UUID") == 0) hdl->action = domainGetUUID;
189 else if (strcmp(this+12, "UUIDString") == 0) hdl->action = domainGetUUIDString;
190 else if (strcmp(this+12, "XMLDesc") == 0) hdl->action = domainGetXMLDesc;
192 else if (strcmp(this+9, "Reboot") == 0) hdl->action = domainReboot;
193 else if (strcmp(this+9, "Shutdown") == 0) hdl->action = domainShutdown;
195 break;
197 case http_post: {
198 off_t postl;
199 cherokee_post_get_len (&conn->post, &postl);
201 if (postl <= 0 || postl >= (INT_MAX-1)) {
202 conn->error_code = http_bad_request;
203 return ret_error;
206 if (strncmp(this, "virDomain", 9) == 0) {
207 if (strcmp(this+9, "AttachDevice") == 0) hdl->action = domainAttachDevice;
208 if (strcmp(this+9, "DetachDevice") == 0) hdl->action = domainDetachDevice;
210 break;
213 default:
214 return ret_error;
217 if (hdl->action <= 0) {
218 conn->error_code = http_bad_request;
219 return ret_error;
223 return virt_build_page(hdl);
226 ret_t
227 cherokee_handler_virt_free (cherokee_handler_virt_t *hdl)
229 cherokee_buffer_mrproper (&hdl->buffer);
230 cherokee_buffer_mrproper (&hdl->user);
231 cherokee_buffer_mrproper (&hdl->vm);
233 return ret_ok;
236 ret_t
237 cherokee_handler_virt_step (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
239 cherokee_buffer_add_buffer (buffer, &hdl->buffer);
240 return ret_eof_have_data;
243 ret_t
244 cherokee_handler_virt_add_headers (cherokee_handler_virt_t *hdl, cherokee_buffer_t *buffer)
246 cherokee_buffer_add_va (buffer, "Content-Length: %d"CRLF, hdl->buffer.len);
248 if (hdl->action > xml)
249 cherokee_buffer_add_str (buffer, "Content-Type: application/xml"CRLF);
250 else
251 cherokee_buffer_add_str (buffer, "Content-Type: text/plain"CRLF);
253 return ret_ok;
257 static ret_t
258 while_func_entries (cherokee_buffer_t *key, void *value, void *param) {
259 virConnectPtr conn = NULL;
260 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
261 cherokee_buffer_t *buf = (cherokee_buffer_t *)param;
263 cherokee_buffer_add_va (&uri, "xen://%s/", value);
265 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE && !(conn = virConnectOpen (uri.buf))) {
266 if (!(conn = virConnectOpen (uri.buf))) {
267 return ret_error;
271 if (!conn && !(conn = virConnectOpenReadOnly (uri.buf))) {
272 return ret_error;
273 } else {
274 virDomainPtr dom;
275 if (!(dom = virDomainLookupByName(conn, (const char *) key->buf))) {
276 return ret_error;
277 } else {
278 char *xml = virDomainGetXMLDesc(dom, 0);
279 cherokee_buffer_add(buf, xml, strlen(xml));
281 virConnectClose(conn);
284 cherokee_buffer_mrproper(&uri);
286 return ret_ok;
289 static ret_t
290 virt_virt_function(cherokee_handler_virt_t *hdl, virDomainPtr dom) {
291 cherokee_connection_t *conn = HANDLER_CONN(hdl);
292 cherokee_buffer_t *buf = &HDL_AVAHI(hdl)->buffer;
294 switch (hdl->action) {
295 case domainAttachDevice: {
296 off_t postl;
297 int result;
298 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
299 cherokee_post_get_len (&conn->post, &postl);
300 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
301 if ((result = virDomainAttachDevice(dom, (const char *) post.buf)) != 0)
302 conn->error_code = http_internal_error;
304 cherokee_buffer_mrproper(&post);
305 cherokee_buffer_add_long10(buf, result);
306 break;
309 case domainDetachDevice: {
310 off_t postl;
311 int result;
312 cherokee_buffer_t post = CHEROKEE_BUF_INIT;
313 cherokee_post_get_len (&conn->post, &postl);
314 cherokee_post_walk_read (&conn->post, &post, (cuint_t) postl);
315 if ((result = virDomainDetachDevice(dom, (const char *) post.buf)) != 0) {
316 conn->error_code = http_internal_error;
318 cherokee_buffer_mrproper(&post);
319 cherokee_buffer_add_long10(buf, result);
320 break;
323 case domainGetID: {
324 cherokee_buffer_add_ulong10(buf, virDomainGetID(dom));
325 break;
327 case domainGetMaxMemory: {
328 cherokee_buffer_add_ulong10(buf, virDomainGetMaxMemory (dom));
329 break;
331 case domainGetMaxVcpus: {
332 cherokee_buffer_add_long10(buf, virDomainGetMaxVcpus (dom));
333 break;
335 case domainGetName: {
336 const char *name = virDomainGetName (dom);
337 cherokee_buffer_add(buf, name, strlen(name));
338 break;
340 case domainGetUUID: {
341 unsigned char uuid[VIR_UUID_BUFLEN];
342 if (virDomainGetUUID(dom, uuid) == 0) {
343 cherokee_buffer_add_str(buf, uuid);
344 } else {
345 conn->error_code = http_internal_error;
346 return ret_error;
348 break;
350 case domainGetUUIDString: {
351 unsigned char uuid[VIR_UUID_STRING_BUFLEN];
352 if (virDomainGetUUIDString(dom, uuid) == 0) {
353 cherokee_buffer_add_str(buf, uuid);
354 } else {
355 conn->error_code = http_internal_error;
356 return ret_error;
358 break;
361 case domainReboot: {
362 cherokee_buffer_add_long10(buf, virDomainReboot (dom, 0));
363 break;
366 case domainShutdown: {
367 cherokee_buffer_add_long10(buf, virDomainShutdown (dom));
368 break;
372 case domainGetOSType: {
373 char *ostype = virDomainGetOSType(dom);
374 cherokee_buffer_add(buf, ostype, strlen(ostype));
375 free(ostype);
376 break;
379 case domainGetXMLDesc: {
380 char *xml = virDomainGetXMLDesc(dom, 0);
381 cherokee_buffer_add(buf, xml, strlen(xml));
382 free(xml);
383 break;
387 return ret_ok;
390 static ret_t
391 virt_virt_do(cherokee_handler_virt_t *hdl, cherokee_buffer_t *domu, cherokee_buffer_t *uri)
393 cherokee_connection_t *conn = HANDLER_CONN(hdl);
395 ret_t ret = ret_error;
396 virConnectPtr virConn = NULL;
399 if (HDL_VIRT_PROPS(hdl)->read_only == FALSE)
400 virConn = virConnectOpen (uri->buf);
402 if (!virConn && !(virConn = virConnectOpenReadOnly (uri->buf))) {
403 conn->error_code = http_service_unavailable;
404 return ret_error;
407 virDomainPtr dom;
408 if (!(dom = virDomainLookupByName(virConn, domu->buf))) {
409 conn->error_code = http_not_found;
410 } else {
411 ret = virt_virt_function(hdl, dom);
413 virConnectClose(virConn);
415 return ret_ok;
418 static ret_t
419 virt_while (cherokee_buffer_t *key, void *value, void *param) {
420 cherokee_handler_virt_t * hdl = param;
421 // cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
422 // cherokee_buffer_add_va (&uri, "xen://%s/", ((cherokee_buffer_t *) value)->buf);
423 // virt_virt_do((cherokee_handler_virt_t *) param, key, &uri);
424 // cherokee_buffer_mrproper(&uri);
426 cherokee_buffer_add_va (&hdl->buffer, "<domain><name>%s</name></domain>", key->buf);
428 return ret_ok;
431 static ret_t
432 virt_while_user (cherokee_buffer_t *key, void *value, void *param) {
433 cherokee_handler_virt_t *hdl = param;
434 if (key->len > hdl->user.len && key->buf[hdl->user.len] == '_' && strncmp(key->buf, hdl->user.buf, hdl->user.len) == 0)
435 return virt_while (key, value, param);
437 return ret_ok;
440 static ret_t
441 virt_build_page (cherokee_handler_virt_t *hdl)
443 ret_t ret;
444 cherokee_connection_t *conn = HANDLER_CONN(hdl);
446 if (hdl->action > xml && HDL_VIRT_PROPS(hdl)->xsl.len > 0)
447 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);
450 /* First, block the event loop */
451 avahi_threaded_poll_lock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
452 switch (hdl->action) {
453 case showall:
454 cherokee_buffer_add_str (&hdl->buffer, "<domains>");
455 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl)->entries, virt_while, hdl, NULL, NULL);
456 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
457 break;
459 case showuservms: {
460 void *param[3];
461 cherokee_buffer_add_str (&hdl->buffer, "<domains>");
462 cherokee_avl_while(&HDL_AVAHI_PROPS(hdl)->entries, virt_while_user, hdl, NULL, NULL);
463 cherokee_buffer_add_str (&hdl->buffer, "</domains>");
464 break;
467 default: {
468 cherokee_buffer_t domu = CHEROKEE_BUF_INIT;
469 cherokee_buffer_t uri = CHEROKEE_BUF_INIT;
470 cherokee_buffer_t *hostname = NULL;
471 cherokee_buffer_add_va (&domu, "%s_%s", hdl->user.buf, hdl->vm.buf);
472 if ((ret = cherokee_avl_get_ptr(&HDL_AVAHI_PROPS(hdl)->entries, domu.buf, (void **) &hostname)) == ret_error) {
473 hdl->action = nothing;
474 conn->error_code = http_not_found;
475 return ret;
477 cherokee_buffer_add_va (&uri, "xen://%s/", hostname->buf);
478 ret = virt_virt_do(hdl, &domu, &uri);
479 cherokee_buffer_mrproper(&domu);
480 cherokee_buffer_mrproper(&uri);
484 /* Finally, unblock the event loop */
485 avahi_threaded_poll_unlock(HDL_AVAHI_PROPS(hdl)->threaded_poll);
487 return ret_ok;
491 ret_t
492 cherokee_handler_virt_new (cherokee_handler_t **hdl, cherokee_connection_t *cnt, cherokee_module_props_t *props)
494 ret_t ret;
495 CHEROKEE_NEW_STRUCT (n, handler_virt);
497 /* Init the base class
500 cherokee_handler_init_base(HANDLER(n), cnt, HANDLER_PROPS(props), PLUGIN_INFO_HANDLER_PTR(virt));
502 MODULE(n)->init = (handler_func_init_t) cherokee_handler_virt_init;
503 MODULE(n)->free = (module_func_free_t) cherokee_handler_virt_free;
504 HANDLER(n)->step = (handler_func_step_t) cherokee_handler_virt_step;
505 HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_virt_add_headers;
507 HANDLER(n)->support = hsupport_length | hsupport_range;
509 ret = cherokee_buffer_init (&n->buffer);
510 if (unlikely(ret != ret_ok))
511 return ret;
513 ret = cherokee_buffer_ensure_size (&n->buffer, 4*1024);
514 if (unlikely(ret != ret_ok))
515 return ret;
517 *hdl = HANDLER(n);
519 return ret_ok;