Revision 9c6d629f

b/snf-astakos-app/astakos/admin/views.py
36 36
from django.utils import simplejson as json
37 37
from snf_django.lib import api
38 38
from astakos.im import settings
39
from synnefo.lib.services import get_path
40 39

  
41 40
from astakos.admin import stats
42 41

  
......
44 43

  
45 44
PERMITTED_GROUPS = settings.ADMIN_STATS_PERMITTED_GROUPS
46 45
try:
47
    AUTH_URL = get_path(settings.astakos_services,
48
                        "astakos_identity.endpoints")[0]["publicURL"]
46
    AUTH_URL = settings.astakos_services\
47
        ["astakos_identity"]["endpoints"][0]["publicURL"]
49 48
except (IndexError, KeyError) as e:
50 49
    logger.error("Failed to load Astakos Auth URL: %s", e)
51 50
    AUTH_URL = None
b/snf-astakos-app/astakos/im/astakos_resources.py
32 32
# or implied, of GRNET S.A.
33 33

  
34 34
from astakos.im.settings import astakos_services
35
from synnefo.util.keypath import get_path
36 35

  
37
resources = get_path(astakos_services, 'astakos_account.resources').values()
36
resources = astakos_services['astakos_account']['resources'].values()
b/snf-astakos-app/astakos/im/settings.py
35 35
from synnefo_branding import settings as synnefo_settings
36 36
from synnefo.lib import parse_base_url
37 37
from astakos.api.services import astakos_services as vanilla_astakos_services
38
from synnefo.util.keypath import get_path
39 38
from synnefo.lib import join_urls
40 39
from synnefo.lib.services import fill_endpoints
41 40

  
......
50 49

  
51 50
astakos_services = deepcopy(vanilla_astakos_services)
52 51
fill_endpoints(astakos_services, BASE_URL)
53
ACCOUNTS_PREFIX = get_path(astakos_services, 'astakos_account.prefix')
54
VIEWS_PREFIX = get_path(astakos_services, 'astakos_ui.prefix')
55
KEYSTONE_PREFIX = get_path(astakos_services, 'astakos_identity.prefix')
56
WEBLOGIN_PREFIX = get_path(astakos_services, 'astakos_weblogin.prefix')
57
ADMIN_PREFIX = get_path(astakos_services, 'astakos_admin.prefix')
52
ACCOUNTS_PREFIX = astakos_services['astakos_account']['prefix']
53
VIEWS_PREFIX = astakos_services['astakos_ui']['prefix']
54
KEYSTONE_PREFIX = astakos_services['astakos_identity']['prefix']
55
WEBLOGIN_PREFIX = astakos_services['astakos_weblogin']['prefix']
56
ADMIN_PREFIX = astakos_services['astakos_admin']['prefix']
58 57

  
59 58
# Set the expiration time of newly created auth tokens
60 59
# to be this many hours after their creation time.
b/snf-common/synnefo/lib/services.py
33 33

  
34 34
from copy import deepcopy
35 35
from synnefo.lib import join_urls
36
from synnefo.util.keypath import get_path, set_path
37 36
from urlparse import urlparse
38 37

  
39 38

  
40 39
def fill_endpoints(services, base_url):
41 40
    for name, service in services.iteritems():
42
        prefix = get_path(service, 'prefix')
43
        endpoints = get_path(service, 'endpoints')
41
        prefix = service['prefix']
42
        endpoints = service['endpoints']
44 43
        for endpoint in endpoints:
45
            version = get_path(endpoint, 'versionId')
46
            publicURL = get_path(endpoint, 'publicURL')
44
            version = endpoint['versionId']
45
            publicURL = endpoint['publicURL']
47 46
            if publicURL is not None:
48 47
                continue
49 48

  
50 49
            publicURL = join_urls(base_url, prefix, version).rstrip('/')
51
            set_path(endpoint, 'publicURL', publicURL)
50
            endpoint['publicURL'] = publicURL
52 51

  
53 52

  
54 53
def filter_public(services):
/dev/null
1
# Copyright 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34

  
35
import re
36
integer_re = re.compile('-?[0-9]+')
37

  
38

  
39
def join_path(sep, path):
40
    iterable = ((str(n) if isinstance(n, (int, long)) else n) for n in path)
41
    return sep.join(iterable)
