root / docs / clients.rst @ 961e6040
History | View | Annotate | Download (8.1 kB)
1 |
For Developers |
---|---|
2 |
============== |
3 |
|
4 |
Creating applications with kamaki API |
5 |
------------------------------------- |
6 |
|
7 |
Kamaki features a clients API for building third-party client applications that communicate with OpenStack and / or Synnefo cloud services. The package is called kamaki.clients and contains a number of |
8 |
|
9 |
A good example of an application build on kamaki.clients is kamaki.cli, the command line interface of kamaki. |
10 |
|
11 |
Since synnefo services are build as OpenStack extensions, an inheritance approach has been chosen for implementing clients for both. In specific, the *compute*, *storage* and *image* modules are clients of the OS compute, OS storage and Glance APIs, respectively. On the contrary, all the other modules are Synnefo extensions (*cyclades* extents *compute*, *pithos* and *pithos_rest_api* extent *storage*) or novel synnefo services (e.g. *astakos*). |
12 |
|
13 |
Setup a client instance |
14 |
^^^^^^^^^^^^^^^^^^^^^^^ |
15 |
|
16 |
External applications may instantiate one or more kamaki clients. |
17 |
|
18 |
.. code-block:: python |
19 |
:emphasize-lines: 1 |
20 |
|
21 |
Example 1.1: Instantiate a Cyclades client |
22 |
|
23 |
|
24 |
from kamaki.clients.cyclades import CycladesClient |
25 |
from kamaki.clients.pithos import PithosClient |
26 |
|
27 |
my_cyclades_client = CycladesClient(base_url, token) |
28 |
my_pithos_client = PithosClient(base_url, token, account, container) |
29 |
|
30 |
.. note:: *cyclades* and *pithos* clients inherit all methods of *compute* and *storage* clients respectively. Separate compute or storage objects should be used only when implementing applications for strict OS Compute or OS Storage services. |
31 |
|
32 |
Use client methods |
33 |
^^^^^^^^^^^^^^^^^^ |
34 |
|
35 |
Client methods can now be called. Developers are advised to consult :ref:`the-client-api-ref` for details on the available methods and how to use them. |
36 |
|
37 |
In the following example, the *cyclades* and *pithos* clients of example 1.1 are used to extract some information, that is then printed to the standard output. |
38 |
|
39 |
|
40 |
.. code-block:: python |
41 |
:emphasize-lines: 1,2 |
42 |
|
43 |
Example 1.2: Print server name and OS for server with server_id |
44 |
Print objects in container mycont |
45 |
|
46 |
|
47 |
srv = my_cyclades_client.get_server_info(server_id) |
48 |
print("Server Name: %s (with OS %s" % (srv['name'], srv['os'])) |
49 |
|
50 |
obj_list = my_pithos_client.list_objects(mycont) |
51 |
for obj in obj_list: |
52 |
print(' %s of %s bytes' % (obj['name'], obj['bytes'])) |
53 |
|
54 |
.. code-block:: console |
55 |
:emphasize-lines: 1 |
56 |
|
57 |
Run of examples 1.1 + 1.2 |
58 |
|
59 |
|
60 |
$ python test_script.py |
61 |
Server Name: A Debian Server (with OS Debian Base) |
62 |
lala.txt of 34 bytes |
63 |
test.txt of 1232 bytes |
64 |
testDir/ of 0 bytes |
65 |
$ |
66 |
|
67 |
Error handling |
68 |
^^^^^^^^^^^^^^ |
69 |
|
70 |
The kamaki.clients standard error is ClientError. A ClientError is raised for any kind of kamaki.clients errors (errors reported by servers, type errors in arguments, etc.). |
71 |
|
72 |
A ClientError contains:: |
73 |
|
74 |
message The error message. |
75 |
status An optional error code, e.g. after a server error. |
76 |
details Optional list of messages with error details. |
77 |
|
78 |
The following example concatenates examples 1.1 and 1.2 plus error handling |
79 |
|
80 |
.. code-block:: python |
81 |
|
82 |
Example 1.3: Error handling |
83 |
|
84 |
|
85 |
from kamaki.clients.cyclades import CycladesClient |
86 |
from kamaki.clients.pithos import PithosClient |
87 |
|
88 |
try: |
89 |
my_cyclades_client = CycladesClient(base_url, token) |
90 |
except ClientError: |
91 |
print('Failed to initialize Cyclades client') |
92 |
|
93 |
try: |
94 |
my_pithos_client = PithosClient(base_url, token, account, container) |
95 |
except ClientError: |
96 |
print('Failed to initialize Pithos+ client') |
97 |
|
98 |
try: |
99 |
srv = my_cyclades_client.get_server_info(server_id) |
100 |
print("Server Name: %s (with OS %s" % (srv['name'], srv['os'])) |
101 |
|
102 |
obj_list = my_pithos_client.list_objects(mycont) |
103 |
for obj in obj_list: |
104 |
print(' %s of %s bytes' % (obj['name'], obj['bytes'])) |
105 |
except ClientError as e: |
106 |
print('Error: %s' % e) |
107 |
if e.status: |
108 |
print('- error code: %s' % e.status) |
109 |
if e.details: |
110 |
for detail in e.details: |
111 |
print('- %s' % detail) |
112 |
|
113 |
Extending kamaki.clients |
114 |
------------------------ |
115 |
|
116 |
By default, kamaki clients are REST clients (they manage HTTP requests and responses to communicate with services). This is achieved by importing the connection module, which is an httplib rapper. |
117 |
|
118 |
Connection |
119 |
^^^^^^^^^^ |
120 |
|
121 |
The connection module features an error handling and logging system, a lazy response mechanism, a pooling mechanism as well as concurrency control for thread-demanding client functions (e.g. store upload). |
122 |
|
123 |
How to build a client |
124 |
^^^^^^^^^^^^^^^^^^^^^ |
125 |
|
126 |
All service clients consist of a subclass of the Client class and implement separate client functionalities as member methods. There is also an error class to raise exceptions that can be handled by kamaki interfaces. |
127 |
|
128 |
.. code-block:: python |
129 |
|
130 |
# ${KAMAKI_PATH}/kamaki/clients/mynewclient.py |
131 |
|
132 |
from kamaki.clients import Client, ClientError |
133 |
|
134 |
class MyNewClient(Client): |
135 |
"""MyNewClient Description Here""" |
136 |
|
137 |
def my_first_method(self, **args): |
138 |
"""Method description""" |
139 |
try: |
140 |
... |
141 |
method code |
142 |
... |
143 |
except SomeKnownException as e1: |
144 |
raise ClientError('MyError: %s' % e1) |
145 |
except SomeOtherException as e2: |
146 |
raise ClientError('MyError: %s' % e2) |
147 |
|
148 |
def my_second_method(self, **params): |
149 |
"""Method description""" |
150 |
... |
151 |
|
152 |
Custom clients can use a set of convenience methods for easy HTTP requests |
153 |
|
154 |
.. code-block:: python |
155 |
|
156 |
def get(self, path, **kwargs) |
157 |
def head(self, path, **kwargs) |
158 |
def post(self, path, **kwargs) |
159 |
def put(self, path, **kwargs) |
160 |
def delete(self, path, **kwargs) |
161 |
def copy(self, path, **kwargs) |
162 |
def move(self, path, **kwargs) |
163 |
|
164 |
How to use your client |
165 |
^^^^^^^^^^^^^^^^^^^^^^ |
166 |
|
167 |
External applications must instantiate a MyNewClient object. |
168 |
|
169 |
.. code-block:: python |
170 |
|
171 |
from kamaki.clients import ClientError |
172 |
from kamaki.clients.mynewclient import MyNewClient |
173 |
|
174 |
... |
175 |
try: |
176 |
cl = MyNewClient(args) |
177 |
cl.my_first_method(other_args) |
178 |
except ClientError as cle: |
179 |
print('Client Error: %s' % cle) |
180 |
... |
181 |
|
182 |
Concurrency control |
183 |
^^^^^^^^^^^^^^^^^^^ |
184 |
|
185 |
Kamaki clients may handle multiple requests at once, using threads. In that case, users might implement their own thread handling mechanism, use an external solution or take advantage of the mechanism featured in kamaki.clients |
186 |
|
187 |
.. code-block:: python |
188 |
|
189 |
from threading import enumerate |
190 |
from kamaki.clients import SilentEvent |
191 |
... |
192 |
|
193 |
class MyNewClient(Client): |
194 |
... |
195 |
|
196 |
def _single_threaded_method(self, **args): |
197 |
... |
198 |
request code |
199 |
... |
200 |
|
201 |
def multithread_method(self): |
202 |
thread_list = [] |
203 |
self._init_thread_limit() |
204 |
while some_condition or thread_list: |
205 |
... |
206 |
event = SilentEvent(self._single_threaded_method, **args) |
207 |
event.start() |
208 |
thread_list.append(event) |
209 |
thread_list = self._watch_thread_limit(thread_list) |
210 |
|
211 |
The CLI API |
212 |
----------- |
213 |
|
214 |
.. toctree:: |
215 |
|
216 |
cli |
217 |
|
218 |
.. _the-client-api-ref: |
219 |
|
220 |
The clients API |
221 |
--------------- |
222 |
|
223 |
Imports |
224 |
^^^^^^^ |
225 |
|
226 |
.. toctree:: |
227 |
connection |
228 |
|
229 |
Modules list |
230 |
^^^^^^^^^^^^ |
231 |
|
232 |
compute |
233 |
^^^^^^^ |
234 |
|
235 |
.. automodule:: kamaki.clients.compute |
236 |
:members: |
237 |
:show-inheritance: |
238 |
:undoc-members: |
239 |
|
240 |
|
241 |
cyclades |
242 |
^^^^^^^^ |
243 |
|
244 |
.. automodule:: kamaki.clients.cyclades |
245 |
:members: |
246 |
:show-inheritance: |
247 |
:undoc-members: |
248 |
|
249 |
|
250 |
storage |
251 |
^^^^^^^ |
252 |
|
253 |
.. automodule:: kamaki.clients.storage |
254 |
:members: |
255 |
:show-inheritance: |
256 |
:undoc-members: |
257 |
|
258 |
|
259 |
pithos |
260 |
^^^^^^ |
261 |
|
262 |
.. automodule:: kamaki.clients.pithos |
263 |
:members: |
264 |
:show-inheritance: |
265 |
:undoc-members: |
266 |
|
267 |
pithos_rest_api |
268 |
^^^^^^^^^^^^^^^ |
269 |
|
270 |
.. automodule:: kamaki.clients.pithos_rest_api |
271 |
:members: |
272 |
:show-inheritance: |
273 |
:undoc-members: |
274 |
|
275 |
|
276 |
image |
277 |
^^^^^ |
278 |
|
279 |
.. automodule:: kamaki.clients.image |
280 |
:members: |
281 |
:show-inheritance: |
282 |
:undoc-members: |
283 |
|
284 |
|
285 |
astakos |
286 |
^^^^^^^ |
287 |
|
288 |
.. automodule:: kamaki.clients.astakos |
289 |
:members: |
290 |
:show-inheritance: |
291 |
:undoc-members: |
292 |
|
293 |
|
294 |
utils |
295 |
^^^^^ |
296 |
|
297 |
.. automodule:: kamaki.clients.utils |
298 |
:members: |
299 |
:show-inheritance: |
300 |
:undoc-members: |