Update image client to the new infrastructure
authorGiorgos Verigakis <verigak@gmail.com>
Thu, 23 Feb 2012 12:51:42 +0000 (14:51 +0200)
committerGiorgos Verigakis <verigak@gmail.com>
Wed, 9 May 2012 10:18:42 +0000 (13:18 +0300)
Delete obsolete HTTPClient.

kamaki/clients/http.py [deleted file]
kamaki/clients/image.py

diff --git a/kamaki/clients/http.py b/kamaki/clients/http.py
deleted file mode 100644 (file)
index fa675f3..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-# Copyright 2011 GRNET S.A. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or
-# without modification, are permitted provided that the following
-# conditions are met:
-#
-#   1. Redistributions of source code must retain the above
-#      copyright notice, this list of conditions and the following
-#      disclaimer.
-#
-#   2. Redistributions in binary form must reproduce the above
-#      copyright notice, this list of conditions and the following
-#      disclaimer in the documentation and/or other materials
-#      provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
-# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and
-# documentation are those of the authors and should not be
-# interpreted as representing official policies, either expressed
-# or implied, of GRNET S.A.
-
-import json
-import logging
-
-from httplib import HTTPConnection, HTTPSConnection
-from urlparse import urlparse
-
-from . import ClientError
-
-
-log = logging.getLogger('kamaki.clients')
-
-
-class HTTPClient(object):
-    def __init__(self, config):
-        self.config = config
-    
-    @property
-    def url(self):
-        url = self.config.get('url')
-        if not url:
-            raise ClientError('No URL was given')
-        return url
-    
-    @property
-    def token(self):
-        token = self.config.get('token')
-        if not token:
-            raise ClientError('No token was given')
-        return token
-    
-    def raw_http_cmd(self, method, path, body=None, headers=None, success=200,
-                     json_reply=False, skip_read=False):
-        p = urlparse(self.url)
-        path = p.path + path
-        if p.scheme == 'http':
-            conn = HTTPConnection(p.netloc)
-        elif p.scheme == 'https':
-            conn = HTTPSConnection(p.netloc)
-        else:
-            raise ClientError('Unknown URL scheme')
-        
-        headers = headers or {}
-        headers['X-Auth-Token'] = self.token
-        if body:
-            headers.setdefault('Content-Type', 'application/json')
-            headers['Content-Length'] = len(body)
-        
-        log.debug('>' * 50)
-        log.debug('%s %s', method, path)
-        for key, val in headers.items():
-            log.debug('%s: %s', key, val)
-        if body:
-            log.debug('')
-            log.debug(body)
-        
-        conn.request(method, path, body, headers)
-        
-        resp = conn.getresponse()
-        reply = '' if skip_read else resp.read()
-        
-        log.debug('<' * 50)
-        log.info('%d %s', resp.status, resp.reason)
-        for key, val in resp.getheaders():
-            log.info('%s: %s', key.capitalize(), val)
-        log.info('')
-        log.debug(reply)
-        log.debug('-' * 50)
-        
-        if json_reply:
-            try:
-                reply = json.loads(reply) if reply else {}
-            except ValueError:
-                raise ClientError('Did not receive valid JSON reply',
-                                  resp.status, reply)
-        
-        if success and resp.status != success:
-            if len(reply) == 1:
-                if json_reply:
-                    key = reply.keys()[0]
-                    val = reply[key]
-                    message = '%s: %s' % (key, val.get('message', ''))
-                    details = val.get('details', '')
-                else:
-                    message = reply
-                    details = ''
-    
-                raise ClientError(message, resp.status, details)
-            else:
-                raise ClientError('Invalid response from the server')
-        
-        return resp, reply
-    
-    def http_cmd(self, method, path, body=None, headers=None, success=200):
-        resp, reply = self.raw_http_cmd(method, path, body, headers, success,
-                                        json_reply=True)
-        return reply
-    
-    def http_get(self, path, success=200):
-        return self.http_cmd('GET', path, success=success)
-    
-    def http_post(self, path, body=None, headers=None, success=202):
-        return self.http_cmd('POST', path, body, headers, success)
-    
-    def http_put(self, path, body=None, headers=None, success=204):
-        return self.http_cmd('PUT', path, body, headers, success)
-    
-    def http_delete(self, path, success=204):
-        return self.http_cmd('DELETE', path, success=success)
index 6495ce2..0156ef7 100644 (file)
 # interpreted as representing official policies, either expressed
 # or implied, of GRNET S.A.
 