42

  
43

  
44
def lookup_path(container, path, sep='.', createpath=False):
45
    """
46
    return (['a','b'],
47
            [container['a'], container['a']['b']],
48
            'c')  where path=sep.join(['a','b','c'])
49

  
50
    """
51
    names = path.split(sep)
52
    dirnames = names[:-1]
53
    basename = names[-1]
54
    if integer_re.match(basename):
55
        basename = int(basename)
56

  
57
    node = container
58
    name_path = []
59
    node_path = [node]
60
    for name in dirnames:
61
        name_path.append(name)
62

  
63
        if integer_re.match(name):
64
            name = int(name)
65

  
66
        try:
67
            node = node[name]
68
        except KeyError as e:
69
            if not createpath:
70
                m = "'{0}': path not found".format(join_path(sep, name_path))
71
                raise KeyError(m)
72
            node[name] = {}
73
            node = node[name]
74
        except IndexError as e:
75
            if not createpath:
76
                m = "'{0}': path not found: {1}".format(
77
                    join_path(sep, name_path), e)
78
                raise KeyError(m)
79
            size = name if name > 0 else -name
80
            node += (dict() for _ in xrange(len(node), size))
81
            node = node[name]
82
        except TypeError as e:
83
            m = "'{0}': cannot traverse path beyond this node: {1}"
84
            m = m.format(join_path(sep, name_path), str(e))
85
            raise ValueError(m)
86
        node_path.append(node)
87

  
88
    return name_path, node_path, basename
89

  
90

  
91
def walk_paths(container):
92
    for name, node in container.iteritems():
93
        if not hasattr(node, 'items'):
94
            yield [name], [node]
95
        else:
96
            for names, nodes in walk_paths(node):
97
                yield [name] + names, [node] + nodes
98

  
99

  
100
def list_paths(container, sep='.'):
101
    """
102
    >>> sorted(list_paths({'a': {'b': {'c': 'd'}}}))
103
    [('a.b.c', 'd')]
104
    >>> sorted(list_paths({'a': {'b': {'c': 'd'}, 'e': 3}}))
105
    [('a.b.c', 'd'), ('a.e', 3)]
106
    >>> sorted(list_paths({'a': {'b': {'c': 'd'}, 'e': {'f': 3}}}))
107
    [('a.b.c', 'd'), ('a.e.f', 3)]
108
    >>> sorted(list_paths({'a': [{'b': 3}, 2]}))
109
    [('a', [{'b': 3}, 2])]
110
    >>> list_paths({})
111
    []
112

  
113
    """
114
    return [(join_path(sep, name_path), node_path[-1])
115
            for name_path, node_path in walk_paths(container)]
116

  
117

  
118
def del_path(container, path, sep='.', collect=True):
119
    """
120
    del container['a']['b']['c'] where path=sep.join(['a','b','c'])
121

  
122
    >>> d = {'a': {'b': {'c': 'd'}}}; del_path(d, 'a.b.c'); d
123
    {}
124
    >>> d = {'a': {'b': {'c': 'd'}}}; del_path(d, 'a.b.c', collect=False); d
125
    {'a': {'b': {}}}
126
    >>> d = {'a': {'b': {'c': 'd'}}}; del_path(d, 'a.b.c.d')
127
    Traceback (most recent call last):
128
    ValueError: 'a.b.c': cannot traverse path beyond this node:\
129
 'str' object does not support item deletion
130
    """
131

  
132
    name_path, node_path, basename = \
133
            lookup_path(container, path, sep=sep, createpath=False)
134

  
135
    lastnode = node_path.pop()
136
    lastname = basename
137
    try:
138
        if basename in lastnode:
139
            del lastnode[basename]
140
    except (TypeError, KeyError) as e:
141
        m = "'{0}': cannot traverse path beyond this node: {1}"
142
        m = m.format(join_path(sep, name_path), str(e))
143
        raise ValueError(m)
144

  
145
    if collect:
146
        while node_path and not lastnode:
147
            basename = name_path.pop()
148
            lastnode = node_path.pop()
149
            del lastnode[basename]
