2 |
2 |
=====================================
|
3 |
3 |
|
4 |
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 serves as a lib.
|
|
5 |
communicate with Synnefo and (in most cases) OpenStack cloud services. The package is
|
|
6 |
called *kamaki.clients* and serves as a library.
|
7 |
7 |
|
8 |
8 |
A showcase of an application built on *kamaki.clients* is *kamaki.cli*, the
|
9 |
9 |
command line interface of kamaki.
|
10 |
10 |
|
11 |
11 |
Since Synnefo services are build as OpenStack extensions, an inheritance
|
12 |
|
approach has been chosen for implementing clients for both. In specific,
|
|
12 |
approach has been chosen for implementing clients for both APIs. In specific,
|
13 |
13 |
the *compute*, *storage* and *image* modules are client implementations for the
|
14 |
14 |
OpenStack compute, OpenStack object-store and Image APIs respectively. The rest
|
15 |
15 |
of the modules implement the Synnefo extensions (i.e., *cyclades* and
|
... | ... | |
19 |
19 |
Setup a client instance
|
20 |
20 |
-----------------------
|
21 |
21 |
|
22 |
|
There is a client for every API, therefore an external applications should
|
23 |
|
instantiate they kamaki clients they need. For example, to manage virtual
|
24 |
|
servers and stored objects / files, an application would probably need to
|
25 |
|
instantiate the CycladesClient and PithosClient respectively.
|
|
22 |
There is a client for every API. An external applications should instantiate
|
|
23 |
the kamaki clients that fit their needs.
|
|
24 |
|
|
25 |
For example, to manage virtual servers and stored objects / files, an
|
|
26 |
application would probably need the CycladesClient and PithosClient
|
|
27 |
respectively.
|
26 |
28 |
|
27 |
29 |
.. code-block:: python
|
28 |
30 |
:emphasize-lines: 1
|
... | ... | |
33 |
35 |
from kamaki.clients.cyclades import CycladesClient
|
34 |
36 |
from kamaki.clients.pithos import PithosClient
|
35 |
37 |
|
36 |
|
my_cyclades_client = CycladesClient(base_url, token)
|
37 |
|
my_pithos_client = PithosClient(base_url, token, account, container)
|
|
38 |
cyclades = CycladesClient(computeURL, token)
|
|
39 |
pithos = PithosClient(object-storeURL, token, account, container)
|
38 |
40 |
|
39 |
41 |
.. note:: *cyclades* and *pithos* clients inherit ComputeClient from *compute*
|
40 |
42 |
and StorageClient from *storage*, respectively. Separate ComputeClient or
|
41 |
43 |
StorageClient objects should be used only when implementing applications for
|
42 |
44 |
strict OpenStack Compute or Storage services.
|
43 |
45 |
|
44 |
|
Using endpoints to get the base_url
|
45 |
|
-----------------------------------
|
|
46 |
Using endpoints to get the authentication url
|
|
47 |
---------------------------------------------
|
46 |
48 |
|
47 |
49 |
In OpenStack, each service (e.g., `compute`, `object-store`, etc.) has a number
|
48 |
|
of `endpoints`. These `endpoints` are URIs that are used by kamaki as
|
49 |
|
prefixes to form the corresponding API calls. Client applications need just
|
50 |
|
one of these these `endpoints`, namely the `publicURL`, which is also referred
|
51 |
|
to as `base_url` in kamaki client libraries.
|
|
50 |
of `endpoints`. These `endpoints` are URIs which are used by kamaki as prefixes
|
|
51 |
to form the corresponding API calls. Client applications need just one of these
|
|
52 |
`endpoints`, namely the `publicURL` (also referred to as `publicURL` in the
|
|
53 |
internals of kamaki client libraries).
|
52 |
54 |
|
53 |
|
Here are instructions for getting the base_url for a service::
|
|
55 |
Here are instructions for getting the publicURL for a service::
|
54 |
56 |
|
55 |
57 |
1. From the deployment UI get the AUTHENTICATION_URL and TOKEN
|
56 |
58 |
(Example 1.2)
|
... | ... | |
58 |
60 |
(Example 1.2)
|
59 |
61 |
3. Use AstakosClient instance to get endpoints for the service of interest
|
60 |
62 |
(Example 1.3)
|
61 |
|
4. The 'publicURL' endpoint is the base_url we are looking for
|
|
63 |
4. The 'publicURL' endpoint is the URL we are looking for
|
62 |
64 |
(Example 1.3)
|
63 |
65 |
|
64 |
66 |
The AstakosClient is a client for the Synnefo/Astakos server. Synnefo/Astakos
|
65 |
|
is an identity server that implements the OpenStack identity API. Therefore, it
|
66 |
|
can be used to get the `base_url` values needed for initializing kamaki clients.
|
67 |
|
Kamaki simplifies this process with the astakos client library.
|
|
67 |
is an identity server that implements the OpenStack identity API and it
|
|
68 |
can be used to get the URLs needed for API calls URL construction. The astakos
|
|
69 |
kamaki client library simplifies this process.
|
68 |
70 |
|
69 |
|
Let's review the process with examples.
|
|
71 |
Let's review with a few examples.
|
70 |
72 |
|
71 |
73 |
First, an astakos client must be initialized (Example 1.2). An
|
72 |
74 |
AUTHENTICATION_URL and a TOKEN can be acquired from the Synnefo deployment UI.
|
... | ... | |
77 |
79 |
Example 1.2: Initialize an astakos client
|
78 |
80 |
|
79 |
81 |
from kamaki.clients.astakos import AstakosClient
|
80 |
|
my_astakos_client = AstakosClient(AUTHENTICATION_URL, TOKEN)
|
|
82 |
astakos = AstakosClient(AUTHENTICATION_URL, TOKEN)
|
81 |
83 |
|
82 |
84 |
|
83 |
|
Next, the astakos client can be used to retrieve the base_url values for the
|
84 |
|
servers of interest. In this case (Example 1.3) they are *cyclades*
|
85 |
|
and *pithos*. A number of endpoints is assigned to each service, but kamaki
|
86 |
|
clients only need the one labeled as ``publicURL``.
|
|
85 |
Next, the astakos client can be used to retrieve the `publicURL` values for the
|
|
86 |
services of interest. In this case (Example 1.3) they are *cyclades* (compute)
|
|
87 |
and *pithos* (object-store). A number of endpoints is related to each service,
|
|
88 |
but kamaki clients only need the ones labeled ``publicURL``.
|
87 |
89 |
|
88 |
90 |
.. code-block:: python
|
89 |
91 |
:emphasize-lines: 1
|
90 |
92 |
|
91 |
|
Example 1.3: Retrieve cyclades and pithos base_url values
|
|
93 |
Example 1.3: Retrieve cyclades and pithos publicURL values
|
92 |
94 |
|
93 |
|
cyclades_endpoints = my_astakos_client.get_service_endpoints('compute')
|
94 |
|
cyclades_base_url = cyclades_endpoints['publicURL']
|
|
95 |
cyclades_endpoints = astakos.get_service_endpoints('compute')
|
|
96 |
cyclades_URL = cyclades_endpoints['publicURL']
|
95 |
97 |
|
96 |
|
pithos_endpoints = my_astakos_client.get_service_endpoints('object-store')
|
97 |
|
pithos_base_url = pithos_endpoints['publicURL']
|
|
98 |
pithos_endpoints = astakos.get_service_endpoints('object-store')
|
|
99 |
pithos_URL = pithos_endpoints['publicURL']
|
98 |
100 |
|
99 |
101 |
The ``get_service_endpoints`` method is called with the service name as an
|
100 |
102 |
argument. Here are the service names for the kamaki clients::
|
... | ... | |
105 |
107 |
image.ImageClient --> image
|
106 |
108 |
astakos.AstakosClient --> identity, account
|
107 |
109 |
|
|
110 |
For example
|
|
111 |
|
|
112 |
.. code-block:: python
|
|
113 |
:emphasize-lines: 1
|
|
114 |
|
|
115 |
Example 1.3.1 Initialize cyclades and pithos clients
|
|
116 |
|
|
117 |
from kamaki.clients.cyclades import CycladesClient
|
|
118 |
from kamaki.clients.pithos import PithosClient
|
|
119 |
|
|
120 |
cyclades = CycladesClient(cyclades_URL, TOKEN)
|
|
121 |
pithos = PithosClient(pithos_URL, TOKEN)
|
|
122 |
|
|
123 |
# Also, setup the account UUID and container for pithos client
|
|
124 |
pithos.account = astakos.user_info['id']
|
|
125 |
pithos.container = 'pithos'
|
|
126 |
|
108 |
127 |
Use client methods
|
109 |
128 |
------------------
|
110 |
129 |
|
... | ... | |
116 |
135 |
:ref:`the-client-api-ref`
|
117 |
136 |
|
118 |
137 |
In the following example, the *cyclades* and *pithos* clients of example 1.1
|
119 |
|
are used to extract some information through the remote service APIs. The information is then printed to the standard output.
|
|
138 |
are used to extract some information through the remote service APIs. The
|
|
139 |
information is then printed to the standard output.
|
120 |
140 |
|
121 |
141 |
|
122 |
142 |
.. code-block:: python
|
123 |
143 |
:emphasize-lines: 1,2
|
124 |
144 |
|
125 |
145 |
Example 1.4: Print server name and OS for server with server_id
|
126 |
|
Print objects in container mycont
|
|
146 |
Print objects in default container
|
127 |
147 |
|
128 |
|
srv = my_cyclades_client.get_server_info(server_id)
|
|
148 |
srv = cyclades.get_server_info(server_id)
|
129 |
149 |
print("Server Name: %s (with OS %s" % (srv['name'], srv['os']))
|
130 |
150 |
|
131 |
|
obj_list = my_pithos_client.list_objects(mycont)
|
|
151 |
obj_list = pithos.list_objects()
|
|
152 |
print("Objects in container '%s':" % pithos.container)
|
132 |
153 |
for obj in obj_list:
|
133 |
154 |
print(' %s of %s bytes' % (obj['name'], obj['bytes']))
|
134 |
155 |
|
... | ... | |
140 |
161 |
|
141 |
162 |
$ python test_script.py
|
142 |
163 |
Server Name: A Debian Server (with OS Debian Base)
|
|
164 |
Objects in container 'pithos':
|
143 |
165 |
lala.txt of 34 bytes
|
144 |
166 |
test.txt of 1232 bytes
|
145 |
167 |
testDir/ of 0 bytes
|
... | ... | |
150 |
172 |
|
151 |
173 |
The *kamaki.clients* error class is ClientError. A ClientError is raised for
|
152 |
174 |
any kind of *kamaki.clients* errors (errors reported by servers, type errors in
|
153 |
|
arguments, etc.).
|
|
175 |
method arguments, etc.).
|
154 |
176 |
|
155 |
177 |
A ClientError contains::
|
156 |
178 |
|
... | ... | |
171 |
193 |
from kamaki.clients.pithos import PithosClient
|
172 |
194 |
|
173 |
195 |
try:
|
174 |
|
my_astakos_client = AstakosClient(AUTHENTICATION_URL, TOKEN)
|
175 |
|
my_astakos_client.authenticate()
|
|
196 |
astakos = AstakosClient(AUTHENTICATION_URL, TOKEN)
|
176 |
197 |
except ClientError:
|
177 |
198 |
print('Failed to authenticate user token')
|
178 |
199 |
return 1
|
179 |
200 |
|
180 |
201 |
try:
|
181 |
|
cyclades_endpoints = my_astakos_client.get_service_endpoints('compute')
|
182 |
|
cyclades_base_url = cyclades_endpoints['publicURL']
|
|
202 |
cyclades_endpoints = astakos.get_service_endpoints('compute')
|
|
203 |
cyclades_publicURL = cyclades_endpoints['publicURL']
|
183 |
204 |
except ClientError:
|
184 |
205 |
print('Failed to get endpoints for cyclades')
|
185 |
206 |
|
186 |
207 |
try:
|
187 |
|
my_cyclades_client = CycladesClient(cyclades_base_url, token)
|
|
208 |
cyclades = CycladesClient(cyclades_publicURL, token)
|
188 |
209 |
except ClientError:
|
189 |
210 |
print('Failed to initialize Cyclades client')
|
190 |
211 |
|
191 |
212 |
try:
|
192 |
|
pithos_endpoints = my_astakos_client.get_service_endpoints('object-store')
|
193 |
|
pithos_base_url = pithos_endpoints['publicURL']
|
|
213 |
pithos_endpoints = astakos.get_service_endpoints('object-store')
|
|
214 |
pithos_publicURL = pithos_endpoints['publicURL']
|
194 |
215 |
except ClientError:
|
195 |
216 |
print('Failed to get endpoints for pithos')
|
196 |
217 |
|
197 |
218 |
try:
|
198 |
|
my_pithos_client = PithosClient(pithos_base_url, token, account, container)
|
|
219 |
pithos = PithosClient(pithos_publicURL, token, account, container)
|
199 |
220 |
except ClientError:
|
200 |
221 |
print('Failed to initialize Pithos+ client')
|
201 |
222 |
|
202 |
223 |
try:
|
203 |
|
srv = my_cyclades_client.get_server_info(server_id)
|
|
224 |
srv = cyclades.get_server_info(server_id)
|
204 |
225 |
print("Server Name: %s (with OS %s" % (srv['name'], srv['os']))
|
205 |
226 |
|
206 |
|
obj_list = my_pithos_client.list_objects(mycont)
|
|
227 |
obj_list = pithos.list_objects()
|
207 |
228 |
for obj in obj_list:
|
208 |
229 |
print(' %s of %s bytes' % (obj['name'], obj['bytes']))
|
209 |
230 |
except ClientError as e:
|