-"""
-    OpenStack Image Service API 1.0 client
-"""
 
-from urllib import quote
+from . import Client, ClientError
 
-from . import ClientError
-from .http import HTTPClient
 
-
-class ImageClient(HTTPClient):
-    @property
-    def url(self):
-        url = self.config.get('image_url') or self.config.get('url')
-        if not url:
-            raise ClientError('No URL was given')
-        return url
+class ImageClient(Client):
+    """OpenStack Image Service API 1.0 and GRNET Plankton client"""
     
-    @property
-    def token(self):
-        token = self.config.get('image_token') or self.config.get('token')
-        if not token:
-            raise ClientError('No token was given')
-        return token
+    def raise_for_status(self, r):
+        if r.status_code == 404:
+            raise ClientError("Image not found", r.status_code)
+        
+        # Fallback to the default
+        super(ImageClient, self).raise_for_status(r)
     
     def list_public(self, detail=False, filters={}, order=''):
         path = '/images/detail' if detail else '/images/'
@@ -70,57 +59,67 @@ class ImageClient(HTTPClient):
         if order:
             params['sort_key'] = order
         
-        if params:
-            path += '?' + '&'.join('%s=%s' % item for item in params.items())
-        return self.http_get(path)
+        r = self.get(path, params=params, success=200)
+        return r.json
     
     def get_meta(self, image_id):
-        path = '/images/%s' % image_id
-        resp, buf = self.raw_http_cmd('HEAD', path)
+        path = '/images/%s' % (image_id,)
+        r = self.head(path, success=200)
+        
         reply = {}
-        prefix = 'x-image-meta-'
-        for key, val in resp.getheaders():
+        properties = {}
+        meta_prefix = 'x-image-meta-'
+        property_prefix = 'x-image-meta-property-'
+        
+        for key, val in r.headers.items():
             key = key.lower()
-            if not key.startswith(prefix):
-                continue
-            key = key[len(prefix):]
-            reply[key] = val
+            if key.startswith(property_prefix):
+                key = key[len(property_prefix):]
+                properties[key] = val
+            elif key.startswith(meta_prefix):
+                key = key[len(meta_prefix):]
+                reply[key] = val
+        
+        if properties:
+            reply['properties'] = properties
         return reply
     
     def register(self, name, location, params={}, properties={}):
         path = '/images/'
         headers = {}
-        headers['x-image-meta-name'] = quote(name)
+        headers['x-image-meta-name'] = name
         headers['x-image-meta-location'] = location
+        
         for key, val in params.items():
             if key in ('id', 'store', 'disk_format', 'container_format',
                        'size', 'checksum', 'is_public', 'owner'):
                 key = 'x-image-meta-' + key.replace('_', '-')
                 headers[key] = val
+        
         for key, val in properties.items():
-            headers['x-image-meta-property-' + quote(key)] = quote(val)
-        return self.http_post(path, headers=headers, success=200)
+            headers['x-image-meta-property-' + key] = val
+        
+        self.post(path, headers=headers, success=200)
     
     def list_members(self, image_id):
-        path = '/images/%s/members' % image_id
-        reply = self.http_get(path)
-        return reply['members']
+        path = '/images/%s/members' % (image_id,)
+        r = self.get(path, success=200)
+        return r.json['members']
 
     def list_shared(self, member):
-        path = '/shared-images/%s' % member
-        reply = self.http_get(path)
-        return reply['shared_images']
+        path = '/shared-images/%s' % (member,)
+        r = self.get(path, success=200)
+        return r.json['shared_images']
 
     def add_member(self, image_id, member):
         path = '/images/%s/members/%s' % (image_id, member)
-        self.http_put(path)
+        r = self.put(path, success=204)
     
     def remove_member(self, image_id, member):
         path = '/images/%s/members/%s' % (image_id, member)
-        self.http_delete(path)
+        self.delete(path, success=204)
     
     def set_members(self, image_id, members):
         path = '/images/%s/members' % image_id
         req = {'memberships': [{'member_id': member} for member in members]}
-        body = json.dumps(req)
-        self.http_put(path, body)
+        self.put(path, json=req, success=204)