Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / astakos / __init__.py @ c6ebe715

History | View | Annotate | Download (9.7 kB)

1 e3f01d64 Stavros Sachtouris
# Copyright 2012-2013 GRNET S.A. All rights reserved.
2 43ca98ee Giorgos Verigakis
#
3 43ca98ee Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
4 43ca98ee Giorgos Verigakis
# without modification, are permitted provided that the following
5 43ca98ee Giorgos Verigakis
# conditions are met:
6 43ca98ee Giorgos Verigakis
#
7 43ca98ee Giorgos Verigakis
#   1. Redistributions of source code must retain the above
8 43ca98ee Giorgos Verigakis
#      copyright notice, this list of conditions and the following
9 43ca98ee Giorgos Verigakis
#      disclaimer.
10 43ca98ee Giorgos Verigakis
#
11 43ca98ee Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
12 43ca98ee Giorgos Verigakis
#      copyright notice, this list of conditions and the following
13 43ca98ee Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
14 43ca98ee Giorgos Verigakis
#      provided with the distribution.
15 43ca98ee Giorgos Verigakis
#
16 43ca98ee Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 43ca98ee Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 43ca98ee Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 43ca98ee Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 43ca98ee Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 43ca98ee Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 43ca98ee Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 43ca98ee Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 43ca98ee Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 43ca98ee Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 43ca98ee Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 43ca98ee Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
28 43ca98ee Giorgos Verigakis
#
29 43ca98ee Giorgos Verigakis
# The views and conclusions contained in the software and
30 43ca98ee Giorgos Verigakis
# documentation are those of the authors and should not be
31 43ca98ee Giorgos Verigakis
# interpreted as representing official policies, either expressed
32 43ca98ee Giorgos Verigakis
# or implied, of GRNET S.A.
33 43ca98ee Giorgos Verigakis
34 528550d9 Stavros Sachtouris
from logging import getLogger
35 85115c12 Stavros Sachtouris
from astakosclient import AstakosClient as SynnefoAstakosClientOrig
36 fa7d08b6 Stavros Sachtouris
from astakosclient import AstakosClientException as SynnefoAstakosClientError
37 9d3cd179 Stavros Sachtouris
38 20211cbb Stavros Sachtouris
from kamaki.clients import Client, ClientError, RequestManager, recvlog
39 528550d9 Stavros Sachtouris
40 528550d9 Stavros Sachtouris
41 fa7d08b6 Stavros Sachtouris
def _astakos_error(foo):
42 fa7d08b6 Stavros Sachtouris
    def wrap(self, *args, **kwargs):
43 fa7d08b6 Stavros Sachtouris
        try:
44 fa7d08b6 Stavros Sachtouris
            return foo(self, *args, **kwargs)
45 fa7d08b6 Stavros Sachtouris
        except SynnefoAstakosClientError as sace:
46 fa7d08b6 Stavros Sachtouris
            self._raise_for_status(sace)
47 fa7d08b6 Stavros Sachtouris
    return wrap
48 fa7d08b6 Stavros Sachtouris
49 fa7d08b6 Stavros Sachtouris
50 20211cbb Stavros Sachtouris
class SynnefoAstakosClient(SynnefoAstakosClientOrig):
51 85115c12 Stavros Sachtouris
    """A synnefo astakosclient.AstakosClient wrapper, that logs"""
52 85115c12 Stavros Sachtouris
53 85115c12 Stavros Sachtouris
    def _dump_response(self, request, status, message, data):
54 20211cbb Stavros Sachtouris
        recvlog.info('\n%d %s' % (status, message))
55 20211cbb Stavros Sachtouris
        recvlog.info('data size: %s' % len(data))
56 20211cbb Stavros Sachtouris
        token = request.headers.get('X-Auth-Token', '')
57 20211cbb Stavros Sachtouris
        data = data.replace(token, '...') if token else data
58 2d1f5058 Stavros Sachtouris
        recvlog.info(data)
