31 |
31 |
# interpreted as representing official policies, either expressed
|
32 |
32 |
# or implied, of GRNET S.A.
|
33 |
33 |
|
|
34 |
"""
|
|
35 |
Plankton attributes are stored as user metadata in Pithos, prefixed with
|
|
36 |
PLANKTON_PREFIX.
|
|
37 |
Exceptions are the following:
|
|
38 |
- location: generated based on the object's path
|
|
39 |
- updated_at: generated based on the modified attribute
|
|
40 |
- created_at: generated based on the modified attribute of the first version
|
|
41 |
- owner: identical to the object's account
|
|
42 |
- is_public: True if there is a * entry for the read permission
|
|
43 |
|
|
44 |
All Plankton properties are JSON serialized and stored as one user meta.
|
|
45 |
"""
|
|
46 |
|
34 |
47 |
import json
|
35 |
48 |
|
36 |
49 |
from binascii import hexlify
|
... | ... | |
49 |
62 |
PLANKTON_PREFIX = 'plankton:'
|
50 |
63 |
|
51 |
64 |
|
52 |
|
def iterblock(data, block_size):
|
53 |
|
while data:
|
54 |
|
yield data[:block_size]
|
55 |
|
data = data[block_size:]
|
56 |
|
|
57 |
|
|
58 |
|
def format_timestamp(t):
|
59 |
|
return strftime('%Y-%m-%d %H:%M:%S', gmtime(t))
|
60 |
|
|
61 |
|
|
62 |
65 |
def set_plankton_attr(d, **kwargs):
|
63 |
66 |
for key, val in kwargs.items():
|
64 |
67 |
d[PLANKTON_PREFIX + key] = str(val) if val is not None else ''
|
65 |
68 |
|
|
69 |
def get_image_id(location):
|
|
70 |
return str(UUID(bytes=md5(location).digest()))
|
|
71 |
|
66 |
72 |
|
67 |
73 |
class BackendException(Exception): pass
|
68 |
74 |
|
69 |
75 |
|
70 |
|
class BackendWrapper(object):
|
71 |
|
"""A proxy object that always passes user as a first argument."""
|
|
76 |
class ImageBackend(object):
|
|
77 |
"""A wrapper arround the pithos backend to simplify image handling."""
|
72 |
78 |
|
73 |
79 |
def __init__(self, user):
|
74 |
80 |
self.user = user
|
... | ... | |
79 |
85 |
except NameError:
|
80 |
86 |
pass # Container already exists
|
81 |
87 |
|
82 |
|
def close(self):
|
83 |
|
self.backend.close()
|
|
88 |
def _get(self, user, account, container, object):
|
|
89 |
def format_timestamp(t):
|
|
90 |
return strftime('%Y-%m-%d %H:%M:%S', gmtime(t))
|
84 |
91 |
|
85 |
|
def _get_image(self, user, account, container, object):
|
86 |
92 |
meta = self.backend.get_object_meta(user, account, container, object)
|
87 |
93 |
image = {
|
88 |
|
'_user': user,
|
89 |
94 |
'_account': account,
|
90 |
95 |
'_container': container,
|
91 |
96 |
'_object': object}
|
... | ... | |
95 |
100 |
val = meta.get(PLANKTON_PREFIX + key, None)
|
96 |
101 |
if val is not None:
|
97 |
102 |
image[key] = val
|
98 |
|
|
|
103 |
|
99 |
104 |
image['location'] = 'pithos://%s/%s/%s' % (account, container, object)
|
100 |
105 |
image['updated_at'] = format_timestamp(meta['modified'])
|
101 |
106 |
image['owner'] = account
|
102 |
|
|
|
107 |
|
103 |
108 |
# Get the creation date from the date of the first version
|
104 |
109 |
version, created = self.backend.list_versions(user, account, container,
|
105 |
110 |
name=object)[0]
|
106 |
111 |
image['created_at'] = format_timestamp(created)
|
107 |
112 |
|
108 |
113 |
# Mark as public if there is a * entry for read
|
109 |
|
action, path, perm = self.backend.get_object_permissions(user, account,
|
110 |
|
container, object)
|
111 |
|
image['is_public'] = '*' in perm.get('read', [])
|
|
114 |
permissions = self._get_permissions(image)
|
|
115 |
image['is_public'] = '*' in permissions.get('read', [])
|
112 |
116 |
|
113 |
117 |
properties = meta.get(PLANKTON_PREFIX + 'properties', None)
|
114 |
118 |
if properties:
|
115 |
119 |
image['properties'] = json.loads(properties)
|
116 |
|
|
117 |
|
return image
|
118 |
|
|
119 |
|
def add_user(self, image_id, user):
|
120 |
|
image = self.get_image(image_id)
|
121 |
|
assert image, "Image not found"
|
122 |
|
|
123 |
|
account = image['_account']
|
124 |
|
container = image['_container']
|
125 |
|
object = image['_object']
|
126 |
|
|
127 |
|
action, path, permissions = self.backend.get_object_permissions(
|
128 |
|
self.user, account, container, object)
|
129 |
|
read_permissions = set(permissions.get('read', []))
|
130 |
|
read_permissions.add(user)
|
131 |
|
permissions['read'] = list(read_permissions)
|
132 |
|
self.backend.update_object_permissions(self.user, account, container,
|
133 |
|
object, permissions)
|
134 |
|
|
135 |
|
def remove_user(self, image_id, user):
|
136 |
|
image = self.get_image(image_id)
|
137 |
|
assert image, "Image not found"
|
138 |
|
|
139 |
|
account = image['_account']
|
140 |
|
container = image['_container']
|
141 |
|
object = image['_object']
|
142 |
|
|
143 |
|
action, path, permissions = self.backend.get_object_permissions(
|
144 |
|
self.user, account, container, object)
|
145 |
|
try:
|
146 |
|
permissions.get('read', []).remove(user)
|
147 |
|
except ValueError:
|
148 |
|
return # User did not have access anyway
|
149 |
|
self.backend.update_object_permissions(self.user, account, container,
|
150 |
|
object, permissions)
|
151 |
|
|
152 |
|
def replace_users(self, image_id, users):
|
153 |
|
image = self.get_image(image_id)
|
154 |
|
assert image, "Image not found"
|
155 |
120 |
|
156 |
|
account = image['_account']
|
157 |
|
container = image['_container']
|
158 |
|
object = image['_object']
|
159 |
|
|
160 |
|
action, path, permissions = self.backend.get_object_permissions(
|
161 |
|
self.user, account, container, object)
|
162 |
|
permissions['read'] = users
|
163 |
|
if image.get('is_public', False):
|
164 |
|
permissions['read'].append('*')
|
165 |
|
self.backend.update_object_permissions(self.user, account, container,
|
166 |
|
object, permissions)
|
|
121 |
return image
|
167 |
122 |
|
168 |
|
def list_users(self, image_id):
|
169 |
|
image = self.get_image(image_id)
|
170 |
|
assert image, "Image not found"
|
171 |
|
|
172 |
|
account = image['_account']
|
173 |
|
container = image['_container']
|
174 |
|
object = image['_object']
|
175 |
|
|
|
123 |
def _get_permissions(self, image):
|
176 |
124 |
action, path, permissions = self.backend.get_object_permissions(
|
177 |
|
self.user, account, container, object)
|
178 |
|
return [user for user in permissions.get('read', []) if user != '*']
|
|
125 |
user=self.user,
|
|
126 |
account=image['_account'],
|
|
127 |
container=image['_container'],
|
|
128 |
name=image['_object'])
|
|
129 |
return permissions
|
179 |
130 |
|
180 |
|
def get_image(self, image_id):
|
|
131 |
def _iter(self, keys=[], public=False):
|
181 |
132 |
backend = self.backend
|
182 |
|
|
183 |
|
user = self.user
|
184 |
133 |
container = self.container
|
185 |
|
|
186 |
|
# Arguments to be passed to list_objects
|
187 |
|
listargs = {
|
188 |
|
'user': user,
|
189 |
|
'container': container,
|
190 |
|
'prefix': '',
|
191 |
|
'delimiter': '/',
|
192 |
|
'keys': [PLANKTON_PREFIX + 'id']}
|
|
134 |
user = None if public else self.user
|
|
135 |
keys = [PLANKTON_PREFIX + key for key in keys]
|
193 |
136 |
|
194 |
137 |
for account in backend.list_accounts(user):
|
195 |
|
listargs['account'] = account
|
196 |
|
for path, version_id in backend.list_objects(**listargs):
|
|
138 |
for path, version_id in backend.list_objects(user, account,
|
|
139 |
container, prefix='', delimiter='/', keys=keys):
|
197 |
140 |
try:
|
198 |
|
image = self._get_image(user, account, container, path)
|
199 |
|
if image['id'] == image_id:
|
200 |
|
return image
|
|
141 |
image = self._get(user, account, container, path)
|
|
142 |
if 'id' in image:
|
|
143 |
yield image
|
201 |
144 |
except NotAllowedError:
|
202 |
145 |
continue
|
|
146 |
|
|
147 |
def _store(self, data):
|
|
148 |
"""Breaks data into blocks and stores them in the backend.
|
203 |
149 |
|
204 |
|
return None
|
|
150 |
Returns a tuple of the hashmap and the MD5 checksum
|
|
151 |
"""
|
|
152 |
|
|
153 |
def iterblock(data, block_size):
|
|
154 |
while data:
|
|
155 |
yield data[:block_size]
|
|
156 |
data = data[block_size:]
|
|
157 |
|
|
158 |
m = md5()
|
|
159 |
hashmap = []
|
|
160 |
|
|
161 |
for block in iterblock(data, self.backend.block_size):
|
|
162 |
hash = self.backend.put_block(block)
|
|
163 |
hashmap.append(hash)
|
|
164 |
m.update(block)
|
|
165 |
|
|
166 |
return hashmap, m.digest()
|
|
167 |
|
|
168 |
def _update_permissions(self, image, permissions):
|
|
169 |
self.backend.update_object_permissions(self.user, image['_account'],
|
|
170 |
image['_container'], image['_object'], permissions)
|
|
171 |
|
|
172 |
def add_user(self, image_id, user):
|
|
173 |
image = self.get_meta(image_id)
|
|
174 |
assert image, "Image not found"
|
|
175 |
|
|
176 |
permissions = self._get_permissions(image)
|
|
177 |
read = set(permissions.get('read', []))
|
|
178 |
read.add(user)
|
|
179 |
permissions['read'] = list(read)
|
|
180 |
self._update_permissions(image, permissions)
|
|
181 |
|
|
182 |
def close(self):
|
|
183 |
self.backend.close()
|
205 |
184 |
|
206 |
|
def get_image_data(self, image):
|
207 |
|
size, hashmap = self.backend.get_object_hashmap(image['_user'],
|
|
185 |
def get_data(self, image):
|
|
186 |
size, hashmap = self.backend.get_object_hashmap(self.user,
|
208 |
187 |
image['_account'], image['_container'], image['_object'])
|
|
188 |
data = ''.join(self.backend.get_block(hash) for hash in hashmap)
|
|
189 |
assert len(data) == size
|
|
190 |
return data
|
|
191 |
|
|
192 |
def get_meta(self, image_id):
|
|
193 |
for image in self._iter(keys=['id']):
|
|
194 |
if image['id'] == image_id:
|
|
195 |
return image
|
|
196 |
return None
|
|
197 |
|
|
198 |
def iter_public(self, filters):
|
|
199 |
keys = set()
|
|
200 |
for key, val in filters.items():
|
|
201 |
if key in ('size_min', 'size_max'):
|
|
202 |
key = 'size'
|
|
203 |
keys.add(key)
|
|
204 |
|
|
205 |
for image in self._iter(keys=keys, public=True):
|
|
206 |
for key, val in filters.items():
|
|
207 |
if key == 'size_min':
|
|
208 |
if image['size'] < int(val):
|
|
209 |
break
|
|
210 |
elif key == 'size_max':
|
|
211 |
if image['size'] > int(val):
|
|
212 |
break
|
|
213 |
else:
|
|
214 |
if image[key] != val:
|
|
215 |
break
|
|
216 |
else:
|
|
217 |
yield image
|
|
218 |
|
|
219 |
def iter_shared(self):
|
|
220 |
for image in self._iter():
|
|
221 |
yield image
|
|
222 |
|
|
223 |
def list_public_images(self, filters, params):
|
|
224 |
images = list(self.iter_public(filters))
|
|
225 |
key = itemgetter(params['sort_key'])
|
|
226 |
reverse = params['sort_dir'] == 'desc'
|
|
227 |
images.sort(key=key, reverse=reverse)
|
|
228 |
return images
|
|
229 |
|
|
230 |
def list_users(self, image_id):
|
|
231 |
image = self.get_meta(image_id)
|
|
232 |
assert image, "Image not found"
|
209 |
233 |
|
210 |
|
buf = []
|
211 |
|
for hash in hashmap:
|
212 |
|
buf.append(self.backend.get_block(hash))
|
213 |
|
return ''.join(buf)
|
|
234 |
permissions = self._get_permissions(image)
|
|
235 |
return [user for user in permissions.get('read', []) if user != '*']
|
214 |
236 |
|
215 |
|
def register_image(self, name, location, store=None, disk_format=None,
|
216 |
|
container_format=None, size=None, checksum=None, is_public=False,
|
217 |
|
owner=None, properties={}):
|
|
237 |
def put(self, name, data, params):
|
|
238 |
meta = {}
|
218 |
239 |
|
219 |
|
backend = self.backend
|
|
240 |
location = 'pithos://%s/%s/%s' % (self.user, self.container, name)
|
|
241 |
image_id = get_image_id(location)
|
220 |
242 |
|
221 |
|
assert location.startswith('pithos://')
|
222 |
|
t = location.split('/', 4)
|
223 |
|
assert len(t) == 5
|
224 |
|
account, container, object = t[2:5]
|
225 |
|
user = self.user
|
|
243 |
params.setdefault('store', settings.DEFAULT_IMAGE_STORE)
|
|
244 |
params.setdefault('disk_format', settings.DEFAULT_DISK_FORMAT)
|
|
245 |
params.setdefault('container_format',
|
|
246 |
settings.DEFAULT_CONTAINER_FORMAT)
|
226 |
247 |
|
227 |
|
store = store or settings.DEFAULT_IMAGE_STORE
|
228 |
|
disk_format = disk_format or settings.DEFAULT_DISK_FORMAT
|
229 |
|
container_format = container_format or \
|
230 |
|
settings.DEFAULT_CONTAINER_FORMAT
|
|
248 |
assert params['store'] in settings.IMAGE_STORES
|
|
249 |
assert params['disk_format'] in settings.IMAGE_DISK_FORMATS
|
|
250 |
assert params['container_format'] in settings.IMAGE_CONTAINER_FORMATS
|
231 |
251 |
|
232 |
|
assert store in settings.IMAGE_STORES
|
233 |
|
assert disk_format in settings.IMAGE_DISK_FORMATS
|
234 |
|
assert container_format in settings.IMAGE_CONTAINER_FORMATS
|
|
252 |
is_public = params.pop('is_public', False)
|
|
253 |
permissions = {'read': ['*']} if is_public else None
|
235 |
254 |
|
236 |
|
sz, hashmap = self.backend.get_object_hashmap(user, account,
|
237 |
|
container, object)
|
238 |
|
if size is not None and size != sz:
|
|
255 |
size = params.get('size', len(data))
|
|
256 |
if size != len(data):
|
239 |
257 |
raise BackendException("Invalid size")
|
240 |
258 |
|
241 |
|
m = md5()
|
242 |
|
for hash in hashmap:
|
243 |
|
m.update(self.backend.get_block(hash))
|
244 |
|
|
245 |
|
digest = m.digest()
|
|
259 |
hashmap, digest = self._store(data)
|
246 |
260 |
hexdigest = hexlify(digest)
|
247 |
|
if checksum is not None and checksum != hexdigest:
|
248 |
|
raise BackendException("Invalid checksum")
|
|
261 |
meta['ETag'] = hexdigest
|
249 |
262 |
|
250 |
|
permissions = {'read': ['*']} if is_public else None
|
|
263 |
checksum = params.pop('checksum', hexdigest)
|
|
264 |
if checksum != hexdigest:
|
|
265 |
raise BackendException("Invalid checksum")
|
251 |
266 |
|
252 |
|
image_meta = {
|
253 |
|
'id': str(UUID(bytes=digest)),
|
254 |
|
'name': name,
|
255 |
|
'status': 'available',
|
256 |
|
'store': store,
|
257 |
|
'disk_format': disk_format,
|
258 |
|
'container_format': container_format,
|
259 |
|
'size': size or sz,
|
260 |
|
'checksum': checksum or hexdigest,
|
261 |
|
'owner': owner,
|
262 |
|
'deleted_at': ''}
|
|
267 |
set_plankton_attr(meta, id=image_id, name=name, status='available',
|
|
268 |
size=size, checksum=checksum, deleted_at='')
|
263 |
269 |
|
|
270 |
properties = params.pop('properties', None)
|
264 |
271 |
if properties:
|
265 |
|
image_meta['properties'] = json.dumps(properties)
|
|
272 |
set_plankton_attr(meta, properties=json.dumps(properties))
|
266 |
273 |
|
267 |
|
meta = {}
|
268 |
|
for key, val in image_meta.items():
|
269 |
|
meta[PLANKTON_PREFIX + key] = str(val) if val is not None else ''
|
|
274 |
set_plankton_attr(meta, **params)
|
270 |
275 |
|
271 |
|
backend.update_object_meta(user, account, container, object, meta)
|
272 |
|
backend.update_object_permissions(user, account, container, object,
|
273 |
|
permissions)
|
|
276 |
self.backend.update_object_hashmap(
|
|
277 |
user=self.user,
|
|
278 |
account=self.user,
|
|
279 |
container=self.container,
|
|
280 |
name=name,
|
|
281 |
size=size,
|
|
282 |
hashmap=hashmap,
|
|
283 |
meta=meta,
|
|
284 |
replace_meta=True,
|
|
285 |
permissions=permissions)
|
274 |
286 |
|
275 |
|
return self.get_image(image_meta['id'])
|
|
287 |
return self.get_meta(image_id)
|
276 |
288 |
|
277 |
|
def put_image(self, name, data, store=None, disk_format=None,
|
278 |
|
container_format=None, size=None, checksum=None, is_public=False,
|
279 |
|
owner=None, properties={}):
|
|
289 |
def register(self, name, location, params):
|
|
290 |
assert location.startswith('pithos://')
|
|
291 |
t = location.split('/', 4)
|
|
292 |
assert len(t) == 5
|
|
293 |
account, container, object = t[2:5]
|
|
294 |
user = self.user
|
|
295 |
image_id = get_image_id(location)
|
280 |
296 |
|
281 |
|
backend = self.backend
|
|
297 |
params.setdefault('store', settings.DEFAULT_IMAGE_STORE)
|
|
298 |
params.setdefault('disk_format', settings.DEFAULT_DISK_FORMAT)
|
|
299 |
params.setdefault('container_format',
|
|
300 |
settings.DEFAULT_CONTAINER_FORMAT)
|
282 |
301 |
|
283 |
|
store = store or settings.DEFAULT_IMAGE_STORE
|
284 |
|
disk_format = disk_format or settings.DEFAULT_DISK_FORMAT
|
285 |
|
container_format = container_format or \
|
286 |
|
settings.DEFAULT_CONTAINER_FORMAT
|
|
302 |
assert params['store'] in settings.IMAGE_STORES
|
|
303 |
assert params['disk_format'] in settings.IMAGE_DISK_FORMATS
|
|
304 |
assert params['container_format'] in settings.IMAGE_CONTAINER_FORMATS
|
287 |
305 |
|
288 |
|
assert store in settings.IMAGE_STORES
|
289 |
|
assert disk_format in settings.IMAGE_DISK_FORMATS
|
290 |
|
assert container_format in settings.IMAGE_CONTAINER_FORMATS
|
|
306 |
sz, hashmap = self.backend.get_object_hashmap(user, account,
|
|
307 |
container, object)
|
291 |
308 |
|
292 |
|
if size is not None and size != len(data):
|
|
309 |
size = params.get('size', sz)
|
|
310 |
if size != sz:
|
293 |
311 |
raise BackendException("Invalid size")
|
294 |
312 |
|
295 |
313 |
m = md5()
|
296 |
|
hashmap = []
|
297 |
|
for block in iterblock(data, backend.block_size):
|
298 |
|
hash = backend.put_block(block)
|
299 |
|
hashmap.append(hash)
|
300 |
|
m.update(block)
|
|
314 |
for hash in hashmap:
|
|
315 |
m.update(self.backend.get_block(hash))
|
301 |
316 |
|
302 |
317 |
digest = m.digest()
|
303 |
318 |
hexdigest = hexlify(digest)
|
304 |
|
image_id = str(UUID(bytes=digest))
|
305 |
|
if checksum is not None and checksum != hexdigest:
|
|
319 |
|
|
320 |
checksum = params.pop('checksum', hexdigest)
|
|
321 |
if checksum != hexdigest:
|
306 |
322 |
raise BackendException("Invalid checksum")
|
307 |
323 |
|
|
324 |
is_public = params.pop('is_public', False)
|
308 |
325 |
permissions = {'read': ['*']} if is_public else None
|
309 |
326 |
|
310 |
|
meta = {'hash': hexdigest}
|
311 |
|
|
312 |
|
set_plankton_attr(meta,
|
313 |
|
id=image_id,
|
314 |
|
name=name,
|
315 |
|
status='available',
|
316 |
|
store=store,
|
317 |
|
disk_format=disk_format,
|
318 |
|
container_format=container_format,
|
319 |
|
size=size or len(data),
|
320 |
|
checksum=checksum or hexdigest,
|
321 |
|
owner=owner,
|
322 |
|
deleted_at='')
|
|
327 |
meta = {}
|
|
328 |
set_plankton_attr(meta, id=image_id, name=name, status='available',
|
|
329 |
size=size, checksum=checksum, deleted_at='')
|
323 |
330 |
|
|
331 |
properties = params.pop('properties', None)
|
324 |
332 |
if properties:
|
325 |
333 |
set_plankton_attr(meta, properties=json.dumps(properties))
|
326 |
334 |
|
327 |
|
backend.update_object_hashmap(
|
328 |
|
user=self.user,
|
329 |
|
account=self.user,
|
330 |
|
container=self.container,
|
331 |
|
name=name,
|
332 |
|
size=len(data),
|
333 |
|
hashmap=hashmap,
|
334 |
|
meta=meta,
|
335 |
|
replace_meta=True,
|
336 |
|
permissions=permissions)
|
337 |
|
|
338 |
|
return self.get_image(image_id)
|
339 |
|
|
340 |
|
def iter_public_images(self, filters):
|
341 |
|
user = None
|
342 |
|
container = self.container
|
|
335 |
set_plankton_attr(meta, **params)
|
343 |
336 |
|
344 |
|
keys = set()
|
345 |
|
for key, val in filters.items():
|
346 |
|
if key in ('size_min', 'size_max'):
|
347 |
|
key = 'size'
|
348 |
|
keys.add(PLANKTON_PREFIX + key)
|
349 |
|
keys = list(keys)
|
|
337 |
self.backend.update_object_meta(user, account, container, object, meta)
|
|
338 |
self.backend.update_object_permissions(user, account, container,
|
|
339 |
object, permissions)
|
350 |
340 |
|
351 |
|
for account in self.backend.list_accounts(None):
|
352 |
|
for path, version_id in self.backend.list_objects(user, account,
|
353 |
|
container, prefix='', delimiter='/', keys=keys):
|
354 |
|
try:
|
355 |
|
image = self._get_image(user, account, container, path)
|
356 |
|
except NotAllowedError:
|
357 |
|
continue
|
358 |
|
|
359 |
|
skip = False
|
360 |
|
for key, val in filters.items():
|
361 |
|
if key == 'size_min':
|
362 |
|
if image['size'] < int(val):
|
363 |
|
skip = True
|
364 |
|
break
|
365 |
|
elif key == 'size_max':
|
366 |
|
if image['size'] > int(val):
|
367 |
|
skip = True
|
368 |
|
break
|
369 |
|
else:
|
370 |
|
if image[key] != val:
|
371 |
|
skip = True
|
372 |
|
break
|
373 |
|
|
374 |
|
if not skip:
|
375 |
|
yield image
|
|
341 |
return self.get_meta(image_id)
|
376 |
342 |
|
377 |
|
def iter_shared_images(self):
|
378 |
|
user = self.user
|
379 |
|
container = self.container
|
380 |
|
|
381 |
|
for account in self.backend.list_accounts(user):
|
382 |
|
for path, version_id in self.backend.list_objects(user, account,
|
383 |
|
container, prefix='', delimiter='/'):
|
384 |
|
try:
|
385 |
|
image = self._get_image(user, account, container, path)
|
386 |
|
if 'id' in image:
|
387 |
|
yield image
|
388 |
|
except NotAllowedError:
|
389 |
|
continue
|
|
343 |
def remove_user(self, image_id, user):
|
|
344 |
image = self.get_meta(image_id)
|
|
345 |
assert image, "Image not found"
|
|
346 |
|
|
347 |
permissions = self._get_permissions(image)
|
|
348 |
try:
|
|
349 |
permissions.get('read', []).remove(user)
|
|
350 |
except ValueError:
|
|
351 |
return # User did not have access anyway
|
|
352 |
self._update_permissions(image, permissions)
|
390 |
353 |
|
391 |
|
def list_public_images(self, filters, params):
|
392 |
|
images = list(self.iter_public_images(filters))
|
393 |
|
|
394 |
|
key = itemgetter(params['sort_key'])
|
395 |
|
reverse = params['sort_dir'] == 'desc'
|
396 |
|
images.sort(key=key, reverse=reverse)
|
|
354 |
def replace_users(self, image_id, users):
|
|
355 |
image = self.get_meta(image_id)
|
|
356 |
assert image, "Image not found"
|
397 |
357 |
|
398 |
|
return images
|
|
358 |
permissions = self._get_permissions(image)
|
|
359 |
permissions['read'] = users
|
|
360 |
if image.get('is_public', False):
|
|
361 |
permissions['read'].append('*')
|
|
362 |
self._update_permissions(image, permissions)
|
399 |
363 |
|
400 |
|
def update_image(self, image_id, meta):
|
401 |
|
image = self.get_image(image_id)
|
|
364 |
def update(self, image_id, meta):
|
|
365 |
image = self.get_meta(image_id)
|
402 |
366 |
assert image, "Image not found"
|
403 |
367 |
|
404 |
|
user = self.user
|
405 |
|
account = image['_account']
|
406 |
|
container = image['_container']
|
407 |
|
object = image['_object']
|
408 |
|
|
409 |
368 |
is_public = meta.pop('is_public', None)
|
410 |
369 |
if is_public is not None:
|
411 |
|
action, path, permissions = self.backend.get_object_permissions(
|
412 |
|
user, account, container, object)
|
413 |
|
read_permissions = set(permissions.get('read', []))
|
|
370 |
permissions = self._get_permissions(image)
|
|
371 |
read = set(permissions.get('read', []))
|
414 |
372 |
if is_public:
|
415 |
|
read_permissions.add('*')
|
|
373 |
read.add('*')
|
416 |
374 |
else:
|
417 |
|
read_permissions.discard('*')
|
418 |
|
permissions['read'] = list(read_permissions)
|
419 |
|
self.backend.update_object_permissions(user, account, container,
|
420 |
|
object, permissions)
|
421 |
|
|
|
375 |
read.discard('*')
|
|
376 |
permissions['read'] = list(read)
|
|
377 |
self.backend._update_permissions(image, permissions)
|
|
378 |
|
422 |
379 |
m = {}
|
423 |
|
set_plankton_attr(m, **meta)
|
424 |
|
|
425 |
|
properties = meta.get('properties', None)
|
|
380 |
|
|
381 |
properties = meta.pop('properties', None)
|
426 |
382 |
if properties:
|
427 |
383 |
set_plankton_attr(m, properties=json.dumps(properties))
|
428 |
384 |
|
429 |
|
self.backend.update_object_meta(user, account, container, object, m)
|
430 |
|
return self.get_image(image_id)
|
|
385 |
set_plankton_attr(m, **meta)
|
|
386 |
|
|
387 |
self.backend.update_object_meta(self.user, image['_account'],
|
|
388 |
image['_container'], image['_object'], m)
|
|
389 |
return self.get_meta(image_id)
|