This class is used to access the oVirt manager through its REST API and get the URL and credentials to use to access the corresponding VM using SPICE. --- src/Makefile.am | 2 + src/ovirt-proxy.c | 661 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ovirt-proxy.h | 70 ++++++ 3 files changed, 733 insertions(+) create mode 100644 src/ovirt-proxy.c create mode 100644 src/ovirt-proxy.h diff --git a/src/Makefile.am b/src/Makefile.am index cd0e988..733fd42 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,12 +52,14 @@ BUILT_SOURCES = \ CLEANFILES = $(BUILT_SOURCES) OVIRT_HEADER_FILES = \ + ovirt-proxy.h \ ovirt-rest-call.h \ ovirt-vm.h \ ovirt-vm-display.h \ $(NULL) COMMON_SOURCES += \ + ovirt-proxy.c \ ovirt-rest-call.c \ ovirt-vm.c \ ovirt-vm-display.c \ diff --git a/src/ovirt-proxy.c b/src/ovirt-proxy.c new file mode 100644 index 0000000..653c3eb --- /dev/null +++ b/src/ovirt-proxy.c @@ -0,0 +1,661 @@ +/* + * ovirt-proxy.c + * + * Copyright (C) 2011, 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Christophe Fergeau <cfergeau@xxxxxxxxxx> + */ + +#undef OVIRT_DEBUG +#include <config.h> + +#include "ovirt-rest-call.h" +#include "ovirt-proxy.h" +#include "ovirt-vm.h" +#include "ovirt-vm-display.h" + +#include <stdlib.h> +#include <string.h> + +#include <rest/rest-proxy.h> +#include <rest/rest-xml-node.h> +#include <rest/rest-xml-parser.h> + +G_DEFINE_TYPE (OvirtProxy, ovirt_proxy, G_TYPE_OBJECT); + +struct _OvirtProxyPrivate { + RestProxy *rest_proxy; + GHashTable *vms; +}; + +#define OVIRT_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), OVIRT_TYPE_PROXY, OvirtProxyPrivate)) + +enum { + PROP_0, + PROP_URI, +}; + +#define ADMIN_LOGIN "admin@internal" +#define ADMIN_PASSWORD "XXXXXXX" +#define API_ENTRY_POINT "/api/" + +enum OvirtResponseStatus { + OVIRT_RESPONSE_UNKNOWN, + OVIRT_RESPONSE_FAILED, + OVIRT_RESPONSE_PENDING, + OVIRT_RESPONSE_IN_PROGRESS, + OVIRT_RESPONSE_COMPLETE +}; + + +#ifdef OVIRT_DEBUG +static void dump_display(OvirtVmDisplay *display) +{ + OvirtVmDisplayType type; + guint monitor_count; + gchar *address; + guint port; + gchar *ticket; + guint expiry; + + g_object_get(G_OBJECT(display), + "type", &type, + "monitor-count", &monitor_count, + "address", &address, + "port", &port, + "ticket", &ticket, + "expiry", &expiry, + NULL); + + g_print("\tDisplay:\n"); + g_print("\t\tType: %s\n", (type == OVIRT_VM_DISPLAY_VNC)?"vnc":"spice"); + g_print("\t\tMonitors: %d\n", monitor_count); + g_print("\t\tAddress: %s\n", address); + g_print("\t\tPort: %d\n", port); + g_print("\t\tTicket: %s\n", ticket); + g_print("\t\tExpiry: %d\n", expiry); + g_free(address); + g_free(ticket); +} + +static void dump_key(gpointer key, gpointer value, gpointer user_data) +{ + g_print("[%s] -> %p\n", (char *)key, value); +} + +static void dump_action(gpointer key, gpointer value, gpointer user_data) +{ + g_print("\t\t%s -> %s\n", (char *)key, (char *)value); +} + +static void dump_vm(OvirtVm *vm) +{ + gchar *name; + gchar *uuid; + gchar *href; + OvirtVmState state; + GHashTable *actions = NULL; + OvirtVmDisplay *display; + + g_object_get(G_OBJECT(vm), + "name", &name, + "uuid", &uuid, + "href", &href, + "state", &state, + "display", &display, + NULL); + + + g_print("VM:\n"); + g_print("\tName: %s\n", name); + g_print("\tuuid: %s\n", uuid); + g_print("\thref: %s\n", href); + g_print("\tState: %s\n", (state == OVIRT_VM_STATE_UP)?"up":"down"); + if (actions != NULL) { + g_print("\tActions:\n"); + g_hash_table_foreach(actions, dump_action, NULL); + g_hash_table_unref(actions); + } + if (display != NULL) { + dump_display(display); + g_object_unref(display); + } + g_free(name); + g_free(uuid); + g_free(href); +} +#endif + +static gboolean vm_set_name_from_xml(OvirtVm *vm, RestXmlNode *node) +{ + RestXmlNode *name_node; + + name_node = rest_xml_node_find(node, "name"); + if (name_node != NULL) { + g_return_val_if_fail(name_node->content != NULL, FALSE); + g_object_set(G_OBJECT(vm), "name", name_node->content, NULL); + return TRUE; + } + + return FALSE; +} + +static gboolean vm_set_display_from_xml(OvirtVm *vm, + RestXmlNode *root) +{ + RestXmlNode *node; + OvirtVmDisplay *display; + const char *display_key = g_intern_string("display"); + const char *type_key = g_intern_string("type"); + const char *address_key = g_intern_string("address"); + const char *port_key = g_intern_string("port"); + const char *monitors_key = g_intern_string("monitors"); + + if (root == NULL) { + return FALSE; + } + root = g_hash_table_lookup(root->children, display_key); + g_return_val_if_fail(root != NULL, FALSE); + display = ovirt_vm_display_new(); + + node = g_hash_table_lookup(root->children, type_key); + g_return_val_if_fail(node != NULL, FALSE); + if (g_strcmp0(node->content, "spice") == 0) { + g_object_set(G_OBJECT(display), "type", OVIRT_VM_DISPLAY_SPICE, NULL); + } else if (g_strcmp0(node->content, "vnc") == 0) { + g_object_set(G_OBJECT(display), "type", OVIRT_VM_DISPLAY_VNC, NULL); + } else { + g_warning("Unknown display type: %s", node->content); + return FALSE; + } + + node = g_hash_table_lookup(root->children, monitors_key); + g_return_val_if_fail(node != NULL, FALSE); + g_object_set(G_OBJECT(display), + "monitor-count", strtoul(node->content, NULL, 0), + NULL); + + /* on non started VMs, these 2 values will not be available */ + node = g_hash_table_lookup(root->children, address_key); + if (node != NULL) { + g_object_set(G_OBJECT(display), "address", node->content, NULL); + } + + node = g_hash_table_lookup(root->children, port_key); + if (node != NULL) { + g_object_set(G_OBJECT(display), + "port", strtoul(node->content, NULL, 0), + NULL); + } + + /* FIXME: this overrides the ticket/expiry which may + * already be set + */ + g_object_set(G_OBJECT(vm), "display", display, NULL); + g_object_unref(G_OBJECT(display)); + + return TRUE; +} + +static gboolean vm_set_state_from_xml(OvirtVm *vm, RestXmlNode *node) +{ + RestXmlNode *state; + + state = rest_xml_node_find(node, "status"); + state = rest_xml_node_find(state, "state"); + if (state != NULL) { + gboolean res = FALSE; + g_return_val_if_fail(state->content != NULL, FALSE); + if (strcmp(state->content, "down") == 0) { + g_object_set(G_OBJECT(vm), "state", OVIRT_VM_STATE_DOWN, NULL); + res = TRUE; + } else if (strcmp(state->content, "up") == 0) { + /* FIXME: check "UP" state name in the rsdl file */ + g_object_set(G_OBJECT(vm), "state", OVIRT_VM_STATE_UP, NULL); + res = TRUE; + } else { + g_warning("Couldn't parse VM state: %s", state->content); + } + return res; + } + + return FALSE; +} + +static gboolean vm_set_actions_from_xml(OvirtVm *vm, RestXmlNode *node) +{ + RestXmlNode *link; + RestXmlNode *rest_actions; + const char *link_key = g_intern_string("link"); + + rest_actions = rest_xml_node_find(node, "actions"); + if (rest_actions == NULL) { + return FALSE; + } + + link = g_hash_table_lookup(rest_actions->children, link_key); + if (link == NULL) + return FALSE; + + for (; link != NULL; link = link->next) { + const char *link_name; + const char *href; + + g_warn_if_fail(link != NULL); + g_warn_if_fail(link->name != NULL); + g_warn_if_fail(strcmp(link->name, "link") == 0); + + link_name = rest_xml_node_get_attr(link, "rel"); + href = rest_xml_node_get_attr(link, "href"); + if (g_str_has_prefix(href, API_ENTRY_POINT)) { + href += strlen(API_ENTRY_POINT); + } else { + /* action href should always be prefixed by /api/ */ + /* it would be easier to remove /api/ from the RestProxy base + * URL but unfortunately I couldn't get this to work + */ + g_warn_if_reached(); + } + + if ((link_name != NULL) && (href != NULL)) { + ovirt_vm_add_action(vm, link_name, href); + } + } + + return TRUE; +} + +static OvirtVm *xml_to_vm(RestXmlNode *node) +{ + OvirtVm *vm; + const char *uuid; + const char *href; + + + uuid = rest_xml_node_get_attr(node, "id"); + g_return_val_if_fail(uuid != NULL, NULL); + href = rest_xml_node_get_attr(node, "href"); + g_return_val_if_fail(href != NULL, NULL); + + vm = ovirt_vm_new(); + g_object_set(G_OBJECT(vm), "uuid", uuid, "href", href, NULL); + + vm_set_name_from_xml(vm, node); + vm_set_state_from_xml(vm, node); + vm_set_actions_from_xml(vm, node); + vm_set_display_from_xml(vm, node); + + return vm; +} + +static GHashTable *parse_vms_xml(RestProxyCall *call) +{ + RestXmlParser *parser; + RestXmlNode *root; + RestXmlNode *xml_vms; + RestXmlNode *node; + GHashTable *vms; + const char *vm_key = g_intern_string("vm"); + + parser = rest_xml_parser_new (); + + root = rest_xml_parser_parse_from_data (parser, + rest_proxy_call_get_payload (call), + rest_proxy_call_get_payload_length (call)); + + vms = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, (GDestroyNotify)g_object_unref); +#ifdef OVIRT_DEBUG + g_hash_table_foreach(root->children, dump_key, NULL); +#endif + xml_vms = g_hash_table_lookup(root->children, vm_key); + for (node = xml_vms; node != NULL; node = node->next) { + OvirtVm *vm; + gchar *name; + vm = xml_to_vm(node); +#ifdef OVIRT_DEBUG + dump_vm(vm); +#endif + if (!OVIRT_IS_VM(vm)) { + g_message("Failed to parse XML VM description"); + continue; + } + g_object_get(G_OBJECT(vm), "name", &name, NULL); + if (name == NULL) { + g_message("VM had no name in its XML description"); + g_object_unref(vm); + continue; + } + if (g_hash_table_lookup(vms, name) != NULL) { + g_message("VM with the same name ('%s') already exists", name); + g_object_unref(vm); + continue; + } + g_hash_table_insert(vms, name, vm); + } + rest_xml_node_unref(root); + g_object_unref(G_OBJECT(parser)); + + return vms; +} + +static gboolean ovirt_proxy_fetch_vms(OvirtProxy *proxy, GError **error) +{ + RestProxyCall *call; + + g_return_val_if_fail(OVIRT_IS_PROXY(proxy), FALSE); + g_return_val_if_fail(REST_IS_PROXY(proxy->priv->rest_proxy), FALSE); + + call = REST_PROXY_CALL(ovirt_rest_call_new(proxy->priv->rest_proxy)); + rest_proxy_call_set_function(call, "vms"); + + if (!rest_proxy_call_sync(call, error)) { + g_warning("Error while getting VM list"); + g_object_unref(G_OBJECT(call)); + return FALSE; + } + + proxy->priv->vms = parse_vms_xml(call); + + g_object_unref(G_OBJECT(call)); + + return TRUE; +} + +OvirtVm *ovirt_proxy_lookup_vm(OvirtProxy *proxy, const char *vm_name, + GError **error) +{ + OvirtVm *vm; + + g_return_val_if_fail(OVIRT_IS_PROXY(proxy), NULL); + g_return_val_if_fail(vm_name != NULL, NULL); + + if (proxy->priv->vms == NULL) { + gboolean success; + success = ovirt_proxy_fetch_vms(proxy, error); + if (!success) + return NULL; + } + if (proxy->priv->vms == NULL) { + return NULL; + } + + vm = g_hash_table_lookup(proxy->priv->vms, vm_name); + + if (vm == NULL) { + return NULL; + } + + return g_object_ref(vm); +} + +static void parse_ticket_status(RestXmlNode *root, OvirtVm *vm, GError **error) +{ + RestXmlNode *node; + const char *ticket_key = g_intern_string("ticket"); + const char *value_key = g_intern_string("value"); + const char *expiry_key = g_intern_string("expiry"); + OvirtVmDisplay *display; + + g_return_if_fail(root != NULL); + g_return_if_fail(vm != NULL); + g_return_if_fail(error == NULL || *error == NULL); + + root = g_hash_table_lookup(root->children, ticket_key); + if (root == NULL) { + g_return_if_reached(); + } + node = g_hash_table_lookup(root->children, value_key); + if (node == NULL) { + g_return_if_reached(); + } + + g_object_get(G_OBJECT(vm), "display", &display, NULL); + g_return_if_fail(display != NULL); + g_object_set(G_OBJECT(display), "ticket", node->content, NULL); + + g_debug("Ticket: %s\n", node->content); + + node = g_hash_table_lookup(root->children, expiry_key); + if (node == NULL) { + g_object_unref(G_OBJECT(display)); + g_return_if_reached(); + } + g_object_set(G_OBJECT(display), + "expiry", strtoul(node->content, NULL, 0), + NULL); + g_object_unref(G_OBJECT(display)); +} + +static enum OvirtResponseStatus parse_action_status(RestXmlNode *root, + GError **error) +{ + RestXmlNode *node; + const char *status_key = g_intern_string("status"); + const char *state_key = g_intern_string("state"); + + g_return_val_if_fail(g_strcmp0(root->name, "action") == 0, + OVIRT_RESPONSE_UNKNOWN); + g_return_val_if_fail(error == NULL || *error == NULL, + OVIRT_RESPONSE_UNKNOWN); + + node = g_hash_table_lookup(root->children, status_key); + if (node == NULL) { + g_return_val_if_reached(OVIRT_RESPONSE_UNKNOWN); + } + node = g_hash_table_lookup(node->children, state_key); + if (node == NULL) { + g_return_val_if_reached(OVIRT_RESPONSE_UNKNOWN); + } + g_debug("State: %s\n", node->content); + if (g_strcmp0(node->content, "complete") == 0) { + return OVIRT_RESPONSE_COMPLETE; + } else if (g_strcmp0(node->content, "pending") == 0) { + return OVIRT_RESPONSE_PENDING; + } else if (g_strcmp0(node->content, "in_progress") == 0) { + return OVIRT_RESPONSE_IN_PROGRESS; + } else if (g_strcmp0(node->content, "failed") == 0) { + return OVIRT_RESPONSE_FAILED; + } + + g_return_val_if_reached(OVIRT_RESPONSE_UNKNOWN); +} + +static void parse_fault(RestXmlNode *root, GError **error) +{ + RestXmlNode *node; + const char *reason_key = g_intern_string("reason"); + const char *detail_key = g_intern_string("detail"); + + g_return_if_fail(g_strcmp0(root->name, "fault") == 0); + + node = g_hash_table_lookup(root->children, reason_key); + if (node == NULL) { + g_return_if_reached(); + } + g_debug("Reason: %s\n", node->content); + node = g_hash_table_lookup(root->children, detail_key); + if (node == NULL) { + g_return_if_reached(); + } + g_debug("Detail: %s\n", node->content); +} + +static void parse_action_response(RestProxyCall *call, OvirtVm *vm, GError **error) +{ + RestXmlParser *parser; + RestXmlNode *root; + + parser = rest_xml_parser_new (); + + root = rest_xml_parser_parse_from_data (parser, + rest_proxy_call_get_payload (call), + rest_proxy_call_get_payload_length (call)); + + if (g_strcmp0(root->name, "action") == 0) { + if (parse_action_status(root, error) == OVIRT_RESPONSE_COMPLETE) { + parse_ticket_status(root, vm, error); + } + } else if (g_strcmp0(root->name, "fault") == 0) { + parse_fault(root, error); + } else { + g_warn_if_reached(); + } + + rest_xml_node_unref(root); + g_object_unref(G_OBJECT(parser)); +} + + +static gboolean ovirt_proxy_vm_action(OvirtProxy *proxy, OvirtVm *vm, + const char *action, GError **error) +{ + RestProxyCall *call; + const char *function; + + g_return_val_if_fail(OVIRT_IS_VM(vm), FALSE); + g_return_val_if_fail(action != NULL, FALSE); + g_return_val_if_fail(OVIRT_IS_PROXY(proxy), FALSE); + g_return_val_if_fail(REST_IS_PROXY(proxy->priv->rest_proxy), FALSE); + g_return_val_if_fail((error == NULL) || (*error == NULL), FALSE); + + function = ovirt_vm_get_action(vm, action); + g_return_val_if_fail(function != NULL, FALSE); + + call = REST_PROXY_CALL(ovirt_rest_call_new(proxy->priv->rest_proxy)); + rest_proxy_call_set_method(call, "POST"); + rest_proxy_call_set_function(call, function); + rest_proxy_call_add_param(call, "async", "false"); + + if (!rest_proxy_call_sync(call, error)) { + g_warning("Error while running %s on %p", action, vm); + parse_action_response(call, vm, NULL); + g_object_unref(G_OBJECT(call)); + return FALSE; + } + + parse_action_response(call, vm, NULL); + + g_object_unref(G_OBJECT(call)); + + return TRUE; +} + +gboolean ovirt_proxy_vm_get_ticket(OvirtProxy *proxy, OvirtVm *vm, GError **error) +{ + return ovirt_proxy_vm_action(proxy, vm, "ticket", error); +} + +gboolean ovirt_proxy_vm_start(OvirtProxy *proxy, OvirtVm *vm, GError **error) +{ + return ovirt_proxy_vm_action(proxy, vm, "start", error); +} + +gboolean ovirt_proxy_vm_stop(OvirtProxy *proxy, OvirtVm *vm, GError **error) +{ + return ovirt_proxy_vm_action(proxy, vm, "stop", error); +} + +static void +ovirt_get_property(GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + OvirtProxy *self = OVIRT_PROXY(object); + + switch (property_id) { + case PROP_URI: { + char *uri; + g_object_get(G_OBJECT(self->priv->rest_proxy), + "url-format", &uri, + NULL); + g_value_take_string(value, uri); + break; + } + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +ovirt_set_property(GObject *object, guint property_id, + const GValue *value G_GNUC_UNUSED, GParamSpec *pspec) +{ + OvirtProxy *self = OVIRT_PROXY(object); + + switch (property_id) { + case PROP_URI: + if (self->priv->rest_proxy) + g_object_unref(self->priv->rest_proxy); + self->priv->rest_proxy = rest_proxy_new_with_authentication(g_value_get_string(value), + FALSE, + ADMIN_LOGIN, + ADMIN_PASSWORD); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + + +static void +ovirt_proxy_dispose(GObject *obj) +{ + OvirtProxy *proxy = OVIRT_PROXY(obj); + + g_clear_object(&proxy->priv->rest_proxy); + if (proxy->priv->vms) { + g_hash_table_unref(proxy->priv->vms); + proxy->priv->vms = NULL; + } + + G_OBJECT_CLASS(ovirt_proxy_parent_class)->dispose(obj); +} + +static void +ovirt_proxy_class_init(OvirtProxyClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS(klass); + + oclass->dispose = ovirt_proxy_dispose; + oclass->get_property = ovirt_get_property; + oclass->set_property = ovirt_set_property; + + g_type_class_add_private(klass, sizeof(OvirtProxyPrivate)); + + g_object_class_install_property(oclass, + PROP_URI, + g_param_spec_string("uri", + "REST URI", + "REST URI", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +ovirt_proxy_init(OvirtProxy *self) +{ + self->priv = OVIRT_PROXY_GET_PRIVATE(self); +} + +OvirtProxy *ovirt_proxy_new(const char *uri) +{ + return g_object_new(OVIRT_TYPE_PROXY, "uri", uri, NULL); +} diff --git a/src/ovirt-proxy.h b/src/ovirt-proxy.h new file mode 100644 index 0000000..18197a0 --- /dev/null +++ b/src/ovirt-proxy.h @@ -0,0 +1,70 @@ +/* + * ovirt-proxy.h: oVirt proxy using the oVirt REST API + * + * Copyright (C) 2012 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Christophe Fergeau <cfergeau@xxxxxxxxxx> + */ +#ifndef __OVIRT_PROXY_H__ +#define __OVIRT_PROXY_H__ + +#include <glib-object.h> +#include <ovirt-vm.h> + +G_BEGIN_DECLS + +#define OVIRT_TYPE_PROXY ovirt_proxy_get_type() + +#define OVIRT_PROXY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), OVIRT_TYPE_PROXY, OvirtProxy)) + +#define OVIRT_PROXY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), OVIRT_TYPE_PROXY, OvirtProxyClass)) + +#define OVIRT_IS_PROXY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OVIRT_TYPE_PROXY)) + +#define OVIRT_IS_PROXY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), OVIRT_TYPE_PROXY)) + +#define OVIRT_PROXY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), OVIRT_TYPE_PROXY, OvirtProxyClass)) + +typedef struct _OvirtProxy OvirtProxy; +typedef struct _OvirtProxyClass OvirtProxyClass; +typedef struct _OvirtProxyPrivate OvirtProxyPrivate; + +struct _OvirtProxy { + GObject parent; + + OvirtProxyPrivate *priv; +}; + +struct _OvirtProxyClass { + GObjectClass parent_class; +}; + +GType ovirt_proxy_get_type(void); + +OvirtProxy *ovirt_proxy_new(const char *uri); +OvirtVm *ovirt_proxy_lookup_vm(OvirtProxy *proxy, const char *vm_name, + GError **error); +gboolean ovirt_proxy_vm_get_ticket(OvirtProxy *proxy, OvirtVm *vm, GError **error); +gboolean ovirt_proxy_vm_start(OvirtProxy *proxy, OvirtVm *vm, GError **error); +gboolean ovirt_proxy_vm_stop(OvirtProxy *proxy, OvirtVm *vm, GError **error); + +#endif -- 1.7.10.2