150

  
151

  
152
def get_path(container, path, sep='.'):
153
    """
154
    return container['a']['b']['c'] where path=sep.join(['a','b','c'])
155

  
156
    >>> get_path({'a': {'b': {'c': 'd'}}}, 'a.b.c.d')
157
    Traceback (most recent call last):
158
    ValueError: 'a.b.c.d': cannot traverse path beyond this node:\
159
 string indices must be integers, not str
160
    >>> get_path({'a': {'b': {'c': 1}}}, 'a.b.c.d')
161
    Traceback (most recent call last):
162
    ValueError: 'a.b.c.d': cannot traverse path beyond this node:\
163
 'int' object is unsubscriptable
164
    >>> get_path({'a': {'b': {'c': 1}}}, 'a.b.c')
165
    1
166
    >>> get_path({'a': {'b': {'c': 1}}}, 'a.b')
167
    {'c': 1}
168
    >>> get_path({'a': [{'z': 1}]}, 'a.0')
169
    {'z': 1}
170
    >>> get_path({'a': [{'z': 1}]}, 'a.0.z')
171
    1
172
    >>> get_path({'a': [{'z': 1}]}, 'a.-1.z')
173
    1
174

  
175
    """
176
    name_path, node_path, basename = \
177
            lookup_path(container, path, sep=sep, createpath=False)
178
    name_path.append(basename)
179
    node = node_path[-1]
180

  
181
    try:
182
        return node[basename]
183
    except TypeError as e:
184
        m = "'{0}': cannot traverse path beyond this node: {1}"
185
        m = m.format(join_path(sep, name_path), str(e))
186
        raise ValueError(m)
187
    except KeyError as e:
188
        m = "'{0}': path not found: {1}"
189
        m = m.format(join_path(sep, name_path), str(e))
190
        raise KeyError(m)
191

  
192

  
193
def set_path(container, path, value, sep='.',
194
             createpath=False, overwrite=True):
195
    """
196
    container['a']['b']['c'] = value where path=sep.join(['a','b','c'])
197

  
198
    >>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.c.d', 1)
199
    Traceback (most recent call last):
200
    ValueError: 'a.b.c.d': cannot index non-object node with string
201
    >>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.x.d', 1)
202
    Traceback (most recent call last):
203
    KeyError: "'a.b.x': path not found"
204
    >>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.x.d', 1, createpath=True)
205
    
206
    >>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.c', 1)
207
    
208
    >>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.c', 1, overwrite=False)
209
    Traceback (most recent call last):
210
    ValueError: will not overwrite path 'a.b.c'
211
    >>> d = {'a': [{'z': 1}]}; set_path(d, 'a.-2.1', 2, createpath=False)
212
    Traceback (most recent call last):
213
    KeyError: "'a.-2': path not found: list index out of range"
214
    >>> d = {'a': [{'z': 1}]}; set_path(d, 'a.-2.1', 2, createpath=True)
215
    Traceback (most recent call last):
216
    ValueError: 'a.-2.1': will not index object node with integer
217
    >>> d = {'a': [{'z': 1}]}; set_path(d, 'a.-2.z', 2, createpath=True); \
218
 d['a'][-2]['z']
219
    2
220

  
221
    """
222
    name_path, node_path, basename = \
223
            lookup_path(container, path, sep=sep, createpath=createpath)
224
    name_path.append(basename)
225
    node = node_path[-1]
226

  
227
    if basename in node and not overwrite:
228
        m = "will not overwrite path '{0}'".format(path)
229
        raise ValueError(m)
230

  
231
    is_object_node = hasattr(node, 'keys')
232
    is_string_name = isinstance(basename, basestring)
233
    if not is_string_name and is_object_node:
234
        m = "'{0}': will not index object node with integer"
235
        m = m.format(join_path(sep, name_path))
236
        raise ValueError(m)
237
    if is_string_name and not is_object_node:
238
        m = "'{0}': cannot index non-object node with string"
239
        m = m.format(join_path(sep, name_path))
240
        raise ValueError(m)
241
    try:
242
        node[basename] = value
243
    except TypeError as e:
244
        m = "'{0}': cannot traverse path beyond this node: {1}"
245
        m = m.format(join_path(sep, name_path), str(e))
246
        raise ValueError(m)
247

  
248

  
249
if __name__ == '__main__':
250
    import doctest
251
    doctest.testmod()
