You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltacloud.apache.org by mf...@apache.org on 2011/02/25 13:53:22 UTC

svn commit: r1074507 - in /incubator/deltacloud/trunk/clients: ./ python/ python/README.markdown python/deltacloud.py

Author: mfojtik
Date: Fri Feb 25 12:53:21 2011
New Revision: 1074507

URL: http://svn.apache.org/viewvc?rev=1074507&view=rev
Log:
Added simple Python client for Deltacloud API

Added:
    incubator/deltacloud/trunk/clients/
    incubator/deltacloud/trunk/clients/python/
    incubator/deltacloud/trunk/clients/python/README.markdown
    incubator/deltacloud/trunk/clients/python/deltacloud.py

Added: incubator/deltacloud/trunk/clients/python/README.markdown
URL: http://svn.apache.org/viewvc/incubator/deltacloud/trunk/clients/python/README.markdown?rev=1074507&view=auto
==============================================================================
--- incubator/deltacloud/trunk/clients/python/README.markdown (added)
+++ incubator/deltacloud/trunk/clients/python/README.markdown Fri Feb 25 12:53:21 2011
@@ -0,0 +1,30 @@
+# Deltacloud Python Bindings
+
+A simple python client for [![Deltacloud API](http://deltacloud.org)] REST interface
+
+
+## FEATURES:
+
+- Basic operations with images, instances, hardware-profiles and realms
+- Manage instances using start, stop, destroy and reboot operations
+- Create new instance from image
+
+## EXAMPLES:
+
+### Launching an instance
+
+    client = Deltacloud('http://localhost:3001/api', 'mockuser', 'mockpassword')
+    instance = client.create_instance('img1', { 'hwp_id' => 'm1-small' })
+
+### Listing images/hardware profiles/realms/instances
+
+    client = Deltacloud('http://localhost:3001/api', 'mockuser', 'mockpassword')
+    print client.images()
+    print client.instances()
+
+### Stopping instance
+
+    client = Deltacloud('http://localhost:3001/api', 'mockuser', 'mockpassword')
+    instance = client.instances()[0]
+    instance.stop()
+

Added: incubator/deltacloud/trunk/clients/python/deltacloud.py
URL: http://svn.apache.org/viewvc/incubator/deltacloud/trunk/clients/python/deltacloud.py?rev=1074507&view=auto
==============================================================================
--- incubator/deltacloud/trunk/clients/python/deltacloud.py (added)
+++ incubator/deltacloud/trunk/clients/python/deltacloud.py Fri Feb 25 12:53:21 2011
@@ -0,0 +1,219 @@
+# Copyright (C) 2009, 2010  Red Hat, Inc.
+#
+# 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.
+
+from httplib2 import Http
+from urllib import urlencode
+import libxml2
+
+class SimpleRestClient:
+    """A simple REST client library"""
+    
+    def __init__(self, api_url, api_user, api_password):
+      self.url, self.user, self.password = api_url, api_user, api_password
+      self.client = Http()
+      self.client.follow_all_redirect = True
+      self.client.add_credentials(self.user, self.password)
+
+    def GET(self, uri):
+      if uri.startswith('http://'):
+	current_url = ''
+      else:
+	current_url = self.url
+      status, response = self.client.request('{url}{uri}'.format(url=current_url, uri=uri), 'GET', headers={'accept':'application/xml'})
+      response = self.parse_xml(response)
+      return status, response
+
+    def POST(self, uri, params={}):
+      if uri.startswith('http://'):
+	current_url = ''
+      else:
+	current_url = self.url
+      if not params:
+	params = {}
+      status, response = self.client.request('{url}{uri}'.format(url=current_url, uri=uri), 'POST',
+	  urlencode(params), headers={'accept':'application/xml'})
+      response = self.parse_xml(response)
+      return status, response
+
+    def DELETE(self, uri):
+      if uri.startswith('http://'):
+	current_url = ''
+      else:
+	current_url = self.url
+      return self.client.request('{url}{uri}'.format(url=current_url, uri=uri), 'DELETE')
+
+    def PUT(self, uri):
+      if uri.startswith('http://'):
+	current_url = ''
+      else:
+	current_url = self.url
+      return self.client.request('{url}{uri}'.format(url=current_url, uri=uri), 'PUT')
+
+    def parse_xml(self, response):
+      return libxml2.parseDoc(response)
+
+
+class Deltacloud:
+  """ Simple Deltacloud client """
+
+  def __init__(self, url, username, password):
+    self.client = SimpleRestClient(url, username, password)
+    self.entrypoints = self.discover_entrypoints()
+
+  def discover_entrypoints(self):
+    doc = self.client.GET('/')[1]
+    entrypoints = {}
+    for link in doc.xpathEval("/api/link"):
+      entrypoints[link.xpathEval("@rel")[0].content] = link.xpathEval("@href")[0].content
+    return entrypoints
+
+  def hardware_profiles(self):
+    doc = self.client.GET(self.entrypoints['hardware_profiles'])[1]
+    profiles = []
+    for profile in doc.xpathEval("/hardware_profiles/hardware_profile"):
+      profiles.append(HardwareProfile(self, profile))
+    return profiles
+
+  def realms(self):
+    doc = self.client.GET(self.entrypoints['realms'])[1]
+    realms = []
+    for realm in doc.xpathEval("/realms/realm"):
+      realms.append(Realm(self, realm))
+    return realms
+
+  def images(self):
+    doc = self.client.GET(self.entrypoints['images'])[1]
+    images = []
+    for image in doc.xpathEval("/images/image"):
+      images.append(Image(self, image))
+    return images
+
+  def instances(self):
+    doc = self.client.GET(self.entrypoints['instances'])[1]
+    instances = []
+    for instance in doc.xpathEval("/instances/instance"):
+      instances.append(Instance(self, instance))
+    return instances
+
+  def create_instance(self, image_id, opts):
+    opts['image_id'] = image_id
+    doc = self.client.POST(self.entrypoints['instances'], opts)[1]
+    instance = doc.xpathEval("/instance")[0]
+    return Instance(self, instance)
+
+
+class Instance(Deltacloud):
+
+  def __init__(self, deltacloud, instance):
+    self.instance, self.deltacloud = instance, deltacloud
+    self.id = instance.xpathEval("@id")[0].content
+    self.name = instance.xpathEval("name")[0].content
+    self.state = instance.xpathEval("state")[0].content
+    self.owner_id = instance.xpathEval("owner_id")[0].content
+    self.public_addresses, self.private_addresses = [], []
+    [self.public_addresses.append(address.content) for address in instance.xpathEval('public_addresses/address')]
+    [self.private_addresses.append(address.content) for address in instance.xpathEval('private_addresses/address')]
+    password_auth = instance.xpathEval("authetication[@type='password']/login")
+    key_auth = instance.xpathEval("authetication[@type='key']/login")
+    if password_auth:
+      self.username = password_auth[0].xpathEval('username')[0].content
+      self.password = password_auth[0].xpathEval('password')[0].content
+    if key_auth:
+      self.key_name = key_auth[0].xpathEval('keyname').content
+
+  def start(self):
+    action = self.instance.xpathEval("actions/link[@rel='start']")
+    if not action:
+      return False
+    else:
+      if self.deltacloud.client.POST(action[0].xpathEval("@href")[0].content, {})[0]['status'] == '200':
+	return True
+      else:
+	return False
+
+  def stop(self):
+    action = self.instance.xpathEval("actions/link[@rel='stop']")
+    if not action:
+      return False
+    else:
+      if self.deltacloud.client.POST(action[0].xpathEval("@href")[0].content, {})[0]['status'] == '200':
+	return True
+      else:
+	return False
+
+  def reboot(self):
+    action = self.instance.xpathEval("actions/link[@rel='reboot']")
+    if not action:
+      return False
+    else:
+      if self.deltacloud.client.POST(action[0].xpathEval("@href")[0].content, {})[0]['status'] == '200':
+	return True
+      else:
+	return False
+
+  def destroy(self):
+    action = self.instance.xpathEval("actions/link[@rel='destroy']")
+    if not action:
+      return False
+    else:
+      if self.deltacloud.client.POST(action[0].xpathEval("@href")[0].content, {})[0]['status'] == '200':
+	return True
+      else:
+	return False
+
+
+class Image(Deltacloud):
+
+  def __init__(self, client, image):
+    self.id = image.xpathEval("@id")[0].content
+    self.name = image.xpathEval("name")[0].content
+    self.state = image.xpathEval("state")[0].content
+    self.owner_id = image.xpathEval("owner_id")[0].content
+    self.architecture = image.xpathEval("architecture")[0].content
+    self.description = image.xpathEval("description")[0].content
+
+class Realm(Deltacloud):
+
+  def __init__(self, client, realm):
+    self.id = realm.xpathEval("@id")[0].content
+    self.name = realm.xpathEval("name")[0].content
+    self.state = realm.xpathEval("state")[0].content
+
+
+class HardwareProfile(Deltacloud):
+
+  def __init__(self, client, profile):
+    self.id = profile.xpathEval("@id")[0].content
+    self.name = profile.xpathEval("name")[0].content
+    self.properties = []
+    for prop in profile.xpathEval("property"):
+      self.properties.append(HardwareProfileProperty(profile, prop))
+
+class HardwareProfileProperty(HardwareProfile):
+
+  def __init__(self, profile, prop):
+    self.name  = prop.xpathEval("@name")[0].content
+    self.kind  = prop.xpathEval("@kind")[0].content
+    self.unit  = prop.xpathEval("@unit")[0].content
+    self.value = prop.xpathEval("@value")[0].content
+    if prop.xpathEval("enum"):
+      self.enums = []
+      [self.enums.append(attr.content) for attr in prop.xpathEval('enum/entry')]
+    if prop.xpathEval("range"):
+      self.range_min = prop.xpathEval('range/@first')[0].content
+      self.range_max = prop.xpathEval('range/@last')[0].content
+