1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """
17 Abstract classes for resource management
18 """
19
20 import copy
21 import inspect
22 import six
23 import time
24
25 from . import constant
26 from . import exception
27 from . import mapper
28 from . import utils
29
30
31 WRAPPER_METHODS = []
32 BAD_ATTRS = ['self']
33
34
36 """Base class for resources."""
37
38 _id = None
39 _attrs = []
40 _loaded = True
41 _sub_manager_list = {}
42 _state_attr = 'status'
43 _stable_state = []
44
45 - def __init__(self, manager, *args, **kwargs):
84
87
94
96 if not isinstance(other, Resource):
97 return False
98 return self._id == other._id
99
101 if not isinstance(other, Resource):
102 return True
103 return self._id != other._id
104
106 if 'name' in self._attrs and self._id_attr != 'name' and self._loaded:
107 return '<%s.%s (%s="%s", name="%s")>' % (
108 self.__module__, self.__class__.__name__, self._id_attr,
109 self._id, self.name)
110 empty = ''
111 if not self._loaded:
112 empty = ' empty'
113 return '<%s.%s (%s="%s"%s)>' % (
114 self.__module__, self.__class__.__name__, self._id_attr,
115 self._id, empty)
116
118 if self._verbose:
119 attrs = self.get_attrs()
120 return '<%s.%s (%s)>' % (
121 self.__module__, self.__class__.__name__, attrs)
122 else:
123 return self.__repr__()
124
134
136 _kwargs = copy.copy(kwargs)
137 for attr in self._attrs:
138 if attr in _kwargs:
139 setattr(self, attr, _kwargs.pop(attr))
140 if not self._has_extra_attr:
141 return
142 for key, value in _kwargs.items():
143 if not key.startswith('_') and key not in BAD_ATTRS:
144 setattr(self, key, value)
145
147 """
148 Clear attributes
149
150 @rtype: None
151 """
152 ret = {}
153 if not self._loaded:
154 return
155 for key in dir(self):
156 if key.startswith('_'):
157 continue
158 if key in self._sub_manager_list:
159 continue
160 value = getattr(self, key)
161 if inspect.ismethod(value) or inspect.isfunction(value):
162 continue
163 delattr(self, key)
164
166 """
167 Query ID of a resource
168
169 @return: ID
170 @rtype: str
171 """
172 return self._id
173
175 """
176 Aquire attributes as a dictionary
177
178 @return: attributes
179 @rtype: dict
180 """
181 ret = {}
182 if not self._loaded:
183 self.reload()
184 self._loaded = True
185 for key in dir(self):
186 if key.startswith('_'):
187 continue
188 value = getattr(self, key)
189 if inspect.ismethod(value) or inspect.isfunction(value):
190 continue
191 ret[key] = value
192 return ret
193
195 """
196 (Re)load attributes of a resource
197
198 @return: Whether attributes are updated
199 @rtype: bool
200 """
201 x = self._manager.get(getattr(self, self._id_attr))
202 if x:
203 self._clear_attrs()
204 self._set_attrs(x.__dict__)
205 self._loaded = True
206 return True
207 return False
208
221
229
231 """
232 Wait for task finished
233
234 @keyword count: Maximum polling time
235 @type count: int
236 @keyword interval: Polling interval in seconds
237 @type interval: int
238 @rtype: None
239 """
240 if self._stable_state == []:
241 return
242 for i in range(count):
243 time.sleep(interval)
244 try:
245 self.reload()
246 except exception.NotFound:
247 return
248 if getattr(self, self._state_attr, None) in self._stable_state:
249 return
250
251
253 """Base class for resource managers."""
254
255 resource_class = None
256 service_type = ''
257 _attr_mapping = []
258 _has_detail = True
259 _has_extra_attr = False
260 _hidden_methods = None
261 _json_resource_key = ''
262 _json_resources_key = ''
263 _id_attr = 'id'
264 _update_method = 'put'
265 _url_resource_path = ''
266 _url_resource_list_path = ''
267
268 - def __init__(self, client, verbose=False, **kwargs):
269 """
270 Create a Manager object
271
272 kwargs: options
273
274 @param client: client object
275 @type client: yakumo.Client
276 @keyword verbose: Whether str(Resource) displays all attributes
277 @type verbose: bool
278 @return: Manager object
279 @rtype: yakumo.base.Manager
280 """
281 self._client = client
282 self._session = client._session
283 self._http = self._session.get_proxy(self.service_type)
284 self._to_json_mapping = {}
285 self._to_attr_mapping = {}
286 self._verbose = verbose
287 if not self._url_resource_list_path:
288 self._url_resource_list_path = self._url_resource_path
289 if self.resource_class is None:
290 return
291 mapper.make_mappings(self._attr_mapping,
292 self._to_json_mapping,
293 self._to_attr_mapping)
294 if self._hidden_methods is not None:
295 for method in self._hidden_methods:
296 setattr(self, method, self._no_such_api)
297
300
302 result = {}
303 for key, value in json_params.items():
304 _map = self._to_attr_mapping.get(key)
305 if _map is not None:
306 result[_map['attr']] = _map['mapper'].to_attr(self, value)
307 elif self._has_extra_attr and \
308 not key.startswith('_') and key not in BAD_ATTRS:
309 result[key] = value
310 return result
311
313 result = {}
314 for key, value in attrs.items():
315 if value is constant.UNDEF:
316 continue
317 _map = self._to_json_mapping.get(key)
318 if _map is not None:
319 result[_map['json_attr']] = \
320 _map['mapper'].to_json(self, value)
321 elif self._has_extra_attr \
322 and not key.startswith('_') and key not in BAD_ATTRS:
323 result[key] = value
324 return result
325
327 """
328 Create a resource object without attributes
329
330 @return: Resource object (empty)
331 @rtype: yakumo.base.Resource
332 """
333 if id is None:
334 return None
335 kwargs = {self._id_attr: id}
336 return self.resource_class(self, **kwargs)
337
352
371
394
395 - def find(self, **kwargs):
396 """
397 Query existing resource object matched the conditions
398
399 kwargs is key=value style query conditions.
400 Returns empty list if no matched resource.
401
402 @return: List of Resource object
403 @rtype: yakumo.base.Resource
404 """
405 return list(self._find_gen(**kwargs))
406
408 """
409 Aquire an existing resource object matched the conditions
410
411 kwargs is key=value style query conditions.
412 Returns None if no matched resource.
413
414 @return: Resource object
415 @rtype: yakumo.base.Resource
416 """
417 try:
418 return six.next(self._find_gen(**kwargs))
419 except StopIteration:
420 return None
421
423 """
424 Aquire an existing resource object
425
426 @return: List of Resource objects
427 @rtype: [yakumo.base.Resource]
428 """
429 return self.find()
430
431
433 """Base class for sub resource managers."""
434
435 - def __init__(self, parent_resource, *args, **kwargs):
444
445
447 """Base class for resource managers which don't use _json_resource_key."""
448
450 """
451 Update a resource and reload it.
452 kwargs: attributes and their values to update
453
454 @rtype: None
455 """
456 json_params = self._attr2json(kwargs)
457 self._http.put(utils.join_path(self._url_resource_path, self._id),
458 data=json_params)
459
460
462 """Base class for resource managers which don't use _json_resource_key."""
463
464 _has_extra_attr = True
465
467 """
468 Create a new resource
469
470 kwargs: attributes of the resource
471
472 @return: Resource object (empty)
473 @rtype: yakumo.base.Resource
474 """
475 json_params = self._attr2json(kwargs)
476 ret = self._http.post(self._url_resource_path, data=json_params)
477 attrs = self._json2attr(ret)
478 return self.get_empty(attrs[self._id_attr])
479
481 """
482 Aquire an existing resource object
483
484 @param id: ID
485 @type id: str
486 @return: Resource object
487 @rtype: yakumo.base.Resource
488 """
489 try:
490 json_params = self._http.get(
491 utils.join_path(self._url_resource_path, id))
492 attrs = self._json2attr(json_params)
493 return self.resource_class(self, **attrs)
494 except exception.NotFound:
495 raise
496 except:
497 return None
498
499
501 """Base class for sub resource managers for GlanceV2Manager."""
502 pass
503
504
506 """resource class for resources on Object Storage V1 API"""
507
509 """
510 Update a volume
511
512 kwargs: attributes of the resource
513 @rtype: None
514 """
515 attrs = self.get_attrs()
516 for key, value in kwargs.items():
517 if value is constant.UNDEF:
518 continue
519 attrs[key] = value
520 headers = self._attr2json(attrs)
521 self._http.post_raw(self._url_resource_path, self._id,
522 headers=headers)
523 self.reload()
524
535
548
563
564
566 """manager class for resources on Object Storage V1 API"""
567
568 _id_attr = 'name'
569
571 metadata = attrs.pop('metadata', {})
572 result = super(SwiftV1Manager, self)._attr2json(attrs)
573 if isinstance(metadata, dict):
574 for key, value in metadata.items():
575 x_key = "x-%s-meta-%s" % (self._json_resource_key, key)
576 if x_key not in attrs:
577 result[x_key] = value
578 return result
579
581 result = {}
582 metadata = {}
583 for key, value in json_params.items():
584 key = key.lower()
585 _map = self._to_attr_mapping.get(key)
586 if _map is not None:
587 result[_map['attr']] = _map['mapper'].to_attr(self, value)
588 else:
589 key_prefix = 'x-%s-meta-' % self._json_resource_key
590 if key.startswith(key_prefix):
591 _key = key[len(key_prefix):]
592 metadata[_key] = value
593 if metadata:
594 result['metadata'] = metadata
595 return result
596
597 - def create(self, name, data=None, **kwargs):
598 """
599 Create a resource
600
601 kwargs: attributes of the resource
602
603 @keyword name: Resource name
604 @type name: str
605 @return: Resource object (empty)
606 @rtype: yakumo.base.Resource
607 """
608 headers = self._attr2json(kwargs)
609 self._http.put_raw(self._url_resource_path, name,
610 headers=headers, data=data)
611 return self.get_empty(name)
612
613 - def get(self, name):
614 """
615 Aquire an existing resource object
616
617 @param name: name
618 @type name: str
619 @return: Resource object
620 @rtype: yakumo.base.Resource
621 """
622 try:
623 json_params = self._http.head(
624 utils.join_path(self._url_resource_path, name))
625 json_params['name'] = name
626 attrs = self._json2attr(json_params)
627 return self.resource_class(self, **attrs)
628 except exception.NotFound:
629 raise
630 except:
631 return None
632
634 try:
635 ret = self._http.get(self._url_resource_path)
636 except:
637 return
638 for x in ret:
639 if 'name' in x:
640 yield self.get_empty(x['name'])
641
642
644 """Base class for sub resource managers for GlanceV2Manager."""
645 pass
646