deltacloud-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mfoj...@apache.org
Subject [8/8] git commit: Python client: Use JSON instead of XML
Date Tue, 21 Aug 2012 11:41:46 GMT
Python client: Use JSON instead of XML

The data structures returned by Deltacloud are more easilly manipulated
in the Python dictionary form -- to which JSON maps better than XML.

As a side benefit, this cuts the number of required external
dependencies from 2 to 1.

Signed-off-by: Tomas Sedovic <tomas@sedovic.cz>


Project: http://git-wip-us.apache.org/repos/asf/deltacloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltacloud/commit/286eb19d
Tree: http://git-wip-us.apache.org/repos/asf/deltacloud/tree/286eb19d
Diff: http://git-wip-us.apache.org/repos/asf/deltacloud/diff/286eb19d

Branch: refs/heads/master
Commit: 286eb19da42dd84b0f84c0739d306327fa5d2f35
Parents: bc5d15b
Author: Tomas Sedovic <tomas@sedovic.cz>
Authored: Thu Aug 9 15:26:45 2012 +0200
Committer: Tomas Sedovic <tomas@sedovic.cz>
Committed: Tue Aug 21 12:06:56 2012 +0200

----------------------------------------------------------------------
 clients/python/deltacloud.py |  214 +++++++++++++++++--------------------
 1 files changed, 97 insertions(+), 117 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/deltacloud/blob/286eb19d/clients/python/deltacloud.py
----------------------------------------------------------------------
diff --git a/clients/python/deltacloud.py b/clients/python/deltacloud.py
index cf091ef..9fae2fd 100644
--- a/clients/python/deltacloud.py
+++ b/clients/python/deltacloud.py
@@ -15,117 +15,96 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-from httplib2 import Http
-from urllib import urlencode
 from urlparse import urljoin
-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 do_request(self, uri, method='GET', params=None):
-        if params:
-            params = urlencode(params)
-        status, response = self.client.request(urljoin(self.url, uri),
-                method=method.upper(),
-                body=params,
-                headers={'accept':'application/xml'})
-        if response:
-            response = self.parse_xml(response)
-        return status, response
-
-    def GET(self, uri):
-        return self.do_request(uri, 'GET')
-
-    def POST(self, uri, params=None):
-        return self.do_request(uri, 'POST', params)
-
-    def DELETE(self, uri):
-        return self.do_request(uri, 'DELETE')
-
-    def PUT(self, uri):
-        return self.do_request(uri, 'PUT')
-
-    def parse_xml(self, response):
-        return libxml2.parseDoc(response)
+import requests
 
 
 class Deltacloud:
     """Simple Deltacloud client"""
 
     def __init__(self, url, username, password):
-        self.client = SimpleRestClient(url, username, password)
+        self.url = url
+        self.username = username
+        self.password = password
         self.entrypoints = self.discover_entrypoints()
 
+    def request(self, path='', params=None, method='get'):
+        url = urljoin(self.url, path)
+        resp = requests.request(method, url,
+                auth=(self.username, self.password),
+                params=params,
+                headers={
+                    'accept': 'application/json',
+                })
+        return resp, resp.json
+
     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
+        status, doc = self.request('')
+        links = [(link['rel'], link['href']) for link in doc['api']['link']]
+        return dict(links)
 
     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
+        status, doc = self.request(self.entrypoints['hardware_profiles'])
+        return [HardwareProfile(self, profile) for profile in
+                get_in_dict(doc, ['hardware_profiles', 'hardware_profile'], [])]
 
     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
+        status, doc = self.request(self.entrypoints['realms'])
+        return [Realm(self, realm) for realm in
+                get_in_dict(doc, ['realms','realm'], [])]
 
     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
+        status, doc = self.request(self.entrypoints['images'])
+        return [Image(self, image) for image in
+                get_in_dict(doc, ['images', 'image'], [])]
 
     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):
