Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
itminedu
synnefo
Commits
c7efef71
Commit
c7efef71
authored
May 31, 2013
by
Georgios D. Tsoukalas
Browse files
astakosclient: add service catalog
parent
76275e79
Changes
4
Hide whitespace changes
Inline
Side-by-side
astakosclient/astakosclient/__init__.py
View file @
c7efef71
...
...
@@ -43,6 +43,11 @@ from astakosclient.utils import \
from
astakosclient.errors
import
\
AstakosClientException
,
Unauthorized
,
BadRequest
,
NotFound
,
Forbidden
,
\
NoUserName
,
NoUUID
,
BadValue
,
QuotaLimit
,
InvalidResponse
from
.keypath
import
get_path
from
.services
import
astakos_services
# Customize astakos_services here?
def
join_urls
(
a
,
b
):
...
...
@@ -51,7 +56,7 @@ def join_urls(a, b):
# --------------------------------------------------------------------
# Astakos API urls
ACCOUNTS_PREFIX
=
'accounts'
ACCOUNTS_PREFIX
=
get_path
(
astakos_services
,
'astakos_account.prefix'
)
API_AUTHENTICATE
=
join_urls
(
ACCOUNTS_PREFIX
,
"authenticate"
)
API_USERCATALOGS
=
join_urls
(
ACCOUNTS_PREFIX
,
"user_catalogs"
)
API_SERVICE_USERCATALOGS
=
join_urls
(
ACCOUNTS_PREFIX
,
"service/user_catalogs"
)
...
...
@@ -65,7 +70,7 @@ API_FEEDBACK = join_urls(ACCOUNTS_PREFIX, "feedback")
# --------------------------------------------------------------------
# Astakos Keystone API urls
KEYSTONE_PREFIX
=
'keystone'
KEYSTONE_PREFIX
=
get_path
(
astakos_services
,
'astakos_keystone.prefix'
)
API_TOKENS
=
join_urls
(
KEYSTONE_PREFIX
,
"tokens"
)
TOKENS_ENDPOINTS
=
join_urls
(
API_TOKENS
,
"endpoints"
)
...
...
astakosclient/astakosclient/keypath.py
0 → 100644
View file @
c7efef71
# Copyright 2012, 2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
def
dict_merge
(
a
,
b
):
"""
http://www.xormedia.com/recursively-merge-dictionaries-in-python/
"""
if
not
isinstance
(
b
,
dict
):
return
b
result
=
copy
.
deepcopy
(
a
)
for
k
,
v
in
b
.
iteritems
():
if
k
in
result
and
isinstance
(
result
[
k
],
dict
):
result
[
k
]
=
dict_merge
(
result
[
k
],
v
)
else
:
result
[
k
]
=
copy
.
deepcopy
(
v
)
return
result
def
lookup_path
(
container
,
path
,
sep
=
'.'
,
createpath
=
False
):
"""
return (['a','b'],
[container['a'], container['a']['b']],
'c') where path=sep.join(['a','b','c'])
"""
names
=
path
.
split
(
sep
)
dirnames
=
names
[:
-
1
]
basename
=
names
[
-
1
]
node
=
container
name_path
=
[]
node_path
=
[
node
]
for
name
in
dirnames
:
name_path
.
append
(
name
)
if
name
not
in
node
:
if
not
createpath
:
m
=
"'{0}': path not found"
.
format
(
sep
.
join
(
name_path
))
raise
KeyError
(
m
)
node
[
name
]
=
{}
try
:
node
=
node
[
name
]
except
TypeError
as
e
:
m
=
"'{0}': cannot traverse path beyond this node: {1}"
m
=
m
.
format
(
sep
.
join
(
name_path
),
str
(
e
))
raise
ValueError
(
m
)
node_path
.
append
(
node
)
return
name_path
,
node_path
,
basename
def
walk_paths
(
container
):
for
name
,
node
in
container
.
iteritems
():
if
not
hasattr
(
node
,
'items'
):
yield
[
name
],
[
node
]
else
:
for
names
,
nodes
in
walk_paths
(
node
):
yield
[
name
]
+
names
,
[
node
]
+
nodes
def
list_paths
(
container
,
sep
=
'.'
):
"""
>>> sorted(list_paths({'a': {'b': {'c': 'd'}}}))
[('a.b.c', 'd')]
>>> sorted(list_paths({'a': {'b': {'c': 'd'}, 'e': 3}}))
[('a.b.c', 'd'), ('a.e', 3)]
>>> sorted(list_paths({'a': {'b': {'c': 'd'}, 'e': {'f': 3}}}))
[('a.b.c', 'd'), ('a.e.f', 3)]
>>> list_paths({})
[]
"""
return
[(
sep
.
join
(
name_path
),
node_path
[
-
1
])
for
name_path
,
node_path
in
walk_paths
(
container
)]
def
del_path
(
container
,
path
,
sep
=
'.'
,
collect
=
True
):
"""
del container['a']['b']['c'] where path=sep.join(['a','b','c'])
>>> d = {'a': {'b': {'c': 'd'}}}; del_path(d, 'a.b.c'); d
{}
>>> d = {'a': {'b': {'c': 'd'}}}; del_path(d, 'a.b.c', collect=False); d
{'a': {'b': {}}}
>>> d = {'a': {'b': {'c': 'd'}}}; del_path(d, 'a.b.c.d')
Traceback (most recent call last):
ValueError: 'a.b.c': cannot traverse path beyond this node:
\
'str' object does not support item deletion
"""
name_path
,
node_path
,
basename
=
\
lookup_path
(
container
,
path
,
sep
=
sep
,
createpath
=
False
)
lastnode
=
node_path
.
pop
()
lastname
=
basename
try
:
if
basename
in
lastnode
:
del
lastnode
[
basename
]
except
(
TypeError
,
KeyError
)
as
e
:
m
=
"'{0}': cannot traverse path beyond this node: {1}"
m
=
m
.
format
(
sep
.
join
(
name_path
),
str
(
e
))
raise
ValueError
(
m
)
if
collect
:
while
node_path
and
not
lastnode
:
basename
=
name_path
.
pop
()
lastnode
=
node_path
.
pop
()
del
lastnode
[
basename
]
def
get_path
(
container
,
path
,
sep
=
'.'
):
"""
return container['a']['b']['c'] where path=sep.join(['a','b','c'])
>>> get_path({'a': {'b': {'c': 'd'}}}, 'a.b.c.d')
Traceback (most recent call last):
ValueError: 'a.b.c.d': cannot traverse path beyond this node:
\
string indices must be integers, not str
>>> get_path({'a': {'b': {'c': 1}}}, 'a.b.c.d')
Traceback (most recent call last):
ValueError: 'a.b.c.d': cannot traverse path beyond this node:
\
'int' object is unsubscriptable
>>> get_path({'a': {'b': {'c': 1}}}, 'a.b.c')
1
>>> get_path({'a': {'b': {'c': 1}}}, 'a.b')
{'c': 1}
"""
name_path
,
node_path
,
basename
=
\
lookup_path
(
container
,
path
,
sep
=
sep
,
createpath
=
False
)
name_path
.
append
(
basename
)
node
=
node_path
[
-
1
]
try
:
return
node
[
basename
]
except
TypeError
as
e
:
m
=
"'{0}': cannot traverse path beyond this node: {1}"
m
=
m
.
format
(
sep
.
join
(
name_path
),
str
(
e
))
raise
ValueError
(
m
)
except
KeyError
as
e
:
m
=
"'{0}': path not found: {1}"
m
=
m
.
format
(
sep
.
join
(
name_path
),
str
(
e
))
raise
KeyError
(
m
)
def
set_path
(
container
,
path
,
value
,
sep
=
'.'
,
createpath
=
False
,
overwrite
=
True
):
"""
container['a']['b']['c'] = value where path=sep.join(['a','b','c'])
>>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.c.d', 1)
Traceback (most recent call last):
ValueError: 'a.b.c.d': cannot traverse path beyond this node:
\
'str' object does not support item assignment
>>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.x.d', 1)
Traceback (most recent call last):
KeyError: "'a.b.x': path not found"
>>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.x.d', 1, createpath=True)
>>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.c', 1)
>>> set_path({'a': {'b': {'c': 'd'}}}, 'a.b.c', 1, overwrite=False)
Traceback (most recent call last):
ValueError: will not overwrite path 'a.b.c'
"""
name_path
,
node_path
,
basename
=
\
lookup_path
(
container
,
path
,
sep
=
sep
,
createpath
=
createpath
)
name_path
.
append
(
basename
)
node
=
node_path
[
-
1
]
if
basename
in
node
and
not
overwrite
:
m
=
"will not overwrite path '{0}'"
.
format
(
path
)
raise
ValueError
(
m
)
try
:
node
[
basename
]
=
value
except
TypeError
as
e
:
m
=
"'{0}': cannot traverse path beyond this node: {1}"
m
=
m
.
format
(
sep
.
join
(
name_path
),
str
(
e
))
raise
ValueError
(
m
)
if
__name__
==
'__main__'
:
import
doctest
doctest
.
testmod
()
astakosclient/astakosclient/services.py
0 → 100644
View file @
c7efef71
# Copyright (C) 2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
astakos_services
=
{
'astakos_account'
:
{
'type'
:
'account'
,
'component'
:
'astakos'
,
'prefix'
:
'account'
,
'public'
:
True
,
'endpoints'
:
[
{
'version'
:
'v1.0'
,
'publicURL'
:
None
},
]},
'astakos_keystone'
:
{
'type'
:
'identity'
,
'component'
:
'astakos'
,
'prefix'
:
'identity'
,
'public'
:
True
,
'endpoints'
:
[
{
'version'
:
'v2.0'
,
'publicURL'
:
None
},
]},
'astakos_ui'
:
{
'type'
:
'astakos_ui'
,
'component'
:
'astakos'
,
'prefix'
:
'ui'
,
'public'
:
False
,
'endpoints'
:
[
{
'version'
:
'v1.0'
,
'publicURL'
:
None
},
]},
}
snf-cyclades-app/synnefo/cyclades_settings.py
View file @
c7efef71
...
...
@@ -35,29 +35,22 @@ from django.conf import settings
from
synnefo.lib
import
join_urls
,
parse_base_url
from
synnefo.util.keypath
import
get_path
from
synnefo.api.services
import
cyclades_services
as
vanilla_cyclades_services
from
astakosclient
import
astakos_services
as
vanilla_astakos_services
from
astakosclient
import
astakos_services
from
copy
import
deepcopy
# Process Cyclades settings
BASE_URL
=
getattr
(
settings
,
'CYCLADES_BASE_URL'
,
'https://compute.example.synnefo.org/compute/'
)
BASE_HOST
,
BASE_PATH
=
parse_base_url
(
BASE_URL
)
ASTAKOS_BASE_URL
=
getattr
(
settings
,
'ASTAKOS_BASE_URL'
,
'https://accounts.example.synnefo.org/astakos/'
)
ASTAKOS_BASE_HOST
,
ASTAKOS_BASE_PATH
=
parse_base_url
(
ASTAKOS_BASE_URL
)
CUSTOMIZE_SERVICES
=
getattr
(
settings
,
'CYCLADES_CUSTOMIZE_SERVICES'
,
())
cyclades_services
=
deepcopy
(
vanilla_cyclades_services
)
for
path
,
value
in
CUSTOMIZE_SERVICES
:
set_path
(
cyclades_services
,
path
,
value
,
createpath
=
True
)
astakos_services
=
deepcopy
(
vanilla_astakos_services
)
CUSTOMIZE_ASTAKOS_SERVICES
=
\
getattr
(
settings
,
'CYCLADES_CUSTOMIZE_ASTAKOS_SERVICES'
,
())
for
path
,
value
in
CUSTOMIZE_ASTAKOS_SERVICES
:
set_path
(
astakos_services
,
path
,
value
,
createpath
=
True
)
COMPUTE_PREFIX
=
get_path
(
cyclades_services
,
'cyclades_compute.prefix'
)
VMAPI_PREFIX
=
get_path
(
cyclades_services
,
'cyclades_vmapi.prefix'
)
PLANKTON_PREFIX
=
get_path
(
cyclades_services
,
'cyclades_plankton.prefix'
)
...
...
@@ -65,13 +58,28 @@ HELPDESK_PREFIX = get_path(cyclades_services, 'cyclades_helpdesk.prefix')
UI_PREFIX
=
get_path
(
cyclades_services
,
'cyclades_ui.prefix'
)
USERDATA_PREFIX
=
get_path
(
cyclades_services
,
'cyclades_userdata.prefix'
)
COMPUTE_ROOT_URL
=
join_urls
(
BASE_URL
,
COMPUTE_PREFIX
)
# Process Astakos settings
ASTAKOS_BASE_URL
=
getattr
(
settings
,
'ASTAKOS_BASE_URL'
,
'https://accounts.example.synnefo.org/astakos/'
)
ASTAKOS_BASE_HOST
,
ASTAKOS_BASE_PATH
=
parse_base_url
(
ASTAKOS_BASE_URL
)
# Patch astakosclient directly, otherwise it will not see any customization
#astakos_services = deepcopy(vanilla_astakos_services)
CUSTOMIZE_ASTAKOS_SERVICES
=
\
getattr
(
settings
,
'CYCLADES_CUSTOMIZE_ASTAKOS_SERVICES'
,
())
for
path
,
value
in
CUSTOMIZE_ASTAKOS_SERVICES
:
set_path
(
astakos_services
,
path
,
value
,
createpath
=
True
)
ASTAKOS_ACCOUNTS_PREFIX
=
get_path
(
astakos_services
,
'astakos_account.prefix'
)
ASTAKOS_VIEWS_PREFIX
=
get_path
(
astakos_services
,
'astakos_ui.prefix'
)
ASTAKOS_KEYSTONE_PREFIX
=
get_path
(
astakos_services
,
'astakos_keystone.prefix'
)
# The API implementation needs to accept and return absolute references
# to its resources. Thus, it needs to know its public URL.
COMPUTE_ROOT_URL
=
join_urls
(
BASE_URL
,
COMPUTE_PREFIX
)
# Proxy Astakos settings
BASE_ASTAKOS_PROXY_PATH
=
getattr
(
settings
,
'CYCLADES_BASE_ASTAKOS_PROXY_PATH'
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment