Revision b32f00e0 kamaki/clients/image.py
b/kamaki/clients/image.py | ||
---|---|---|
31 | 31 |
# interpreted as representing official policies, either expressed |
32 | 32 |
# or implied, of GRNET S.A. |
33 | 33 |
|
34 |
""" |
|
35 |
OpenStack Image Service API 1.0 client |
|
36 |
""" |
|
37 | 34 |
|
38 |
from urllib import quote
|
|
35 |
from . import Client, ClientError
|
|
39 | 36 |
|
40 |
from . import ClientError |
|
41 |
from .http import HTTPClient |
|
42 | 37 |
|
43 |
|
|
44 |
class ImageClient(HTTPClient): |
|
45 |
@property |
|
46 |
def url(self): |
|
47 |
url = self.config.get('image_url') or self.config.get('url') |
|
48 |
if not url: |
|
49 |
raise ClientError('No URL was given') |
|
50 |
return url |
|
38 |
class ImageClient(Client): |
|
39 |
"""OpenStack Image Service API 1.0 and GRNET Plankton client""" |
|
51 | 40 |
|
52 |
@property
|
|
53 |
def token(self):
|
|
54 |
token = self.config.get('image_token') or self.config.get('token')
|
|
55 |
if not token: |
|
56 |
raise ClientError('No token was given')
|
|
57 |
return token
|
|
41 |
def raise_for_status(self, r):
|
|
42 |
if r.status_code == 404:
|
|
43 |
raise ClientError("Image not found", r.status_code)
|
|
44 |
|
|
45 |
# Fallback to the default
|
|
46 |
super(ImageClient, self).raise_for_status(r)
|
|
58 | 47 |
|
59 | 48 |
def list_public(self, detail=False, filters={}, order=''): |
60 | 49 |
path = '/images/detail' if detail else '/images/' |
... | ... | |
70 | 59 |
if order: |
71 | 60 |
params['sort_key'] = order |
72 | 61 |
|
73 |
if params: |
|
74 |
path += '?' + '&'.join('%s=%s' % item for item in params.items()) |
|
75 |
return self.http_get(path) |
|
62 |
r = self.get(path, params=params, success=200) |
|
63 |
return r.json |
|
76 | 64 |
|
77 | 65 |
def get_meta(self, image_id): |
78 |
path = '/images/%s' % image_id |
|
79 |
resp, buf = self.raw_http_cmd('HEAD', path) |
|
66 |
path = '/images/%s' % (image_id,) |
|
67 |
r = self.head(path, success=200) |
|
68 |
|
|
80 | 69 |
reply = {} |
81 |
prefix = 'x-image-meta-' |
|
82 |
for key, val in resp.getheaders(): |
|
70 |
properties = {} |
|
71 |
meta_prefix = 'x-image-meta-' |
|
72 |
property_prefix = 'x-image-meta-property-' |
|
73 |
|
|
74 |
for key, val in r.headers.items(): |
|
83 | 75 |
key = key.lower() |
84 |
if not key.startswith(prefix): |
|
85 |
continue |
|
86 |
key = key[len(prefix):] |
|
87 |
reply[key] = val |
|
76 |
if key.startswith(property_prefix): |
|
77 |
key = key[len(property_prefix):] |
|
78 |
properties[key] = val |
|
79 |
elif key.startswith(meta_prefix): |
|
80 |
key = key[len(meta_prefix):] |
|
81 |
reply[key] = val |
|
82 |
|
|
83 |
if properties: |
|
84 |
reply['properties'] = properties |
|
88 | 85 |
return reply |
89 | 86 |
|
90 | 87 |
def register(self, name, location, params={}, properties={}): |
91 | 88 |
path = '/images/' |
92 | 89 |
headers = {} |
93 |
headers['x-image-meta-name'] = quote(name)
|
|
90 |
headers['x-image-meta-name'] = name
|
|
94 | 91 |
headers['x-image-meta-location'] = location |
92 |
|
|
95 | 93 |
for key, val in params.items(): |
96 | 94 |
if key in ('id', 'store', 'disk_format', 'container_format', |
97 | 95 |
'size', 'checksum', 'is_public', 'owner'): |
98 | 96 |
key = 'x-image-meta-' + key.replace('_', '-') |
99 | 97 |
headers[key] = val |
98 |
|
|
100 | 99 |
for key, val in properties.items(): |
101 |
headers['x-image-meta-property-' + quote(key)] = quote(val) |
|
102 |
return self.http_post(path, headers=headers, success=200) |
|
100 |
headers['x-image-meta-property-' + key] = val |
|
101 |
|
|
102 |
self.post(path, headers=headers, success=200) |
|
103 | 103 |
|
104 | 104 |
def list_members(self, image_id): |
105 |
path = '/images/%s/members' % image_id
|
|
106 |
reply = self.http_get(path)
|
|
107 |
return reply['members']
|
|
105 |
path = '/images/%s/members' % (image_id,)
|
|
106 |
r = self.get(path, success=200)
|
|
107 |
return r.json['members']
|
|
108 | 108 |
|
109 | 109 |
def list_shared(self, member): |
110 |
path = '/shared-images/%s' % member
|
|
111 |
reply = self.http_get(path)
|
|
112 |
return reply['shared_images']
|
|
110 |
path = '/shared-images/%s' % (member,)
|
|
111 |
r = self.get(path, success=200)
|
|
112 |
return r.json['shared_images']
|
|
113 | 113 |
|
114 | 114 |
def add_member(self, image_id, member): |
115 | 115 |
path = '/images/%s/members/%s' % (image_id, member) |
116 |
self.http_put(path)
|
|
116 |
r = self.put(path, success=204)
|
|
117 | 117 |
|
118 | 118 |
def remove_member(self, image_id, member): |
119 | 119 |
path = '/images/%s/members/%s' % (image_id, member) |
120 |
self.http_delete(path)
|
|
120 |
self.delete(path, success=204)
|
|
121 | 121 |
|
122 | 122 |
def set_members(self, image_id, members): |
123 | 123 |
path = '/images/%s/members' % image_id |
124 | 124 |
req = {'memberships': [{'member_id': member} for member in members]} |
125 |
body = json.dumps(req) |
|
126 |
self.http_put(path, body) |
|
125 |
self.put(path, json=req, success=204) |
Also available in: Unified diff