59 2d1f5058 Stavros Sachtouris
        recvlog.info('-             -        -     -   -  - -')
60 85115c12 Stavros Sachtouris
61 85115c12 Stavros Sachtouris
    def _call_astakos(self, *args, **kwargs):
62 85115c12 Stavros Sachtouris
        r = super(SynnefoAstakosClient, self)._call_astakos(*args, **kwargs)
63 85115c12 Stavros Sachtouris
        try:
64 85115c12 Stavros Sachtouris
            log_request = getattr(self, 'log_request', None)
65 85115c12 Stavros Sachtouris
            if log_request:
66 85115c12 Stavros Sachtouris
                req = RequestManager(
67 85115c12 Stavros Sachtouris
                    method=log_request['method'],
68 85115c12 Stavros Sachtouris
                    url='%s://%s' % (self.scheme, self.astakos_base_url),
69 85115c12 Stavros Sachtouris
                    path=log_request['path'],
70 85115c12 Stavros Sachtouris
                    data=log_request.get('body', None),
71 85115c12 Stavros Sachtouris
                    headers=log_request.get('headers', dict()))
72 85115c12 Stavros Sachtouris
                req.dump_log()
73 85115c12 Stavros Sachtouris
                log_response = getattr(self, 'log_response', None)
74 85115c12 Stavros Sachtouris
                if log_response:
75 85115c12 Stavros Sachtouris
                    self._dump_response(
76 85115c12 Stavros Sachtouris
                        req,
77 85115c12 Stavros Sachtouris
                        status=log_response['status'],
78 85115c12 Stavros Sachtouris
                        message=log_response['message'],
79 85115c12 Stavros Sachtouris
                        data=log_response.get('data', ''))
80 20211cbb Stavros Sachtouris
        except Exception:
81 20211cbb Stavros Sachtouris
            pass
82 85115c12 Stavros Sachtouris
        finally:
83 85115c12 Stavros Sachtouris
            return r
84 85115c12 Stavros Sachtouris
85 85115c12 Stavros Sachtouris
86 43ca98ee Giorgos Verigakis
class AstakosClient(Client):
87 cabc72ae Stavros Sachtouris
    """Synnefo Astakos cached client wraper"""
88 44b8928d Giorgos Verigakis
89 fa7d08b6 Stavros Sachtouris
    @_astakos_error
90 528550d9 Stavros Sachtouris
    def __init__(self, base_url, token=None):
91 33dc6317 Stavros Sachtouris
        super(AstakosClient, self).__init__(base_url, token)
92 cabc72ae Stavros Sachtouris
        self._astakos = dict()
93 cabc72ae Stavros Sachtouris
        self._uuids = dict()
94 cabc72ae Stavros Sachtouris
        self._cache = dict()
95 cabc72ae Stavros Sachtouris
        self._uuids2usernames = dict()
96 cabc72ae Stavros Sachtouris
        self._usernames2uuids = dict()
97 cabc72ae Stavros Sachtouris
98 cabc72ae Stavros Sachtouris
    def _resolve_token(self, token):
99 cabc72ae Stavros Sachtouris
        """
100 cabc72ae Stavros Sachtouris
        :returns: (str) a single token
101 cabc72ae Stavros Sachtouris

102 cabc72ae Stavros Sachtouris
        :raises AssertionError: if no token exists (either param or member)
103 cabc72ae Stavros Sachtouris
        """
104 91478081 Stavros Sachtouris
        token = token or self.token
105 cabc72ae Stavros Sachtouris
        assert token, 'No token provided'
106 cabc72ae Stavros Sachtouris
        return token[0] if (
107 cabc72ae Stavros Sachtouris
            isinstance(token, list) or isinstance(token, tuple)) else token
108 cabc72ae Stavros Sachtouris
109 172ee8f9 Stavros Sachtouris
    def get_client(self, token=None):
110 172ee8f9 Stavros Sachtouris
        """Get the Synnefo AstakosClient instance used by client"""
