76
74
class Manager(object):
77
"""Managers interact with a particular type of API (servers, flavors,
78
images, etc.) and provide CRUD operations for them.
75
"""Basic manager type providing common operations.
77
Managers interact with a particular type of API (servers, flavors, images,
78
etc.) and provide CRUD operations for them.
80
80
resource_class = None
82
def __init__(self, api):
82
def __init__(self, client):
83
"""Initializes Manager with `client`.
85
:param client: instance of BaseClient descendant for HTTP requests
87
super(Manager, self).__init__()
92
"""Deprecated. Use `client` instead.
85
96
def _list(self, url, response_key, obj_class=None, body=None):
97
"""List the collection.
99
:param url: a partial URL, e.g., '/servers'
100
:param response_key: the key to be looked up in response dictionary,
102
:param obj_class: class for constructing the returned objects
103
(self.resource_class will be used by default)
104
:param body: data that will be encoded as JSON and passed in POST
105
request (GET will be sent by default)
88
resp, body = self.api.post(url, body=body)
108
resp, body = self.client.post(url, body=body)
90
resp, body = self.api.get(url)
110
resp, body = self.client.get(url)
92
112
if obj_class is None:
93
113
obj_class = self.resource_class
95
115
data = body[response_key]
96
116
# NOTE(ja): keystone returns values as list as {'values': [ ... ]}
97
117
# unlike other services which just return the list...
98
if type(data) is dict:
99
119
data = data['values']
120
except (KeyError, TypeError):
100
123
return [obj_class(self, res, loaded=True) for res in data if res]
102
125
def _get(self, url, response_key):
103
resp, body = self.api.get(url)
126
"""Get an object from collection.
128
:param url: a partial URL, e.g., '/servers'
129
:param response_key: the key to be looked up in response dictionary,
132
resp, body = self.client.get(url)
104
133
return self.resource_class(self, body[response_key], loaded=True)
106
135
def _head(self, url):
107
resp, body = self.api.head(url)
136
"""Retrieve request headers for an object.
138
:param url: a partial URL, e.g., '/servers'
140
resp, body = self.client.head(url)
108
141
return resp.status_code == 204
110
143
def _create(self, url, body, response_key, return_raw=False):
111
resp, body = self.api.post(url, body=body)
144
"""Deprecated. Use `_post` instead.
146
return self._post(url, body, response_key, return_raw)
148
def _post(self, url, body, response_key, return_raw=False):
151
:param url: a partial URL, e.g., '/servers'
152
:param body: data that will be encoded as JSON and passed in POST
153
request (GET will be sent by default)
154
:param response_key: the key to be looked up in response dictionary,
156
:param return_raw: flag to force returning raw JSON instead of
157
Python object of self.resource_class
159
resp, body = self.client.post(url, body=body)
113
161
return body[response_key]
114
162
return self.resource_class(self, body[response_key])
164
def _put(self, url, body=None, response_key=None):
165
"""Update an object with PUT method.
167
:param url: a partial URL, e.g., '/servers'
168
:param body: data that will be encoded as JSON and passed in POST
169
request (GET will be sent by default)
170
:param response_key: the key to be looked up in response dictionary,
173
resp, body = self.client.put(url, body=body)
174
# PUT requests may not return a body
176
if response_key is not None:
177
return self.resource_class(self, body[response_key])
179
return self.resource_class(self, body)
181
def _patch(self, url, body=None, response_key=None):
182
"""Update an object with PATCH method.
184
:param url: a partial URL, e.g., '/servers'
185
:param body: data that will be encoded as JSON and passed in POST
186
request (GET will be sent by default)
187
:param response_key: the key to be looked up in response dictionary,
190
resp, body = self.client.patch(url, body=body)
191
if response_key is not None:
192
return self.resource_class(self, body[response_key])
194
return self.resource_class(self, body)
116
196
def _delete(self, url):
117
resp, body = self.api.delete(url)
199
:param url: a partial URL, e.g., '/servers/my-server'
201
return self.client.delete(url)
119
203
def _update(self, url, body=None, response_key=None, method="PUT",
120
204
management=True):
121
methods = {"PUT": self.api.put,
122
"POST": self.api.post,
123
"PATCH": self.api.patch}
205
methods = {"PUT": self.client.put,
206
"POST": self.client.post,
207
"PATCH": self.client.patch}
126
resp, body = methods[method](url, body=body,
127
management=management)
129
resp, body = methods[method](url, management=management)
209
resp, body = methods[method](url, body=body,
210
management=management)
131
212
raise exceptions.ClientException("Invalid update method: %s"
305
385
class Resource(object):
306
"""A resource represents a particular instance of an object (tenant, user,
307
etc). This is pretty much just a bag for attributes.
386
"""Base class for OpenStack resources (tenant, user, etc.).
309
:param manager: Manager object
310
:param info: dictionary representing resource attributes
311
:param loaded: prevent lazy-loading if set to True
388
This is pretty much just a bag for attributes.
313
394
def __init__(self, manager, info, loaded=False):
395
"""Populate and bind to a manager.
397
:param manager: Manager object
398
:param info: dictionary representing resource attributes
399
:param loaded: prevent lazy-loading if set to True
314
401
self.manager = manager
316
403
self._add_details(info)
317
404
self._loaded = loaded
408
"""Human-readable ID which can be used for bash completion.
410
if self.NAME_ATTR in self.__dict__ and self.HUMAN_ID:
411
return strutils.to_slug(getattr(self, self.NAME_ATTR))
319
414
def _add_details(self, info):
320
for (k, v) in info.iteritems():
415
for (k, v) in six.iteritems(info):
321
416
setattr(self, k, v)
323
419
def __getattr__(self, k):
324
420
if k not in self.__dict__: