Commit 5bcc72b0 authored by Stavros Sachtouris's avatar Stavros Sachtouris

Initial commit for snf-occi 0.3 with SOI

In version 0.3, a radically different implementation approach is
chosen. The OOI (Openstack OCCI Interface) is used as the primary
tool for processing and operating OCCI calls. The new package, SOI
(Synnefo OCCI Interface) is a wrapper of OOI. It manages the calls
to Synnefo and adjusts OOI to play with Synnefo, through patching.
parent 0822b733
......@@ -17,14 +17,14 @@ from setuptools import setup
setup(
name='snf-occi',
version='0.3',
version='0.4',
description='OCCI to Openstack/Cyclades API bridge',
url='http://code.grnet.gr/projects/snf-occi',
license='BSD',
packages=['snfOCCI', 'snfOCCI.extensions'],
license='GPLv3',
packages=['soi', ],
entry_points='''
[paste.app_factory]
snf_occi_app = snfOCCI:main
snf_occi_app=soi:main
''',
install_requires=['kamaki', 'pyssf', 'pyyaml', 'WebOb']
install_requires=['kamaki', 'ooi', ]
)
# Copyright (C) 2016 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This it the entry point for paste deploy .
Paste config file needs to point to egg:<package name>:<entrypoint name>:
use = egg:snfOCCI#sample_app
sample_app entry point is defined in setup.py:
entry_points='''
[paste.app_factory]
sample_app = soi:main
''',
which point to this function call (<module name>:function).
"""
from soi import wsgi
from soi import synnefo
# W0613:unused args
# pylint: disable=W0613
# noinspection PyUnusedLocal
def main(global_config, **settings):
"""This is the entry point for paste into the OCCI OS world."""
factory = wsgi.SNFOCCIMiddleware.factory({'openstack_version': 'v2.1'})
return factory(synnefo.call_kamaki)
# Copyright (C) 2016 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from functools import wraps
def _reavealer(f, logstr, *args, **kwargs):
"""Reveal when a method is called and finished"""
print "---> {0}".format(logstr)
try:
r = f(*args, **kwargs)
except Exception as e:
print '-X- {0}: {1}'.format(logstr, e)
raise
print "<--- {0}".format(logstr)
return r
def reveale_me(f):
"""Reveal stand alone methods"""
@wraps(f)
def wrapper(*args, **kwargs):
logstr = "{me}".format(me=f.__name__)
return _reavealer(f, logstr, *args, **kwargs)
return wrapper
def reveale_cme(f):
"""reveal class member methods"""
@wraps(f)
def wrapper(*args, **kwargs):
logstr = "{self}.{me}".format(self=args[0], me=f.__name__)
return _reavealer(f, logstr, *args, **kwargs)
return wrapper
# Copyright 2016 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, self.list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, self.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.
from soi.log import reveale_me
import json
from kamaki.clients.astakos import AstakosClient, CachedAstakosClient
from kamaki.clients.cyclades import CycladesComputeClient
from kamaki.clients.utils import https
# Constants and classes for kamaki/synnefo calls
AUTH_URL = 'https://accounts.okeanos.grnet.gr/identity/v2.0'
ADMIN_TOKEN = 'some-token'
CA_CERTS = '/etc/ssl/certs/ca-certificates.crt'
https.patch_with_certs(CA_CERTS)
auth = CachedAstakosClient(AUTH_URL, ADMIN_TOKEN)
endpoints, client_classes = {}, {}
for cls in (AstakosClient, CycladesComputeClient):
service_type = CycladesComputeClient.service_type
endpoints[service_type] = auth.get_endpoint_url(service_type)
client_classes[service_type] = cls
@reveale_me
def call_kamaki(environ, start_response, *args, **kwargs):
"""Initialize the requested kamaki client, call the requested method
:param cls: the kamaki client Class, e.g, CycladesComputeClient
:param method_name: name of the method to call, e.g. list_servers
:param args: args for the method method
:param kwargs: kwargs for the method
:returns: the response from kamaki, WSGI compliant
"""
service_type = environ.pop('service_type')
method_name = environ.pop('method_name')
kwargs = environ.pop('kwargs', {})
endpoint = endpoints[service_type]
token = environ['HTTP_X_AUTH_TOKEN']
cls = client_classes[service_type]
client = cls(endpoint, token)
method = getattr(client, method_name)
r = method(*args, **kwargs)
body = _stringify_json_values(r.json)
bodystr = json.dumps(body)
headers, key = r.headers, 'content-length'
if key in headers:
headers[key] = '{0}'.format(len(bodystr))
start_response('{0} {1}'.format(r.status_code, r.status), headers.items())
return bodystr
def _stringify_json_values(data):
"""If a sinlge value is not a string, make it"""
if isinstance(data, dict):
return dict(
map(lambda (k, v): (k, _stringify_json_values(v)), data.items()))
# new_d = dict(data)
# for k, v in data.items():
# new_d[k] = _stringify_json_values(v)
# return new_d
if isinstance(data, list):
return map(_stringify_json_values, data)
return '{0}'.format(data) if data else data
# Copyright (C) 2016 GRNET S.A.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from ooi.wsgi import OCCIMiddleware
from ooi.api.helpers import OpenStackHelper
def snf_index(cls, req):
"""Synnefo-compliant method"""
req.environ['service_type'] = 'compute'
req.environ['method_name'] = 'servers_get'
response = req.get_response(cls.app)
return cls.get_from_response(response, "servers", [])
OpenStackHelper.index = snf_index
class SNFOCCIMiddleware(OCCIMiddleware):
"""Synnefo wrapper for OCCIMiddleware"""
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment