Fix some spelling and typoes in docs
[kamaki] / docs / developers / clients-api.rst
1 Creating applications with kamaki API
2 =====================================
3
4 Kamaki features a clients API for building third-party client applications that
5 communicate with OpenStack and / or Synnefo cloud services. The package is
6 called kamaki.clients and servers as a lib.
7
8 A showcase of an application built on kamaki.clients is kamaki.cli, the command
9 line interface of kamaki.
10
11 Since synnefo services are build as OpenStack extensions, an inheritance
12 approach has been chosen for implementing clients for both. In specific,
13 the *compute*, *storage* and *image* modules are clients of the OS compute, OS
14 object-store, respectively. On the contrary, all the other modules are Synnefo
15 extensions (*cyclades* extents *compute*, *pithos* and *pithos_rest_api*
16 extent *storage*) or novel synnefo services (e.g. *astakos* for IM, *image*
17 for *plankton*).
18
19 Setup a client instance
20 -----------------------
21
22 External applications may instantiate one or more kamaki clients.
23
24 .. code-block:: python
25     :emphasize-lines: 1
26
27     Example 1.1: Instantiate Cyclades and Pithos client
28
29
30     from kamaki.clients.cyclades import CycladesClient
31     from kamaki.clients.pithos import PithosClient
32
33     my_cyclades_client = CycladesClient(base_url, token)
34     my_pithos_client = PithosClient(base_url, token, account, container)
35
36 .. note:: *cyclades* and *pithos* clients inherit all methods of *compute*
37     and *storage* clients respectively. Separate compute or storage objects
38     should be used only when implementing applications for strict OS Compute or
39     OS Storage services.
40
41 Using endpoints to get the base_url
42 -----------------------------------
43
44 In OpenStack, each service (e.g. `compute`, `object-store`, etc.) has a number
45 of `endpoints`. These `endpoints` are actually URIs that are needed as prefixes
46 for the API calls the kamaki client generates. In this context, we need just
47 one of these these `endpoints`, the `publicURL`, which is also referred to as
48 `base_url` in kamaki client libraries.
49
50 In general, this is the suggested way of getting the base_url::
51
52     1. From the deployment UI get the AUTHENTICATION_URL and TOKEN
53         (Example 1.2)
54     2. Use them to instantiate an AstakosClient
55         (Example 1.2)
56     3. Use AstakosClient instance to get the endpoints of the service of interest
57         (Example 1.3)
58     4. The 'publicURL' endpoint is the base_url we are looking for
59         (Example 1.3)
60
61 The AstakosClient is a client for the Synnefo/Astakos server. Synnefo/Astakos
62 is an advanced identity server based on OpenStack identity specifications.
63 Therefore, it can be used to get the `base_url` values needed for initializing
64 kamaki clients. Kamaki simplifies this process with the astakos client library.
65
66 Let's review the process with examples.
67
68 First, an astakos client must be initialized (Example 1.2). An
69 AUTHENTICATION_URL and a TOKEN can be acquired from the synnefo deployment UI.
70
71 .. code-block:: python
72     :emphasize-lines: 1
73
74     Example 1.2: Initialize an astakos client
75
76     from kamaki.clients.astakos import AstakosClient
77     my_astakos_client = AstakosClient(AUTHENTICATION_URL, TOKEN)
78         
79
80 Next, the astakos client can be used to retrieve the base_url values for the
81 servers of interest. In this case (Example 1.3) they are *cyclades*
82 and *pithos*. A number of endpoints is assigned to each service, but kamaki
83 clients only need the one labeled as ``publicURL``.
84
85 .. code-block:: python
86     :emphasize-lines: 1
87
88     Example 1.3: Retrieve cyclades and pithos base_url values
89
90     cyclades_endpoints = my_astakos_client.get_service_endpoints('compute')
91     cyclades_base_url = cyclades_endpoints['publicURL']
92
93     pithos_endpoints = my_astakos_client.get_service_endpoints('object-store')
94     pithos_base_url = pithos_endpoints['publicURL']
95
96 The ``get_service_endpoints`` method gets the service name as an argument. Here
97 are the service names for the most popular kamaki clients::
98
99     storage, pithos     -->     object-store
100     compute, cyclades   -->     compute
101     image               -->     image
102     astakos             -->     identity
103
104 Use client methods
105 ------------------
106
107 Client methods can now be called. Developers are advised to
108 consult :ref:`the-client-api-ref` for details on the available methods and how
109 to use them.
110
111 In the following example, the *cyclades* and *pithos* clients of example 1.1
112 are used to extract some information, that is then printed to the standard
113 output.
114
115
116 .. code-block:: python
117     :emphasize-lines: 1,2
118
119     Example 1.4: Print server name and OS for server with server_id
120                 Print objects in container mycont
121
122
123     srv = my_cyclades_client.get_server_info(server_id)
124     print("Server Name: %s (with OS %s" % (srv['name'], srv['os']))
125
126     obj_list = my_pithos_client.list_objects(mycont)
127     for obj in obj_list:
128         print('  %s of %s bytes' % (obj['name'], obj['bytes']))
129
130 .. code-block:: console
131     :emphasize-lines: 1
132
133     Run of examples 1.1 + 1.4
134
135
136     $ python test_script.py
137     Server Name: A Debian Server (with OS Debian Base)
138       lala.txt of 34 bytes
139       test.txt of 1232 bytes
140       testDir/ of 0 bytes
141     $ 
142
143 Error handling
144 --------------
145
146 The kamaki.clients standard error is ClientError. A ClientError is raised for
147 any kind of kamaki.clients errors (errors reported by servers, type errors in
148 arguments, etc.).
149
150 A ClientError contains::
151
152     message     The error message.
153     status      An optional error code, e.g. after a server error.
154     details     Optional list of messages with error details.
155
156 The following example concatenates examples 1.1 to 1.4 plus error handling
157
158 .. code-block:: python
159
160     Example 1.5: Error handling
161
162     from kamaki.clients.astakos import AstakosClient
163     from kamaki.clients.cyclades import CycladesClient
164     from kamaki.clients.pithos import PithosClient
165
166     try:
167         my_astakos_client = AstakosClient(AUTHENTICATION_URL, TOKEN)
168     except ClientError:
169         print('Failed to authenticate user token')
170         return 1
171
172     try:
173         cyclades_endpoints = my_astakos_client.get_service_endpoints('compute')
174         cyclades_base_url = cyclades_endpoints['publicURL']
175     except ClientError:
176         print('Failed to get endpoints for cyclades')
177
178     try:
179         my_cyclades_client = CycladesClient(cyclades_base_url, token)
180     except ClientError:
181         print('Failed to initialize Cyclades client')
182
183     try:
184         pithos_endpoints = my_astakos_client.get_service_endpoints('object-store')
185         pithos_base_url = pithos_endpoints['publicURL']
186     except ClientError:
187         print('Failed to get endpoints for pithos')
188
189     try:
190         my_pithos_client = PithosClient(pithos_base_url, token, account, container)
191     except ClientError:
192         print('Failed to initialize Pithos+ client')
193
194     try:
195         srv = my_cyclades_client.get_server_info(server_id)
196         print("Server Name: %s (with OS %s" % (srv['name'], srv['os']))
197
198         obj_list = my_pithos_client.list_objects(mycont)
199         for obj in obj_list:
200             print('  %s of %s bytes' % (obj['name'], obj['bytes']))
201     except ClientError as e:
202         print('Error: %s' % e)
203         if e.status:
204             print('- error code: %s' % e.status)
205         if e.details:
206             for detail in e.details:
207                 print('- %s' % detail)
208
209
210 Scripts
211 -------
212
213 Batch-create servers
214 ''''''''''''''''''''
215
216 .. code-block:: python
217
218     #/usr/bin/python
219
220     from kamaki.clients.astakos import AstakosClient
221     from kamaki.clients.cyclades import CycladesClient
222
223     AUTHENTICATION_URL = 'https://accounts.example.com/identity/v2.0'
224     TOKEN = 'replace this with your token'
225
226     user = AstakosClient(AUTHENTICATION_URL, TOKEN)
227
228     cyclades_endpoints = user.get_endpoints('compute')
229     CYCLADES_URL = cyclades_endpoints['publicURL']
230     cyclades = CycladesClient(CYCLADES_URL, TOKEN)
231
232     #  (name, flavor-id, image-id)
233     servers = [
234         ('My Debian Server', 1, 'my-debian-base-image-id'),
235         ('My Windows Server', 3, 'my-windows-8-image-id'),
236         ('My Ubuntu Server', 3, 'my-ubuntu-12-image-id'),
237     ]
238
239     for name, flavor_id, image_id in servers:
240         cyclades.create_server(name, flavor_id, image_id)
241
242
243 Batch-create 4 servers of the same kind
244 '''''''''''''''''''''''''''''''''''''''
245
246 .. code-block:: python
247
248     #/usr/bin/python
249
250     from kamaki.clients.astakos import AstakosClient
251     from kamaki.clients.cyclades import CycladesClient
252
253     AUTHENTICATION_URL = 'https://accounts.example.com/identity/v2.0'
254     TOKEN = 'replace this with your token'
255
256     user = AstakosClient(AUTHENTICATION_URL, TOKEN)
257
258     cyclades_endpoints = user.get_endpoints('compute')
259     CYCLADES_URL = cyclades_endpoints['publicURL']
260     cyclades = CycladesClient(CYCLADES_URL, TOKEN)
261
262     for i in range(4):
263         name, flavor_id, image_id = 'Server %s' % (i + 1), 3, 'some-image-id'
264         cyclades.create_server(name, flavor_id, image_id)