-        #if opts is None:
-        #  opts={}
+        status, doc = self.request(self.entrypoints['instances'])
+        return [Instance(self, instance) for instance in
+                get_in_dict(doc, ['instances', 'instance'], [])]
+
+    def create_instance(self, image_id, opts=None):
+        if opts is None:
+            opts = {}
         opts['image_id'] = image_id
-        doc = self.client.POST(self.entrypoints['instances'], opts)[1]
-        instance = doc.xpathEval("/instance")[0]
+        response, doc = self.request(self.entrypoints['instances'], opts, 'post')
+        instance = get_in_dict(doc, ['instance'])
         return Instance(self, instance)
 
+def get_in_dict(dictionary, path, default=None):
+    '''
+    Return the value at the path in the nested dictionary.
+
+    If the path isn't available, return the default value instead.
+    '''
+    if not path:
+        return default
+    if not dictionary:
+        return default
+    if len(path) == 1:
+        return dictionary.get(path[0], default)
+    return get_in_dict(dictionary.get(path[0], {}), path[1:], default)
 
 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("authentication[@type='password']/login")
-        key_auth = instance.xpathEval("authentication[@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')[0].content
+        self.id = instance["id"]
+        self.name = instance["name"]
+        self.state = instance["state"]
+        self.owner_id = instance["owner_id"]
+
+        self.public_addresses = [instance['public_addresses']['address']]
+        self.private_addresses = [instance['private_addresses']['address']]
+
+        auth_type = get_in_dict(instance, ['authentication', 'type'])
+        login = get_in_dict(instance, ['authentication', 'login'], {})
+        if auth_type == 'key':
+            self.key_name = login.get('keyname')
+        if auth_type == 'password':
+            self.username = login.get('username')
+            self.password = login.get('password')
 
     def start(self):
         return self.do_action('start')
@@ -141,63 +120,64 @@ class Instance(Deltacloud):
 
     def actions(self):
         '''Return all the actions allowed on the instance.'''
-        return [link.xpathEval('@rel')[0].content for link in
-                self.instance.xpathEval('actions/link')]
+        return [link['rel'] for link in
+                get_in_dict(self.instance, ['actions', 'link'], [])]
 
     def do_action(self, action):
         '''Run the specified action.'''
         if not action in self.actions():
             return False
-        action = self.instance.xpathEval("actions/link[@rel='%s']" % action)[0]
-        url = action.xpathEval('@href')[0].content
-        method = action.xpathEval('@method')[0].content
-        response, body = self.deltacloud.client.do_request(url, method)
-        if not response['status'][0] == '2':  # HTTP 2xx codes mean success
+        action_links = [link for link in
+                        get_in_dict(self.instance, ['actions', 'link'], [])
+                        if link['rel'] == action]
+        action = action_links[0]
+        url = action['href']
+        method = action['method']
+        response, body = self.deltacloud.request(url, method=method)
+        if response.status_code >= 400:
             return False
-        if body:
-            self.instance = body.xpathEval('instance')[0]
+        if body and 'instance' in body:
+            self.instance = body['instance']
         return True
 
 
 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
+        self.id = image["id"]
+        self.name = image["name"]
+        self.state = image["state"]
+        self.owner_id = image["owner_id"]
+        self.architecture = image["architecture"]
+        self.description = image["description"]
 
 
 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
+        self.id = realm['id']
+        self.name = realm['name']
+        self.state = realm['state']
 
 
 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))
+        self.id = profile['id']
+        self.name = profile['name']
+        self.properties = [HardwareProfileProperty(profile, prop) for prop in
+                           profile.get('property', [])]
 
 
 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
+        self.name  = prop['name']
+        self.kind  = prop['kind']
+        self.unit  = prop['unit']
+        self.value = prop['value']
+        if 'enum' in prop:
+            self.enums = [enum['value'] for enum in prop['enum']['entry']]
+        if 'range' in prop:
+            self.range_min = prop['range']['first']
+            self.range_max = prop['range']['last']


Mime
View raw message