You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by to...@apache.org on 2013/01/25 06:48:37 UTC

svn commit: r1438331 [1/2] - in /libcloud/trunk: ./ libcloud/common/ libcloud/compute/ libcloud/compute/drivers/ libcloud/test/compute/ libcloud/test/compute/fixtures/abiquo/

Author: tomaz
Date: Fri Jan 25 05:48:36 2013
New Revision: 1438331

URL: http://svn.apache.org/viewvc?rev=1438331&view=rev
Log:
Add new compute driver for Abiquo provider (http://www.abiquo.com/).

Contributed by Jaume Devesa, part of LIBCLOUD-250.

Added:
    libcloud/trunk/libcloud/common/abiquo.py
    libcloud/trunk/libcloud/compute/drivers/abiquo.py
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/dcs.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/login.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/not_found_error.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/privilege_errors.html
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/unauthorized_user.html
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_undeploy_task_failed.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_allocated.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deploy_task_failed.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_deployed.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_nics.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_reset_task.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_3_undeploy_task_failed.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vm_creation_ok.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_6_vms_allocated.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_creation_ok.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapps.xml
    libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdcs.xml
    libcloud/trunk/libcloud/test/compute/test_abiquo.py
Modified:
    libcloud/trunk/CHANGES
    libcloud/trunk/libcloud/compute/drivers/__init__.py
    libcloud/trunk/libcloud/compute/providers.py
    libcloud/trunk/libcloud/compute/types.py

Modified: libcloud/trunk/CHANGES
URL: http://svn.apache.org/viewvc/libcloud/trunk/CHANGES?rev=1438331&r1=1438330&r2=1438331&view=diff
==============================================================================
--- libcloud/trunk/CHANGES (original)
+++ libcloud/trunk/CHANGES Fri Jan 25 05:48:36 2013
@@ -100,6 +100,9 @@ Changes with Apache Libcloud in developm
      (cr1.8xlarge).
      [Tomaz Muraus]
 
+   - Add new driver for Abiquo provider - http://www.abiquo.com (LIBCLOUD-250).
+     [Jaume Devesa]
+
   *) Storage
 
     - Add a new local storage driver.

Added: libcloud/trunk/libcloud/common/abiquo.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/common/abiquo.py?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/common/abiquo.py (added)
+++ libcloud/trunk/libcloud/common/abiquo.py Fri Jan 25 05:48:36 2013
@@ -0,0 +1,245 @@
+# 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}.
+"""
+import base64
+
+from libcloud.common.base import ConnectionUserAndKey, PollingConnection
+from libcloud.common.base import XmlResponse
+from libcloud.common.types import InvalidCredsError, LibcloudError
+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=self.connection.driver)
+        elif self.status == httplib.FORBIDDEN:
+            raise ForbiddenError(self.connection.driver)
+        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 in [httplib.OK, httplib.CREATED, httplib.NO_CONTENT,
+                               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
+        """
+        b64string = b('%s:%s' % (self.user_id, self.key))
+        encoded = base64.b64encode(b64string).decode('utf-8')
+
+        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 in ['FINISHED_SUCCESSFULLY', 'ABORTED',
+                              'FINISHED_UNSUCCESSFULLY']
+
+
+class ForbiddenError(LibcloudError):
+    """
+    Exception used when credentials are ok but user has not permissions.
+    """
+
+    def __init__(self, driver):
+        message = 'User has not permission to perform this task.'
+        super(LibcloudError, self).__init__(message, driver)

Modified: libcloud/trunk/libcloud/compute/drivers/__init__.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/__init__.py?rev=1438331&r1=1438330&r2=1438331&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/__init__.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/__init__.py Fri Jan 25 05:48:36 2013
@@ -18,6 +18,7 @@ Drivers for working with different provi
 """
 
 __all__ = [
+    'abiquo',
     'brightbox',
     'bluebox',
     'dummy',

Added: libcloud/trunk/libcloud/compute/drivers/abiquo.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/abiquo.py?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/abiquo.py (added)
+++ libcloud/trunk/libcloud/compute/drivers/abiquo.py Fri Jan 25 05:48:36 2013
@@ -0,0 +1,760 @@
+# 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)
+"""
+import xml.etree.ElementTree as ET
+
+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
+
+
+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 constants
+    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}
+        """
+        # 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)
+
+        # Define the Group
+        group = self._define_create_node_group(xml_loc, loc, **kwargs)
+
+        # Register the Node
+        vm = self._define_create_node_node(group, **kwargs)
+
+        # Execute the 'create' in hypervisor action
+        self._deploy_remote(vm)
+
+        # 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
+        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 in ['ALLOCATED', 'CONFIGURED', 'LOCKED', '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'):
+            key = get_href(dc, 'edit')
+            dc_dict[key] = 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 in ['NOT_DEPLOYED', '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 to list images for.
+        @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()
+
+    # -------------------------
+    # Extenstion 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 in ['publicnetwork', 'externalnetwork',
+                             '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')
+
+    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
+
+    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)

Modified: libcloud/trunk/libcloud/compute/providers.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/providers.py?rev=1438331&r1=1438330&r2=1438331&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/providers.py (original)
+++ libcloud/trunk/libcloud/compute/providers.py Fri Jan 25 05:48:36 2013
@@ -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')
 }
 
 

Modified: libcloud/trunk/libcloud/compute/types.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/types.py?rev=1438331&r1=1438330&r2=1438331&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/types.py (original)
+++ libcloud/trunk/libcloud/compute/types.py Fri Jan 25 05:48:36 2013
@@ -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'

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/dcs.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/dcs.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/dcs.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/dcs.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_template_11.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcrep_2_templates.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/ent_1_dcreps.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/login.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/login.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/login.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/login.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/not_found_error.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/not_found_error.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/not_found_error.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/not_found_error.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/privilege_errors.html
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/privilege_errors.html?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/privilege_errors.html (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/privilege_errors.html Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/unauthorized_user.html
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/unauthorized_user.html?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/unauthorized_user.html (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/unauthorized_user.html Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_needs_sync.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vm_3_not_allocated.xml Fri Jan 25 05:48:36 2013
@@ -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>

Added: libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml?rev=1438331&view=auto
==============================================================================
--- libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml (added)
+++ libcloud/trunk/libcloud/test/compute/fixtures/abiquo/vdc_4_vapp_5_vms.xml Fri Jan 25 05:48:36 2013
@@ -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>