From 77c28bd8d7e1cd268d2dd1d95b2c8c4c72badbd0 Mon Sep 17 00:00:00 2001
From: Jaume Devesa <jaumedevesa@gmail.com>
Date: Sun, 13 Jan 2013 19:46:05 +0100
Subject: [PATCH 1/2] Abiquo Compute Driver

Abiquo Driver for Libcloud.
Jira issue: https://issues.apache.org/jira/browse/LIBCLOUD-250
---
 libcloud/common/abiquo.py                          |  230 +++++++
 libcloud/compute/drivers/__init__.py               |    1 +
 libcloud/compute/drivers/abiquo.py                 |  702 ++++++++++++++++++++
 libcloud/compute/providers.py                      |    4 +-
 libcloud/compute/types.py                          |    2 +
 libcloud/test/compute/fixtures/abiquo/dcs.xml      |   78 +++
 libcloud/test/compute/fixtures/abiquo/ent_1.xml    |   33 +
 .../test/compute/fixtures/abiquo/ent_1_dcrep_2.xml |    8 +
 .../fixtures/abiquo/ent_1_dcrep_2_template_11.xml  |   28 +
 .../fixtures/abiquo/ent_1_dcrep_2_templates.xml    |   41 ++
 .../test/compute/fixtures/abiquo/ent_1_dcreps.xml  |   10 +
 libcloud/test/compute/fixtures/abiquo/login.xml    |   17 +
 .../compute/fixtures/abiquo/not_found_error.xml    |    7 +
 .../compute/fixtures/abiquo/privilege_errors.html  |   23 +
 .../compute/fixtures/abiquo/unauthorized_user.html |   23 +
 libcloud/test/compute/fixtures/abiquo/vdc_4.xml    |   47 ++
 .../test/compute/fixtures/abiquo/vdc_4_vapp_5.xml  |   18 +
 .../fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml    |   18 +
 .../abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml     |   38 ++
 .../compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml   |   23 +
 .../test/compute/fixtures/abiquo/vdc_4_vapp_6.xml  |   19 +
 .../fixtures/abiquo/vdc_4_vapp_6_undeploy.xml      |    5 +
 .../fixtures/abiquo/vdc_4_vapp_6_undeploy_task.xml |   31 +
 .../abiquo/vdc_4_vapp_6_undeploy_task_failed.xml   |   31 +
 .../compute/fixtures/abiquo/vdc_4_vapp_6_vm_3.xml  |   22 +
 .../abiquo/vdc_4_vapp_6_vm_3_allocated.xml         |   22 +
 .../fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy.xml   |    3 +
 .../abiquo/vdc_4_vapp_6_vm_3_deploy_task.xml       |   31 +
 .../vdc_4_vapp_6_vm_3_deploy_task_failed.xml       |   31 +
 .../fixtures/abiquo/vdc_4_vapp_6_vm_3_deployed.xml |   22 +
 .../fixtures/abiquo/vdc_4_vapp_6_vm_3_nics.xml     |   10 +
 .../fixtures/abiquo/vdc_4_vapp_6_vm_3_reset.xml    |    5 +
 .../abiquo/vdc_4_vapp_6_vm_3_reset_task.xml        |   22 +
 .../fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy.xml |    5 +
 .../abiquo/vdc_4_vapp_6_vm_3_undeploy_task.xml     |   22 +
 .../vdc_4_vapp_6_vm_3_undeploy_task_failed.xml     |   22 +
 .../abiquo/vdc_4_vapp_6_vm_creation_ok.xml         |   20 +
 .../compute/fixtures/abiquo/vdc_4_vapp_6_vms.xml   |   23 +
 .../fixtures/abiquo/vdc_4_vapp_6_vms_allocated.xml |   23 +
 .../fixtures/abiquo/vdc_4_vapp_creation_ok.xml     |   18 +
 .../test/compute/fixtures/abiquo/vdc_4_vapps.xml   |   25 +
 libcloud/test/compute/fixtures/abiquo/vdcs.xml     |   49 ++
 libcloud/test/compute/test_abiquo.py               |  401 +++++++++++
 43 files changed, 2212 insertions(+), 1 deletions(-)
 create mode 100644 libcloud/common/abiquo.py
 create mode 100644 libcloud/compute/drivers/abiquo.py
 create mode 100644 libcloud/test/compute/fixtures/abiquo/dcs.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/ent_1.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/login.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/not_found_error.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/privilege_errors.html
 create mode 100644 libcloud/test/compute/fixtures/abiquo/unauthorized_user.html
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task_failed.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_allocated.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task_failed.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deployed.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_nics.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset_task.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task_failed.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_creation_ok.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms_allocated.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_creation_ok.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdc_4_vapps.xml
 create mode 100644 libcloud/test/compute/fixtures/abiquo/vdcs.xml
 create mode 100644 libcloud/test/compute/test_abiquo.py