111 172ee8f9 Stavros Sachtouris
        token = self._resolve_token(token)
112 172ee8f9 Stavros Sachtouris
        self._validate_token(token)
113 172ee8f9 Stavros Sachtouris
        return self._astakos[self._uuids[token]]
114 172ee8f9 Stavros Sachtouris
115 fa7d08b6 Stavros Sachtouris
    @_astakos_error
116 0238c167 Stavros Sachtouris
    def authenticate(self, token=None):
117 409371de Stavros Sachtouris
        """Get authentication information and store it in this client
118 409371de Stavros Sachtouris
        As long as the AstakosClient instance is alive, the latest
119 409371de Stavros Sachtouris
        authentication information for this token will be available
120 409371de Stavros Sachtouris

121 0d79eb23 Stavros Sachtouris
        :param token: (str) custom token to authenticate
122 0d79eb23 Stavros Sachtouris
        """
123 cabc72ae Stavros Sachtouris
        token = self._resolve_token(token)
124 cabc72ae Stavros Sachtouris
        astakos = SynnefoAstakosClient(
125 91478081 Stavros Sachtouris
            token, self.base_url, logger=getLogger('astakosclient'))
126 fa7d08b6 Stavros Sachtouris
        r = astakos.authenticate()
127 b44a5a37 Stavros Sachtouris
        uuid = r['access']['user']['id']
128 db93db3e Stavros Sachtouris
        self._uuids[token] = uuid
129 b44a5a37 Stavros Sachtouris
        self._cache[uuid] = r
130 cabc72ae Stavros Sachtouris
        self._astakos[uuid] = astakos
131 91478081 Stavros Sachtouris
        self._uuids2usernames[uuid] = dict()
132 91478081 Stavros Sachtouris
        self._usernames2uuids[uuid] = dict()
133 f24819ad Stavros Sachtouris
        return self._cache[uuid]
134 b44a5a37 Stavros Sachtouris
135 fa7d08b6 Stavros Sachtouris
    def remove_user(self, uuid):
136 fa7d08b6 Stavros Sachtouris
        self._uuids.pop(self.get_token(uuid))
137 fa7d08b6 Stavros Sachtouris
        self._cache.pop(uuid)
138 fa7d08b6 Stavros Sachtouris
        self._astakos.pop(uuid)
139 fa7d08b6 Stavros Sachtouris
        self._uuids2usernames.pop(uuid)
140 fa7d08b6 Stavros Sachtouris
        self._usernames2uuids.pop(uuid)
141 fa7d08b6 Stavros Sachtouris
142 b44a5a37 Stavros Sachtouris
    def get_token(self, uuid):
143 b44a5a37 Stavros Sachtouris
        return self._cache[uuid]['access']['token']['id']
144 5207c784 Stavros Sachtouris
145 cabc72ae Stavros Sachtouris
    def _validate_token(self, token):
146 cabc72ae Stavros Sachtouris
        if (token not in self._uuids) or (
147 cabc72ae Stavros Sachtouris
                self.get_token(self._uuids[token]) != token):
148 cabc72ae Stavros Sachtouris
            self._uuids.pop(token, None)
149 cabc72ae Stavros Sachtouris
            self.authenticate(token)
150 cabc72ae Stavros Sachtouris
151 528550d9 Stavros Sachtouris
    def get_services(self, token=None):
152 528550d9 Stavros Sachtouris
        """
153 528550d9 Stavros Sachtouris
        :returns: (list) [{name:..., type:..., endpoints:[...]}, ...]
154 528550d9 Stavros Sachtouris
        """
155 cabc72ae Stavros Sachtouris
        token = self._resolve_token(token)
156 cabc72ae Stavros Sachtouris
        self._validate_token(token)
157 cabc72ae Stavros Sachtouris
        r = self._cache[self._uuids[token]]
158 3950a864 Stavros Sachtouris
        return r['access']['serviceCatalog']
159 528550d9 Stavros Sachtouris
160 528550d9 Stavros Sachtouris
    def get_service_details(self, service_type, token=None):
