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 2011/10/05 10:48:24 UTC
svn commit: r1179108 - in /libcloud/trunk: libcloud/common/
libcloud/compute/drivers/ test/compute/ test/compute/fixtures/gandi/
Author: tomaz
Date: Wed Oct 5 08:48:23 2011
New Revision: 1179108
URL: http://svn.apache.org/viewvc?rev=1179108&view=rev
Log:
Add some extra methods to Gandi compute driver. This patch has been contributed by Aymeric Barantal <mric at gandi dot net> and is part of LIBCLOUD-115.
Added:
libcloud/trunk/libcloud/common/gandi.py
libcloud/trunk/test/compute/fixtures/gandi/disk_attach.xml
libcloud/trunk/test/compute/fixtures/gandi/disk_create_from.xml
libcloud/trunk/test/compute/fixtures/gandi/disk_detach.xml
libcloud/trunk/test/compute/fixtures/gandi/disk_list.xml
libcloud/trunk/test/compute/fixtures/gandi/disk_update.xml
libcloud/trunk/test/compute/fixtures/gandi/iface_attach.xml
libcloud/trunk/test/compute/fixtures/gandi/iface_detach.xml
libcloud/trunk/test/compute/fixtures/gandi/iface_list.xml
Modified:
libcloud/trunk/libcloud/compute/drivers/gandi.py
libcloud/trunk/test/compute/test_gandi.py
Added: libcloud/trunk/libcloud/common/gandi.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/common/gandi.py?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/libcloud/common/gandi.py (added)
+++ libcloud/trunk/libcloud/common/gandi.py Wed Oct 5 08:48:23 2011
@@ -0,0 +1,217 @@
+# 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.
+"""
+Gandi driver base classes
+"""
+
+import time
+import hashlib
+import xmlrpclib
+
+import libcloud
+from libcloud.common.base import ConnectionKey
+from libcloud.compute.types import Provider, NodeState
+from libcloud.compute.base import NodeDriver, Node, \
+ NodeLocation, NodeSize, NodeImage
+
+# Global constants
+API_VERSION = '2.0'
+API_PREFIX = "https://rpc.gandi.net/xmlrpc/%s/" % API_VERSION
+
+DEFAULT_TIMEOUT = 600 # operation pooling max seconds
+DEFAULT_INTERVAL = 20 # seconds between 2 operation.info
+
+
+class GandiException(Exception):
+ """
+ Exception class for Gandi driver
+ """
+ def __str__(self):
+ return "(%u) %s" % (self.args[0], self.args[1])
+
+ def __repr__(self):
+ return "<GandiException code %u '%s'>" % (self.args[0], self.args[1])
+
+
+class GandiSafeTransport(xmlrpclib.SafeTransport):
+ pass
+
+
+class GandiTransport(xmlrpclib.Transport):
+ pass
+
+
+class GandiProxy(xmlrpclib.ServerProxy):
+ transportCls = (GandiTransport, GandiSafeTransport)
+
+ def __init__(self, user_agent, verbose=0):
+ cls = self.transportCls[0]
+ if API_PREFIX.startswith("https://"):
+ cls = self.transportCls[1]
+ t = cls(use_datetime=0)
+ t.user_agent = user_agent
+ xmlrpclib.ServerProxy.__init__(
+ self,
+ uri="%s" % (API_PREFIX),
+ transport=t,
+ verbose=verbose,
+ allow_none=True
+ )
+
+
+class GandiConnection(ConnectionKey):
+ """
+ Connection class for the Gandi driver
+ """
+
+ proxyCls = GandiProxy
+
+ def __init__(self, key, password=None):
+ super(GandiConnection, self).__init__(key)
+ self.driver = BaseGandiDriver
+
+ try:
+ self._proxy = self.proxyCls(self._user_agent())
+ except xmlrpclib.Fault, e:
+ raise GandiException(1000, e)
+
+ def request(self, method, *args):
+ """ Request xmlrpc method with given args"""
+ try:
+ return getattr(self._proxy, method)(self.key, *args)
+ except xmlrpclib.Fault, e:
+ raise GandiException(1001, e)
+
+
+class BaseGandiDriver(object):
+ """
+ Gandi base driver
+
+ """
+ connectionCls = GandiConnection
+ name = 'Gandi'
+
+ def __init__(self, key, secret=None, secure=False):
+ self.key = key
+ self.secret = secret
+ self.connection = self.connectionCls(key, secret)
+ self.connection.driver = self
+
+ # Specific methods for gandi
+ def _wait_operation(self, id, \
+ timeout=DEFAULT_TIMEOUT, check_interval=DEFAULT_INTERVAL):
+ """ Wait for an operation to succeed"""
+
+ for i in range(0, timeout, check_interval):
+ try:
+ op = self.connection.request('operation.info', int(id))
+
+ if op['step'] == 'DONE':
+ return True
+ if op['step'] in ['ERROR', 'CANCEL']:
+ return False
+ except (KeyError, IndexError):
+ pass
+ except Exception, e:
+ raise GandiException(1002, e)
+
+ time.sleep(check_interval)
+ return False
+
+
+class BaseObject(object):
+ """Base class for objects not conventional"""
+
+ uuid_prefix = ''
+
+ def __init__(self, id, state, driver):
+ self.id = str(id) if id else None
+ self.state = state
+ self.driver = driver
+ self.uuid = self.get_uuid()
+
+ def get_uuid(self):
+ """Unique hash for this object
+
+ @return: C{string}
+
+ The hash is a function of an SHA1 hash of prefix, the object's ID and
+ its driver which means that it should be unique between all
+ interfaces.
+ TODO : to review
+ >>> from libcloud.compute.drivers.dummy import DummyNodeDriver
+ >>> driver = DummyNodeDriver(0)
+ >>> vif = driver.create_interface()
+ >>> vif.get_uuid()
+ 'd3748461511d8b9b0e0bfa0d4d3383a619a2bb9f'
+
+ Note, for example, that this example will always produce the
+ same UUID!
+ """
+ return hashlib.sha1("%s:%s:%d" % \
+ (self.uuid_prefix, self.id, self.driver.type)).hexdigest()
+
+
+class IPAddress(BaseObject):
+ """
+ Provide a common interface for ip addresses
+ """
+
+ uuid_prefix = 'inet:'
+
+ def __init__(self, id, state, inet, driver, version=4, extra=None):
+ super(IPAddress, self).__init__(id, state, driver)
+ self.inet = inet
+ self.version = version
+ self.extra = extra or {}
+
+ def __repr__(self):
+ return (('<IPAddress: id=%s, address=%s, state=%s, driver=%s ...>')
+ % (self.id, self.inet, self.state, self.driver.name))
+
+
+class NetworkInterface(BaseObject):
+ """
+ Provide a common interface for network interfaces
+ """
+
+ uuid_prefix = 'if:'
+
+ def __init__(self, id, state, mac_address, driver,
+ ips=None, node_id=None, extra=None):
+ super(NetworkInterface, self).__init__(id, state, driver)
+ self.mac = mac_address
+ self.ips = ips or {}
+ self.node_id = node_id
+ self.extra = extra or {}
+
+ def __repr__(self):
+ return (('<Interface: id=%s, mac=%s, state=%s, driver=%s ...>')
+ % (self.id, self.mac, self.state, self.driver.name))
+
+
+class Disk(BaseObject):
+ """
+ Gandi disk component
+ """
+ def __init__(self, id, state, name, driver, size, extra=None):
+ super(Disk, self).__init__(id, state, driver)
+ self.name = name
+ self.size = size
+ self.extra = extra or {}
+
+ def __repr__(self):
+ return (('<Disk: id=%s, name=%s, state=%s, size=%s, driver=%s ...>')
+ % (self.id, self.name, self.state, self.size, self.driver.name))
Modified: libcloud/trunk/libcloud/compute/drivers/gandi.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/libcloud/compute/drivers/gandi.py?rev=1179108&r1=1179107&r2=1179108&view=diff
==============================================================================
--- libcloud/trunk/libcloud/compute/drivers/gandi.py (original)
+++ libcloud/trunk/libcloud/compute/drivers/gandi.py Wed Oct 5 08:48:23 2011
@@ -13,149 +13,48 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""
-Gandi driver
+Gandi driver for compute
"""
+from datetime import datetime
-import time
-import xmlrpclib
+from libcloud.common.gandi import BaseGandiDriver, GandiException, \
+ NetworkInterface, IPAddress, Disk
+from libcloud.compute.types import NodeState, Provider
+from libcloud.compute.base import Node, NodeDriver
+from libcloud.compute.base import NodeSize, NodeImage, NodeLocation
-import libcloud
-from libcloud.compute.types import Provider, NodeState
-from libcloud.compute.base import NodeDriver, Node, NodeLocation, NodeSize, NodeImage
-
-# Global constants
-API_VERSION = '2.0'
-API_PREFIX = "https://rpc.gandi.net/xmlrpc/%s/" % API_VERSION
-
-DEFAULT_TIMEOUT = 600 # operation pooling max seconds
-DEFAULT_INTERVAL = 20 # seconds between 2 operation.info
NODE_STATE_MAP = {
'running': NodeState.RUNNING,
'halted': NodeState.TERMINATED,
'paused': NodeState.TERMINATED,
- 'locked' : NodeState.TERMINATED,
- 'being_created' : NodeState.PENDING,
- 'invalid' : NodeState.UNKNOWN,
- 'legally_locked' : NodeState.PENDING,
- 'deleted' : NodeState.TERMINATED
+ 'locked': NodeState.TERMINATED,
+ 'being_created': NodeState.PENDING,
+ 'invalid': NodeState.UNKNOWN,
+ 'legally_locked': NodeState.PENDING,
+ 'deleted': NodeState.TERMINATED
}
NODE_PRICE_HOURLY_USD = 0.02
-class GandiException(Exception):
- """
- Exception class for Gandi driver
- """
- def __str__(self):
- return "(%u) %s" % (self.args[0], self.args[1])
- def __repr__(self):
- return "<GandiException code %u '%s'>" % (self.args[0], self.args[1])
-
-class GandiSafeTransport(xmlrpclib.SafeTransport):
- pass
-
-class GandiTransport(xmlrpclib.Transport):
- pass
-
-class GandiProxy(xmlrpclib.ServerProxy):
- transportCls = (GandiTransport, GandiSafeTransport)
-
- def __init__(self,user_agent, verbose=0):
- cls = self.transportCls[0]
- if API_PREFIX.startswith("https://"):
- cls = self.transportCls[1]
- t = cls(use_datetime=0)
- t.user_agent = user_agent
- xmlrpclib.ServerProxy.__init__(
- self,
- uri="%s" % (API_PREFIX),
- transport=t,
- verbose=verbose,
- allow_none=True
- )
-
-class GandiConnection(object):
- """
- Connection class for the Gandi driver
- """
-
- proxyCls = GandiProxy
- driver = 'gandi'
-
- def __init__(self, user, password=None):
- self.ua = []
-
- # Connect only with an api_key generated on website
- self.api_key = user
-
- try:
- self._proxy = self.proxyCls(self._user_agent())
- except xmlrpclib.Fault, e:
- raise GandiException(1000, e)
-
- def _user_agent(self):
- return 'libcloud/%s (%s)%s' % (
- libcloud.__version__,
- self.driver,
- "".join([" (%s)" % x for x in self.ua]))
-
- def user_agent_append(self, s):
- self.ua.append(s)
-
- def request(self,method,*args):
- """ Request xmlrpc method with given args"""
- try:
- return getattr(self._proxy, method)(self.api_key,*args)
- except xmlrpclib.Fault, e:
- raise GandiException(1001, e)
-
-class GandiNodeDriver(NodeDriver):
+class GandiNodeDriver(BaseGandiDriver, NodeDriver):
"""
Gandi node driver
"""
- connectionCls = GandiConnection
- name = 'Gandi'
api_name = 'gandi'
friendly_name = 'Gandi.net'
country = 'FR'
type = Provider.GANDI
# TODO : which features to enable ?
- features = { }
-
- def __init__(self, key, secret=None, secure=False):
- self.key = key
- self.secret = secret
- self.connection = self.connectionCls(key, secret)
- self.connection.driver = self
-
- # Specific methods for gandi
- def _wait_operation(self, id, timeout=DEFAULT_TIMEOUT, check_interval=DEFAULT_INTERVAL):
- """ Wait for an operation to succeed"""
-
- for i in range(0, timeout, check_interval):
- try:
- op = self.connection.request('operation.info', int(id))
-
- if op['step'] == 'DONE':
- return True
- if op['step'] in ['ERROR','CANCEL']:
- return False
- except (KeyError, IndexError):
- pass
- except Exception, e:
- raise GandiException(1002, e)
-
- time.sleep(check_interval)
- return False
+ features = {}
- def _node_info(self,id):
+ def _node_info(self, id):
try:
- obj = self.connection.request('vm.info',int(id))
+ obj = self.connection.request('vm.info', int(id))
return obj
- except Exception,e:
+ except Exception, e:
raise GandiException(1003, e)
return None
@@ -172,9 +71,9 @@ class GandiNodeDriver(NodeDriver):
private_ip='',
driver=self,
extra={
- 'ai_active' : vm.get('ai_active'),
- 'datacenter_id' : vm.get('datacenter_id'),
- 'description' : vm.get('description')
+ 'ai_active': vm.get('ai_active'),
+ 'datacenter_id': vm.get('datacenter_id'),
+ 'description': vm.get('description')
}
)
@@ -193,9 +92,9 @@ class GandiNodeDriver(NodeDriver):
return nodes
def reboot_node(self, node):
- op = self.connection.request('vm.reboot',int(node.id))
+ op = self.connection.request('vm.reboot', int(node.id))
op_res = self._wait_operation(op['id'])
- vm = self.connection.request('vm.info',int(node.id))
+ vm = self.connection.request('vm.info', int(node.id))
if vm['state'] == 'running':
return True
return False
@@ -204,18 +103,18 @@ class GandiNodeDriver(NodeDriver):
vm = self._node_info(node.id)
if vm['state'] == 'running':
# Send vm_stop and wait for accomplish
- op_stop = self.connection.request('vm.stop',int(node.id))
+ op_stop = self.connection.request('vm.stop', int(node.id))
if not self._wait_operation(op_stop['id']):
raise GandiException(1010, 'vm.stop failed')
# Delete
- op = self.connection.request('vm.delete',int(node.id))
+ op = self.connection.request('vm.delete', int(node.id))
if self._wait_operation(op['id']):
return True
return False
def deploy_node(self, **kwargs):
- raise NotImplementedError, \
- 'deploy_node not implemented for gandi driver'
+ raise NotImplementedError(
+ 'deploy_node not implemented for gandi driver')
def create_node(self, **kwargs):
"""Create a new Gandi node
@@ -234,7 +133,7 @@ class GandiNodeDriver(NodeDriver):
(required)
@type size: L{NodeSize}
- @keyword login: user name to create for login on this machine (required)
+ @keyword login: user name to create for login on machine (required)
@type login: String
@keyword password: password for user that'll be created (required)
@@ -245,17 +144,20 @@ class GandiNodeDriver(NodeDriver):
"""
if kwargs.get('login') is None or kwargs.get('password') is None:
- raise GandiException(1020, 'login and password must be defined for node creation')
+ raise GandiException(1020,
+ 'login and password must be defined for node creation')
location = kwargs.get('location')
- if location and isinstance(location,NodeLocation):
+ if location and isinstance(location, NodeLocation):
dc_id = int(location.id)
else:
- raise GandiException(1021, 'location must be a subclass of NodeLocation')
+ raise GandiException(1021,
+ 'location must be a subclass of NodeLocation')
size = kwargs.get('size')
- if not size and not isinstance(size,NodeSize):
- raise GandiException(1022, 'size must be a subclass of NodeSize')
+ if not size and not isinstance(size, NodeSize):
+ raise GandiException(1022,
+ 'size must be a subclass of NodeSize')
src_disk_id = int(kwargs['image'].id)
@@ -271,20 +173,21 @@ class GandiNodeDriver(NodeDriver):
'password': kwargs['password'], # TODO : use NodeAuthPassword
'memory': int(size.ram),
'cores': int(size.id),
- 'bandwidth' : int(size.bandwidth),
- 'ip_version': kwargs.get('inet_family',4),
+ 'bandwidth': int(size.bandwidth),
+ 'ip_version': kwargs.get('inet_family', 4),
}
# Call create_from helper api. Return 3 operations : disk_create,
# iface_create,vm_create
- (op_disk,op_iface,op_vm) = self.connection.request(
+ (op_disk, op_iface, op_vm) = self.connection.request(
'vm.create_from',
- vm_spec,disk_spec,src_disk_id
+ vm_spec, disk_spec, src_disk_id
)
# We wait for vm_create to finish
if self._wait_operation(op_vm['id']):
- # after successful operation, get ip information thru first interface
+ # after successful operation, get ip information
+ # thru first interface
node = self._node_info(op_vm['vm_id'])
ifaces = node.get('ifaces')
if len(ifaces) > 0:
@@ -305,10 +208,10 @@ class GandiNodeDriver(NodeDriver):
def list_images(self, location=None):
try:
if location:
- filtering = { 'datacenter_id' : int(location.id) }
+ filtering = {'datacenter_id': int(location.id)}
else:
filtering = {}
- images = self.connection.request('image.list', filtering )
+ images = self.connection.request('image.list', filtering)
return [self._to_image(i) for i in images]
except Exception, e:
raise GandiException(1011, e)
@@ -340,8 +243,8 @@ class GandiNodeDriver(NodeDriver):
if available_res['servers'] < 1:
# No server quota, no way
return shares
- for i in range(1,max_core + 1):
- share = {id:i}
+ for i in range(1, max_core + 1):
+ share = {id: i}
share_is_available = True
for k in ['memory', 'disk', 'bandwidth']:
if share_def[k] * i > available_res[k]:
@@ -351,7 +254,7 @@ class GandiNodeDriver(NodeDriver):
share[k] = share_def[k] * i
if share_is_available:
nb_core = i
- shares.append(self._to_size(nb_core,share))
+ shares.append(self._to_size(nb_core, share))
return shares
def _to_loc(self, loc):
@@ -365,3 +268,131 @@ class GandiNodeDriver(NodeDriver):
def list_locations(self):
res = self.connection.request("datacenter.list")
return [self._to_loc(l) for l in res]
+
+ def _to_iface(self, iface):
+ ips = []
+ for ip in iface.get('ips', []):
+ new_ip = IPAddress(
+ ip['id'],
+ NODE_STATE_MAP.get(
+ ip['state'],
+ NodeState.UNKNOWN
+ ),
+ ip['ip'],
+ self.connection.driver,
+ version=ip.get('version'),
+ extra={'reverse': ip['reverse']}
+ )
+ ips.append(new_ip)
+ return NetworkInterface(
+ iface['id'],
+ NODE_STATE_MAP.get(
+ iface['state'],
+ NodeState.UNKNOWN
+ ),
+ mac_address=None,
+ driver=self.connection.driver,
+ ips=ips,
+ node_id=iface.get('vm_id'),
+ extra={'bandwidth': iface['bandwidth']},
+ )
+
+ def _to_ifaces(self, ifaces):
+ return [self._to_iface(i) for i in ifaces]
+
+ def ex_list_interfaces(self):
+ """Specific method to list network interfaces"""
+ ifaces = self.connection.request('iface.list')
+ ips = self.connection.request('ip.list')
+ for iface in ifaces:
+ iface['ips'] = filter(lambda i: i['iface_id'] == iface['id'], ips)
+ return self._to_ifaces(ifaces)
+
+ def _to_disk(self, element):
+ disk = Disk(
+ id=element['id'],
+ state=NODE_STATE_MAP.get(
+ element['state'],
+ NodeState.UNKNOWN
+ ),
+ name=element['name'],
+ driver=self.connection.driver,
+ size=element['size'],
+ extra={'can_snapshot': element['can_snapshot']}
+ )
+ return disk
+
+ def _to_disks(self, elements):
+ return [self._to_disk(el) for el in elements]
+
+ def ex_list_disks(self):
+ """Specific method to list all disk"""
+ res = self.connection.request('disk.list', {})
+ disks = []
+ return self._to_disks(res)
+
+ def ex_node_attach_disk(self, node, disk):
+ """Specific method to attach a disk to a node"""
+ op = self.connection.request('vm.disk_attach',
+ int(node.id), int(disk.id))
+ if self._wait_operation(op['id']):
+ return True
+ return False
+
+ def ex_node_detach_disk(self, node, disk):
+ """Specific method to detach a disk from a node"""
+ op = self.connection.request('vm.disk_detach',
+ int(node.id), int(disk.id))
+ if self._wait_operation(op['id']):
+ return True
+ return False
+
+ def ex_node_attach_interface(self, node, iface):
+ """Specific method to attach an interface to a node"""
+ op = self.connection.request('vm.iface_attach',
+ int(node.id), int(iface.id))
+ if self._wait_operation(op['id']):
+ return True
+ return False
+
+ def ex_node_detach_interface(self, node, iface):
+ """Specific method to detach an interface from a node"""
+ op = self.connection.request('vm.iface_detach',
+ int(node.id), int(iface.id))
+ if self._wait_operation(op['id']):
+ return True
+ return False
+
+ def ex_snapshot_disk(self, disk, name=None):
+ """Specific method to make a snapshot of a disk"""
+ if not disk.extra.get('can_snapshot'):
+ raise GandiException(1021, "Disk %s can't snapshot" % disk.id)
+ if not name:
+ suffix = datetime.today().strftime("%Y%m%d")
+ name = "snap_%s" % (suffix)
+ op = self.connection.request('disk.create_from',
+ {
+ 'name': name,
+ 'type': 'snapshot',
+ },
+ int(disk.id),
+ )
+ if self._wait_operation(op['id']):
+ return True
+ return False
+
+ def ex_update_disk(self, disk, new_size=None, new_name=None):
+ """Specific method to update size or name of a disk
+ WARNING: if a server is attached it'll be rebooted
+ """
+ params = {}
+ if new_size:
+ params.update({'size': new_size})
+ if new_name:
+ params.update({'name': new_name})
+ op = self.connection.request('disk.update',
+ int(disk.id),
+ params)
+ if self._wait_operation(op['id']):
+ return True
+ return False
Added: libcloud/trunk/test/compute/fixtures/gandi/disk_attach.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/gandi/disk_attach.xml?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/gandi/disk_attach.xml (added)
+++ libcloud/trunk/test/compute/fixtures/gandi/disk_attach.xml Wed Oct 5 08:48:23 2011
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<methodResponse>
+<params>
+<param>
+<value><struct>
+<member>
+<name>iface_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110921T12:57:05</dateTime.iso8601></value>
+</member>
+<member>
+<name>vm_id</name>
+<value><int>250133</int></value>
+</member>
+<member>
+<name>date_start</name>
+<value><string></string></value>
+</member>
+<member>
+<name>disk_id</name>
+<value><int>34918</int></value>
+</member>
+<member>
+<name>source</name>
+<value><string>AB3917-GANDI</string></value>
+</member>
+<member>
+<name>step</name>
+<value><string>WAIT</string></value>
+</member>
+<member>
+<name>ip_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110921T12:57:05</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>disk_attach</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>657982</int></value>
+</member>
+</struct></value>
+</param>
+</params>
+</methodResponse>
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/gandi/disk_create_from.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/gandi/disk_create_from.xml?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/gandi/disk_create_from.xml (added)
+++ libcloud/trunk/test/compute/fixtures/gandi/disk_create_from.xml Wed Oct 5 08:48:23 2011
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<methodResponse>
+<params>
+<param>
+<value><struct>
+<member>
+<name>iface_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110921T14:20:56</dateTime.iso8601></value>
+</member>
+<member>
+<name>vm_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_start</name>
+<value><string></string></value>
+</member>
+<member>
+<name>disk_id</name>
+<value><int>35288</int></value>
+</member>
+<member>
+<name>source</name>
+<value><string>AB3917-GANDI</string></value>
+</member>
+<member>
+<name>step</name>
+<value><string>WAIT</string></value>
+</member>
+<member>
+<name>ip_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110921T14:20:56</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>disk_create</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>657985</int></value>
+</member>
+</struct></value>
+</param>
+</params>
+</methodResponse>
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/gandi/disk_detach.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/gandi/disk_detach.xml?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/gandi/disk_detach.xml (added)
+++ libcloud/trunk/test/compute/fixtures/gandi/disk_detach.xml Wed Oct 5 08:48:23 2011
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<methodResponse>
+<params>
+<param>
+<value><struct>
+<member>
+<name>iface_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110921T12:57:35</dateTime.iso8601></value>
+</member>
+<member>
+<name>vm_id</name>
+<value><int>250133</int></value>
+</member>
+<member>
+<name>date_start</name>
+<value><string></string></value>
+</member>
+<member>
+<name>disk_id</name>
+<value><int>34918</int></value>
+</member>
+<member>
+<name>source</name>
+<value><string>AB3917-GANDI</string></value>
+</member>
+<member>
+<name>step</name>
+<value><string>WAIT</string></value>
+</member>
+<member>
+<name>ip_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110921T12:57:35</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>disk_detach</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>657983</int></value>
+</member>
+</struct></value>
+</param>
+</params>
+</methodResponse>
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/gandi/disk_list.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/gandi/disk_list.xml?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/gandi/disk_list.xml (added)
+++ libcloud/trunk/test/compute/fixtures/gandi/disk_list.xml Wed Oct 5 08:48:23 2011
@@ -0,0 +1,200 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<methodResponse>
+<params>
+<param>
+<value><array><data>
+<value><struct>
+<member>
+<name>datacenter_id</name>
+<value><int>1</int></value>
+</member>
+<member>
+<name>name</name>
+<value><string>disk_libcloud2</string></value>
+</member>
+<member>
+<name>kernel_version</name>
+<value><string>2.6.32</string></value>
+</member>
+<member>
+<name>can_snapshot</name>
+<value><boolean>0</boolean></value>
+</member>
+<member>
+<name>visibility</name>
+<value><string>private</string></value>
+</member>
+<member>
+<name>label</name>
+<value><string>Debian 5</string></value>
+</member>
+<member>
+<name>vms_id</name>
+<value><array><data>
+</data></array></value>
+</member>
+<member>
+<name>source</name>
+<value><int>23351</int></value>
+</member>
+<member>
+<name>state</name>
+<value><string>created</string></value>
+</member>
+<member>
+<name>is_boot_disk</name>
+<value><boolean>0</boolean></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20101116T10:51:59</dateTime.iso8601></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20101028T13:52:38</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>data</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>34918</int></value>
+</member>
+<member>
+<name>size</name>
+<value><int>3072</int></value>
+</member>
+</struct></value>
+<value><struct>
+<member>
+<name>datacenter_id</name>
+<value><int>1</int></value>
+</member>
+<member>
+<name>name</name>
+<value><string>test1</string></value>
+</member>
+<member>
+<name>kernel_version</name>
+<value><string>2.6.32</string></value>
+</member>
+<member>
+<name>can_snapshot</name>
+<value><string></string></value>
+</member>
+<member>
+<name>visibility</name>
+<value><string>private</string></value>
+</member>
+<member>
+<name>label</name>
+<value><string>Debian 5</string></value>
+</member>
+<member>
+<name>vms_id</name>
+<value><array><data>
+<value><int>250133</int></value>
+</data></array></value>
+</member>
+<member>
+<name>source</name>
+<value><int>23351</int></value>
+</member>
+<member>
+<name>state</name>
+<value><string>created</string></value>
+</member>
+<member>
+<name>is_boot_disk</name>
+<value><boolean>1</boolean></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110120T15:02:01</dateTime.iso8601></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110120T14:57:55</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>data</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>34951</int></value>
+</member>
+<member>
+<name>size</name>
+<value><int>3072</int></value>
+</member>
+</struct></value>
+<value><struct>
+<member>
+<name>datacenter_id</name>
+<value><int>1</int></value>
+</member>
+<member>
+<name>name</name>
+<value><string>test_disk</string></value>
+</member>
+<member>
+<name>kernel_version</name>
+<value><string>2.6.32</string></value>
+</member>
+<member>
+<name>can_snapshot</name>
+<value><boolean>1</boolean></value>
+</member>
+<member>
+<name>visibility</name>
+<value><string>private</string></value>
+</member>
+<member>
+<name>label</name>
+<value><string>Debian 5</string></value>
+</member>
+<member>
+<name>vms_id</name>
+<value><array><data>
+<value><int>250288</int></value>
+</data></array></value>
+</member>
+<member>
+<name>source</name>
+<value><int>23351</int></value>
+</member>
+<member>
+<name>state</name>
+<value><string>created</string></value>
+</member>
+<member>
+<name>is_boot_disk</name>
+<value><boolean>1</boolean></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110325T16:31:11</dateTime.iso8601></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110324T17:14:06</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>data</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>35170</int></value>
+</member>
+<member>
+<name>size</name>
+<value><int>3072</int></value>
+</member>
+</struct></value>
+</data></array></value>
+</param>
+</params>
+</methodResponse>
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/gandi/disk_update.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/gandi/disk_update.xml?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/gandi/disk_update.xml (added)
+++ libcloud/trunk/test/compute/fixtures/gandi/disk_update.xml Wed Oct 5 08:48:23 2011
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<methodResponse>
+<params>
+<param>
+<value><struct>
+<member>
+<name>iface_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110921T14:23:10</dateTime.iso8601></value>
+</member>
+<member>
+<name>vm_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_start</name>
+<value><string></string></value>
+</member>
+<member>
+<name>disk_id</name>
+<value><int>34951</int></value>
+</member>
+<member>
+<name>source</name>
+<value><string>AB3917-GANDI</string></value>
+</member>
+<member>
+<name>step</name>
+<value><string>WAIT</string></value>
+</member>
+<member>
+<name>ip_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110921T14:23:10</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>disk_update</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>657987</int></value>
+</member>
+</struct></value>
+</param>
+</params>
+</methodResponse>
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/gandi/iface_attach.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/gandi/iface_attach.xml?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/gandi/iface_attach.xml (added)
+++ libcloud/trunk/test/compute/fixtures/gandi/iface_attach.xml Wed Oct 5 08:48:23 2011
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<methodResponse>
+<params>
+<param>
+<value><struct>
+<member>
+<name>iface_id</name>
+<value><int>7857</int></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110921T12:49:35</dateTime.iso8601></value>
+</member>
+<member>
+<name>vm_id</name>
+<value><int>250133</int></value>
+</member>
+<member>
+<name>date_start</name>
+<value><string></string></value>
+</member>
+<member>
+<name>disk_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>source</name>
+<value><string>AB3917-GANDI</string></value>
+</member>
+<member>
+<name>step</name>
+<value><string>WAIT</string></value>
+</member>
+<member>
+<name>ip_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110921T12:49:35</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>iface_attach</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>657980</int></value>
+</member>
+</struct></value>
+</param>
+</params>
+</methodResponse>
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/gandi/iface_detach.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/gandi/iface_detach.xml?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/gandi/iface_detach.xml (added)
+++ libcloud/trunk/test/compute/fixtures/gandi/iface_detach.xml Wed Oct 5 08:48:23 2011
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<methodResponse>
+<params>
+<param>
+<value><struct>
+<member>
+<name>iface_id</name>
+<value><int>7857</int></value>
+</member>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110921T12:53:29</dateTime.iso8601></value>
+</member>
+<member>
+<name>vm_id</name>
+<value><int>250133</int></value>
+</member>
+<member>
+<name>date_start</name>
+<value><string></string></value>
+</member>
+<member>
+<name>disk_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>source</name>
+<value><string>AB3917-GANDI</string></value>
+</member>
+<member>
+<name>step</name>
+<value><string>WAIT</string></value>
+</member>
+<member>
+<name>ip_id</name>
+<value><string></string></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110921T12:53:29</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>iface_detach</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>657981</int></value>
+</member>
+</struct></value>
+</param>
+</params>
+</methodResponse>
\ No newline at end of file
Added: libcloud/trunk/test/compute/fixtures/gandi/iface_list.xml
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/fixtures/gandi/iface_list.xml?rev=1179108&view=auto
==============================================================================
--- libcloud/trunk/test/compute/fixtures/gandi/iface_list.xml (added)
+++ libcloud/trunk/test/compute/fixtures/gandi/iface_list.xml Wed Oct 5 08:48:23 2011
@@ -0,0 +1,99 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<methodResponse>
+<params>
+<param>
+<value><array><data>
+<value><struct>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110120T14:58:44</dateTime.iso8601></value>
+</member>
+<member>
+<name>vm_id</name>
+<value><int>250133</int></value>
+</member>
+<member>
+<name>bandwidth</name>
+<value><double>5120.0</double></value>
+</member>
+<member>
+<name>datacenter_id</name>
+<value><int>1</int></value>
+</member>
+<member>
+<name>state</name>
+<value><string>used</string></value>
+</member>
+<member>
+<name>num</name>
+<value><int>0</int></value>
+</member>
+<member>
+<name>ips_id</name>
+<value><array><data>
+<value><int>9256</int></value>
+<value><int>9294</int></value>
+</data></array></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110120T14:57:55</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>public</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>7857</int></value>
+</member>
+</struct></value>
+<value><struct>
+<member>
+<name>date_updated</name>
+<value><dateTime.iso8601>20110324T17:14:16</dateTime.iso8601></value>
+</member>
+<member>
+<name>vm_id</name>
+<value><int>250288</int></value>
+</member>
+<member>
+<name>bandwidth</name>
+<value><double>5192.0</double></value>
+</member>
+<member>
+<name>datacenter_id</name>
+<value><int>1</int></value>
+</member>
+<member>
+<name>state</name>
+<value><string>used</string></value>
+</member>
+<member>
+<name>num</name>
+<value><int>0</int></value>
+</member>
+<member>
+<name>ips_id</name>
+<value><array><data>
+<value><int>9298</int></value>
+<value><int>9508</int></value>
+</data></array></value>
+</member>
+<member>
+<name>date_created</name>
+<value><dateTime.iso8601>20110324T17:14:06</dateTime.iso8601></value>
+</member>
+<member>
+<name>type</name>
+<value><string>public</string></value>
+</member>
+<member>
+<name>id</name>
+<value><int>8019</int></value>
+</member>
+</struct></value>
+</data></array></value>
+</param>
+</params>
+</methodResponse>
\ No newline at end of file
Modified: libcloud/trunk/test/compute/test_gandi.py
URL: http://svn.apache.org/viewvc/libcloud/trunk/test/compute/test_gandi.py?rev=1179108&r1=1179107&r2=1179108&view=diff
==============================================================================
--- libcloud/trunk/test/compute/test_gandi.py (original)
+++ libcloud/trunk/test/compute/test_gandi.py Wed Oct 5 08:48:23 2011
@@ -21,6 +21,7 @@ import httplib
import xmlrpclib
from libcloud.compute.drivers.gandi import GandiNodeDriver as Gandi
+from libcloud.common.gandi import GandiException
from libcloud.compute.types import NodeState
from xml.etree import ElementTree as ET
@@ -28,6 +29,7 @@ from test import MockHttp
from test.file_fixtures import ComputeFileFixtures
from test.secrets import GANDI_PARAMS
+
class MockGandiTransport(xmlrpclib.Transport):
def request(self, host, handler, request_body, verbose=0):
@@ -43,11 +45,14 @@ class MockGandiTransport(xmlrpclib.Trans
response = self.parse_response(resp.body)
return response
+
class GandiTests(unittest.TestCase):
node_name = 'test2'
+
def setUp(self):
- Gandi.connectionCls.proxyCls.transportCls = [MockGandiTransport, MockGandiTransport]
+ Gandi.connectionCls.proxyCls.transportCls = \
+ [MockGandiTransport, MockGandiTransport]
self.driver = Gandi(*GANDI_PARAMS)
def test_list_nodes(self):
@@ -55,11 +60,13 @@ class GandiTests(unittest.TestCase):
self.assertTrue(len(nodes) > 0)
def test_list_locations(self):
- loc = filter(lambda x: 'france' in x.country.lower(), self.driver.list_locations())[0]
+ loc = filter(lambda x: 'france' in x.country.lower(),
+ self.driver.list_locations())[0]
self.assertEqual(loc.country, 'France')
def test_list_images(self):
- loc = filter(lambda x: 'france' in x.country.lower(), self.driver.list_locations())[0]
+ loc = filter(lambda x: 'france' in x.country.lower(),
+ self.driver.list_locations())[0]
images = self.driver.list_images(loc)
self.assertTrue(len(images) > 2)
@@ -84,18 +91,64 @@ class GandiTests(unittest.TestCase):
def test_create_node(self):
login = 'libcloud'
- passwd = ''.join(random.choice(string.letters + string.digits) for i in xrange(10))
+ passwd = ''.join(random.choice(string.letters + string.digits)
+ for i in xrange(10))
# Get france datacenter
- loc = filter(lambda x: 'france' in x.country.lower(), self.driver.list_locations())[0]
+ loc = filter(lambda x: 'france' in x.country.lower(),
+ self.driver.list_locations())[0]
# Get a debian image
images = self.driver.list_images(loc)
images = [x for x in images if x.name.lower().startswith('debian')]
img = filter(lambda x: '5' in x.name, images)[0]
# Get a configuration size
size = self.driver.list_sizes()[0]
- node = self.driver.create_node(name=self.node_name, login=login, password=passwd, image=img, location=loc, size=size)
+ node = self.driver.create_node(name=self.node_name, login=login,
+ password=passwd, image=img, location=loc, size=size)
self.assertEqual(node.name, self.node_name)
+ def test_ex_list_disks(self):
+ disks = self.driver.ex_list_disks()
+ self.assertTrue(len(disks) > 0)
+
+ def test_ex_list_interfaces(self):
+ ifaces = self.driver.ex_list_interfaces()
+ self.assertTrue(len(ifaces) > 0)
+
+ def test_ex_attach_interface(self):
+ ifaces = self.driver.ex_list_interfaces()
+ nodes = self.driver.list_nodes()
+ res = self.driver.ex_node_attach_interface(nodes[0], ifaces[0])
+ self.assertTrue(res)
+
+ def test_ex_detach_interface(self):
+ ifaces = self.driver.ex_list_interfaces()
+ nodes = self.driver.list_nodes()
+ res = self.driver.ex_node_detach_interface(nodes[0], ifaces[0])
+ self.assertTrue(res)
+
+ def test_ex_attach_disk(self):
+ disks = self.driver.ex_list_disks()
+ nodes = self.driver.list_nodes()
+ res = self.driver.ex_node_attach_disk(nodes[0], disks[0])
+ self.assertTrue(res)
+
+ def test_ex_detach_disk(self):
+ disks = self.driver.ex_list_disks()
+ nodes = self.driver.list_nodes()
+ res = self.driver.ex_node_detach_disk(nodes[0], disks[0])
+ self.assertTrue(res)
+
+ def test_ex_snapshot_disk(self):
+ disks = self.driver.ex_list_disks()
+ self.assertTrue(self.driver.ex_snapshot_disk(disks[2]))
+ self.assertRaises(GandiException,
+ self.driver.ex_snapshot_disk, disks[0])
+
+ def test_ex_update_disk(self):
+ disks = self.driver.ex_list_disks()
+ self.assertTrue(self.driver.ex_update_disk(disks[0], new_size=4096))
+
+
class GandiMockHttp(MockHttp):
fixtures = ComputeFileFixtures('gandi')
@@ -144,5 +197,37 @@ class GandiMockHttp(MockHttp):
body = self.fixtures.load('vm_stop.xml')
return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+ def _xmlrpc_2_0__iface_list(self, method, url, body, headers):
+ body = self.fixtures.load('iface_list.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _xmlrpc_2_0__disk_list(self, method, url, body, headers):
+ body = self.fixtures.load('disk_list.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _xmlrpc_2_0__vm_iface_attach(self, method, url, body, headers):
+ body = self.fixtures.load('iface_attach.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _xmlrpc_2_0__vm_iface_detach(self, method, url, body, headers):
+ body = self.fixtures.load('iface_detach.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _xmlrpc_2_0__vm_disk_attach(self, method, url, body, headers):
+ body = self.fixtures.load('disk_attach.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _xmlrpc_2_0__vm_disk_detach(self, method, url, body, headers):
+ body = self.fixtures.load('disk_detach.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _xmlrpc_2_0__disk_create_from(self, method, url, body, headers):
+ body = self.fixtures.load('disk_create_from.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
+ def _xmlrpc_2_0__disk_update(self, method, url, body, headers):
+ body = self.fixtures.load('disk_update.xml')
+ return (httplib.OK, body, {}, httplib.responses[httplib.OK])
+
if __name__ == '__main__':
sys.exit(unittest.main())