diff --git libcloud/common/abiquo.py libcloud/common/abiquo.py
new file mode 100644
index 0000000..7b92831
--- /dev/null
+++ libcloud/common/abiquo.py
@@ -0,0 +1,230 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Abiquo Utilities Module for the Abiquo Driver.
+
+Common utilities needed by the L{AbiquoNodeDriver}.
+"""
+
+from libcloud.common.base import ConnectionUserAndKey, PollingConnection
+from libcloud.common.base import XmlResponse
+from libcloud.common.types import InvalidCredsError, LibcloudError
+import base64
+import sys
+from libcloud.utils.py3 import httplib
+from libcloud.utils.py3 import urlparse
+from libcloud.utils.py3 import b
+from libcloud.compute.base import NodeState
+
+
+def get_href(element, rel):
+    """ Search a RESTLink element in the L{AbiquoResponse}
+
+    Abiquo, as a REST API, it offers self-discovering functionality.
+    That means that you could walk through the whole API only
+    navigating from the links offered by the entities.
+
+    This is a basic method to find the 'relations' of an entity searching into
+    its links.
+
+    For instance, a Rack entity serialized as XML as the following::
+
+        <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+        <rack>
+         <link href="http://host/api/admin/datacenters/1"
+            type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+         <link href="http://host/api/admin/datacenters/1/racks/1"
+            type="application/vnd.abiquo.rack+xml" rel="edit"/>
+         <link href="http://host/api/admin/datacenters/1/racks/1/machines"
+            type="application/vnd.abiquo.machines+xml" rel="machines"/>
+         <haEnabled>false</haEnabled>
+         <id>1</id>
+         <longDescription></longDescription>
+         <name>racacaca</name>
+         <nrsq>10</nrsq>
+         <shortDescription></shortDescription>
+         <vlanIdMax>4094</vlanIdMax>
+         <vlanIdMin>2</vlanIdMin>
+         <vlanPerVdcReserved>1</vlanPerVdcReserved>
+         <vlansIdAvoided></vlansIdAvoided>
+        </rack>
+
+    offers link to datacenters (rel='datacenter'), to itself (rel='edit') and
+    to the machines defined in it (rel='machines')
+
+    A call to this method with the 'rack' element using 'datacenter' as 'rel'
+    will return:
+
+    'http://10.60.12.7:80/api/admin/datacenters/1'
+
+    @type  element: C{xml.etree.ElementTree}
+    @param element: Xml Entity returned by Abiquo API (required)
+    @type      rel: C{string}
+    @param     rel: relation link name
+    @rtype:         C{string}
+    @return:        the 'href' value according to the 'rel' input parameter
+    """
+    links = element.findall('link')
+    for link in links:
+        if link.attrib['rel'] == rel:
+            href = link.attrib['href']
+            # href is something like:
+            #
+            # 'http://localhost:80/api/admin/enterprises'
+            #
+            # we are only interested in '/admin/enterprises/' part
+            return urlparse.urlparse(href).path[len(b('/api')):]
+
+
+class AbiquoResponse(XmlResponse):
+    """ Abiquo XML Response
+
+    Wraps the response in XML bodies or extract the error data in
+    case of error. """
+
+    # Map between abiquo state and Libcloud State
+    NODE_STATE_MAP = {
+        "NOT_ALLOCATED": NodeState.TERMINATED,
+        "ALLOCATED": NodeState.PENDING,
+        "CONFIGURED": NodeState.PENDING,
+        "ON": NodeState.RUNNING,
+        "PAUSED": NodeState.PENDING,
+        "OFF": NodeState.PENDING,
+        "LOCKED": NodeState.PENDING,
+        "UNKNOWN": NodeState.UNKNOWN
+    }
+
+    def parse_error(self):
+        """ Parse the error messages
+
+        Response body can easily be handled by this class parent
+        L{XmlResponse}, but there are use cases which Abiquo API
+        does not respond an XML but an HTML. So we need to
+        handle these special cases"""
+        if self.status == httplib.UNAUTHORIZED:
+            raise InvalidCredsError(driver='AbiquoNodeDriver')
+        elif self.status == httplib.FORBIDDEN:
+            raise ForbiddenError()
+        else:
+            errors = self.parse_body().findall('error')
+            # Most of the exceptions only have one error
+            raise LibcloudError(errors[0].findtext('message'))
+
+    def success(self):
+        """ Determine if the request was successful.
+
+        Any of the 2XX HTTP response codes are accepted as successfull requests
+
+        @rtype:  C{bool}
+        @return: successful request or not"""
+        return (self.status == httplib.OK or self.status == httplib.CREATED or
+                self.status == httplib.NO_CONTENT or
+                self.status == httplib.ACCEPTED)
+
+    def async_success(self):
+        """ Determinate if async request was successful
+
+        An async_request retrieves for a task object that can be successfully
+        retrieved (self.status == OK), but the asyncronous task (the body of
+        the HTTP response) which we are asking for has finished with an error.
+        So this method checks if the status code is 'OK' and if the task
+        has finished successfully.
+
+        @rtype:  C{bool}
+        @return: successful asynchronous request or not"""
+        if self.success():
+            # So we have a 'task' object in the body
+            task = self.parse_body()
+            return task.findtext('state') == 'FINISHED_SUCCESSFULLY'
+        else:
+            return False
+
+
+class AbiquoConnection(ConnectionUserAndKey, PollingConnection):
+    """ A Connection to Abiquo API
+
+    Basic L{ConnectionUserAndKey} connection with L{PollingConnection} features
+    for asynchronous tasks"""
+
+    responseCls = AbiquoResponse
+
+    def add_default_headers(self, headers):
+        """ Add Basic Authentication header to all the requests
+
+        It injects the 'Authorization: Basic Base64String===' header
+        in each request
+
+        @type  headers: C{dict}
+        @param headers: Default input headers
+        @rtype          C{dict}
+        @return:        Default input headers with the 'Authorization'
+                            header"""
+        encoded = base64.b64encode(b('%s:%s' % (self.user_id, self.key)))
+
+        if sys.version_info >= (3, 0):
+            encoded = encoded.decode()
+
+        authorization = 'Basic ' + encoded
+
+        headers['Authorization'] = authorization
+        return headers
+
+    def get_poll_request_kwargs(self, response, context, request_kwargs):
+        """ Manage polling request arguments
+
+        Return keyword arguments which are passed to the L{NodeDriver.request}
+        method when polling for the job status. The Abiquo Asynchronous
+        Response returns and 'acceptedrequest' XmlElement as the following::
+
+            <acceptedrequest>
+                <link href="http://uri/to/task" rel="status"/>
+                <message>You can follow the progress in the link</message>
+            </acceptedrequest>
+
+        We need to extract the href URI to poll.
+
+        @type    response:       C{xml.etree.ElementTree}
+        @keyword response:       Object returned by poll request.
+        @type    request_kwargs: C{dict}
+        @keyword request_kwargs: Default request arguments and headers
+        @rtype:                  C{dict}
+        @return:                 Modified keyword arguments"""
+        accepted_request_obj = response.object
+        link_poll = get_href(accepted_request_obj, 'status')
+
+        # Override just the 'action' and 'method' keys of the previous dict
+        request_kwargs['action'] = link_poll
+        request_kwargs['method'] = 'GET'
+        return request_kwargs
+
+    def has_completed(self, response):
+        """ Decide if the asynchronous job has ended
+
+        @type  response: C{xml.etree.ElementTree}
+        @param response: Response object returned by poll request
+        @rtype:          C{bool}
+        @return:         Whether the job has completed"""
+        task = response.object
+        task_state = task.findtext('state')
+        return (task_state == 'FINISHED_SUCCESSFULLY' or
+                task_state == 'FINISHED_UNSUCCESSFULLY' or
+                task_state == 'ABORTED')
+
+
+class ForbiddenError(LibcloudError):
+    """Exception used when credentials are ok but user has not permissions"""
+
+    def __init__(self):
+        message = 'User has not permission to perform this task.'
+        super(LibcloudError, self).__init__(message, 'AbiquoNodeDriver')
diff --git libcloud/compute/drivers/__init__.py libcloud/compute/drivers/__init__.py
index 31af06d..68f273a 100644
--- libcloud/compute/drivers/__init__.py
+++ libcloud/compute/drivers/__init__.py
@@ -18,6 +18,7 @@ Drivers for working with different providers
 """
 
 __all__ = [
+    'abiquo',
     'brightbox',
     'bluebox',
     'dummy',
diff --git libcloud/compute/drivers/abiquo.py libcloud/compute/drivers/abiquo.py
new file mode 100644
index 0000000..04af66c
--- /dev/null
+++ libcloud/compute/drivers/abiquo.py
@@ -0,0 +1,702 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Abiquo Compute Driver
+
+The driver implements the compute Abiquo functionality for the Abiquo API.
+This version is compatible with the following versions of Abiquo:
+
+    * Abiquo 2.0 (http://wiki.abiquo.com/display/ABI20/The+Abiquo+API)
+    * Abiquo 2.2 (http://wiki.abiquo.com/display/ABI22/The+Abiquo+API)
+"""
+from libcloud.compute.base import NodeDriver, NodeSize
+from libcloud.compute.types import Provider, LibcloudError
+from libcloud.common.abiquo import (AbiquoConnection, get_href,
+                                    AbiquoResponse)
+from libcloud.compute.base import NodeLocation, NodeImage, Node
+from libcloud.utils.py3 import tostring
+import xml.etree.ElementTree as ET
+
+
+class AbiquoNodeDriver(NodeDriver):
+    """Implements the L{NodeDriver}'s for the Abiquo Compute Provider"""
+
+    type = Provider.ABIQUO
+    name = "Abiquo"
+    website = 'http://www.abiquo.com/'
+    connectionCls = AbiquoConnection
+    features = {"create_node": ['password']}
+    timeout = 2000  # some images take a lot of time!
+
+    # Media Types
+    NODES_MIME_TYPE = "application/vnd.abiquo.virtualmachineswithnode+xml"
+    NODE_MIME_TYPE = "application/vnd.abiquo.virtualmachinewithnode+xml"
+    VAPP_MIME_TYPE = "application/vnd.abiquo.virtualappliance+xml"
+    VM_TASK_MIME_TYPE = 'application/vnd.abiquo.virtualmachinetask+xml'
+
+    #Others
+    GIGABYTE = 1073741824
+
+    def __init__(self, user_id, secret, endpoint, **kwargs):
+        """Initializes Abiquo Driver
+
+        Initializes the L{NodeDriver} object. After that, it generates the
+        context
+
+        @param       user_id: identifier of Abiquo user (required)
+        @type        user_id: C{str}
+        @param       secret: password of the Abiquo user (required)
+        @type        secret: C{str}
+        @param       endpoint: Abiquo API endpoint (required)
+        @type        endpoint: C{str} that can be parsed as URL """
+        self.endpoint = endpoint
+        super(AbiquoNodeDriver, self).__init__(key=user_id, secret=secret,
+                                               secure=False, host=None,
+                                               port=None, **kwargs)
+        self.ex_set_context()
+
+    def create_node(self, **kwargs):
+        """Create a new node instance in Abiquo
+
+        All the L{Node}s need to be defined inside a VirtualAppliance
+        (called L{NodeGroup} here). If there is no group name defined,
+        'libcloud' name will be used instead.
+
+        This method wraps these Abiquo actions:
+
+            1. Create a group if it does not exist.
+            2. Register a new node in the group.
+            3. Deploy the node and boot it.
+            4. Retrieves it again to get schedule-time attributes (such as ips
+               and vnc ports).
+
+        The rest of the driver methods has been created in a way that, if any
+        of these actions fail, the user can not reach an inconsistent state
+
+        @keyword    name:   The name for this new node (required)
+        @type       name:   C{str}
+
+        @keyword    size:   The size of resources allocated to this node.
+        @type       size:   L{NodeSize}
+
+        @keyword    image:  OS Image to boot on node. (required)
+        @type       image:  L{NodeImage}
+
+        @keyword    location: Which data center to create a node in. If empty,
+                              undefined behavoir will be selected. (optional)
+        @type       location: L{NodeLocation}
+
+        @keyword    auth:   Initial authentication information for the node
+                            (optional)
+        @type       auth:   L{NodeAuthPassword}
+
+        @keyword   group_name:  Which group this node belongs to. If empty,
+                                 it will be created into 'libcloud' group. If
+                                 it does not found any group in the target
+                                 location (random location if you have not set
+                                 the parameter), then it will create a new
+                                 group with this name.
+        @type     group_name:  c{str}
+
+        @return:               The newly created node.
+        @rtype:                L{Node}
+        """
+
+        #first, get image location
+        if not 'image' in kwargs:
+            error = "'image' parameter is mandatory"
+            raise LibcloudError(error, self)
+
+        image = kwargs['image']
+
+        # Get the location argument
+        location = None
+        if 'location' in kwargs:
+            location = kwargs['location']
+            if not location in self.list_locations():
+                raise LibcloudError('Location does not exist')
+
+        # Check if the image is compatible with any of the locations or
+        # the input location
+        loc = None
+        target_loc = None
+        for candidate_loc in self._get_locations(location):
+            link_vdc = self.connection.context['locations'][candidate_loc]
+            e_vdc = self.connection.request(link_vdc).object
+            # url_location = get_href(e_vdc, 'datacenter')
+            for img in self.list_images(candidate_loc):
+                if img.id == image.id:
+                    # To be clear:
+                    # 'loc' is the xml element we navigate into
+                    # 'target_loc' is the L{NodeLocation} entity
+                    loc = e_vdc
+                    target_loc = candidate_loc
+                    break
+        if loc is None:
+            error = 'The image can not be used in any location'
+            raise LibcloudError(error, self)
+
+        # -------------------------------------------------------
+        #  Define the Group
+        # -------------------------------------------------------
+        if not 'group_name' in kwargs:
+            group_name = NodeGroup.DEFAULT_GROUP_NAME
+        else:
+            group_name = kwargs['group_name']
+
+        # find group into location
+        groups_link = get_href(loc, 'virtualappliances')
+        vapps_element = self.connection.request(groups_link).object
+        target_group = None
+        nodes_link = None
+        for vapp in vapps_element.findall('virtualAppliance'):
+            if vapp.findtext('name') == group_name:
+                target_group = vapp
+                nodes_link = get_href(target_group, 'virtualmachines')
+                break
+
+        # target group not found: create it
+        if target_group is None:
+            target_group = self.ex_create_group(group_name, target_loc)
+            nodes_link = target_group.uri + '/virtualmachines'
+
+        # -------------------------------------------------------
+        # Register the Node
+        # -------------------------------------------------------
+        # prepare the element
+        vm = ET.Element('virtualmachinewithnode')
+        if 'name' in kwargs:
+            vmname = ET.SubElement(vm, 'nodeName')
+            vmname.text = kwargs['name']
+        attrib = {'type': 'application/vnd.abiquo/virtualmachinetemplate+xml',
+                  'rel': 'virtualmachinetemplate',
+                  'href': image.extra['url']}
+        ET.SubElement(vm, 'link', attrib=attrib)
+        headers = {'Content-type': self.NODE_MIME_TYPE}
+        if 'size' in kwargs:
+            # Override the 'NodeSize' data
+            ram = ET.SubElement(vm, 'ram')
+            ram.text = str(kwargs['size'].ram)
+            hd = ET.SubElement(vm, 'hdInBytes')
+            hd.text = str(int(kwargs['size'].disk) * self.GIGABYTE)
+
+        # Create the virtual machine
+        vm = self.connection.request(nodes_link, data=tostring(vm),
+                                     headers=headers, method='POST').object
+        edit_vm = get_href(vm, 'edit')
+        headers = {'Accept': self.NODE_MIME_TYPE}
+        vm = self.connection.request(edit_vm, headers=headers).object
+
+        # Execute the 'deploy' action
+        self._deploy_remote(vm)
+
+        # --------------------------------------------------------
+        #     Retrieve it again, to get some schedule-defined
+        #     values.
+        # --------------------------------------------------------
+        edit_vm = get_href(vm, 'edit')
+        headers = {'Accept': self.NODE_MIME_TYPE}
+        vm = self.connection.request(edit_vm, headers=headers).object
+        return self._to_node(vm, self)
+
+    def destroy_node(self, node):
+        """Destroy a node
+
+        Depending on the provider, this may destroy all data associated with
+        the node, including backups.
+
+        @param node: The node to be destroyed
+        @type node: L{Node}
+
+        @return: True if the destroy was successful, otherwise False
+        @rtype: C{bool}
+        """
+
+        # Refresh node state
+        e_vm = self.connection.request(node.extra['uri_id']).object
+        state = e_vm.findtext('state')
+        if (state == 'ALLOCATED' or state == 'CONFIGURED' or state ==
+                'LOCKED' or state == 'UNKNOWN'):
+            raise LibcloudError('Invalid Node state', self)
+
+        if state != 'NOT_ALLOCATED':
+            # prepare the element that forces the undeploy
+            vm_task = ET.Element('virtualmachinetask')
+            force_undeploy = ET.SubElement(vm_task, 'forceUndeploy')
+            force_undeploy.text = 'True'
+            # Set the URI
+            destroy_uri = node.extra['uri_id'] + '/action/undeploy'
+            # Prepare the headers
+            headers = {'Content-type': self.VM_TASK_MIME_TYPE}
+            res = self.connection.async_request(action=destroy_uri,
+                                                method='POST',
+                                                data=tostring(vm_task),
+                                                headers=headers)
+
+        if state == 'NOT_ALLOCATED' or res.async_success():
+            self.connection.request(action=node.extra['uri_id'],
+                                    method='DELETE')
+            return True
+        else:
+            return False
+
+    def ex_run_node(self, node):
+        """ Runs a node
+
+        Here there is a bit difference between Abiquo states and libcloud
+        states, so this method is created to have better compatibility. In
+        libcloud, if the node is not running, then it does not exist (avoiding
+        UNKNOWN and temporal states). In Abiquo, you can define a node, and
+        then deploy it.
+
+        If the node is in L{NodeState.TERMINATED} libcloud's state and in
+        'NOT_DEPLOYED' Abiquo state, there is a way to run and recover it
+        for libcloud using this method. There is no way to reach this state
+        if you are using only libcloud, but you may have used another Abiquo
+        client and now you want to recover your node to be used by libcloud.
+
+        @param node: The node to run
+        @type node: L{Node}
+
+        @return: The node itself, but with the new state
+        @rtype: L{Node}
+        """
+        # Refresh node state
+        e_vm = self.connection.request(node.extra['uri_id']).object
+        state = e_vm.findtext('state')
+
+        if state != 'NOT_ALLOCATED':
+            raise LibcloudError('Invalid Node state', self)
+
+        # --------------------------------------------------------
+        #     Deploy the Node
+        # --------------------------------------------------------
+        self._deploy_remote(e_vm)
+
+        # --------------------------------------------------------
+        #     Retrieve it again, to get some schedule-defined
+        #     values.
+        # --------------------------------------------------------
+        edit_vm = get_href(e_vm, 'edit')
+        headers = {'Accept': self.NODE_MIME_TYPE}
+        e_vm = self.connection.request(edit_vm, headers=headers).object
+        return self._to_node(e_vm, self)
+
+    def ex_set_context(self):
+        """ Generates the context
+
+        For each connection, it is good to store some objects that will be
+        useful for further requests, such as the 'user' and the 'enterprise'
+        objects.
+
+        Executes the 'login' resource after setting the connection parameters
+        and, if the execution is successful, it sets the 'user' object into
+        context. After that, it also requests for the 'enterprise' and
+        'locations' data.
+
+        List of locations should remain the same for a single libcloud
+        connection. However, this method is public and you are able to
+        refresh the list of locations any time.
+        """
+        user = self.connection.request('/login').object
+        self.connection.context['user'] = user
+        e_ent = get_href(self.connection.context['user'],
+                         'enterprise')
+        ent = self.connection.request(e_ent).object
+        self.connection.context['enterprise'] = ent
+
+        uri_vdcs = '/cloud/virtualdatacenters'
+        e_vdcs = self.connection.request(uri_vdcs).object
+
+        # Set a dict for the datacenter and its href for a further search
+        params = {"idEnterprise": self._get_enterprise_id()}
+        e_dcs = self.connection.request('/admin/datacenters',
+                                        params=params).object
+        dc_dict = {}
+        for dc in e_dcs.findall('datacenter'):
+            dc_dict[get_href(dc, 'edit')] = dc
+
+        # Set the context for the locations
+        self.connection.context['locations'] = {}
+        for e_vdc in e_vdcs.findall('virtualDatacenter'):
+            dc_link = get_href(e_vdc, 'datacenter')
+            loc = self._to_location(e_vdc, dc_dict[dc_link], self)
+
+            # Save into context the link to the itself because we will need
+            # it in the future, but we save here to don't extend the class
+            # L{NodeLocation}.
+            # So here we have the dict: L{NodeLocation} -> link_datacenter
+            self.connection.context['locations'][loc] = get_href(e_vdc, 'edit')
+
+    def ex_create_group(self, name, location=None):
+        """ Create an empty group
+
+        You can specify the location as well.
+
+        @param     name:     name of the group (required)
+        @type      name:     C{str}
+
+        @param     location: location were to create the group
+        @type      location: L{NodeLocation}
+
+        @returns:            the created group
+        @rtype:              L{NodeGroup}
+        """
+        # prepare the element
+        vapp = ET.Element('virtualAppliance')
+        vapp_name = ET.SubElement(vapp, 'name')
+        vapp_name.text = name
+
+        if location is None:
+            location = self.list_locations()[0]
+        elif not location in self.list_locations():
+            raise LibcloudError('Location does not exist')
+
+        link_vdc = self.connection.context['locations'][location]
+        e_vdc = self.connection.request(link_vdc).object
+
+        creation_link = get_href(e_vdc, 'virtualappliances')
+        headers = {'Content-type': self.VAPP_MIME_TYPE}
+        vapp = self.connection.request(creation_link, data=tostring(vapp),
+                                       headers=headers, method='POST').object
+
+        uri_vapp = get_href(vapp, 'edit')
+
+        return NodeGroup(self, vapp.findtext('name'),
+                         uri=uri_vapp)
+
+    def ex_destroy_group(self, group):
+        """ Destroy a group
+
+        Be careful! Destroying a group means destroying all the L{Node}s there
+        and the group itself!
+
+        If there is currently any action over any L{Node} of the L{NodeGroup},
+        then the method will raise an exception.
+
+        @param     name: The group (required)
+        @type      name: L{NodeGroup}
+
+        @return:         If the group was destroyed successfully
+        @rtype:          C{bool}
+        """
+        # Refresh group state
+        e_group = self.connection.request(group.uri).object
+        state = e_group.findtext('state')
+
+        if state != 'NOT_DEPLOYED' and state != 'DEPLOYED':
+            error = 'Can not destroy group because of current state'
+            raise LibcloudError(error, self)
+
+        if state == 'DEPLOYED':
+            # prepare the element that forces the undeploy
+            vm_task = ET.Element('virtualmachinetask')
+            force_undeploy = ET.SubElement(vm_task, 'forceUndeploy')
+            force_undeploy.text = 'True'
+
+            # Set the URI
+            undeploy_uri = group.uri + '/action/undeploy'
+
+            # Prepare the headers
+            headers = {'Content-type': self.VM_TASK_MIME_TYPE}
+            res = self.connection.async_request(action=undeploy_uri,
+                                                method='POST',
+                                                data=tostring(vm_task),
+                                                headers=headers)
+
+        if state == 'NOT_DEPLOYED' or res.async_success():
+            # The node is no longer deployed. Unregister it.
+            self.connection.request(action=group.uri,
+                                    method='DELETE')
+            return True
+        else:
+            return False
+
+    def ex_list_groups(self, location=None):
+        """
+        List all groups
+
+        @param location: filter the groups by location (optional)
+        @type  location: a L{NodeLocation} instance.
+
+        @return:         the list of L{NodeGroup}
+        """
+        groups = []
+        for vdc in self._get_locations(location):
+            link_vdc = self.connection.context['locations'][vdc]
+            e_vdc = self.connection.request(link_vdc).object
+            apps_link = get_href(e_vdc, 'virtualappliances')
+            vapps = self.connection.request(apps_link).object
+            for vapp in vapps.findall('virtualAppliance'):
+                nodes = []
+                vms_link = get_href(vapp, 'virtualmachines')
+                headers = {'Accept': self.NODES_MIME_TYPE}
+                vms = self.connection.request(vms_link, headers=headers).object
+                for vm in vms.findall('virtualmachinewithnode'):
+                    nodes.append(self._to_node(vm, self))
+
+                group = NodeGroup(self, vapp.findtext('name'),
+                                  nodes, get_href(vapp, 'edit'))
+                groups.append(group)
+
+        return groups
+
+    def list_images(self, location=None):
+        """
+        List images on Abiquo Repositories
+
+        @keyword location: The location at to list images
+        @type    location: L{NodeLocation}
+
+        @return:           list of node image objects
+        @rtype:            C{list} of L{NodeImage}
+        """
+        enterprise_id = self._get_enterprise_id()
+        uri = "/admin/enterprises/%s/datacenterrepositories/" % enterprise_id
+        repos = self.connection.request(uri).object
+
+        images = []
+        for repo in repos.findall('datacenterRepository'):
+            # filter by location. Skips when the name of the location
+            # is different from the 'datacenterRepository' element
+            for vdc in self._get_locations(location):
+                # Check if the virtual datacenter belongs to this repo
+                link_vdc = self.connection.context['locations'][vdc]
+                e_vdc = self.connection.request(link_vdc).object
+                dc_link_vdc = get_href(e_vdc, 'datacenter')
+                dc_link_repo = get_href(repo, 'datacenter')
+                if dc_link_vdc == dc_link_repo:
+                    # Filter the template in case we don't have it yet
+                    url_templates = get_href(repo, 'virtualmachinetemplates')
+                    hypervisor_type = e_vdc.findtext('hypervisorType')
+                    params = {'hypervisorTypeName': hypervisor_type}
+                    templates = self.connection.request(url_templates,
+                                                        params).object
+                    for templ in templates.findall('virtualMachineTemplate'):
+                        # Avoid duplicated templates
+                        id_template = templ.findtext('id')
+                        ids = [image.id for image in images]
+                        if id_template not in ids:
+                            images.append(self._to_nodeimage(templ, self,
+                                                             get_href(repo,
+                                                                      'edit')))
+
+        return images
+
+    def list_locations(self):
+        """Return list of locations where the user has access to
+
+        @return: the list of L{NodeLocation} available for the current user
+        @rtype:  C{list} of L{NodeLocation}
+        """
+        return list(self.connection.context['locations'].keys())
+
+    def list_nodes(self, location=None):
+        """List all nodes
+
+        @param location: Filter the groups by location (optional)
+        @type  location: a L{NodeLocation} instance.
+
+        @return:  List of node objects
+        @rtype: C{list} of L{Node}
+        """
+        nodes = []
+
+        for group in self.ex_list_groups(location):
+            nodes.extend(group.nodes)
+
+        return nodes
+
+    def list_sizes(self, location=None):
+        """List sizes on a provider
+
+        Abiquo does not work with sizes. However, this method
+        returns a list of predefined ones (copied from L{DummyNodeDriver} but
+        without price neither bandwidth) to help the users to create their own.
+
+        If you call the method L{AbiquoNodeDriver.create_node} with the size
+        informed, it will just override the 'ram' value of the 'image'
+        template. So it is no too much usefull work with sizes...
+
+        @return: The list of sizes
+        @rtype:  C{list} of L{NodeSizes}
+        """
+        return [
+            NodeSize(id=1,
+                     name="Small",
+                     ram=128,
+                     disk=4,
+                     bandwidth=None,
+                     price=None,
+                     driver=self),
+            NodeSize(id=2,
+                     name="Medium",
+                     ram=512,
+                     disk=16,
+                     bandwidth=None,
+                     price=None,
+                     driver=self),
+            NodeSize(id=3,
+                     name="Big",
+                     ram=4096,
+                     disk=32,
+                     bandwidth=None,
+                     price=None,
+                     driver=self),
+            NodeSize(id=4,
+                     name="XXL Big",
+                     ram=4096 * 2,
+                     disk=32 * 4,
+                     bandwidth=None,
+                     price=None,
+                     driver=self)
+        ]
+
+    def reboot_node(self, node):
+        """Reboot a node
+
+        @param node: The node to be rebooted
+        @type node: L{Node}
+
+        @return: True if the reboot was successful, otherwise False
+        @rtype: C{bool}
+        """
+        reboot_uri = node.extra['uri_id'] + '/action/reset'
+        res = self.connection.async_request(action=reboot_uri, method='POST')
+        return res.async_success()
+
+    # -------------------------
+    # Auxiliar methods
+    # -------------------------
+
+    def _ex_connection_class_kwargs(self):
+        """Set the endpoint as an extra L{AbiquoConnection} argument
+
+        According to Connection code, the "url" argument should be
+        parsed properly to connection.
+
+        @return: C{dict} of L{AbiquoConnection} input arguments
+        """
+
+        return {'url': self.endpoint}
+
+    def _deploy_remote(self, e_vm):
+        """ Asynchronous call to create the node"""
+        # --------------------------------------------------------
+        #     Deploy the Node
+        # --------------------------------------------------------
+        # prepare the element that forces the deploy
+        vm_task = ET.Element('virtualmachinetask')
+        force_deploy = ET.SubElement(vm_task, 'forceEnterpriseSoftLimits')
+        force_deploy.text = 'True'
+
+        # Prepare the headers
+        headers = {'Content-type': self.VM_TASK_MIME_TYPE}
+        link_deploy = get_href(e_vm, 'deploy')
+        res = self.connection.async_request(action=link_deploy, method='POST',
+                                            data=tostring(vm_task),
+                                            headers=headers)
+        if not res.async_success():
+            raise LibcloudError('Could not run the node', self)
+
+    def _to_location(self, vdc, dc, driver):
+        """ Generates the L{NodeLocation} class"""
+        identifier = vdc.findtext('id')
+        name = vdc.findtext('name')
+        country = dc.findtext('name')
+        return NodeLocation(identifier, name, country, driver)
+
+    def _to_node(self, vm, driver):
+        """ Generates the L{Node} class"""
+        identifier = vm.findtext('id')
+        name = vm.findtext('nodeName')
+        state = AbiquoResponse.NODE_STATE_MAP[vm.findtext('state')]
+
+        link_image = get_href(vm, 'virtualmachinetemplate')
+        image_element = self.connection.request(link_image).object
+        repo_link = get_href(image_element, 'datacenterrepository')
+        image = self._to_nodeimage(image_element, self, repo_link)
+
+        ## Fill the 'ips' data
+        private_ips = []
+        public_ips = []
+        nics_element = self.connection.request(get_href(vm, 'nics')).object
+        for nic in nics_element.findall('nic'):
+            ip = nic.findtext('ip')
+            for link in nic.findall('link'):
+                rel = link.attrib['rel']
+                if rel == 'privatenetwork':
+                    private_ips.append(ip)
+                elif (rel == 'publicnetwork' or rel == 'externalnetwork'
+                        or rel == 'unmanagednetwork'):
+                    public_ips.append(ip)
+
+        extra = {'uri_id': get_href(vm, 'edit')}
+
+        if vm.find('vdrpIp') is not None:
+            extra['vdrp_ip'] = vm.findtext('vdrpIP')
+            extra['vdrp_port'] = vm.findtext('vdrpPort')
+
+        return Node(identifier, name, state, public_ips, private_ips,
+                    driver, image=image, extra=extra)
+
+    def _to_nodeimage(self, template, driver, repo):
+        """Generates the L{NodeImage} class"""
+        identifier = template.findtext('id')
+        name = template.findtext('name')
+        url = get_href(template, 'edit')
+        extra = {'repo': repo, 'url': url}
+        return NodeImage(identifier, name, driver, extra)
+
+    def _get_locations(self, location=None):
+        """Returns the locations as a generator"""
+        if location is not None:
+            yield location
+        else:
+            for loc in self.list_locations():
+                yield loc
+
+    def _get_enterprise_id(self):
+        """Returns the identifier of the logged user's enterprise"""
+        return self.connection.context['enterprise'].findtext('id')
+
+
+class NodeGroup(object):
+    """Group of virtual machines that can be managed together
+
+    All L{Node}s in Abiquo must be defined inside a Virtual Appliance.
+    We offer a way to handle virtual appliances (called NodeGroup to
+    maintain some kind of name conventions here) inside the L{AbiquoNodeDriver}
+    without breaking compatibility of the rest of libcloud API.
+
+    If the user does not want to handle groups, all the virtual machines
+    will be created inside a group named 'libcloud'
+    """
+    DEFAULT_GROUP_NAME = 'libcloud'
+
+    def __init__(self, driver, name=DEFAULT_GROUP_NAME, nodes=[], uri=''):
+        """Initialize a new group object"""
+        self.driver = driver
+        self.name = name
+        self.nodes = nodes
+        self.uri = uri
+
+    def __repr__(self):
+        return (('<NodeGroup: name=%s, nodes=[%s] >')
+                % (self.name, ",".join(map(str, self.nodes))))
+
+    def destroy(self):
+        """Destroys the group delegating the execution to L{AbiquoNodeDriver}
+        """
+        return self.driver.ex_destroy_group(self)
diff --git libcloud/compute/providers.py libcloud/compute/providers.py
index 488901b..bdb1ba9 100644
--- libcloud/compute/providers.py
+++ libcloud/compute/providers.py
@@ -120,7 +120,9 @@ DRIVERS = {
     Provider.KTUCLOUD:
         ('libcloud.compute.drivers.ktucloud', 'KTUCloudNodeDriver'),
     Provider.HOSTVIRTUAL:
-        ('libcloud.compute.drivers.hostvirtual', 'HostVirtualNodeDriver')
+        ('libcloud.compute.drivers.hostvirtual', 'HostVirtualNodeDriver'),
+    Provider.ABIQUO:
+        ('libcloud.compute.drivers.abiquo', 'AbiquoNodeDriver')
 }
 
 
diff --git libcloud/compute/types.py libcloud/compute/types.py
index be35e3e..431944d 100644
--- libcloud/compute/types.py
+++ libcloud/compute/types.py
@@ -69,6 +69,7 @@ class Provider(object):
     @cvar VCL: VCL driver
     @cvar KTUCLOUD: kt ucloud driver
     @cvar GRIDSPOT: Gridspot driver
+    @cvar ABIQUO: Abiquo driver
     """
     DUMMY = 'dummy'
     EC2 = 'ec2'
@@ -112,6 +113,7 @@ class Provider(object):
     GRIDSPOT = 'gridspot'
     RACKSPACE_FIRST_GEN = 'rackspace_first_gen'
     HOSTVIRTUAL = 'hostvirtual'
+    ABIQUO = 'abiquo'
 
     # Deprecated constants which are still supported
     EC2_US_EAST = 'ec2_us_east'
diff --git libcloud/test/compute/fixtures/abiquo/dcs.xml libcloud/test/compute/fixtures/abiquo/dcs.xml
new file mode 100644
index 0000000..a014a42
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/dcs.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<datacenters>
+    <datacenter>
+        <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/admin/datacenters/2/action/getlimits" type="application/vnd.abiquo.limit+xml" rel="getLimits"/>
+        <link href="http://10.60.12.7:80/api/admin/datacenters/2/racks" type="application/vnd.abiquo.racks+xml" rel="racks"/>
+        <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices" type="application/vnd.abiquo.remoteservices+xml" rel="remoteservices"/>
+        <link href="http://10.60.12.7:80/api/admin/datacenters/2/storage/tiers" type="application/vnd.abiquo.tiers+xml" rel="tiers"/>
+        <id>2</id>
+        <location>barcelona</location>
+        <name>barcelona</name>
+        <remoteServices>
+            <remoteService>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/virtualfactory/action/check" rel="check"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/virtualfactory" type="application/vnd.abiquo.remoteservice+xml" rel="edit"/>
+                <id>3</id>
+                <status>1</status>
+                <type>VIRTUAL_FACTORY</type>
+                <uri>http://10.60.12.7:80/virtualfactory</uri>
+            </remoteService>
+            <remoteService>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/virtualsystemmonitor/action/check" rel="check"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/virtualsystemmonitor" type="application/vnd.abiquo.remoteservice+xml" rel="edit"/>
+                <id>4</id>
+                <status>1</status>
+                <type>VIRTUAL_SYSTEM_MONITOR</type>
+                <uri>http://10.60.12.7:80/vsm</uri>
+            </remoteService>
+            <remoteService>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/appliancemanager/action/check" rel="check"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/appliancemanager" type="application/vnd.abiquo.remoteservice+xml" rel="edit"/>
+                <id>5</id>
+                <status>1</status>
+                <type>APPLIANCE_MANAGER</type>
+                <uri>http://10.60.12.7:80/am</uri>
+            </remoteService>
+            <remoteService>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/nodecollector/action/check" rel="check"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/nodecollector" type="application/vnd.abiquo.remoteservice+xml" rel="edit"/>
+                <id>6</id>
+                <status>1</status>
+                <type>NODE_COLLECTOR</type>
+                <uri>http://10.60.12.7:80/nodecollector</uri>
+            </remoteService>
+            <remoteService>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/storagesystemmonitor/action/check" rel="check"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/storagesystemmonitor" type="application/vnd.abiquo.remoteservice+xml" rel="edit"/>
+                <id>7</id>
+                <status>1</status>
+                <type>STORAGE_SYSTEM_MONITOR</type>
+                <uri>http://10.60.12.7:80/ssm</uri>
+            </remoteService>
+            <remoteService>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/dhcpservice" type="application/vnd.abiquo.remoteservice+xml" rel="edit"/>
+                <id>8</id>
+                <status>1</status>
+                <type>DHCP_SERVICE</type>
+                <uri>omapi://10.60.12.7:7911</uri>
+            </remoteService>
+            <remoteService>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/bpmservice/action/check" rel="check"/>
+                <link href="http://10.60.12.7:80/api/admin/datacenters/2/remoteservices/bpmservice" type="application/vnd.abiquo.remoteservice+xml" rel="edit"/>
+                <id>9</id>
+                <status>1</status>
+                <type>BPM_SERVICE</type>
+                <uri>http://10.60.12.7:80/bpm-async</uri>
+            </remoteService>
+        </remoteServices>
+        <uuid>Abiquo</uuid>
+    </datacenter>
+</datacenters>
diff --git libcloud/test/compute/fixtures/abiquo/ent_1.xml libcloud/test/compute/fixtures/abiquo/ent_1.xml
new file mode 100644
index 0000000..80b0554
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/ent_1.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<enterprise>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/appslib/templateDefinitionLists" type="application/vnd.abiquo.templatedefinitionlists+xml" rel="appslib/templateDefinitionLists"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/appslib/templateDefinitions" type="application/vnd.abiquo.templatedefinitions+xml" rel="appslib/templateDefinitions"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/action/virtualdatacenters" type="application/vnd.abiquo.virtualdatacenters+xml" rel="cloud/virtualdatacenters"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/action/externalnetworks" type="application/vnd.abiquo.vlans+xml" rel="externalnetworks"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/action/ips" rel="ips" title="ips"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/limits" type="application/vnd.abiquo.limits+xml" rel="limits"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/reservedmachines" type="application/vnd.abiquo.machines+xml" rel="reservedmachines"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/users" type="application/vnd.abiquo.users+xml" rel="users"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/action/virtualappliances" type="application/vnd.abiquo.virtualappliances+xml; version=2.0" rel="virtualappliances"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/action/virtualappliances" rel="virtualappliances" title="virtualappliances"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/action/virtualmachines" type="application/vnd.abiquo.virtualmachines+xml" rel="virtualmachines"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/action/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpuHard>0</cpuHard>
+    <cpuSoft>0</cpuSoft>
+    <hdHard>0</hdHard>
+    <hdSoft>0</hdSoft>
+    <publicIpsHard>0</publicIpsHard>
+    <publicIpsSoft>0</publicIpsSoft>
+    <ramHard>0</ramHard>
+    <ramSoft>0</ramSoft>
+    <storageHard>0</storageHard>
+    <storageSoft>0</storageSoft>
+    <vlansHard>0</vlansHard>
+    <vlansSoft>0</vlansSoft>
+    <id>1</id>
+    <isReservationRestricted>false</isReservationRestricted>
+    <name>Abiquo</name>
+    <repositoryHard>0</repositoryHard>
+    <repositorySoft>0</repositorySoft>
+</enterprise>
diff --git libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml
new file mode 100644
index 0000000..61264c7
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<datacenterRepository>
+    <link href="http://10.60.12.7:80/am/erepos/1" rel="applianceManagerRepositoryUri"/><link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter" title="barcelona"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2" type="application/vnd.abiquo.datacenterrepository+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/actions/refresh" rel="refresh"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates" type="application/vnd.abiquo.virtualmachinetemplates+xml" rel="virtualmachinetemplates"/>
+<id>2</id><name>virtual image repo</name><repositoryCapacityMb>0</repositoryCapacityMb><repositoryLocation>10.60.1.72:/opt/vm_repository</repositoryLocation><repositoryRemainingMb>0</repositoryRemainingMb></datacenterRepository>
diff --git libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml
new file mode 100644
index 0000000..7127c10
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualMachineTemplate>
+    <link href="http://10.60.12.7:80/api/config/categories/1" type="application/vnd.abiquo.category+xml" rel="category" title="Others"/>
+    <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2" type="application/vnd.abiquo.datacenterrepository+xml" rel="datacenterrepository"/>
+    <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/269/desc.ovf?format=diskFile" rel="diskfile"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="edit" title="m0n0wall-vhd"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/269/desc.ovf?format=envelope" rel="ovfdocument"/>
+    <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/269/desc.ovf" rel="template"/>
+    <link href="http://rs:9000/ovf/269/desc.ovf" rel="templatedefinition"/>
+    <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/269/desc.ovf?format=status" rel="templatestatus"/>
+    <id>11</id>
+    <name>m0n0wall-vhd</name>
+    <description>m0n0wall image in VHD format ready for XenServer and HyperV</description>
+    <path>1/rs/abiport9000/ovf/269/m0n0wall-1.3b18-i386-flat.vmdk-VHD_SPARSE.vhd</path>
+    <diskFormatType>VHD_SPARSE</diskFormatType>
+    <diskFileSize>10490880</diskFileSize>
+    <cpuRequired>1</cpuRequired>
+    <ramRequired>128</ramRequired>
+    <hdRequired>27262976</hdRequired>
+    <shared>false</shared>
+    <costCode>0</costCode>
+    <creationDate>2013-01-10T20:25:12-05:00</creationDate>
+    <creationUser>SYSTEM</creationUser>
+    <chefEnabled>false</chefEnabled>
+    <iconUrl>http://icons.abiquo.com/monowall.jpg</iconUrl>
+</virtualMachineTemplate>
diff --git libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml
new file mode 100644
index 0000000..a165f12
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualMachineTemplates>
+    <virtualMachineTemplate>
+        <link href="http://10.60.12.7:80/api/config/categories/1" type="application/vnd.abiquo.category+xml" rel="category" title="Others"/><link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2" type="application/vnd.abiquo.datacenterrepository+xml" rel="datacenterrepository"/>
+        <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/269/desc.ovf?format=diskFile" rel="diskfile"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="edit" title="m0n0wall-vhd"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/269/desc.ovf?format=envelope" rel="ovfdocument"/>
+        <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/269/desc.ovf" rel="template"/>
+        <link href="http://rs:9000/ovf/269/desc.ovf" rel="templatedefinition"/>
+        <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/269/desc.ovf?format=status" rel="templatestatus"/>
+    <id>11</id><name>m0n0wall-vhd</name><description>m0n0wall image in VHD format ready for XenServer and HyperV</description><path>1/rs/abiport9000/ovf/269/m0n0wall-1.3b18-i386-flat.vmdk-VHD_SPARSE.vhd</path><diskFormatType>VHD_SPARSE</diskFormatType><diskFileSize>10490880</diskFileSize><cpuRequired>1</cpuRequired><ramRequired>128</ramRequired><hdRequired>27262976</hdRequired><shared>false</shared><costCode>0</costCode><creationDate>2013-01-10T20:25:12-05:00</creationDate><creationUser>SYSTEM</creationUser><chefEnabled>false</chefEnabled><iconUrl>http://icons.abiquo.com/monowall.jpg</iconUrl></virtualMachineTemplate>
+    <virtualMachineTemplate>
+        <link href="http://10.60.12.7:80/api/config/categories/1" type="application/vnd.abiquo.category+xml" rel="category" title="Others"/>
+        <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2" type="application/vnd.abiquo.datacenterrepository+xml" rel="datacenterrepository"/>
+        <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/73/desc.ovf?format=diskFile" rel="diskfile"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/19" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="edit" title="RHEL6 Build Bot"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/73/desc.ovf?format=envelope" rel="ovfdocument"/>
+        <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/73/desc.ovf" rel="template"/>
+        <link href="http://rs:9000/ovf/73/desc.ovf" rel="templatedefinition"/>
+        <link href="http://10.60.12.7:80/am/erepos/1/templates/rs%3A9000/ovf/73/desc.ovf?format=status" rel="templatestatus"/>
+        <id>19</id>
+        <name>RHEL6 Build Bot</name>
+        <description>RHEL6 Build Bot</description>
+        <path>1/rs/abiport9000/ovf/73/build-bot-rhel6-disk1.vmdk</path>
+        <diskFormatType>VMDK_STREAM_OPTIMIZED</diskFormatType>
+        <diskFileSize>351064576</diskFileSize>
+        <cpuRequired>1</cpuRequired>
+        <ramRequired>1024</ramRequired>
+        <hdRequired>4294967296</hdRequired>
+        <shared>false</shared>
+        <costCode>0</costCode>
+        <creationDate>2013-01-10T20:25:12-05:00</creationDate>
+        <creationUser>SYSTEM</creationUser>
+        <chefEnabled>false</chefEnabled>
+        <iconUrl>http://rs.bcn.abiquo.com:9000/public/icons/q.png</iconUrl>
+    </virtualMachineTemplate>
+</virtualMachineTemplates>
diff --git libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml
new file mode 100644
index 0000000..b8b4fca
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<datacenterRepositories>
+    <datacenterRepository>
+        <link href="http://10.60.12.7:80/am/erepos/1" rel="applianceManagerRepositoryUri"/><link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter" title="barcelona"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2" type="application/vnd.abiquo.datacenterrepository+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/actions/refresh" rel="refresh"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates" type="application/vnd.abiquo.virtualmachinetemplates+xml" rel="virtualmachinetemplates"/>
+    <id>2</id><name>virtual image repo</name><repositoryCapacityMb>0</repositoryCapacityMb><repositoryLocation>10.60.1.72:/opt/vm_repository</repositoryLocation><repositoryRemainingMb>0</repositoryRemainingMb></datacenterRepository>
+</datacenterRepositories>
diff --git libcloud/test/compute/fixtures/abiquo/login.xml libcloud/test/compute/fixtures/abiquo/login.xml
new file mode 100644
index 0000000..32ac4d4
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/login.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<user>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/admin/roles/2" type="application/vnd.abiquo.role+xml" rel="role"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2/action/virtualmachines" type="application/vnd.abiquo.virtualmachines+xml" rel="virtualmachines"/>
+    <active>true</active>
+    <authType>ABIQUO</authType>
+    <description>Standard user</description>
+    <email></email>
+    <id>2</id>
+    <locale>en_US</locale>
+    <name>Standard</name>
+    <nick>user</nick>
+    <password>c69a39bd64ffb77ea7ee3369dce742f3</password>
+    <surname>User</surname>
+</user>
diff --git libcloud/test/compute/fixtures/abiquo/not_found_error.xml libcloud/test/compute/fixtures/abiquo/not_found_error.xml
new file mode 100644
index 0000000..8aeb650
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/not_found_error.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<errors>
+    <error>
+        <code>DC-0</code>
+        <message>The requested datacenter does not exist</message>
+    </error>
+</errors>
diff --git libcloud/test/compute/fixtures/abiquo/privilege_errors.html libcloud/test/compute/fixtures/abiquo/privilege_errors.html
new file mode 100644
index 0000000..888e4bd
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/privilege_errors.html
@@ -0,0 +1,23 @@
+<html>
+    <head>
+        <title>Apache Tomcat/6.0.35 - Error report</title>
+        <style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style>
+     </head>
+    <body>
+        <h1>HTTP Status 403 - Access is denied</h1>
+        <HR size="1" noshade="noshade">
+            <p>
+                <b>type</b>
+             Status report</p>
+            <p>
+                <b>message</b>
+                 <u>Access is denied</u>
+            </p>
+            <p>
+                <b>description</b>
+                 <u>Access to the specified resource (Access is denied) has been forbidden.</u>
+            </p>
+            <HR size="1" noshade="noshade">
+                <h3>Apache Tomcat/6.0.35</h3>
+            </body>
+        </html>
diff --git libcloud/test/compute/fixtures/abiquo/unauthorized_user.html libcloud/test/compute/fixtures/abiquo/unauthorized_user.html
new file mode 100644
index 0000000..b35026d
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/unauthorized_user.html
@@ -0,0 +1,23 @@
+<html>
+    <head>
+        <title>Apache Tomcat/6.0.35 - Error report</title>
+        <style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style>
+     </head>
+    <body>
+        <h1>HTTP Status 401 - Bad credentials</h1>
+        <HR size="1" noshade="noshade">
+            <p>
+                <b>type</b>
+             Status report</p>
+            <p>
+                <b>message</b>
+                 <u>Bad credentials</u>
+            </p>
+            <p>
+                <b>description</b>
+                 <u>This request requires HTTP authentication (Bad credentials).</u>
+            </p>
+            <HR size="1" noshade="noshade">
+                <h3>Apache Tomcat/6.0.35</h3>
+            </body>
+        </html>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4.xml libcloud/test/compute/fixtures/abiquo/vdc_4.xml
new file mode 100644
index 0000000..54f2957
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualDatacenter>
+    <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2" type="application/vnd.abiquo.vlan+xml" rel="defaultnetwork"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/action/dhcpinfo" type="text/plain" rel="dhcpinfo"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/action/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks" type="application/vnd.abiquo.vlans+xml" rel="privatenetworks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/publicips/purchased" type="application/vnd.abiquo.ips+xml" rel="purchased"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/volumes/action/statefulcandidates" type="application/vnd.abiquo.iscsivolumes+xml" rel="statefulcandidates"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/tiers" type="application/vnd.abiquo.tiers+xml" rel="tiers"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/publicips/topurchase" type="application/vnd.abiquo.ips+xml" rel="topurchase"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances" type="application/vnd.abiquo.virtualappliances+xml" rel="virtualappliances"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpuHard>0</cpuHard>
+    <cpuSoft>0</cpuSoft>
+    <hdHard>0</hdHard>
+    <hdSoft>0</hdSoft>
+    <publicIpsHard>0</publicIpsHard>
+    <publicIpsSoft>0</publicIpsSoft>
+    <ramHard>0</ramHard>
+    <ramSoft>0</ramSoft>
+    <storageHard>0</storageHard>
+    <storageSoft>0</storageSoft>
+    <vlansHard>0</vlansHard>
+    <vlansSoft>0</vlansSoft>
+    <hypervisorType>KVM</hypervisorType>
+    <id>4</id>
+    <name>vdc_kvm</name>
+    <network>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2" type="application/vnd.abiquo.vlan+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+        <address>192.168.0.0</address>
+        <dhcpOptions/>
+        <gateway>192.168.0.1</gateway>
+        <id>2</id>
+        <mask>24</mask>
+        <name>default_private_network</name>
+        <primaryDNS></primaryDNS>
+        <secondaryDNS></secondaryDNS>
+        <sufixDNS></sufixDNS>
+        <type>INTERNAL</type>
+    </network>
+</virtualDatacenter>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml
new file mode 100644
index 0000000..171f1ab
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualAppliance>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5" type="application/vnd.abiquo.virtualappliance+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/price" type="text/plain" rel="price"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/state" type="application/vnd.abiquo.virtualappliancestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/virtualmachines" type="application/vnd.abiquo.virtualmachines+xml" rel="virtualmachines"/>
+    <error>0</error>
+    <highDisponibility>0</highDisponibility>
+    <id>5</id>
+    <name>libcloud_test_group</name>
+    <publicApp>0</publicApp>
+    <state>NOT_DEPLOYED</state>
+</virtualAppliance>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml
new file mode 100644
index 0000000..4f831b2
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualAppliance>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5" type="application/vnd.abiquo.virtualappliance+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/price" type="text/plain" rel="price"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/state" type="application/vnd.abiquo.virtualappliancestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/virtualmachines" type="application/vnd.abiquo.virtualmachines+xml" rel="virtualmachines"/>
+    <error>0</error>
+    <highDisponibility>0</highDisponibility>
+    <id>5</id>
+    <name>libcloud_test_group</name>
+    <publicApp>0</publicApp>
+    <state>NEEDS_SYNC</state>
+</virtualAppliance>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml
new file mode 100644
index 0000000..6b70396
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualmachinewithnode>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations" type="application/vnd.abiquo.virtualmachinenetworkconfigurations+xml" rel="configurations"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/instance" type="application/vnd.abiquo.acceptedrequest+xml" rel="instance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations/2" type="application/vnd.abiquo.virtualmachinenetworkconfiguration+xml" rel="network_configuration"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics" type="application/vnd.abiquo.nics+xml" rel="nics"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2/ips/64" type="application/vnd.abiquo.ip+xml" rel="privateip"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/reset" type="application/vnd.abiquo.acceptedrequest+xml" rel="reset"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/state" type="application/vnd.abiquo.virtualmachinestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" type="application/vnd.abiquo.tasks+xml" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="user"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml; version=2.0" rel="virtualappliance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter" title="KVM"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="virtualmachine"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="virtualmachinetemplate"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpu>1</cpu>
+    <hdInBytes>27262976</hdInBytes>
+    <highDisponibility>0</highDisponibility>
+    <id>3</id>
+    <idState>1</idState>
+    <idType>1</idType>
+    <name>ABQ_914f8125-33d3-4fe3-a162-5d6f5bf32614</name>
+    <ram>128</ram>
+    <state>NOT_ALLOCATED</state>
+    <uuid>914f8125-33d3-4fe3-a162-5d6f5bf32614</uuid>
+    <vdrpPort>0</vdrpPort>
+    <nodeId>3</nodeId>
+    <nodeName>node-name</nodeName>
+    <x>0</x>
+    <y>0</y>
+</virtualmachinewithnode>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml
new file mode 100644
index 0000000..5a4eefd
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualmachineswithnode>
+    <virtualmachinewithnode>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations" type="application/vnd.abiquo.virtualmachinenetworkconfigurations+xml" rel="configurations"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/instance" type="application/vnd.abiquo.acceptedrequest+xml" rel="instance"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations/2" type="application/vnd.abiquo.virtualmachinenetworkconfiguration+xml" rel="network_configuration"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics" type="application/vnd.abiquo.nics+xml" rel="nics"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/reset" type="application/vnd.abiquo.acceptedrequest+xml" rel="reset"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/state" type="application/vnd.abiquo.virtualmachinestate+xml" rel="state"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" type="application/vnd.abiquo.tasks+xml" rel="tasks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="tasks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="user"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml; version=2.0" rel="virtualappliance"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter" title="KVM"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="virtualmachine"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="virtualmachinetemplate"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpu>1</cpu><hdInBytes>27262976</hdInBytes><highDisponibility>0</highDisponibility><id>3</id><idState>1</idState><idType>1</idType><name>ABQ_914f8125-33d3-4fe3-a162-5d6f5bf32614</name><ram>128</ram><state>NOT_ALLOCATED</state><uuid>914f8125-33d3-4fe3-a162-5d6f5bf32614</uuid><vdrpPort>0</vdrpPort><nodeId>3</nodeId><nodeName>node-name</nodeName><x>0</x><y>0</y></virtualmachinewithnode>
+</virtualmachineswithnode>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6.xml
new file mode 100644
index 0000000..4e0e069
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualAppliance>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/action/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/action/price" type="text/plain" rel="price"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/state" type="application/vnd.abiquo.virtualappliancestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines" type="application/vnd.abiquo.virtualmachines+xml" rel="virtualmachines"/>
+    <error>0</error>
+    <highDisponibility>0</highDisponibility>
+    <id>6</id>
+    <name>libcloud</name>
+    <nodeconnections>&lt;connections/&gt;</nodeconnections>
+    <publicApp>0</publicApp>
+    <state>DEPLOYED</state>
+</virtualAppliance>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy.xml
new file mode 100644
index 0000000..a20e8bd
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<acceptedrequest>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/1da8c8b6-86f6-49ef-9d29-57dcc73b875a" rel="status"/>
+    <message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
+</acceptedrequest>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task.xml
new file mode 100644
index 0000000..96db33b
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<task>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="parent"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/1da8c8b6-86f6-49ef-9d29-57dcc73b875a" rel="self"/>
+    <jobs>
+        <job>
+            <description>Undeploy task's power off on virtual machine with id 3</description>
+            <id>1da8c8b6-86f6-49ef-9d29-57dcc73b875a.103a1a6b-4de2-48d8-9a38-8698561020b8</id>
+            <parentTaskId>1da8c8b6-86f6-49ef-9d29-57dcc73b875a</parentTaskId>
+            <rollbackState>UNKNOWN</rollbackState>
+            <state>DONE</state>
+            <timestamp>1358012669</timestamp>
+            <type>POWER_OFF</type>
+        </job>
+        <job>
+            <description>Undeploy task's deconfigure on virtual machine with id 3</description>
+            <id>1da8c8b6-86f6-49ef-9d29-57dcc73b875a.e4250ca9-505d-4640-9ad2-fb101f9e9978</id>
+            <parentTaskId>1da8c8b6-86f6-49ef-9d29-57dcc73b875a</parentTaskId>
+            <rollbackState>UNKNOWN</rollbackState>
+            <state>DONE</state>
+            <timestamp>1358012669</timestamp>
+            <type>DECONFIGURE</type>
+        </job>
+    </jobs>
+    <ownerId>3</ownerId>
+    <state>FINISHED_SUCCESSFULLY</state>
+    <taskId>1da8c8b6-86f6-49ef-9d29-57dcc73b875a</taskId>
+    <timestamp>1358012669</timestamp>
+    <type>UNDEPLOY</type>
+    <userId>admin</userId>
+</task>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task_failed.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task_failed.xml
new file mode 100644
index 0000000..9f4ce06
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task_failed.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<task>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="parent"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/1da8c8b6-86f6-49ef-9d29-57dcc73b875a" rel="self"/>
+    <jobs>
+        <job>
+            <description>Undeploy task's power off on virtual machine with id 3</description>
+            <id>1da8c8b6-86f6-49ef-9d29-57dcc73b875a.103a1a6b-4de2-48d8-9a38-8698561020b8</id>
+            <parentTaskId>1da8c8b6-86f6-49ef-9d29-57dcc73b875a</parentTaskId>
+            <rollbackState>UNKNOWN</rollbackState>
+            <state>DONE</state>
+            <timestamp>1358012669</timestamp>
+            <type>POWER_OFF</type>
+        </job>
+        <job>
+            <description>Undeploy task's deconfigure on virtual machine with id 3</description>
+            <id>1da8c8b6-86f6-49ef-9d29-57dcc73b875a.e4250ca9-505d-4640-9ad2-fb101f9e9978</id>
+            <parentTaskId>1da8c8b6-86f6-49ef-9d29-57dcc73b875a</parentTaskId>
+            <rollbackState>UNKNOWN</rollbackState>
+            <state>DONE</state>
+            <timestamp>1358012669</timestamp>
+            <type>DECONFIGURE</type>
+        </job>
+    </jobs>
+    <ownerId>3</ownerId>
+    <state>FINISHED_UNSUCCESSFULLY</state>
+    <taskId>1da8c8b6-86f6-49ef-9d29-57dcc73b875a</taskId>
+    <timestamp>1358012669</timestamp>
+    <type>UNDEPLOY</type>
+    <userId>admin</userId>
+</task>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3.xml
new file mode 100644
index 0000000..17efdc4
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualmachinewithnode>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations" type="application/vnd.abiquo.virtualmachinenetworkconfigurations+xml" rel="configurations"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/instance" type="application/vnd.abiquo.acceptedrequest+xml" rel="instance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations/2" type="application/vnd.abiquo.virtualmachinenetworkconfiguration+xml" rel="network_configuration"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics" type="application/vnd.abiquo.nics+xml" rel="nics"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2/ips/64" type="application/vnd.abiquo.ip+xml" rel="privateip"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/reset" type="application/vnd.abiquo.acceptedrequest+xml" rel="reset"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/state" type="application/vnd.abiquo.virtualmachinestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" type="application/vnd.abiquo.tasks+xml" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="user"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml; version=2.0" rel="virtualappliance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter" title="KVM"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="virtualmachine"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="virtualmachinetemplate"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpu>1</cpu><hdInBytes>27262976</hdInBytes><highDisponibility>0</highDisponibility><id>3</id><idState>1</idState><idType>1</idType><name>ABQ_914f8125-33d3-4fe3-a162-5d6f5bf32614</name><ram>128</ram><state>NOT_ALLOCATED</state><uuid>914f8125-33d3-4fe3-a162-5d6f5bf32614</uuid><vdrpPort>5901</vdrpPort><nodeId>3</nodeId><nodeName>node-name</nodeName><x>0</x><y>0</y><vdrpIp>80.12.23.43</vdrpIp></virtualmachinewithnode>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_allocated.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_allocated.xml
new file mode 100644
index 0000000..2135a00
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_allocated.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualmachinewithnode>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations" type="application/vnd.abiquo.virtualmachinenetworkconfigurations+xml" rel="configurations"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/instance" type="application/vnd.abiquo.acceptedrequest+xml" rel="instance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations/2" type="application/vnd.abiquo.virtualmachinenetworkconfiguration+xml" rel="network_configuration"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics" type="application/vnd.abiquo.nics+xml" rel="nics"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2/ips/64" type="application/vnd.abiquo.ip+xml" rel="privateip"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/reset" type="application/vnd.abiquo.acceptedrequest+xml" rel="reset"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/state" type="application/vnd.abiquo.virtualmachinestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" type="application/vnd.abiquo.tasks+xml" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="user"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml; version=2.0" rel="virtualappliance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter" title="KVM"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="virtualmachine"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="virtualmachinetemplate"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpu>1</cpu><hdInBytes>27262976</hdInBytes><highDisponibility>0</highDisponibility><id>3</id><idState>1</idState><idType>1</idType><name>ABQ_914f8125-33d3-4fe3-a162-5d6f5bf32614</name><ram>128</ram><state>ALLOCATED</state><uuid>914f8125-33d3-4fe3-a162-5d6f5bf32614</uuid><vdrpPort>5901</vdrpPort><nodeId>3</nodeId><nodeName>node-name</nodeName><x>0</x><y>0</y><vdrpIp>80.12.23.43</vdrpIp></virtualmachinewithnode>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy.xml
new file mode 100644
index 0000000..2e376c6
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<acceptedrequest>
+<link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/b44fe278-6b0f-4dfb-be81-7c03006a93cb" rel="status"/><message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">You can keep track of the progress in the link</message></acceptedrequest>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task.xml
new file mode 100644
index 0000000..11cc5ed
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<task>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="parent"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/b44fe278-6b0f-4dfb-be81-7c03006a93cb" rel="self"/>
+    <jobs>
+        <job>
+            <description>Deploy task's configure on virtual machine with id 3</description>
+            <id>b44fe278-6b0f-4dfb-be81-7c03006a93cb.a04623bd-7b2c-4c23-9441-aeaa39dd4893</id>
+            <parentTaskId>b44fe278-6b0f-4dfb-be81-7c03006a93cb</parentTaskId>
+            <rollbackState>UNKNOWN</rollbackState>
+            <state>DONE</state>
+            <timestamp>1357872859</timestamp>
+            <type>CONFIGURE</type>
+        </job>
+        <job>
+            <description>Deploy task's power on on virtual machine with id 3</description>
+            <id>b44fe278-6b0f-4dfb-be81-7c03006a93cb.2fdee19a-4fad-4040-bc94-7acfd6fedc48</id>
+            <parentTaskId>b44fe278-6b0f-4dfb-be81-7c03006a93cb</parentTaskId>
+            <rollbackState>UNKNOWN</rollbackState>
+            <state>DONE</state>
+            <timestamp>1357872859</timestamp>
+            <type>POWER_ON</type>
+        </job>
+    </jobs>
+    <ownerId>3</ownerId>
+    <state>FINISHED_SUCCESSFULLY</state>
+    <taskId>b44fe278-6b0f-4dfb-be81-7c03006a93cb</taskId>
+    <timestamp>1357872859</timestamp>
+    <type>DEPLOY</type>
+    <userId>user</userId>
+</task>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task_failed.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task_failed.xml
new file mode 100644
index 0000000..80f85ba
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task_failed.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<task>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="parent"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/b44fe278-6b0f-4dfb-be81-7c03006a93cb" rel="self"/>
+    <jobs>
+        <job>
+            <description>Deploy task's configure on virtual machine with id 3</description>
+            <id>b44fe278-6b0f-4dfb-be81-7c03006a93cb.a04623bd-7b2c-4c23-9441-aeaa39dd4893</id>
+            <parentTaskId>b44fe278-6b0f-4dfb-be81-7c03006a93cb</parentTaskId>
+            <rollbackState>UNKNOWN</rollbackState>
+            <state>DONE</state>
+            <timestamp>1357872859</timestamp>
+            <type>CONFIGURE</type>
+        </job>
+        <job>
+            <description>Deploy task's power on on virtual machine with id 3</description>
+            <id>b44fe278-6b0f-4dfb-be81-7c03006a93cb.2fdee19a-4fad-4040-bc94-7acfd6fedc48</id>
+            <parentTaskId>b44fe278-6b0f-4dfb-be81-7c03006a93cb</parentTaskId>
+            <rollbackState>UNKNOWN</rollbackState>
+            <state>DONE</state>
+            <timestamp>1357872859</timestamp>
+            <type>POWER_ON</type>
+        </job>
+    </jobs>
+    <ownerId>3</ownerId>
+    <state>ABORTED</state>
+    <taskId>b44fe278-6b0f-4dfb-be81-7c03006a93cb</taskId>
+    <timestamp>1357872859</timestamp>
+    <type>DEPLOY</type>
+    <userId>user</userId>
+</task>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deployed.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deployed.xml
new file mode 100644
index 0000000..648da69
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deployed.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualmachinewithnode>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations" type="application/vnd.abiquo.virtualmachinenetworkconfigurations+xml" rel="configurations"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/instance" type="application/vnd.abiquo.acceptedrequest+xml" rel="instance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations/2" type="application/vnd.abiquo.virtualmachinenetworkconfiguration+xml" rel="network_configuration"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics" type="application/vnd.abiquo.nics+xml" rel="nics"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2/ips/64" type="application/vnd.abiquo.ip+xml" rel="privateip"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/reset" type="application/vnd.abiquo.acceptedrequest+xml" rel="reset"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/state" type="application/vnd.abiquo.virtualmachinestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" type="application/vnd.abiquo.tasks+xml" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="user"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml; version=2.0" rel="virtualappliance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter" title="KVM"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="virtualmachine"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="virtualmachinetemplate"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpu>1</cpu><hdInBytes>27262976</hdInBytes><highDisponibility>0</highDisponibility><id>3</id><idState>1</idState><idType>1</idType><name>ABQ_914f8125-33d3-4fe3-a162-5d6f5bf32614</name><ram>128</ram><state>ON</state><uuid>914f8125-33d3-4fe3-a162-5d6f5bf32614</uuid><vdrpPort>5901</vdrpPort><nodeId>3</nodeId><nodeName>node-name</nodeName><x>0</x><y>0</y><vdrpIp>80.12.23.43</vdrpIp></virtualmachinewithnode>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_nics.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_nics.xml
new file mode 100644
index 0000000..5825c04
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_nics.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<nics>
+    <nic>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics/64" type="application/vnd.abiquo.nic+xml" rel="edit"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2/ips/64" type="application/vnd.abiquo.ip+xml" rel="privateip"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2" type="application/vnd.abiquo.vlan+xml" rel="privatenetwork" title="default_private_network"/>
+    <id>64</id><ip>192.168.0.2</ip><mac>52:54:00:b7:f7:85</mac><sequence>0</sequence></nic>
+    <nic>
+        <link href="http://10.60.12.7:80/api/cloud/datacenters/4/networks/4" type="application/vnd.abiquo.vlan+xml" rel="publicnetwork" title="public_network"/>
+    <id>364</id><ip>34.34.34.5</ip><mac>52:54:00:b7:f7:88</mac><sequence>0</sequence></nic>
+</nics>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset.xml
new file mode 100644
index 0000000..05b858a
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<acceptedrequest>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/a8c9818e-f389-45b7-be2c-3db3a9689940" rel="status"/>
+    <message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">You can keep track of the progress in the link</message>
+</acceptedrequest>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset_task.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset_task.xml
new file mode 100644
index 0000000..3cff94b
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset_task.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<task>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="parent"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/a8c9818e-f389-45b7-be2c-3db3a9689940" rel="self"/>
+    <jobs>
+        <job>
+            <description>Reset task's reset on virtual machine with id 3</description>
+            <id>a8c9818e-f389-45b7-be2c-3db3a9689940.5f42a7fc-82f3-4121-be26-da62eb8b9b92</id>
+            <parentTaskId>a8c9818e-f389-45b7-be2c-3db3a9689940</parentTaskId>
+            <rollbackState>ROLLBACK_DONE</rollbackState>
+            <state>FAILED</state>
+            <timestamp>1357873142</timestamp>
+            <type>RESET</type>
+        </job>
+    </jobs>
+    <ownerId>3</ownerId>
+    <state>FINISHED_SUCCESSFULLY</state>
+    <taskId>a8c9818e-f389-45b7-be2c-3db3a9689940</taskId>
+    <timestamp>1357873142</timestamp>
+    <type>RESET</type>
+    <userId>user</userId>
+</task>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy.xml
new file mode 100644
index 0000000..05b858a
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<acceptedrequest>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/a8c9818e-f389-45b7-be2c-3db3a9689940" rel="status"/>
+    <message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">You can keep track of the progress in the link</message>
+</acceptedrequest>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task.xml
new file mode 100644
index 0000000..3cff94b
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<task>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="parent"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/a8c9818e-f389-45b7-be2c-3db3a9689940" rel="self"/>
+    <jobs>
+        <job>
+            <description>Reset task's reset on virtual machine with id 3</description>
+            <id>a8c9818e-f389-45b7-be2c-3db3a9689940.5f42a7fc-82f3-4121-be26-da62eb8b9b92</id>
+            <parentTaskId>a8c9818e-f389-45b7-be2c-3db3a9689940</parentTaskId>
+            <rollbackState>ROLLBACK_DONE</rollbackState>
+            <state>FAILED</state>
+            <timestamp>1357873142</timestamp>
+            <type>RESET</type>
+        </job>
+    </jobs>
+    <ownerId>3</ownerId>
+    <state>FINISHED_SUCCESSFULLY</state>
+    <taskId>a8c9818e-f389-45b7-be2c-3db3a9689940</taskId>
+    <timestamp>1357873142</timestamp>
+    <type>RESET</type>
+    <userId>user</userId>
+</task>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task_failed.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task_failed.xml
new file mode 100644
index 0000000..007c12b
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task_failed.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<task>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="parent"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks/a8c9818e-f389-45b7-be2c-3db3a9689940" rel="self"/>
+    <jobs>
+        <job>
+            <description>Reset task's reset on virtual machine with id 3</description>
+            <id>a8c9818e-f389-45b7-be2c-3db3a9689940.5f42a7fc-82f3-4121-be26-da62eb8b9b92</id>
+            <parentTaskId>a8c9818e-f389-45b7-be2c-3db3a9689940</parentTaskId>
+            <rollbackState>ROLLBACK_DONE</rollbackState>
+            <state>FAILED</state>
+            <timestamp>1357873142</timestamp>
+            <type>RESET</type>
+        </job>
+    </jobs>
+    <ownerId>3</ownerId>
+    <state>FINISHED_UNSUCCESSFULLY</state>
+    <taskId>a8c9818e-f389-45b7-be2c-3db3a9689940</taskId>
+    <timestamp>1357873142</timestamp>
+    <type>RESET</type>
+    <userId>user</userId>
+</task>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_creation_ok.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_creation_ok.xml
new file mode 100644
index 0000000..3bc9f0b
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_creation_ok.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualMachine>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/><link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="user"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter" title="KVM"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml; version=2.0" rel="virtualappliance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations" type="application/vnd.abiquo.virtualmachinenetworkconfigurations+xml" rel="configurations"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations/2" type="application/vnd.abiquo.virtualmachinenetworkconfiguration+xml" rel="network_configuration"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics" type="application/vnd.abiquo.nics+xml" rel="nics"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/ips" type="application/vnd.abiquo.ips+xml" rel="ips"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/state" type="application/vnd.abiquo.virtualmachinestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/reset" type="application/vnd.abiquo.acceptedrequest+xml" rel="reset"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/instance" type="application/vnd.abiquo.acceptedrequest+xml" rel="instance"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" type="application/vnd.abiquo.tasks+xml" rel="tasks"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="virtualmachinetemplate"/>
+<cpu>1</cpu><hdInBytes>27262976</hdInBytes><highDisponibility>0</highDisponibility><id>3</id><idState>1</idState><idType>1</idType><name>ABQ_914f8125-33d3-4fe3-a162-5d6f5bf32614</name><ram>128</ram><state>NOT_ALLOCATED</state><uuid>914f8125-33d3-4fe3-a162-5d6f5bf32614</uuid><vdrpPort>0</vdrpPort></virtualMachine>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms.xml
new file mode 100644
index 0000000..5a4eefd
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualmachineswithnode>
+    <virtualmachinewithnode>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations" type="application/vnd.abiquo.virtualmachinenetworkconfigurations+xml" rel="configurations"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/instance" type="application/vnd.abiquo.acceptedrequest+xml" rel="instance"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations/2" type="application/vnd.abiquo.virtualmachinenetworkconfiguration+xml" rel="network_configuration"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics" type="application/vnd.abiquo.nics+xml" rel="nics"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/reset" type="application/vnd.abiquo.acceptedrequest+xml" rel="reset"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/state" type="application/vnd.abiquo.virtualmachinestate+xml" rel="state"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" type="application/vnd.abiquo.tasks+xml" rel="tasks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="tasks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="user"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml; version=2.0" rel="virtualappliance"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter" title="KVM"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="virtualmachine"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="virtualmachinetemplate"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpu>1</cpu><hdInBytes>27262976</hdInBytes><highDisponibility>0</highDisponibility><id>3</id><idState>1</idState><idType>1</idType><name>ABQ_914f8125-33d3-4fe3-a162-5d6f5bf32614</name><ram>128</ram><state>NOT_ALLOCATED</state><uuid>914f8125-33d3-4fe3-a162-5d6f5bf32614</uuid><vdrpPort>0</vdrpPort><nodeId>3</nodeId><nodeName>node-name</nodeName><x>0</x><y>0</y></virtualmachinewithnode>
+</virtualmachineswithnode>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms_allocated.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms_allocated.xml
new file mode 100644
index 0000000..a1658f0
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms_allocated.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualmachineswithnode>
+    <virtualmachinewithnode>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations" type="application/vnd.abiquo.virtualmachinenetworkconfigurations+xml" rel="configurations"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/instance" type="application/vnd.abiquo.acceptedrequest+xml" rel="instance"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/configurations/2" type="application/vnd.abiquo.virtualmachinenetworkconfiguration+xml" rel="network_configuration"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/network/nics" type="application/vnd.abiquo.nics+xml" rel="nics"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/reset" type="application/vnd.abiquo.acceptedrequest+xml" rel="reset"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/state" type="application/vnd.abiquo.virtualmachinestate+xml" rel="state"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" type="application/vnd.abiquo.tasks+xml" rel="tasks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/tasks" rel="tasks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/users/2" type="application/vnd.abiquo.user+xml" rel="user"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml; version=2.0" rel="virtualappliance"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter" title="KVM"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3" type="application/vnd.abiquo.virtualmachine+xml" rel="virtualmachine"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1/datacenterrepositories/2/virtualmachinetemplates/11" type="application/vnd.abiquo.virtualmachinetemplate+xml" rel="virtualmachinetemplate"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines/3/storage/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+    <cpu>1</cpu><hdInBytes>27262976</hdInBytes><highDisponibility>0</highDisponibility><id>3</id><idState>1</idState><idType>1</idType><name>ABQ_914f8125-33d3-4fe3-a162-5d6f5bf32614</name><ram>128</ram><state>ALLOCATED</state><uuid>914f8125-33d3-4fe3-a162-5d6f5bf32614</uuid><vdrpPort>0</vdrpPort><nodeId>3</nodeId><nodeName>node-name</nodeName><x>0</x><y>0</y></virtualmachinewithnode>
+</virtualmachineswithnode>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_creation_ok.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_creation_ok.xml
new file mode 100644
index 0000000..30baf15
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_creation_ok.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualAppliance>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5" type="application/vnd.abiquo.virtualappliance+xml" rel="edit"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter"/>
+    <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/virtualmachines" type="application/vnd.abiquo.virtualmachines+xml" rel="virtualmachines"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/state" type="application/vnd.abiquo.virtualappliancestate+xml" rel="state"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/price" type="text/plain" rel="price"/>
+    <error>0</error>
+    <highDisponibility>0</highDisponibility>
+    <id>5</id>
+    <name>libcloud_test_group</name>
+    <publicApp>0</publicApp>
+    <state>NOT_DEPLOYED</state>
+</virtualAppliance>
diff --git libcloud/test/compute/fixtures/abiquo/vdc_4_vapps.xml libcloud/test/compute/fixtures/abiquo/vdc_4_vapps.xml
new file mode 100644
index 0000000..f4271aa
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdc_4_vapps.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualAppliances>
+    <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances" rel="first"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances?startwith=0" rel="last"/>
+    <totalSize>2</totalSize>
+    <virtualAppliance>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6" type="application/vnd.abiquo.virtualappliance+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/action/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/action/price" type="text/plain" rel="price"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/state" type="application/vnd.abiquo.virtualappliancestate+xml" rel="state"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/6/virtualmachines" type="application/vnd.abiquo.virtualmachines+xml" rel="virtualmachines"/>
+    <error>0</error><highDisponibility>0</highDisponibility><id>6</id><name>libcloud</name><publicApp>0</publicApp><state>DEPLOYED</state></virtualAppliance>
+    <virtualAppliance>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/deploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="deploy"/><link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5" type="application/vnd.abiquo.virtualappliance+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/price" type="text/plain" rel="price"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/state" type="application/vnd.abiquo.virtualappliancestate+xml" rel="state"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/action/undeploy" type="application/vnd.abiquo.acceptedrequest+xml" rel="undeploy"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances/5/virtualmachines" type="application/vnd.abiquo.virtualmachines+xml" rel="virtualmachines"/>
+    <error>0</error><highDisponibility>0</highDisponibility><id>5</id><name>libcloud_test_group</name><publicApp>0</publicApp><state>NOT_DEPLOYED</state></virtualAppliance>
+</virtualAppliances>
diff --git libcloud/test/compute/fixtures/abiquo/vdcs.xml libcloud/test/compute/fixtures/abiquo/vdcs.xml
new file mode 100644
index 0000000..726b99e
--- /dev/null
+++ libcloud/test/compute/fixtures/abiquo/vdcs.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualDatacenters>
+    <virtualDatacenter>
+        <link href="http://10.60.12.7:80/api/admin/datacenters/2" type="application/vnd.abiquo.datacenter+xml" rel="datacenter"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2" type="application/vnd.abiquo.vlan+xml" rel="defaultnetwork"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/action/dhcpinfo" type="text/plain" rel="dhcpinfo"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/disks" type="application/vnd.abiquo.harddisks+xml" rel="disks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="edit"/>
+        <link href="http://10.60.12.7:80/api/admin/enterprises/1" type="application/vnd.abiquo.enterprise+xml" rel="enterprise"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/action/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks" type="application/vnd.abiquo.vlans+xml" rel="privatenetworks"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/publicips/purchased" type="application/vnd.abiquo.ips+xml" rel="purchased"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/volumes/action/statefulcandidates" type="application/vnd.abiquo.iscsivolumes+xml" rel="statefulcandidates"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/tiers" type="application/vnd.abiquo.tiers+xml" rel="tiers"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/publicips/topurchase" type="application/vnd.abiquo.ips+xml" rel="topurchase"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/virtualappliances" type="application/vnd.abiquo.virtualappliances+xml" rel="virtualappliances"/>
+        <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/volumes" type="application/vnd.abiquo.iscsivolumes+xml" rel="volumes"/>
+        <cpuHard>0</cpuHard>
+        <cpuSoft>0</cpuSoft>
+        <hdHard>0</hdHard>
+        <hdSoft>0</hdSoft>
+        <publicIpsHard>0</publicIpsHard>
+        <publicIpsSoft>0</publicIpsSoft>
+        <ramHard>0</ramHard>
+        <ramSoft>0</ramSoft>
+        <storageHard>0</storageHard>
+        <storageSoft>0</storageSoft>
+        <vlansHard>0</vlansHard>
+        <vlansSoft>0</vlansSoft>
+        <hypervisorType>KVM</hypervisorType>
+        <id>4</id>
+        <name>vdc_kvm</name>
+        <network>
+            <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4" type="application/vnd.abiquo.virtualdatacenter+xml" rel="virtualdatacenter"/>
+            <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2" type="application/vnd.abiquo.vlan+xml" rel="edit"/>
+            <link href="http://10.60.12.7:80/api/cloud/virtualdatacenters/4/privatenetworks/2/ips" type="application/vnd.abiquo.ip+xml" rel="ips"/>
+            <address>192.168.0.0</address>
+            <dhcpOptions/>
+            <gateway>192.168.0.1</gateway>
+            <id>2</id>
+            <mask>24</mask>
+            <name>default_private_network</name>
+            <primaryDNS></primaryDNS>
+            <secondaryDNS></secondaryDNS>
+            <sufixDNS></sufixDNS>
+            <type>INTERNAL</type>
+        </network>
+    </virtualDatacenter>
+</virtualDatacenters>
diff --git libcloud/test/compute/test_abiquo.py libcloud/test/compute/test_abiquo.py
new file mode 100644
index 0000000..59c3b53
--- /dev/null
+++ libcloud/test/compute/test_abiquo.py
@@ -0,0 +1,401 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Abiquo Test Suite"""
+import unittest
+import sys
+
+from libcloud.utils.py3 import httplib
+
+from xml.etree import ElementTree as ET
+from libcloud.compute.drivers.abiquo import AbiquoNodeDriver
+from libcloud.common.abiquo import ForbiddenError
+from libcloud.common.types import InvalidCredsError, LibcloudError
+from libcloud.compute.base import NodeLocation, NodeImage
+from libcloud.test.compute import TestCaseMixin
+from libcloud.test import MockHttpTestCase
+from libcloud.test.file_fixtures import ComputeFileFixtures
+
+
+class AbiquoNodeDriverTest(unittest.TestCase, TestCaseMixin):
+    """Abiquo Node Driver test suite"""
+    def setUp(self):
+        """Set up the driver with the main user"""
+        AbiquoNodeDriver.connectionCls.conn_classes = (AbiquoMockHttp, None)
+        self.driver = AbiquoNodeDriver('son', 'goku',
+                                       'http://dummy.host.com/api')
+
+    def test_unauthorized_controlled(self):
+        """Test the Unauthorized Exception is Controlled
+
+        Test, through the 'login' method, that a '401 Unauthorized'
+        raises a 'InvalidCredsError' instead of the 'MalformedUrlException'
+        """
+        AbiquoNodeDriver.connectionCls.conn_classes = (AbiquoMockHttp, None)
+        self.assertRaises(InvalidCredsError, AbiquoNodeDriver, 'son',
+                          'goten', 'http://dummy.host.com/api')
+
+    def test_forbidden_controlled(self):
+        """Test the Forbidden Exception is Controlled
+
+        Test, through the 'list_images' method, that a '403 Forbidden'
+        raises an 'ForbidenError' instead of the 'MalformedUrlException'
+        """
+        AbiquoNodeDriver.connectionCls.conn_classes = (AbiquoMockHttp, None)
+        conn = AbiquoNodeDriver('son', 'gohan', 'http://dummy.host.com/api')
+        self.assertRaises(ForbiddenError, conn.list_images)
+
+    def test_handle_other_errors_such_as_not_found(self):
+        """Test common 'logical' exceptions are controlled
+
+        Test that common exception (normally 404-Not Found and 409-Conflict),
+        that return an XMLResponse with the explanation of the errors are
+        controlled.
+        """
+        self.driver = AbiquoNodeDriver('go', 'trunks',
+                                       'http://dummy.host.com/api')
+        self.assertRaises(LibcloudError, self.driver.list_images)
+
+    def test_ex_create_and_delete_empty_group(self):
+        """Test the creation and deletion of an empty group"""
+        group = self.driver.ex_create_group('libcloud_test_group')
+        group.destroy()
+
+    def test_create_node_no_image_raise_exception(self):
+        """Test 'create_node' without image
+
+        Test the 'create_node' function without 'image' parameter raises
+        an Exception
+        """
+        self.assertRaises(LibcloudError, self.driver.create_node)
+
+    def test_create_node_specify_location(self):
+        """Test you can create a node specifying the location"""
+        image = self.driver.list_images()[0]
+        location = self.driver.list_locations()[0]
+        self.driver.create_node(image=image, location=location)
+
+    def test_create_node_specify_wrong_location(self):
+        """Test you can not create a node with wrong location"""
+        image = self.driver.list_images()[0]
+        location = NodeLocation(435, 'fake-location', 'Spain', self.driver)
+        self.assertRaises(LibcloudError, self.driver.create_node, image=image,
+                          location=location)
+
+    def test_create_node_specify_wrong_image(self):
+        """Test image compatibility
+
+        Some locations only can handle a group of images, not all of them.
+        Test you can not create a node with incompatible image-location"""
+        # Create fake NodeImage
+        image = NodeImage(3234, 'dummy-image', self.driver)
+        location = self.driver.list_locations()[0]
+        # With this image, it should raise an Exception
+        self.assertRaises(LibcloudError, self.driver.create_node, image=image,
+                          location=location)
+
+    def test_create_node_specify_group_name(self):
+        """Test 'create_node' into a concrete group"""
+        image = self.driver.list_images()[0]
+        self.driver.create_node(image=image, group_name='new_group_name')
+
+    def test_create_group_location_does_not_exist(self):
+        """Test 'create_node' with an unexistent location
+
+        Defines a 'fake' location and tries to create a node into it"""
+        location = NodeLocation(435, 'fake-location', 'Spain', self.driver)
+        # With this location, it should raise an Exception
+        self.assertRaises(LibcloudError, self.driver.ex_create_group,
+                          name='new_group_name',
+                          location=location)
+
+    def test_destroy_node_response(self):
+        """'destroy_node' basic test
+
+        Override the destroy to return a different node available
+        to be undeployed. (by default it returns an already undeployed node,
+        for test creation)"""
+        self.driver = AbiquoNodeDriver('go', 'trunks',
+                                       'http://dummy.host.com/api')
+        node = self.driver.list_nodes()[0]
+        ret = self.driver.destroy_node(node)
+        self.assertTrue(isinstance(ret, bool))
+
+    def test_destroy_node_response_failed(self):
+        """'destroy_node' asynchronous error.
+
+        Test that the driver handles correctly when, for some reason,
+        the 'destroy' job fails.
+        """
+        self.driver = AbiquoNodeDriver('muten', 'roshi',
+                                       'http://dummy.host.com/api')
+        node = self.driver.list_nodes()[0]
+        self.assertFalse(self.driver.destroy_node(node))
+
+    def test_destroy_node_allocation_state(self):
+        """Test the 'destroy_node' invalid state
+
+        Try to destroy a node when the node is not running"""
+        self.driver = AbiquoNodeDriver('ve', 'geta',
+                                       'http://dummy.host.com/api')
+        # Override the destroy to return a different node available to be
+        # undeployed
+        node = self.driver.list_nodes()[0]
+        # The mock class with the user:password 've:geta' returns a node that
+        # is in 'ALLOCATION' state and hence, the 'destroy_node' method should
+        # raise a LibcloudError
+        self.assertRaises(LibcloudError, self.driver.destroy_node, node)
+
+    def test_destroy_not_deployed_group(self):
+        """Test 'ex_destroy_group' when group is not deployed"""
+        location = self.driver.list_locations()[0]
+        group = self.driver.ex_list_groups(location)[1]
+        self.assertTrue(group.destroy())
+
+    def test_destroy_deployed_group(self):
+        """Test 'ex_destroy_group' when there are machines running"""
+        location = self.driver.list_locations()[0]
+        group = self.driver.ex_list_groups(location)[0]
+        self.assertTrue(group.destroy())
+
+    def test_destroy_deployed_group_failed(self):
+        """Test 'ex_destroy_group' fails
+
+        Test driver handles correctly when, for some reason, the
+        asynchronous job fails"""
+        self.driver = AbiquoNodeDriver('muten', 'roshi',
+                                       'http://dummy.host.com/api')
+        location = self.driver.list_locations()[0]
+        group = self.driver.ex_list_groups(location)[0]
+        self.assertFalse(group.destroy())
+
+    def test_destroy_group_invalid_state(self):
+        """Test 'ex_destroy_group' invalid state
+
+        Test the Driver raises an exception when the group is in
+        invalid temporal state"""
+        self.driver = AbiquoNodeDriver('ve', 'geta',
+                                       'http://dummy.host.com/api')
+        location = self.driver.list_locations()[0]
+        group = self.driver.ex_list_groups(location)[1]
+        self.assertRaises(LibcloudError, group.destroy)
+
+    def test_run_node(self):
+        """Test 'ex_run_node' feature"""
+        node = self.driver.list_nodes()[0]
+        # Node is by default in NodeState.TERMINATED and AbiquoState ==
+        # 'NOT_ALLOCATED'
+        # so it is available to be runned
+        self.driver.ex_run_node(node)
+
+    def test_run_node_invalid_state(self):
+        """Test 'ex_run_node' invalid state
+
+        Test the Driver raises an exception when try to run a
+        node that is in invalid state to run"""
+        self.driver = AbiquoNodeDriver('go', 'trunks',
+                                       'http://dummy.host.com/api')
+        node = self.driver.list_nodes()[0]
+        # Node iis by default in AbiquoState = 'ON' for user 'go:trunks'
+        # so is not available to be runned
+        self.assertRaises(LibcloudError, self.driver.ex_run_node, node)
+
+    def test_run_node_failed(self):
+        """Test 'ex_run_node' fails
+
+        Test driver handles correctly when, for some reason, the
+        asynchronous job fails"""
+        self.driver = AbiquoNodeDriver('ten', 'shin',
+                                       'http://dummy.host.com/api')
+        node = self.driver.list_nodes()[0]
+        # Node is in the correct state, but it fails because of the
+        # async task and it raises the error.
+        self.assertRaises(LibcloudError, self.driver.ex_run_node, node)
+
+
+class AbiquoMockHttp(MockHttpTestCase):
+    """Mock the functionallity of the remote Abiquo API"""
+    fixtures = ComputeFileFixtures('abiquo')
+    fixture_tag = 'default'
+
+    def _api_login(self, method, url, body, headers):
+        if headers['Authorization'] == 'Basic c29uOmdvdGVu':
+            expected_response = self.fixtures.load('unauthorized_user.html')
+            expected_status = httplib.UNAUTHORIZED
+        else:
+            expected_response = self.fixtures.load("login.xml")
+            expected_status = httplib.OK
+        return (expected_status, expected_response, {}, '')
+
+    def _api_cloud_virtualdatacenters(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('vdcs.xml'), {}, '')
+
+    def _api_cloud_virtualdatacenters_4(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('vdc_4.xml'), {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances(self, method, url, body, headers):
+        if method == 'POST':
+            vapp_name = ET.XML(body).findtext('name')
+            if vapp_name == 'libcloud_test_group':
+                # we come from 'test_ex_create_and_delete_empty_group(self):'
+                # method and so, we return the 'ok' return
+                response = self.fixtures.load('vdc_4_vapp_creation_ok.xml')
+                return (httplib.OK, response, {}, '')
+            elif vapp_name == 'new_group_name':
+                # we come from 'test_ex_create_and_delete_empty_group(self):'
+                # method and so, we return the 'ok' return
+                response = self.fixtures.load('vdc_4_vapp_creation_ok.xml')
+                return (httplib.OK, response, {}, '')
+        else:
+            # It will be a 'GET';
+            return (httplib.OK, self.fixtures.load('vdc_4_vapps.xml'), {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_5(self, method, url, body, headers):
+        if method == 'GET':
+            if headers['Authorization'] == 'Basic dmU6Z2V0YQ==':
+                # Try to destroy a group with 'needs_sync' state
+                response = self.fixtures.load('vdc_4_vapp_5_needs_sync.xml')
+            else:
+                # Try to destroy a group with 'undeployed' state
+                response = self.fixtures.load('vdc_4_vapp_5.xml')
+            return (httplib.OK, response, {}, '')
+        else:
+            # it will be a 'DELETE'
+            return (httplib.NO_CONTENT, '', {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6(self, method, url, body, headers):
+        if method == 'GET':
+            # deployed vapp
+            response = self.fixtures.load('vdc_4_vapp_6.xml')
+            return (httplib.OK, response, {}, '')
+        else:
+            # it will be a 'DELETE'
+            return (httplib.NO_CONTENT, '', {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3_tasks_1da8c8b6_86f6_49ef_9d29_57dcc73b875a(self, method, url, body, headers):
+        if headers['Authorization'] == 'Basic bXV0ZW46cm9zaGk=':
+            # User 'muten:roshi' failed task
+            response = self.fixtures.load('vdc_4_vapp_6_undeploy_task_failed.xml')
+        else:
+            response = self.fixtures.load('vdc_4_vapp_6_undeploy_task.xml')
+        return (httplib.OK, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_5_virtualmachines(
+            self, method, url, body, headers):
+        # This virtual app never have virtual machines
+        if method == 'GET':
+            response = self.fixtures.load('vdc_4_vapp_5_vms.xml')
+            return (httplib.OK, response, {}, '')
+        elif method == 'POST':
+            # it must be a POST
+            response = self.fixtures.load('vdc_4_vapp_6_vm_creation_ok.xml')
+            return (httplib.CREATED, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines(
+            self, method, url, body, headers):
+        # Default-created virtual app virtual machines'
+        if method == 'GET':
+            if headers['Authorization'] == 'Basic dmU6Z2V0YQ==':
+                response = self.fixtures.load('vdc_4_vapp_6_vms_allocated.xml')
+            else:
+                response = self.fixtures.load('vdc_4_vapp_6_vms.xml')
+            return (httplib.OK, response, {}, '')
+        else:
+            # it must be a POST
+            response = self.fixtures.load('vdc_4_vapp_6_vm_creation_ok.xml')
+            return (httplib.CREATED, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3(self, method, url, body, headers):
+        if (headers['Authorization'] == 'Basic Z286dHJ1bmtz' or
+                headers['Authorization'] == 'Basic bXV0ZW46cm9zaGk='):
+            # Undeploy node
+            response = self.fixtures.load("vdc_4_vapp_6_vm_3_deployed.xml")
+        elif headers['Authorization'] == 'Basic dmU6Z2V0YQ==':
+            # Try to undeploy a node with 'allocation' state
+            response = self.fixtures.load('vdc_4_vapp_6_vm_3_allocated.xml')
+        else:
+            # Get node
+            response = self.fixtures.load('vdc_4_vapp_6_vm_3.xml')
+        return (httplib.OK, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3_action_deploy(self, method, url, body, headers):
+        response = self.fixtures.load('vdc_4_vapp_6_vm_3_deploy.xml')
+        return (httplib.CREATED, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3_tasks_b44fe278_6b0f_4dfb_be81_7c03006a93cb(self, method, url, body, headers):
+
+        if headers['Authorization'] == 'Basic dGVuOnNoaW4=':
+            # User 'ten:shin' failed task
+            response = self.fixtures.load('vdc_4_vapp_6_vm_3_deploy_task_failed.xml')
+        else:
+            response = self.fixtures.load('vdc_4_vapp_6_vm_3_deploy_task.xml')
+        return (httplib.OK, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_action_undeploy(
+            self, method, url, body, headers):
+        response = self.fixtures.load('vdc_4_vapp_6_undeploy.xml')
+        return (httplib.OK, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3_action_reset(self, method, url, body, headers):
+        response = self.fixtures.load('vdc_4_vapp_6_vm_3_reset.xml')
+        return (httplib.CREATED, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3_tasks_a8c9818e_f389_45b7_be2c_3db3a9689940(self, method, url, body, headers):
+        if headers['Authorization'] == 'Basic bXV0ZW46cm9zaGk=':
+            # User 'muten:roshi' failed task
+            response = self.fixtures.load('vdc_4_vapp_6_undeploy_task_failed.xml')
+        else:
+            response = self.fixtures.load('vdc_4_vapp_6_vm_3_reset_task.xml')
+        return (httplib.OK, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3_action_undeploy(self, method, url, body, headers):
+        response = self.fixtures.load('vdc_4_vapp_6_vm_3_undeploy.xml')
+        return (httplib.CREATED, response, {}, '')
+
+    def _api_cloud_virtualdatacenters_4_virtualappliances_6_virtualmachines_3_network_nics(self, method, url, body, headers):
+        response = self.fixtures.load('vdc_4_vapp_6_vm_3_nics.xml')
+        return (httplib.OK, response, {}, '')
+
+    def _api_admin_datacenters(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('dcs.xml'), {}, '')
+
+    def _api_admin_enterprises_1(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('ent_1.xml'), {}, '')
+
+    def _api_admin_enterprises_1_datacenterrepositories(self, method, url, body, headers):
+        # When the user is the common one for all the tests ('son, 'goku')
+        # it creates this basic auth and we return the datacenters  value
+        if headers['Authorization'] == 'Basic Z286dHJ1bmtz':
+            expected_response = self.fixtures.load("not_found_error.xml")
+            return (httplib.NOT_FOUND, expected_response, {}, '')
+        elif headers['Authorization'] != 'Basic c29uOmdvaGFu':
+            return (httplib.OK, self.fixtures.load('ent_1_dcreps.xml'), {}, '')
+        else:
+            # son:gohan user: forbidden error
+            expected_response = self.fixtures.load("privilege_errors.html")
+            return (httplib.FORBIDDEN, expected_response, {}, '')
+
+    def _api_admin_enterprises_1_datacenterrepositories_2(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('ent_1_dcrep_2.xml'), {}, '')
+
+    def _api_admin_enterprises_1_datacenterrepositories_2_virtualmachinetemplates(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('ent_1_dcrep_2_templates.xml'),
+                {}, '')
+
+    def _api_admin_enterprises_1_datacenterrepositories_2_virtualmachinetemplates_11(self, method, url, body, headers):
+        return (httplib.OK, self.fixtures.load('ent_1_dcrep_2_template_11.xml'),
+                {}, '')
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())
-- 
1.7.2.5


From b82e22a3a6b67c7f15920583fc8ea5d908ebd719 Mon Sep 17 00:00:00 2001
From: Jaume Devesa <jaumedevesa@gmail.com>
Date: Wed, 23 Jan 2013 12:41:15 +0100
Subject: [PATCH 2/2] Add @Kami 's recommendations.

---
 libcloud/common/abiquo.py            |   25 ++---
 libcloud/compute/drivers/abiquo.py   |  190 ++++++++++++++++++----------------
 libcloud/test/compute/test_abiquo.py |    1 -
 3 files changed, 113 insertions(+), 103 deletions(-)

diff --git libcloud/common/abiquo.py libcloud/common/abiquo.py
index 7b92831..f6cc9eb 100644
--- libcloud/common/abiquo.py
+++ libcloud/common/abiquo.py
@@ -21,7 +21,6 @@ from libcloud.common.base import ConnectionUserAndKey, PollingConnection
 from libcloud.common.base import XmlResponse
 from libcloud.common.types import InvalidCredsError, LibcloudError
 import base64
-import sys
 from libcloud.utils.py3 import httplib
 from libcloud.utils.py3 import urlparse
 from libcloud.utils.py3 import b
@@ -113,9 +112,9 @@ class AbiquoResponse(XmlResponse):
         does not respond an XML but an HTML. So we need to
         handle these special cases"""
         if self.status == httplib.UNAUTHORIZED:
-            raise InvalidCredsError(driver='AbiquoNodeDriver')
+            raise InvalidCredsError(driver=self.connection.driver)
         elif self.status == httplib.FORBIDDEN:
-            raise ForbiddenError()
+            raise ForbiddenError(self.connection.driver)
         else:
             errors = self.parse_body().findall('error')
             # Most of the exceptions only have one error
@@ -128,9 +127,8 @@ class AbiquoResponse(XmlResponse):
 
         @rtype:  C{bool}
         @return: successful request or not"""
-        return (self.status == httplib.OK or self.status == httplib.CREATED or
-                self.status == httplib.NO_CONTENT or
-                self.status == httplib.ACCEPTED)
+        return self.status in [httplib.OK, httplib.CREATED, httplib.NO_CONTENT,
+                               httplib.ACCEPTED]
 
     def async_success(self):
         """ Determinate if async request was successful
@@ -170,10 +168,8 @@ class AbiquoConnection(ConnectionUserAndKey, PollingConnection):
         @rtype          C{dict}
         @return:        Default input headers with the 'Authorization'
                             header"""
-        encoded = base64.b64encode(b('%s:%s' % (self.user_id, self.key)))
-
-        if sys.version_info >= (3, 0):
-            encoded = encoded.decode()
+        b64string = b('%s:%s' % (self.user_id, self.key))
+        encoded = base64.b64encode(b64string).decode('utf-8')
 
         authorization = 'Basic ' + encoded
 
@@ -217,14 +213,13 @@ class AbiquoConnection(ConnectionUserAndKey, PollingConnection):
         @return:         Whether the job has completed"""
         task = response.object
         task_state = task.findtext('state')
-        return (task_state == 'FINISHED_SUCCESSFULLY' or
-                task_state == 'FINISHED_UNSUCCESSFULLY' or
-                task_state == 'ABORTED')
+        return task_state in ['FINISHED_SUCCESSFULLY', 'ABORTED',
+                              'FINISHED_UNSUCCESSFULLY']
 
 
 class ForbiddenError(LibcloudError):
     """Exception used when credentials are ok but user has not permissions"""
 
-    def __init__(self):
+    def __init__(self, driver):
         message = 'User has not permission to perform this task.'
-        super(LibcloudError, self).__init__(message, 'AbiquoNodeDriver')
+        super(LibcloudError, self).__init__(message, driver)
diff --git libcloud/compute/drivers/abiquo.py libcloud/compute/drivers/abiquo.py
index 04af66c..3026b1b 100644
--- libcloud/compute/drivers/abiquo.py
+++ libcloud/compute/drivers/abiquo.py
@@ -112,99 +112,22 @@ class AbiquoNodeDriver(NodeDriver):
         @return:               The newly created node.
         @rtype:                L{Node}
         """
+        # Define the location
+        # To be clear:
+        #     'xml_loc' is the xml element we navigate into (we need links)
+        #     'loc' is the L{NodeLocation} entity
+        xml_loc, loc = self._define_create_node_location(**kwargs)
 
-        #first, get image location
-        if not 'image' in kwargs:
-            error = "'image' parameter is mandatory"
-            raise LibcloudError(error, self)
-
-        image = kwargs['image']
-
-        # Get the location argument
-        location = None
-        if 'location' in kwargs:
-            location = kwargs['location']
-            if not location in self.list_locations():
-                raise LibcloudError('Location does not exist')
-
-        # Check if the image is compatible with any of the locations or
-        # the input location
-        loc = None
-        target_loc = None
-        for candidate_loc in self._get_locations(location):
-            link_vdc = self.connection.context['locations'][candidate_loc]
-            e_vdc = self.connection.request(link_vdc).object
-            # url_location = get_href(e_vdc, 'datacenter')
-            for img in self.list_images(candidate_loc):
-                if img.id == image.id:
-                    # To be clear:
-                    # 'loc' is the xml element we navigate into
-                    # 'target_loc' is the L{NodeLocation} entity
-                    loc = e_vdc
-                    target_loc = candidate_loc
-                    break
-        if loc is None:
-            error = 'The image can not be used in any location'
-            raise LibcloudError(error, self)
-
-        # -------------------------------------------------------
-        #  Define the Group
-        # -------------------------------------------------------
-        if not 'group_name' in kwargs:
-            group_name = NodeGroup.DEFAULT_GROUP_NAME
-        else:
-            group_name = kwargs['group_name']
+        # Define the Group
+        group = self._define_create_node_group(xml_loc, loc, **kwargs)
 
-        # find group into location
-        groups_link = get_href(loc, 'virtualappliances')
-        vapps_element = self.connection.request(groups_link).object
-        target_group = None
-        nodes_link = None
-        for vapp in vapps_element.findall('virtualAppliance'):
-            if vapp.findtext('name') == group_name:
-                target_group = vapp
-                nodes_link = get_href(target_group, 'virtualmachines')
-                break
-
-        # target group not found: create it
-        if target_group is None:
-            target_group = self.ex_create_group(group_name, target_loc)
-            nodes_link = target_group.uri + '/virtualmachines'
-
-        # -------------------------------------------------------
         # Register the Node
-        # -------------------------------------------------------
-        # prepare the element
-        vm = ET.Element('virtualmachinewithnode')
-        if 'name' in kwargs:
-            vmname = ET.SubElement(vm, 'nodeName')
-            vmname.text = kwargs['name']
-        attrib = {'type': 'application/vnd.abiquo/virtualmachinetemplate+xml',
-                  'rel': 'virtualmachinetemplate',
-                  'href': image.extra['url']}
-        ET.SubElement(vm, 'link', attrib=attrib)
-        headers = {'Content-type': self.NODE_MIME_TYPE}
-        if 'size' in kwargs:
-            # Override the 'NodeSize' data
-            ram = ET.SubElement(vm, 'ram')
-            ram.text = str(kwargs['size'].ram)
-            hd = ET.SubElement(vm, 'hdInBytes')
-            hd.text = str(int(kwargs['size'].disk) * self.GIGABYTE)
+        vm = self._define_create_node_node(group, **kwargs)
 
-        # Create the virtual machine
-        vm = self.connection.request(nodes_link, data=tostring(vm),
-                                     headers=headers, method='POST').object
-        edit_vm = get_href(vm, 'edit')
-        headers = {'Accept': self.NODE_MIME_TYPE}
-        vm = self.connection.request(edit_vm, headers=headers).object
-
-        # Execute the 'deploy' action
+        # Execute the 'create' in hypervisor action
         self._deploy_remote(vm)
 
-        # --------------------------------------------------------
-        #     Retrieve it again, to get some schedule-defined
-        #     values.
-        # --------------------------------------------------------
+        # Retrieve it again, to get some schedule-time defined values
         edit_vm = get_href(vm, 'edit')
         headers = {'Accept': self.NODE_MIME_TYPE}
         vm = self.connection.request(edit_vm, headers=headers).object
@@ -671,6 +594,99 @@ class AbiquoNodeDriver(NodeDriver):
         """Returns the identifier of the logged user's enterprise"""
         return self.connection.context['enterprise'].findtext('id')
 
+    def _define_create_node_location(self, **kwargs):
+        """Search for a location where to create the node.
+
+        Based on 'create_node' **kwargs argument, decide in which
+        location will be created."""
+        #first, get image location
+        if not 'image' in kwargs:
+            error = "'image' parameter is mandatory"
+            raise LibcloudError(error, self)
+
+        image = kwargs['image']
+
+        # Get the location argument
+        location = None
+        if 'location' in kwargs:
+            location = kwargs['location']
+            if not location in self.list_locations():
+                raise LibcloudError('Location does not exist')
+
+        # Check if the image is compatible with any of the locations or
+        # the input location
+        loc = None
+        target_loc = None
+        for candidate_loc in self._get_locations(location):
+            link_vdc = self.connection.context['locations'][candidate_loc]
+            e_vdc = self.connection.request(link_vdc).object
+            # url_location = get_href(e_vdc, 'datacenter')
+            for img in self.list_images(candidate_loc):
+                if img.id == image.id:
+                    loc = e_vdc
+                    target_loc = candidate_loc
+                    break
+        if loc is None:
+            error = 'The image can not be used in any location'
+            raise LibcloudError(error, self)
+
+        return loc, target_loc
+
+    def _define_create_node_group(self, xml_loc, loc, **kwargs):
+        """Search for a group where to create the node.
+
+        If we can not find any group, create it into argument 'location'
+        """
+        if not 'group_name' in kwargs:
+            group_name = NodeGroup.DEFAULT_GROUP_NAME
+        else:
+            group_name = kwargs['group_name']
+
+        # We search if the group is already defined into the location
+        groups_link = get_href(xml_loc, 'virtualappliances')
+        vapps_element = self.connection.request(groups_link).object
+        target_group = None
+        for vapp in vapps_element.findall('virtualAppliance'):
+            if vapp.findtext('name') == group_name:
+                uri_vapp = get_href(vapp, 'edit')
+                return  NodeGroup(self, vapp.findtext('name'), uri=uri_vapp)
+
+        # target group not found: create it. Since it is an extension of
+        # the basic 'libcloud' functionality, we try to be as flexible as
+        # possible.
+        if target_group is None:
+            return self.ex_create_group(group_name, loc)
+
+    def _define_create_node_node(self, group, **kwargs):
+        """Defines the node before to create.
+
+        In Abiquo, you first need to 'register' or 'define' the node in
+        the API before to create it into the target hypervisor"""
+        vm = ET.Element('virtualmachinewithnode')
+        if 'name' in kwargs:
+            vmname = ET.SubElement(vm, 'nodeName')
+            vmname.text = kwargs['name']
+        attrib = {'type': 'application/vnd.abiquo/virtualmachinetemplate+xml',
+                  'rel': 'virtualmachinetemplate',
+                  'href': kwargs['image'].extra['url']}
+        ET.SubElement(vm, 'link', attrib=attrib)
+        headers = {'Content-type': self.NODE_MIME_TYPE}
+        if 'size' in kwargs:
+            # Override the 'NodeSize' data
+            ram = ET.SubElement(vm, 'ram')
+            ram.text = str(kwargs['size'].ram)
+            hd = ET.SubElement(vm, 'hdInBytes')
+            hd.text = str(int(kwargs['size'].disk) * self.GIGABYTE)
+
+        # Create the virtual machine
+        nodes_link = group.uri + '/virtualmachines'
+        vm = self.connection.request(nodes_link, data=tostring(vm),
+                                     headers=headers, method='POST').object
+        edit_vm = get_href(vm, 'edit')
+        headers = {'Accept': self.NODE_MIME_TYPE}
+
+        return self.connection.request(edit_vm, headers=headers).object
+
 
 class NodeGroup(object):
     """Group of virtual machines that can be managed together
diff --git libcloud/test/compute/test_abiquo.py libcloud/test/compute/test_abiquo.py
index 59c3b53..f056fcd 100644
--- libcloud/test/compute/test_abiquo.py
+++ libcloud/test/compute/test_abiquo.py
@@ -42,7 +42,6 @@ class AbiquoNodeDriverTest(unittest.TestCase, TestCaseMixin):
         Test, through the 'login' method, that a '401 Unauthorized'
         raises a 'InvalidCredsError' instead of the 'MalformedUrlException'
         """
-        AbiquoNodeDriver.connectionCls.conn_classes = (AbiquoMockHttp, None)
         self.assertRaises(InvalidCredsError, AbiquoNodeDriver, 'son',
                           'goten', 'http://dummy.host.com/api')
 
-- 
1.7.2.5

