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

Update licence and remove snfServer

parent 81d8c4c5
# Copyright (C) 2012-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 setuptools import setup
setup(
......@@ -6,10 +21,10 @@ setup(
description='OCCI to Openstack/Cyclades API bridge',
url='http://code.grnet.gr/projects/snf-occi',
license='BSD',
packages = [
packages=[
'snfOCCI', 'snfOCCI.snf_voms', 'snfOCCI.extensions', 'astavomaki'],
entry_points = '''
entry_points='''
[paste.app_factory]
snf_occi_app = snfOCCI:main
''',
)
''',
)
#!/usr/bin/env python
# Copyright (C) 2012-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/>.
import json
import uuid
......
# Copyright (C) 2012-2014 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 .
......@@ -22,9 +35,7 @@ which point to this function call (<module name>:function).
from snfOCCI import APIserver
#noinspection PyUnusedLocal
# noinspection PyUnusedLocal
def main(global_config, **settings):
"""
This is the entry point for paste into the OCCI OS world.
"""
return APIserver.MyAPP()
\ No newline at end of file
"""This is the entry point for paste into the OCCI OS world."""
return APIserver.MyAPP()
# Copyright 2012-2013 GRNET S.A. All rights reserved.
# Copyright (C) 2012-2013 GRNET S.A.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
# 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.
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
# 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.
#
# 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.
# 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 snfOCCI.config import SERVER_CONFIG
......@@ -44,7 +26,8 @@ from occi.exceptions import HTTPError
from base64 import b64encode, b64decode
import json, yaml
#Compute Backend for snf-occi-server
# Compute Backend for snf-occi-server
class MyBackend(KindBackend, ActionBackend):
......@@ -55,10 +38,10 @@ class MyBackend(KindBackend, ActionBackend):
def replace(self, old, new, extras):
raise HTTPError(501, "Replace is currently no applicable")
class SNFBackend(MixinBackend, ActionBackend):
pass
......@@ -68,9 +51,7 @@ class ComputeBackend(MyBackend):
'''
def create(self, entity, extras):
#Creating new compute instance
# Creating new compute instance
try:
snf_network = extras['snf_network']
......@@ -84,23 +65,23 @@ class ComputeBackend(MyBackend):
elif mixin.related[0].term == 'resource_tpl':
flavor = mixin
flavor_id = mixin.attributes['occi.core.id']
vm_name = entity.attributes['occi.core.title']
user_data = None
user_pub_key = None
meta_json = None
personality = []
if entity.attributes.has_key('org.openstack.compute.user_data'):
user_data = b64decode(entity.attributes['org.openstack.compute.user_data'])
#user_data = entity.attributes['org.openstack.compute.user_data']
# user_data = entity.attributes['org.openstack.compute.user_data']
if entity.attributes.has_key('org.openstack.credentials.publickey.data'):
user_pub_key = entity.attributes['org.openstack.credentials.publickey.data']
# Implementation for the meta.json file to use the respective NoCloud cloudinit driver
# if user_data and user_pub_key:
# meta_json = json.dumps({'dsmode':'net','public-keys':user_pub_key,'user-data': user_data}, sort_keys=True,indent=4, separators=(',', ': ') )
......@@ -108,7 +89,7 @@ class ComputeBackend(MyBackend):
# meta_json = json.dumps({'dsmode':'net','user-data': user_data}, sort_keys=True,indent=4, separators=(',', ': ') )
# elif user_pub_key:
# meta_json = json.dumps({'dsmode':'net','public-keys':user_pub_key}, sort_keys=True,indent=4, separators=(',', ': ') )
# if meta_json:
# print "!!!!!!!!!!!!!!!!!!!!!!!!!!!! CONTEXTUALIZATION!!!!!!!!!!!!!!!!!!!!!!"
# personality.append({'contents':b64encode(meta_json),
......@@ -116,7 +97,7 @@ class ComputeBackend(MyBackend):
# info = snf.create_server(vm_name, flavor_id, image_id,personality=personality)
# else:
# info = snf.create_server(vm_name, flavor_id, image_id)
if user_data:
#userDataDict = dict([('user-data', user_data)])
#userData = yaml.dump(userDataDict)
......@@ -125,7 +106,7 @@ class ComputeBackend(MyBackend):
pub_keyDict = dict([('public-keys',user_pub_key)])
pub_key = yaml.dump(pub_keyDict)
# kwargs = dict(project_id='6d9ec935-fcd4-4ae1-a3a0-10e612c4f867')
# kwargs = dict(project_id='6d9ec935-fcd4-4ae1-a3a0-10e612c4f867')
kwargs = dict(project_id=extras.get('snf_project', None))
if user_data and user_pub_key:
......@@ -154,7 +135,7 @@ class ComputeBackend(MyBackend):
else:
raise ce
else:
print 'Create a server with some attributes...'
print 'Create a server with some attributes...'
for retries in range(2):
try:
info = snf.create_server(vm_name, flavor_id, image_id, **kwargs)
......@@ -165,19 +146,17 @@ class ComputeBackend(MyBackend):
snf_network.create_floatingip(**kwargs)
else:
raise ce
entity.attributes['occi.compute.state'] = 'inactive'
entity.attributes['occi.core.id'] = str(info['id'])
entity.attributes['occi.compute.architecture'] = SERVER_CONFIG['compute_arch']
entity.attributes['occi.compute.cores'] = flavor.attributes['occi.compute.cores']
entity.attributes['occi.compute.memory'] = flavor.attributes['occi.compute.memory']
entity.actions = [infrastructure.STOP,
infrastructure.SUSPEND,
infrastructure.RESTART]
entity.actions = [
infrastructure.STOP,
infrastructure.SUSPEND,
infrastructure.RESTART]
# entity.attributes['occi.compute.hostname'] = SERVER_CONFIG['hostname'] % {'id':info['id']}
info['adminPass']= ""
......@@ -296,5 +275,3 @@ class ComputeBackend(MyBackend):
elif action == infrastructure.SUSPEND:
raise HTTPError(501, "This actions is currently no applicable")
......@@ -9,15 +9,15 @@ KAMAKI_CONFIG = {
'astakos_url': 'https://accounts.okeanos.grnet.gr/identity/v2.0/',
'network_url': 'https://cyclades.okeanos.grnet.gr/network/v2.0'
}
VOMS_CONFIG = {
'enable_voms' : 'True',
'voms_policy' : '/etc/snf/voms.json',
'vomsdir_path' : '/etc/grid-security/vomsdir/',
'enable_voms': 'True',
'voms_policy': '/etc/snf/voms.json',
'vomsdir_path': '/etc/grid-security/vomsdir/',
'ca_path': '/etc/grid-security/certificates/',
'cert_dir' : '/etc/ssl/certs/',
'key_dir' : '/etc/ssl/private/',
'token' : 'rCfDs3MHoh_h6ZgA7KofBfxWGOeSuXeVVJ4US21I9FM'
'cert_dir': '/etc/ssl/certs/',
'key_dir': '/etc/ssl/private/',
'token': 'rCfDs3MHoh_h6ZgA7KofBfxWGOeSuXeVVJ4US21I9FM'
}
KEYSTONE_URL = 'https://okeanos-astavoms.hellasgrid.gr'
# Copyright (C) 2012-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/>.
......@@ -12,7 +12,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# import os
from paste import deploy
from snfOCCI.config import CNF
......
......@@ -16,6 +16,7 @@
from occi.backend import ActionBackend, KindBackend, MixinBackend
from occi.exceptions import HTTPError
class NetworkBackend(KindBackend, ActionBackend):
"""Network Backend for snf-occi-server"""
def create(self, entity, extras):
......@@ -47,4 +48,3 @@ class NetworkInterfaceBackend(KindBackend):
def replace(self, old, new, extras):
raise HTTPError(501, "Currently not supported.")
# Copyright (C) 2012-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 kamaki.clients.compute import ComputeClient
from kamaki.clients.cyclades import CycladesClient
from kamaki.cli.config import Config
from kamaki.cli.config import Config
from occi import registry
from occi.core_model import Mixin
from occi.backend import MixinBackend
from occi.extensions.infrastructure import RESOURCE_TEMPLATE, OS_TEMPLATE
class snfRegistry(registry.NonePersistentRegistry):
def add_resource(self, key, resource, extras):
......@@ -17,4 +33,5 @@ class snfRegistry(registry.NonePersistentRegistry):
super(snfRegistry, self).add_resource(key, resource, extras)
def set_hostname(self, hostname):
super(snfRegistry, self).set_hostname("https://okeanos-occi2.hellasgrid.gr:9000")
super(snfRegistry, self).set_hostname(
"https://okeanos-occi2.hellasgrid.gr:9000")
import functools
import os
import logging
LOG = logging.getLogger(__name__)
__all__ = ['Server', 'httplib', 'subprocess']
_configured = False
Server = None
httplib = None
subprocess = None
def configure_once(name):
"""Ensure that environment configuration is only run once.
If environment is reconfigured in the same way then it is ignored.
It is an error to attempt to reconfigure environment in a different way.
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
global _configured
if _configured:
if _configured == name:
return
else:
raise SystemError("Environment has already been "
"configured as %s" % _configured)
LOG.info(_("Environment configured as: %s"), name)
_configured = name
return func(*args, **kwargs)
return wrapper
return decorator
@configure_once('eventlet')
def use_eventlet(monkeypatch_thread=None):
global httplib, subprocess, Server
import eventlet
from eventlet.green import httplib as _httplib
from eventlet.green import subprocess as _subprocess
from snfOCCI.snfServer import ssl_server
if monkeypatch_thread is None:
monkeypatch_thread = not os.getenv('STANDARD_THREADS')
eventlet.patcher.monkey_patch(all=False, socket=True, time=True,
thread=monkeypatch_thread)
Server = ssl_server.Server
httplib = _httplib
subprocess = _subprocess
@configure_once('stdlib')
def use_stdlib():
global httplib, subprocess
import httplib as _httplib
import subprocess as _subprocess
httplib = _httplib
subprocess = _subprocess
'''
Created on Aug 22, 2013
@author: nassia
'''
import eventlet
from eventlet import wsgi
from logging import getLogger
import ssl
import sys
import socket
import greenlet
import logging
#LOG = getLogger(__name__)
class Server(object):
"""Server class to manage multiple WSGI sockets and applications."""
def __init__(self, application, host=None, port=None, threads=1000):
self.application = application
self.host = host or '0.0.0.0'
self.port = port or 0
self.pool = eventlet.GreenPool(threads)
self.socket_info = {}
self.greenthread = None
self.do_ssl = False
self.cert_required = False
def start(self, key=None, backlog=128):
"""Run a WSGI server with the given application."""
# LOG.debug(('Starting %(arg0)s on %(host)s:%(port)s') %
print (('Starting %(arg0)s on %(host)s:%(port)s') %
{'arg0': sys.argv[0],
'host': self.host,
'port': self.port})
# TODO(dims): eventlet's green dns/socket module does not actually
# support IPv6 in getaddrinfo(). We need to get around this in the
# future or monitor upstream for a fix
info = socket.getaddrinfo(self.host,
self.port,
socket.AF_UNSPEC,
socket.SOCK_STREAM)[0]
_socket = eventlet.listen(info[-1],
family=info[0],
backlog=backlog)
if key:
self.socket_info[key] = _socket.getsockname()
# SSL is enabled
if self.do_ssl:
if self.cert_required:
cert_reqs = ssl.CERT_REQUIRED
else:
cert_reqs = ssl.CERT_NONE
sslsocket = eventlet.wrap_ssl(_socket, certfile=self.certfile,
keyfile=self.keyfile,
server_side=True,
cert_reqs=cert_reqs,
ca_certs=self.ca_certs)
_socket = sslsocket
self.greenthread = self.pool.spawn(self._run,
self.application,
_socket)
def set_ssl(self, certfile, keyfile=None, ca_certs=None,
cert_required=True):
self.certfile = certfile
self.keyfile = keyfile
self.ca_certs = ca_certs
self.cert_required = cert_required
self.do_ssl = True
print certfile, keyfile, ca_certs, cert_required
def kill(self):
if self.greenthread:
self.greenthread.kill()
def wait(self):
"""Wait until all servers have completed running."""
try:
self.pool.waitall()
except KeyboardInterrupt:
pass
except greenlet.GreenletExit:
pass
def _run(self, application, socket):
"""Start a WSGI server in a new green thread."""
print "IN HERE!!!!"
log = getLogger('eventlet.wsgi.server')
try:
eventlet.wsgi.server(socket, application, custom_pool=self.pool,
log = logging.basicConfig())
except Exception:
#LOG.exception(('Server error'))
print "Server error"
raise
# Copyright (C) 2013-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/>.
'''
Created on Jul 31, 2013
......@@ -15,7 +30,7 @@ from astavomaki.client import AstavomsClient
# import saferun
LOG = getLogger(__name__)
LOG = getLogger(__name__)
# Environment variable used to pass the request context
......@@ -31,7 +46,7 @@ VOMS_POLICY = "/etc/snf/voms.json"
VOMSDIR_PATH = "/etc/grid-security/vomsdir/"
CA_PATH = "/etc/grid-security/certificates/"
VOMSAPI_LIB = "/usr/lib/libvomsapi.so.1"
#VOMSAPI_LIB = "voms.x86_64 0:2.0.10-3.el6"
# VOMSAPI_LIB = "voms.x86_64 0:2.0.10-3.el6"
AUTOCREATE_USERS = False
PARAMS_ENV = 'snf_voms.params'
......@@ -39,36 +54,6 @@ ASTAVOMS_URL = 'https://okeanos-astavoms.hellasgrid.gr'
ASTAVOMS_TOKEN = 'Nothing for now'
#saferun.logger.setLevel(DEBUG)
#@saferun.saferun
#def test_and_log_astavoms(ssl_certs):
# astavoms = AstavomsClient(ASTAVOMS_URL, ASTAVOMS_TOKEN)
# saferun.logger.info('LALA 1')
# astavoms.astacert = '/etc/grid-security/certificates/TERENA-eScience-SSL-CA-3.pem'
# saferun.logger.info('LALA 2')
# saferun.logger.info('Authenticate this: {certs}'.format(certs=ssl_certs))
# saferun.logger.info('LALA 3')
# # Not tryied that yet, do it next
# from kamaki.clients.utils import https
# #https.patch_with_certs(CA_PATH)
# https.patch_ignore_ssl()
# r = astavoms.authenticate(**ssl_certs)
# from kamaki.clients.utils import https
# saferun.logger.info('SAFERUN RESPONSE: {0}'.format(json.dumps(r, indent=2)))
# return r
#@saferun.saferun
#def compare_results(old, new):
# saferun.logger.info('OLD: {old}\nNEW:{new}'.format(old=old, new=new))
# keydiff = set(old).symmetric_difference(new)
# saferun.logger.info('KEY DIFF: %s', keydiff)
# for k in set(old).intersection(new):
# ov, nv = old[k], new[k]
# msg = ' OK' if ov == nv else ' diff: %s != %s' % (ov, nv)
# saferun.logger.info('Check key %s ... %s' % (k, msg))
class VomsError():
"""Voms credential management error"""
......@@ -113,12 +98,13 @@ class VomsError():
self.code = code
self.title = title
class VomsAuthN():
"""Filter that checks for the SSL data in the reqest.
Sets 'ssl' in the context as a dictionary containing this data.
"""
def __init__(self, *args, **kwargs):
self.astavoms = AstavomsClient(ASTAVOMS_URL, ASTAVOMS_TOKEN)
# VOMS stuff
......@@ -134,7 +120,7 @@ class VomsAuthN():
'No loading of VOMS json file',
details='The VOMS json file located in %s was not loaded (%s:, e)' % (
VOMS_POLICY, type(e), e))
self._no_verify = False
#super(VomsAuthN, self).__init__(*args, **kwargs)
......@@ -151,14 +137,14 @@ class VomsAuthN():
def _get_voms_info(self, ssl_info):
"""Extract voms info from ssl_info and return dict with it."""
# Use astavoms instead of doing it by yourself
# astaresults = test_and_log_astavoms(ssl_info)
# Use astavoms instead of doing it by yourself
# astaresults = test_and_log_astavoms(ssl_info)
from kamaki.clients.utils import https
https.patch_ignore_ssl()
return self.astavoms.authenticate(**ssl_info)
# STOP HERE
# STOP HERE
# Keep this until verification is supported in astavoms
try:
cert, chain = self._get_cert_chain(ssl_info)
......@@ -167,15 +153,14 @@ class VomsAuthN():
'SSL data not verified',
details=CONTEXT_ENV)
with voms_helper.VOMS(VOMSDIR_PATH,
CA_PATH, VOMSAPI_LIB) as v:
if self._no_verify:
v.set_no_verify()
voms_data = v.retrieve(cert, chain)
if not voms_data:
# TODO(aloga): move this to a keystone exception
raise VomsError(v.error.value)
......@@ -195,7 +180,7 @@ class VomsAuthN():
break
d["fqans"].append(fqan)
# compare_results(d, astaresults)
# compare_results(d, astaresults)
return d
......@@ -210,9 +195,9 @@ class VomsAuthN():
role = l.pop().split("=")[-1]
vogroup = "/".join(l)
return (vogroup, role, capability)
def _process_environ(self, environ):
LOG.warning("Getting the environment parameters...")
# the environment variable CONTENT_LENGTH may be empty or missing
try:
......@@ -222,9 +207,9 @@ class VomsAuthN():
raise ClientError(
'Not auth method provided',
details='The request body is empty, while it should contain the authentication method')
request_body = environ['wsgi.input'].read(request_body_size)
# print request_body
request_body = request_body.replace("true","\"true\"")
request_body = request_body.replace('"','\'' )
......@@ -242,8 +227,7 @@ class VomsAuthN():
if k.startswith('_'):
continue
params[k] = v
environ[PARAMS_ENV] = params
# print environ[PARAMS_ENV]
......@@ -258,12 +242,12 @@ class VomsAuthN():
return True
else:
raise ClientError(
'Error in json',
details='Error in JSON, voms must be set to true')
'Error in json',
details='Error in JSON, voms must be set to true')
return False
def authenticate(self,ssl_data):
def authenticate(self, ssl_data):
try:
voms_info = self._get_voms_info(ssl_data)
......@@ -271,13 +255,12 @@ class VomsAuthN():
raise e
user_dn = voms_info["user"]
user_vo = voms_info["voname"]
user_fqans = voms_info["fqans"]
user_fqans = voms_info["fqans"]
return (
user_dn, user_vo, user_fqans, voms_info['snf:token'],
voms_info['snf:project'])
def process_request(self, environ):
print "Inside process_request!!!!"
if not self.is_applicable(environ):
......@@ -295,16 +278,15 @@ class VomsAuthN():
voms_info = self._get_voms_info(ssl_dict)
params = environ[PARAMS_ENV]
params = environ[PARAMS_ENV]
tenant_from_req = params["auth"].get("tenantName", None)