b/snf-cyclades-app/synnefo/cyclades_settings.py
35 35

  
36 36
from django.conf import settings
37 37
from synnefo.lib import join_urls, parse_base_url
38
from synnefo.util.keypath import get_path, set_path
39 38
from synnefo.api.services import cyclades_services as vanilla_cyclades_services
40 39
from synnefo.lib.services import fill_endpoints
41 40
from astakosclient import AstakosClient
......
53 52
BASE_HOST, BASE_PATH = parse_base_url(BASE_URL)
54 53
SERVICE_TOKEN = getattr(settings, 'CYCLADES_SERVICE_TOKEN', "")
55 54

  
56
CUSTOMIZE_SERVICES = getattr(settings, 'CYCLADES_CUSTOMIZE_SERVICES', ())
57 55
cyclades_services = deepcopy(vanilla_cyclades_services)
58 56
fill_endpoints(cyclades_services, BASE_URL)
59
for path, value in CUSTOMIZE_SERVICES:
60
    set_path(cyclades_services, path, value, createpath=True)
61

  
62
COMPUTE_PREFIX = get_path(cyclades_services, 'cyclades_compute.prefix')
63
NETWORK_PREFIX = get_path(cyclades_services, 'cyclades_network.prefix')
64
VMAPI_PREFIX = get_path(cyclades_services, 'cyclades_vmapi.prefix')
65
PLANKTON_PREFIX = get_path(cyclades_services, 'cyclades_plankton.prefix')
66
HELPDESK_PREFIX = get_path(cyclades_services, 'cyclades_helpdesk.prefix')
67
UI_PREFIX = get_path(cyclades_services, 'cyclades_ui.prefix')
68
USERDATA_PREFIX = get_path(cyclades_services, 'cyclades_userdata.prefix')
69
ADMIN_PREFIX = get_path(cyclades_services, 'cyclades_admin.prefix')
57

  
58
COMPUTE_PREFIX = cyclades_services['cyclades_compute']['prefix']
59
NETWORK_PREFIX = cyclades_services['cyclades_network']['prefix']
60
VMAPI_PREFIX = cyclades_services['cyclades_vmapi']['prefix']
61
PLANKTON_PREFIX = cyclades_services['cyclades_plankton']['prefix']
62
HELPDESK_PREFIX = cyclades_services['cyclades_helpdesk']['prefix']
63
UI_PREFIX = cyclades_services['cyclades_ui']['prefix']
64
USERDATA_PREFIX = cyclades_services['cyclades_userdata']['prefix']
65
ADMIN_PREFIX = cyclades_services['cyclades_admin']['prefix']
70 66

  
71 67
COMPUTE_ROOT_URL = join_urls(BASE_URL, COMPUTE_PREFIX)
72 68

  
b/snf-cyclades-app/synnefo/quotas/resources.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from synnefo.util.keypath import get_path
35 34
from synnefo.api.services import cyclades_services
36 35

  
37 36
resources = \
38
    get_path(cyclades_services, 'cyclades_compute.resources').values() +\
39
    get_path(cyclades_services, 'cyclades_network.resources').values()
37
    cyclades_services['cyclades_compute']['resources'].values() +\
38
    cyclades_services['cyclades_network']['resources'].values()
b/snf-pithos-app/pithos/api/resources.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from synnefo.util.keypath import get_path
35 34
from pithos.api.settings import pithos_services
36 35

  
37
resources = get_path(pithos_services, 'pithos_object-store.resources').values()
36
resources = pithos_services['pithos_object-store']['resources'].values()
b/snf-pithos-app/pithos/api/settings.py
37 37
from django.conf import settings
38 38
from synnefo.lib import parse_base_url, join_urls
39 39
from synnefo.lib.services import fill_endpoints
40
from synnefo.util.keypath import get_path
41 40
from pithos.api.services import pithos_services as vanilla_pithos_services
42 41
from astakosclient import AstakosClient
43 42

  
......
59 58

  
60 59
pithos_services = deepcopy(vanilla_pithos_services)
61 60
fill_endpoints(pithos_services, BASE_URL)
62
PITHOS_PREFIX = get_path(pithos_services, 'pithos_object-store.prefix')
63
PUBLIC_PREFIX = get_path(pithos_services, 'pithos_public.prefix')
64
UI_PREFIX = get_path(pithos_services, 'pithos_ui.prefix')
61
PITHOS_PREFIX = pithos_services['pithos_object-store']['prefix']
62
PUBLIC_PREFIX = pithos_services['pithos_public']['prefix']
63
UI_PREFIX = pithos_services['pithos_ui']['prefix']
65 64
VIEW_PREFIX = join_urls(UI_PREFIX, 'view')
66 65

  
67 66

  

Also available in: Unified diff