libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From je...@apache.org
Subject svn commit: r1054893 - in /incubator/libcloud/trunk/libcloud: base.py drivers/dummy.py
Date Tue, 04 Jan 2011 04:28:40 GMT
Author: jerry
Date: Tue Jan  4 04:28:40 2011
New Revision: 1054893

URL: http://svn.apache.org/viewvc?rev=1054893&view=rev
Log:
Documentation with doctests for base.py and dummy.py; LIBCLOUD-64

Submitted By: Michael De La Rue

Modified:
    incubator/libcloud/trunk/libcloud/base.py
    incubator/libcloud/trunk/libcloud/drivers/dummy.py

Modified: incubator/libcloud/trunk/libcloud/base.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/base.py?rev=1054893&r1=1054892&r2=1054893&view=diff
==============================================================================
--- incubator/libcloud/trunk/libcloud/base.py (original)
+++ incubator/libcloud/trunk/libcloud/base.py Tue Jan  4 04:28:40 2011
@@ -33,7 +33,48 @@ from pipes import quote as pquote
 
 class Node(object):
     """
-    A Base Node class to derive from.
+    Provide a common interface for handling nodes of all types.
+
+    The Node object provides the interface in libcloud through which
+    we can manipulate nodes in different cloud providers in the same
+    way.  Node objects don't actually do much directly themselves,
+    instead the node driver handles the connection to the node.
+
+    You don't normally create a node object yourself; instead you use
+    a driver and then have that create the node for you.
+
+    >>> from libcloud.drivers.dummy import DummyNodeDriver
+    >>> driver = DummyNodeDriver(0)
+    >>> node = driver.create_node()
+    >>> node.public_ip[0]
+    '127.0.0.3'
+    >>> node.name
+    'dummy-3'
+
+    You can also get nodes from the driver's list_node function.
+
+    >>> node = driver.list_nodes()[0]
+    >>> node.name
+    'dummy-1'
+
+    the node keeps a reference to its own driver which means that we
+    can work on nodes from different providers without having to know
+    which is which.
+
+    >>> driver = DummyNodeDriver(72)
+    >>> node2 = driver.create_node()
+    >>> node.driver.creds
+    0
+    >>> node2.driver.creds
+    72
+
+    Althrough Node objects can be subclassed, this isn't normally
+    done.  Instead, any driver specific information is stored in the
+    "extra" proproperty of the node.
+
+    >>> node.extra
+    {'foo': 'bar'}
+
     """
 
     def __init__(self, id, name, state, public_ip, private_ip,
@@ -52,19 +93,67 @@ class Node(object):
 
     def get_uuid(self):
         """Unique hash for this node
+
         @return: C{string}
+
+        The hash is a function of an SHA1 hash of the node's ID and
+        its driver which means that it should be unique between all
+        nodes.  In some subclasses (e.g. GoGrid) there is no ID
+        available so the public IP address is used.  This means that,
+        unlike a properly done system UUID, the same UUID may mean a
+        different system install at a different time
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> node = driver.create_node()
+        >>> node.get_uuid()
+        'd3748461511d8b9b0e0bfa0d4d3383a619a2bb9f'
+
+        Note, for example, that this example will always produce the
+        same UUID!
         """
         return hashlib.sha1("%s:%d" % (self.id,self.driver.type)).hexdigest()
 
     def reboot(self):
         """Reboot this node
+
         @return: C{bool}
+
+        This calls the node's driver and reboots the node
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> node = driver.create_node()
+        >>> from libcloud.types import NodeState
+        >>> node.state == NodeState.RUNNING
+        True
+        >>> node.state == NodeState.REBOOTING
+        False
+        >>> node.reboot()
+        True
+        >>> node.state == NodeState.REBOOTING
+        True
         """
         return self.driver.reboot_node(self)
 
     def destroy(self):
         """Destroy this node
+
         @return: C{bool}
+
+        This calls the node's driver and destroys the node
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> from libcloud.types import NodeState
+        >>> node = driver.create_node()
+        >>> node.state == NodeState.RUNNING
+        True
+        >>> node.destroy()
+        True
+        >>> node.state == NodeState.RUNNING
+        False
+
         """
         return self.driver.destroy_node(self)
 
@@ -78,6 +167,25 @@ class Node(object):
 class NodeSize(object):
     """
     A Base NodeSize class to derive from.
+
+    NodeSizes are objects which are typically returned a driver's
+    list_sizes function.  They contain a number of different
+    parameters which define how big an image is.
+
+    The exact parameters available depends on the provider.
+
+    N.B. Where a parameter is "unlimited" (for example bandwidth in
+    Amazon) this will be given as 0.
+
+    >>> from libcloud.drivers.dummy import DummyNodeDriver
+    >>> driver = DummyNodeDriver(0)
+    >>> size = driver.list_sizes()[0]
+    >>> size.ram
+    128
+    >>> size.bandwidth
+    500
+    >>> size.price
+    4
     """
 
     def __init__(self, id, name, ram, disk, bandwidth, price, driver):
@@ -97,7 +205,25 @@ class NodeSize(object):
 
 class NodeImage(object):
     """
-    A Base NodeImage class to derive from.
+    An operating system image.
+
+    NodeImage objects are typically returned by the driver for the
+    cloud provider in response to the list_images function
+
+    >>> from libcloud.drivers.dummy import DummyNodeDriver
+    >>> driver = DummyNodeDriver(0)
+    >>> image = driver.list_images()[0]
+    >>> image.name
+    'Ubuntu 9.10'
+
+    Apart from name and id, there is no further standard information;
+    other parameters are stored in a driver specific "extra" variable
+
+    When creating a node, a node image should be given as an argument
+    to the create_node function to decide which OS image to use.
+
+    >>> node = driver.create_node(image=image)
+
     """
 
     def __init__(self, id, name, driver, extra=None):
@@ -114,7 +240,13 @@ class NodeImage(object):
 
 class NodeLocation(object):
     """
-    A base NodeLocation class to derive from.
+    A physical location where nodes can be.
+
+    >>> from libcloud.drivers.dummy import DummyNodeDriver
+    >>> driver = DummyNodeDriver(0)
+    >>> location = driver.list_locations()[0]
+    >>> location.country
+    'US'
     """
 
     def __init__(self, id, name, country, driver):
@@ -129,6 +261,16 @@ class NodeLocation(object):
 class NodeAuthSSHKey(object):
     """
     An SSH key to be installed for authentication to a node.
+
+    This is the actual contents of the users ssh public key which will
+    normally be installed as root's public key on the node.
+
+    >>> pubkey = '...' # read from file
+    >>> from libcloud.base import NodeAuthSSHKey
+    >>> k = NodeAuthSSHKey(pubkey)
+    >>> k
+    <NodeAuthSSHKey>
+
     """
     def __init__(self, pubkey):
         self.pubkey = pubkey
@@ -494,6 +636,11 @@ class ConnectionUserAndKey(ConnectionKey
 class NodeDriver(object):
     """
     A base NodeDriver class to derive from
+
+    This class is always subclassed by a specific driver.  For
+    examples of base behavior of most functions (except deploy node)
+    see the dummy driver.
+
     """
 
     connectionCls = ConnectionKey
@@ -637,7 +784,7 @@ class NodeDriver(object):
         Depends on a Provider Driver supporting either using a specific password
         or returning a generated password.
 
-        This function may raise a L{DeplyomentException}, if a create_node
+        This function may raise a L{DeploymentException}, if a create_node
         call was successful, but there is a later error (like SSH failing or
         timing out).  This exception includes a Node object which you may want
         to destroy if incomplete deployments are not desirable.
@@ -653,6 +800,24 @@ class NodeDriver(object):
         @type       ssh_port: C{int}
 
         See L{NodeDriver.create_node} for more keyword args.
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> from libcloud.deployment import ScriptDeployment, MultiStepDeployment
+        >>> from libcloud.base import NodeAuthSSHKey
+        >>> driver = DummyNodeDriver(0)
+        >>> key = NodeAuthSSHKey('...') # read from file
+        >>> script = ScriptDeployment("yum -y install emacs strace tcpdump")
+        >>> msd = MultiStepDeployment([key, script])
+        >>> def d():
+        ...     try:
+        ...         node = driver.deploy_node(deploy=msd)
+        ...     except NotImplementedError:
+        ...         print "not implemented for dummy driver"
+        >>> d()
+        not implemented for dummy driver
+
+        Deploy node is typically not overridden in subclasses.  The
+        existing implementation should be able to handle most such.
         """
         # TODO: support ssh keys
         WAIT_PERIOD=3
@@ -738,3 +903,8 @@ def is_private_subnet(ip):
             return True
 
     return False
+
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()

Modified: incubator/libcloud/trunk/libcloud/drivers/dummy.py
URL: http://svn.apache.org/viewvc/incubator/libcloud/trunk/libcloud/drivers/dummy.py?rev=1054893&r1=1054892&r2=1054893&view=diff
==============================================================================
--- incubator/libcloud/trunk/libcloud/drivers/dummy.py (original)
+++ incubator/libcloud/trunk/libcloud/drivers/dummy.py Tue Jan  4 04:28:40 2011
@@ -36,6 +36,28 @@ class DummyConnection(ConnectionKey):
 class DummyNodeDriver(NodeDriver):
     """
     Dummy node driver
+
+    This is a fake driver which appears to always create or destroy
+    nodes successfully.
+
+    >>> from libcloud.drivers.dummy import DummyNodeDriver
+    >>> driver = DummyNodeDriver(0)
+    >>> node=driver.create_node()
+    >>> node.public_ip[0]
+    '127.0.0.3'
+    >>> node.name
+    'dummy-3'
+
+    If the credentials you give convert to an integer then the next
+    node to be created will be one higher.
+
+    Each time you create a node you will get a different IP address.
+
+    >>> driver = DummyNodeDriver(22)
+    >>> node=driver.create_node()
+    >>> node.name
+    'dummy-23'
+
     """
 
     name = "Dummy Node Provider"
@@ -84,18 +106,85 @@ class DummyNodeDriver(NodeDriver):
         return str(uuid.uuid4())
 
     def list_nodes(self):
+        """
+        List the nodes known to a particular driver;
+        There are two default nodes created at the beginning
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> node_list=driver.list_nodes()
+        >>> sorted([node.name for node in node_list ])
+        ['dummy-1', 'dummy-2']
+
+        each item in the list returned is a node object from which you
+        can carry out any node actions you wish
+
+        >>> node_list[0].reboot()
+        True
+
+        As more nodes are added, list_nodes will return them
+
+        >>> node=driver.create_node()
+        >>> sorted([node.name for node in driver.list_nodes()])
+        ['dummy-1', 'dummy-2', 'dummy-3']
+        """
         return self.nl
 
     def reboot_node(self, node):
+        """
+        Sets the node state to rebooting; in this dummy driver always
+        returns True as if the reboot had been successful.
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> node=driver.create_node()
+        >>> from libcloud.types import NodeState
+        >>> node.state == NodeState.RUNNING
+        True
+        >>> node.state == NodeState.REBOOTING
+        False
+        >>> driver.reboot_node(node)
+        True
+        >>> node.state == NodeState.REBOOTING
+        True
+
+        Please note, dummy nodes never recover from the reboot.
+        """
+
         node.state = NodeState.REBOOTING
         return True
 
     def destroy_node(self, node):
+        """
+        Sets the node state to terminated and removes it from the node list
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> from libcloud.types import NodeState
+        >>> node = [node for node in driver.list_nodes() if node.name == 'dummy-1'][0]
+        >>> node.state == NodeState.RUNNING
+        True
+        >>> driver.destroy_node(node)
+        True
+        >>> node.state == NodeState.RUNNING
+        False
+        >>> [node for node in driver.list_nodes() if node.name == 'dummy-1']
+        []
+        """
+
         node.state = NodeState.TERMINATED
         self.nl.remove(node)
         return True
 
     def list_images(self, location=None):
+        """
+        Returns a list of images as a cloud provider might have
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> sorted([image.name for image in driver.list_images()])
+        ['Slackware 4', 'Ubuntu 9.04', 'Ubuntu 9.10']
+        """
         return [
             NodeImage(id=1, name="Ubuntu 9.10", driver=self),
             NodeImage(id=2, name="Ubuntu 9.04", driver=self),
@@ -103,54 +192,89 @@ class DummyNodeDriver(NodeDriver):
         ]
 
     def list_sizes(self, location=None):
+        """
+        Returns a list of node sizes as a cloud provider might have
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> sorted([size.ram for size in driver.list_sizes()])
+        [128, 512, 4096, 8192]
+        """
+
         return [
-          NodeSize(id=1,
-                   name="Small",
-                   ram=128,
-                   disk=4,
-                   bandwidth=500,
-                   price=4,
-                   driver=self),
-          NodeSize(id=2,
-                   name="Medium",
-                   ram=512,
-                   disk=16,
-                   bandwidth=1500,
-                   price=8,
-                   driver=self),
-          NodeSize(id=3,
-                   name="Big",
-                   ram=4096,
-                   disk=32,
-                   bandwidth=2500,
-                   price=32,
-                   driver=self),
-          NodeSize(id=4,
-                   name="XXL Big",
-                   ram=4096*2,
-                   disk=32*4,
-                   bandwidth=2500*3,
-                   price=32*2,
-                   driver=self),
+            NodeSize(id=1,
+                     name="Small",
+                     ram=128,
+                     disk=4,
+                     bandwidth=500,
+                     price=4,
+                     driver=self),
+            NodeSize(id=2,
+                     name="Medium",
+                     ram=512,
+                     disk=16,
+                     bandwidth=1500,
+                     price=8,
+                     driver=self),
+            NodeSize(id=3,
+                     name="Big",
+                     ram=4096,
+                     disk=32,
+                     bandwidth=2500,
+                     price=32,
+                     driver=self),
+            NodeSize(id=4,
+                     name="XXL Big",
+                     ram=4096*2,
+                     disk=32*4,
+                     bandwidth=2500*3,
+                     price=32*2,
+                     driver=self),
         ]
 
     def list_locations(self):
+        """
+        Returns a list of locations of nodes
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> sorted([loc.name + " in " + loc.country for loc in driver.list_locations()])
+        ['Island Datacenter in FJ', 'London Loft in GB', "Paul's Room in US"]
+        """
         return [
-          NodeLocation(id=1,
-                       name="Paul's Room",
-                       country='US',
-                       driver=self),
-          NodeLocation(id=2,
-                       name="London Loft",
-                       country='GB',
-                       driver=self),
-          NodeLocation(id=3,
-                       name="Island Datacenter",
-                       country='FJ',
-                       driver=self),
+            NodeLocation(id=1,
+                         name="Paul's Room",
+                         country='US',
+                         driver=self),
+            NodeLocation(id=2,
+                         name="London Loft",
+                         country='GB',
+                         driver=self),
+            NodeLocation(id=3,
+                         name="Island Datacenter",
+                         country='FJ',
+                         driver=self),
         ]
 
     def create_node(self, **kwargs):
+        """
+        Creates a dummy node; the node id is equal to the number of
+        nodes in the node list
+
+        >>> from libcloud.drivers.dummy import DummyNodeDriver
+        >>> driver = DummyNodeDriver(0)
+        >>> sorted([node.name for node in driver.list_nodes()])
+        ['dummy-1', 'dummy-2']
+        >>> nodeA = driver.create_node()
+        >>> sorted([node.name for node in driver.list_nodes()])
+        ['dummy-1', 'dummy-2', 'dummy-3']
+        >>> driver.create_node().name
+        'dummy-4'
+        >>> driver.destroy_node(nodeA)
+        True
+        >>> sorted([node.name for node in driver.list_nodes()])
+        ['dummy-1', 'dummy-2', 'dummy-4']
+        """
         l = len(self.nl) + 1
         n = Node(id=l,
                  name='dummy-%d' % l,
@@ -167,3 +291,7 @@ def _ip_to_int(ip):
 
 def _int_to_ip(ip):
     return socket.inet_ntoa(struct.pack('I', socket.ntohl(ip)))
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()



Mime
View raw message