161 528550d9 Stavros Sachtouris
        """
162 528550d9 Stavros Sachtouris
        :param service_type: (str) compute, object-store, image, account, etc.
163 528550d9 Stavros Sachtouris

164 528550d9 Stavros Sachtouris
        :returns: (dict) {name:..., type:..., endpoints:[...]}
165 528550d9 Stavros Sachtouris

166 528550d9 Stavros Sachtouris
        :raises ClientError: (600) if service_type not in service catalog
167 528550d9 Stavros Sachtouris
        """
168 528550d9 Stavros Sachtouris
        services = self.get_services(token)
169 528550d9 Stavros Sachtouris
        for service in services:
170 528550d9 Stavros Sachtouris
            try:
171 528550d9 Stavros Sachtouris
                if service['type'].lower() == service_type.lower():
172 528550d9 Stavros Sachtouris
                    return service
173 528550d9 Stavros Sachtouris
            except KeyError:
174 528550d9 Stavros Sachtouris
                self.log.warning('Misformated service %s' % service)
175 528550d9 Stavros Sachtouris
        raise ClientError(
176 528550d9 Stavros Sachtouris
            'Service type "%s" not in service catalog' % service_type, 600)
177 528550d9 Stavros Sachtouris
178 528550d9 Stavros Sachtouris
    def get_service_endpoints(self, service_type, version=None, token=None):
179 528550d9 Stavros Sachtouris
        """
180 528550d9 Stavros Sachtouris
        :param service_type: (str) can be compute, object-store, etc.
181 528550d9 Stavros Sachtouris

182 528550d9 Stavros Sachtouris
        :param version: (str) the version id of the service
183 528550d9 Stavros Sachtouris

184 528550d9 Stavros Sachtouris
        :returns: (dict) {SNF:uiURL, adminURL, internalURL, publicURL, ...}
185 528550d9 Stavros Sachtouris

186 528550d9 Stavros Sachtouris
        :raises ClientError: (600) if service_type not in service catalog
187 528550d9 Stavros Sachtouris

188 528550d9 Stavros Sachtouris
        :raises ClientError: (601) if #matching endpoints != 1
189 528550d9 Stavros Sachtouris
        """
190 528550d9 Stavros Sachtouris
        service = self.get_service_details(service_type, token)
191 528550d9 Stavros Sachtouris
        matches = []
192 528550d9 Stavros Sachtouris
        for endpoint in service['endpoints']:
193 528550d9 Stavros Sachtouris
            if (not version) or (
194 e7884f25 Stavros Sachtouris
                    endpoint['versionId'].lower() == version.lower()):
195 528550d9 Stavros Sachtouris
                matches.append(endpoint)
196 528550d9 Stavros Sachtouris
        if len(matches) != 1:
197 528550d9 Stavros Sachtouris
            raise ClientError(
198 528550d9 Stavros Sachtouris
                '%s endpoints match type %s %s' % (
199 528550d9 Stavros Sachtouris
                    len(matches), service_type,
200 e7884f25 Stavros Sachtouris
                    ('and versionId %s' % version) if version else ''),
201 528550d9 Stavros Sachtouris
                601)
202 528550d9 Stavros Sachtouris
        return matches[0]
203 528550d9 Stavros Sachtouris
204 528550d9 Stavros Sachtouris
    def list_users(self):
205 528550d9 Stavros Sachtouris
        """list cached users information"""
206 9a8861d1 Stavros Sachtouris
        if not self._cache:
207 9a8861d1 Stavros Sachtouris
            self.authenticate()
208 2182231b Stavros Sachtouris
        r = []
209 2182231b Stavros Sachtouris
        for k, v in self._cache.items():
210 3950a864 Stavros Sachtouris
            r.append(dict(v['access']['user']))
211 b44a5a37 Stavros Sachtouris
            r[-1].update(dict(auth_token=self.get_token(k)))
212 2182231b Stavros Sachtouris
        return r
213 76d3b2d7 Stavros Sachtouris
214 528550d9 Stavros Sachtouris
    def user_info(self, token=None):
215 2182231b Stavros Sachtouris
        """Get (cached) user information"""
216 cabc72ae Stavros Sachtouris
        token = self._resolve_token(token)
217 cabc72ae Stavros Sachtouris
        self._validate_token(token)
218 cabc72ae Stavros Sachtouris
        r = self._cache[self._uuids[token]]
219 3950a864 Stavros Sachtouris
        return r['access']['user']
220 76d3b2d7 Stavros Sachtouris
221 5207c784 Stavros Sachtouris
    def term(self, key, token=None):
222 5207c784 Stavros Sachtouris
        """Get (cached) term, from user credentials"""
223 f724cd35 Stavros Sachtouris
        return self.user_term(key, token)
224 f724cd35 Stavros Sachtouris
225 f724cd35 Stavros Sachtouris
    def user_term(self, key, token=None):
226 f724cd35 Stavros Sachtouris
        """Get (cached) term, from user credentials"""
227 528550d9 Stavros Sachtouris
        return self.user_info(token).get(key, None)
228 9d3cd179 Stavros Sachtouris
229 cabc72ae Stavros Sachtouris
    def post_user_catalogs(self, uuids=None, displaynames=None, token=None):
230 9d3cd179 Stavros Sachtouris
        """POST base_url/user_catalogs
231 9d3cd179 Stavros Sachtouris

232 9d3cd179 Stavros Sachtouris
        :param uuids: (list or tuple) user uuids
233 9d3cd179 Stavros Sachtouris

234 95641ecc Stavros Sachtouris
        :param displaynames: (list or tuple) usernames (mut. excl. to uuids)
235 95641ecc Stavros Sachtouris

236 95641ecc Stavros Sachtouris
        :returns: (dict) {uuid1: name1, uuid2: name2, ...} or oposite
237 9d3cd179 Stavros Sachtouris
        """
238 cabc72ae Stavros Sachtouris
        return self.uuids2usernames(uuids, token) if (
239 fa7d08b6 Stavros Sachtouris
            uuids) else self.usernames2uuids(displaynames, token)
240 cabc72ae Stavros Sachtouris
241 fa7d08b6 Stavros Sachtouris
    @_astakos_error
242 cabc72ae Stavros Sachtouris
    def uuids2usernames(self, uuids, token=None):
243 cabc72ae Stavros Sachtouris
        token = self._resolve_token(token)
244 cabc72ae Stavros Sachtouris
        self._validate_token(token)
245 91478081 Stavros Sachtouris
        uuid = self._uuids[token]
246 91478081 Stavros Sachtouris
        astakos = self._astakos[uuid]
247 91478081 Stavros Sachtouris
        if set(uuids).difference(self._uuids2usernames[uuid]):
248 91478081 Stavros Sachtouris
            self._uuids2usernames[uuid].update(astakos.get_usernames(uuids))
249 91478081 Stavros Sachtouris
        return self._uuids2usernames[uuid]
250 cabc72ae Stavros Sachtouris
251 fa7d08b6 Stavros Sachtouris
    @_astakos_error
252 cabc72ae Stavros Sachtouris
    def usernames2uuids(self, usernames, token=None):
253 cabc72ae Stavros Sachtouris
        token = self._resolve_token(token)
254 cabc72ae Stavros Sachtouris
        self._validate_token(token)
255 91478081 Stavros Sachtouris
        uuid = self._uuids[token]
256 91478081 Stavros Sachtouris
        astakos = self._astakos[uuid]
257 91478081 Stavros Sachtouris
        if set(usernames).difference(self._usernames2uuids[uuid]):
258 91478081 Stavros Sachtouris
            self._usernames2uuids[uuid].update(astakos.get_uuids(usernames))
259 91478081 Stavros Sachtouris
        return self._usernames2uuids[uuid]