This repository was archived by the owner on Aug 20, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathcontainer.py
More file actions
executable file
·341 lines (279 loc) · 10.9 KB
/
container.py
File metadata and controls
executable file
·341 lines (279 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
"""
Container module
See COPYING for license information
"""
import os
import six
from object_storage.utils import json, Model
from object_storage import errors
from object_storage.storage_object import StorageObject
from object_storage.utils import get_path
class ContainerModel(Model):
def __init__(self, controller, name, headers={}):
self.name = name
_headers = {}
# Lowercase headers
for key, value in headers.items():
_key = key.lower()
_headers[_key] = value
self.headers = _headers
self._meta = None
_properties = {'name': self.name}
_properties['count'] = int(self.headers.get('x-container-object-count')
or self.headers.get('count') or 0)
_properties['object_count'] = _properties['count']
_properties['size'] = int(self.headers.get('x-container-bytes-used') or
self.headers.get('size') or 0)
_properties['read'] = (self.headers.get('x-container-read') or
self.headers.get('read'))
_properties['write'] = (self.headers.get('x-container-read') or
self.headers.get('read'))
_properties['ttl'] = int(self.headers.get('x-cdn-ttl') or 0)
_properties['date'] = self.headers.get('date')
_properties['cdn_url'] = self.headers.get('x-cdn-url')
_properties['cdn_ssl_url'] = self.headers.get('x-cdn-ssl-url')
_properties['path'] = controller.path
_properties['url'] = controller.url
meta = {}
for key, value in self.headers.items():
if key.startswith('meta_'):
meta[key[5:]] = value
elif key.startswith('x-container-meta-'):
meta[key[17:]] = value
self.meta = meta
_properties['meta'] = self.meta
self.properties = _properties
self.data = self.properties
def __len__(self):
return len(self.properties)
def __iter__(self):
return iter(self.properties)
class Container:
""" Container class. Encapsulates Storage containers. """
def __init__(self, name, headers=None, client=None):
""" constructor for Container
@param name: container name
@param headers: init headers to use when initializing the container
@param client: `object_storage.client` instance.
"""
self.name = name
self.client = client
self.model = None
if headers:
self.model = ContainerModel(self, self.name, headers)
def exists(self):
""" Tries to load the container to check existance
@raises ResponseError
@return: boolean, true if exists else false
"""
def _formatter(res):
self.model = ContainerModel(self, self.name, res.headers)
return True
try:
return self.make_request('HEAD', formatter=_formatter)
except errors.NotFound:
return False
def load(self, cdn=False):
""" load data for the container
@param cdn: True if you want CDN information; default=False
@return: object_storage.container, self
"""
headers = {}
if cdn:
headers.setdefault('X-Context', 'cdn')
def _formatter(res):
self.model = ContainerModel(self, self.name, res.headers)
return self
return self.make_request('HEAD', headers=headers, formatter=_formatter)
def get_info(self):
""" loads data if not already available and returns the properties """
if not self.model:
self.load()
return self.model.properties
@property
def properties(self):
""" loads data if not already available and returns the properties """
return self.get_info()
props = properties
@property
def headers(self):
""" loads data if not already available and returns the raw headers for
the container """
if not self.model:
self.load()
return self.model.headers
@property
def meta(self):
""" loads data if not already available and returns the metadata for
the container """
if not self.model:
self.load()
return self.model.meta
@property
def path(self):
""" returns path of the container """
path = [self.name]
return get_path(path)
@property
def url(self):
""" Returns the url of the container """
path = [self.name]
return self.client.get_url(path)
def is_dir(self):
""" Returns if the container is a directory (always True) """
return True
def set_metadata(self, meta):
""" Sets metadata for the container
@param meta: dict of metadata on the container
@raises ResponseError
"""
meta_headers = {}
for k, v in meta.items():
meta_headers["x-container-meta-%s" % (k, )] = v
return self.make_request('POST', headers=meta_headers)
def create(self):
""" Create container
@raises ResponseError
@return: Containert - self
"""
def _formatter(res):
return self
return self.make_request('PUT',
formatter=_formatter,
headers={'Content-Length': '0'})
def delete(self, recursive=False):
""" Delete container
@param recursive: true if you want to delete all of the
objects in the container as well.
@raises ResponseError
@return: True
"""
return self.client.delete_container(self.name, recursive=recursive)
def delete_all_objects(self):
""" Deletes all objects in the container
@raises ResponseError
"""
resps = []
for item in self.objects():
resps.append(item.delete())
return resps
def delete_object(self, obj):
""" Deletes an object in the container
@param obj: object name to delete
@raises ResponseError
"""
if isinstance(obj, StorageObject):
obj = obj.name
return self.client.delete_object(self.name, obj)
def rename(self, new_container):
""" Rename container. Will not work if container is not empty.
@param new_container: new container name
@raises ResponseError
"""
self.delete()
new_container.create()
def objects(self, limit=None, marker=None, base_only=False, headers=None):
""" Lists objects in the container.
@param limit: limit of results to return.
@param marker: start listing after this object name
@param base_only: only return the base objects.
container/object not container/dir/object
@param headers: extra headers to use in the request
@raises ResponseError
@return: list of StorageObject instances
"""
params = {'format': 'json'}
if base_only:
params['delimiter'] = self.client.delimiter
if limit:
params['limit'] = limit
if marker:
params['marker'] = marker
def _formatter(res):
objects = {}
if res.content:
items = json.loads(res.content if isinstance(res.content, six.string_types) else res.content.decode('utf8'))
for item in items:
if 'name' in item:
objects[item['name']] = self.storage_object(
item['name'], item)
elif 'subdir' in item:
item['name'] = item['subdir'].rstrip('/')
item['content_type'] = 'application/directory'
objects[item['name']] = self.storage_object(
item['name'], item)
return objects.values()
return self.make_request('GET',
params=params,
headers=headers,
formatter=_formatter)
def set_ttl(self, ttl):
""" Set time to live for CDN
@param ttl: time in seconds to set as the TTL
@raises ResponseError
"""
if not ttl:
ttl = ' '
headers = {'x-cdn-ttl': str(ttl)}
return self.make_request('POST', headers=headers)
def set_read_acl(self, acl):
""" Set read ACL
@param acl: ACL to set for the container
@raises ResponseError
"""
headers = {'x-container-read': acl}
return self.make_request('POST', headers=headers)
def set_write_acl(self, acl):
""" Set write ACL
@param acl: ACL to set for the container
@raises ResponseError
"""
headers = {'x-container-write': acl}
return self.make_request('POST', headers=headers)
def make_public(self, ttl=1440):
""" Make container public
@param ttl: time in seconds to set as the TTL
@raises ResponseError
"""
headers = {'x-container-read': '.r:*', 'x-cdn-ttl': str(ttl)}
return self.make_request('POST', headers=headers)
enable_cdn = make_public
def make_private(self):
""" Make container private (empty ACL)
@raises ResponseError
"""
headers = {'x-container-read': ' '}
return self.make_request('POST', headers=headers)
disable_cdn = make_private
def search(self, q=None, options=None, **kwargs):
""" Search within container. """
options = options or {}
options.update({'path': self.name})
return self.client.search(q=q, options=options, **kwargs)
def get_object(self, name):
""" Calls get_object() on the client. """
return self.client.get_object(self.name, name)
def storage_object(self, name, headers=None):
""" Creates a new instance of Object """
return self.client.storage_object(self.name, name, headers=headers)
def load_from_filename(self, filename):
""" Creates an object from a file. Uses the basename of the file path
as the object name. """
name = os.path.basename(filename)
return self.storage_object(name).load_from_filename(filename)
def make_request(self, method, path=None, *args, **kwargs):
""" Makes a request on the resource. """
path = [self.name]
return self.client.make_request(method, path, *args, **kwargs)
def __getitem__(self, name):
""" Returns object corresponding to the given name """
return self.storage_object(name)
def __str__(self):
return self.name
def __repr__(self):
return 'Container(%s)' % (self.name.encode("utf-8"), )
def __iter__(self):
""" Returns an interator based on results of self.objects() """
listing = self.objects()
for obj in listing:
yield obj