Commit a85c7fad authored by Kostas Papadimitriou's avatar Kostas Papadimitriou

Initial commit for snf-webproject

- new package snf-webproject
- moved basic django related settings in snf-webproject
- added new entry point utils to ease the extension mechanism of
  snf-webproject (urlpatterns, middleware, static_files, installed_apps)
- setup.py changes to keep up with the new entry points
parent b479b82a
......@@ -203,8 +203,10 @@ setup(
'snf-cloud = synnefo.tools.cloud:main',
],
'synnefo': [
'settings = synnefo.app_settings',
'apps = synnefo.app_settings:getapps',
'default_settings = synnefo.app_settings.default',
'web_apps = synnefo.app_settings:synnefo_web_apps',
'web_middleware = synnefo.app_settings:synnefo_web_middleware',
'urls = synnefo.app_settings.urls:urlpatterns',
]
},
)
......
# Copyright 2011 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.
# this is a namespace package
try:
import pkg_resources
......
from synnefo.app_settings.default import *
synnefo_web_apps = [
'synnefo.aai',
'synnefo.admin',
'synnefo.api',
'synnefo.ui',
'synnefo.db',
'synnefo.logic',
'synnefo.invitations',
'synnefo.helpdesk',
'synnefo.plankton',
'synnefo.ui.userdata',
]
def getapps():
return INSTALLED_APPS
synnefo_web_middleware = [
{'after': 'django.middleware.locale.LocaleMiddleware', 'insert': [
'synnefo.aai.middleware.SynnefoAuthMiddleware',
'synnefo.api.middleware.ApiAuthMiddleware',
'synnefo.helpdesk.middleware.HelpdeskMiddleware'
]
}
]
......@@ -31,13 +31,7 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from synnefo.app_settings.default.admins import *
from synnefo.app_settings.default.apps import *
from synnefo.app_settings.default.deploy import *
from synnefo.app_settings.default.logging import *
from synnefo.app_settings.default.site import *
from synnefo.app_settings.default.backend import *
from synnefo.app_settings.default.database import *
from synnefo.app_settings.default.queues import *
from synnefo.app_settings.default.api import *
from synnefo.app_settings.default.plankton import *
......
# -*- coding: utf-8 -*-
from synnefo.util.entry_points import extend_list_from_entry_point
#
# AAI configuration
#####################
......@@ -23,3 +24,5 @@ BYPASS_AUTHENTICATION_SECRET_TOKEN = '5e41595e9e884543fa048e07c1094d74'
# Urls that bypass Shibboleth authentication
AAI_SKIP_AUTH_URLS = ['/api', '/plankton', '/invitations/login']
AAI_SKIP_AUTH_URLS = extend_list_from_entry_point(AAI_SKIP_AUTH_URLS, \
'synnefo', 'web_skip_urls')
......@@ -3,12 +3,12 @@
# UI settings
###################
from admins import *
from site import *
from synnefo.webproject.settings.default.site import *
from synnefo.settings.default.admins import *
# base url for ui static files
# if not set, defaults to MEDIA_URL + 'snf-<latest_ui_version>/'
UI_MEDIA_URL = MEDIA_URL + 'snf/'
UI_MEDIA_URL = '/ui/static/' + 'snf/'
# UI requests to the API layer time out after that many milliseconds
TIMEOUT = 10 * 1000
......
# Copyright 2011 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
......@@ -25,7 +25,7 @@
# 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
......@@ -33,13 +33,12 @@
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^', include('synnefo.ui.urls')),
(r'^admin', include('synnefo.admin.urls')),
(r'^ui/', include('synnefo.ui.urls')),
(r'^admin/', include('synnefo.admin.urls')),
(r'^api/', include('synnefo.api.urls')),
(r'^helpdesk/?', include('synnefo.helpdesk.urls')),
(r'^plankton/', include('synnefo.plankton.urls')),
(r'^invitations/?', include('synnefo.invitations.urls')),
(r'^lang/$', 'synnefo.ui.i18n.set_language')
)
......@@ -42,7 +42,7 @@ from synnefo.util.entry_points import extend_settings
from synnefo.settings.default import *
# autodetect default settings provided by synnefo applications
extend_settings('synnefo', __name__)
extend_settings(__name__, 'synnefo')
# extend default settings with settings provided within *.conf user files
# located in directory specified in the SYNNEFO_SETTINGS_DIR
......@@ -55,7 +55,7 @@ if os.path.exists(SYNNEFO_SETTINGS_DIR):
try:
execfile(os.path.abspath(f))
except Exception as e:
print >>sys.stderr, "Failed to read settings file: %s" % \
os.path.abspath(f)
print >>sys.stderr, "Failed to read settings file: %s [%s]" % \
(os.path.abspath(f), e)
from synnefo.settings.default.admins import *
from synnefo.settings.default.logging import *
from synnefo.settings.default.database import *
# Copyright 2011 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.
import sys
import pkg_resources
import inspect
import types
def get_entry_ponts(ns, name):
def get_entry_points(ns, name):
for entry_point in pkg_resources.iter_entry_points(group=ns):
if entry_point.name == name:
yield entry_point
def extend_settings(ns, module_name):
def extend_module(module_name, attrs):
module = sys.modules[module_name]
for k,v in attrs.iteritems():
setattr(module, k, v)
def entry_point_to_object(ep):
object_or_func = ep.load()
# user defined entry point is a function
# get the return value
obj = object_or_func
if hasattr(object_or_func, '__call__'):
obj = object_or_func()
if type(obj) == types.ModuleType:
dct = {}
for k in dir(obj):
if k.startswith("__"):
continue
dct[k] = getattr(obj, k)
obj = dct
return obj
def extend_module_from_entry_point(module_name, ns):
"""
Extend module from entry_point hooks
Extend a settings module from entry_point hooks
"""
settings = sys.modules[module_name]
# apps hook
app_entry_points = get_entry_ponts(ns, 'apps')
# settings hook
settings_entry_points = get_entry_ponts(ns, 'settings')
# extend INSTALLED_APPS setting
NEW_INSTALLED_APPS = list(getattr(settings, 'INSTALLED_APPS', []));
# if failed to execute app hook as function parse it as string
# synnefo.app:get_additional_apps or app1,app2,app3
for e in app_entry_points:
try:
NEW_INSTALLED_APPS = list(e.load()())
except Exception, ex:
NEW_INSTALLED_APPS = NEW_INSTALLED_APPS + \
e.module_name.split(",")
# extend additional settings
# TODO: existing settings logic ??
for e in settings_entry_points:
module = e.load()
for k in dir(module):
if k == k.upper():
setattr(settings, k, getattr(module, k))
setattr(settings, 'INSTALLED_APPS', NEW_INSTALLED_APPS)
for e in get_entry_points(ns, 'default_settings'):
extend_module(module_name, entry_point_to_object(e))
def extend_dict_from_entry_point(settings_object, ns, entry_point_name):
for e in get_entry_points(ns, entry_point_name):
settings_object.update(entry_point_to_object(e))
return settings_object
def extend_list_from_entry_point(settings_object, ns, entry_point_name,
unique=True):
settings_object = list(settings_object)
for e in get_entry_points(ns, entry_point_name):
obj = entry_point_to_object(e)
for row in obj:
if type(row) == dict and (row.get('before', False) or \
row.get('after', False)):
if row.get('before', False):
position = settings_object.index(row.get('before'))
insert_at = position - 1
else:
position = settings_object.index(row.get('after'))
insert_at = position + 1
if insert_at < 0:
insert_at = 0
inserts = row.get('insert', [])
if not type(inserts) == list:
inserts = [inserts]
for entry in inserts:
if not entry in settings_object:
settings_object.insert(insert_at, entry)
insert_at = insert_at + 1
else:
settings_object.append(row)
return settings_object
def extend_settings(mname, ns):
extend_module_from_entry_point(mname, ns)
def extend_urls(patterns, ns):
for e in get_entry_points(ns, 'urls'):
patterns += e.load()
return patterns
synnefo_web_apps = ['okeanos_site']
synnefo_static_files = {'okeanos_site': ''}
synnefo_skip_urls = ['/about', '/intro', '/okeanos_static']
# extend specific synnefo default settings
from synnefo.app_settings import *
# extend static files map
STATIC_FILES['okeanos_site'] = ''
# append okeanos_site application to django installed apps
INSTALLED_APPS = list(INSTALLED_APPS) + ['okeanos_site']
# invitations only, no login page exists
# redirect client to the intro page
LOGIN_URL = "http://okeanos.grnet.gr/intro"
# redirect to login url (intro) on user logout
LOGOUT_URL = LOGIN_URL
# bypass Shibboleth authentication for /okeanos and /intro pages
# (they should be available to the public)
AAI_SKIP_AUTH_URLS = list(AAI_SKIP_AUTH_URLS) + ['/about', '/intro', '/okeanos_static']
# change django url configuration
# okeanos_site.urls includes and extends/modifies synnefo.urls
# based on the needs of okeanos aplha release
ROOT_URLCONF = 'okeanos_site.urls'
# the url that is linked with okenaos_site.views.index view
OKEANOS_SITE_URL = "/about"
......@@ -50,3 +25,4 @@ OKEANOS_VIDEO_POSTER_IMAGE_URL = "/intro_video/intro_video.png"
#
# flowplayer.controls swf should be placed on the same url as flowplayer swf
OKEANOS_VIDEO_FLOWPLAYER_URL = "http://okeanos.grnet.gr/intro_video/flowplayer-3.2.1.swf"
......@@ -3,8 +3,6 @@ import os
from django.conf.urls.defaults import *
from django.conf import settings
from synnefo.urls import urlpatterns as synnefo_urls
urlpatterns = patterns('',
# change app url from root (/) to (/ui)
......@@ -17,12 +15,8 @@ urlpatterns = patterns('',
# video/info page
url(r'^about$', 'okeanos_site.views.index', name='okeanos_index'),
)
urlpatterns += synnefo_urls
urlpatterns += patterns('',
url(r'^okeanos_static/(.*)$', 'django.views.static.serve',
{'document_root': os.path.join(os.path.dirname(__file__), 'static/okeanos_static')}),
......
......@@ -62,8 +62,10 @@ setup(
entry_points = {
'synnefo': [
'settings = okeanos_site.settings',
'apps = okeanos_site'
'default_settings = okeanos_site.settings',
'web_apps = okeanos_site:synnefo_web_apps',
'web_static = okeanos_site:synnefo_static_files',
'urls = okeanos_site.urls:urlpatterns'
]
},
......
Changelog
=========
Synnefo web project
===================
A synnefo helper package to ease up the deployment of synnefo components.
The package wraps a django project which extends itself (urls, default_settings,
installed_apps, middleware_classes) based on the synnefo components/packages
installed on the system.
The extending mechanism is based on the python setuptools `entry_points`. So
if an application (synnefo component) wants to plug additional configuration
to the django project it should define within its setup.py file the 'synnefo'
appropriate entry_points.
For usage example please take a look how snf-app package defines its entry
points in:
- snf-app/setup.py
- snf-app/app_settings/__init__.py
#!python
"""Bootstrap distribute installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from distribute_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import os
import sys
import time
import fnmatch
import tempfile
import tarfile
from distutils import log
try:
from site import USER_SITE
except ImportError:
USER_SITE = None
try:
import subprocess
def _python_cmd(*args):
args = (sys.executable,) + args
return subprocess.call(args) == 0
except ImportError:
# will be used for python 2.3
def _python_cmd(*args):
args = (sys.executable,) + args
# quoting arguments if windows
if sys.platform == 'win32':
def quote(arg):
if ' ' in arg:
return '"%s"' % arg
return arg
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
DEFAULT_VERSION = "0.6.10"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
SETUPTOOLS_PKG_INFO = """\
Metadata-Version: 1.0
Name: setuptools
Version: %s
Summary: xxxx
Home-page: xxx
Author: xxx
Author-email: xxx
License: xxx
Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
def _install(tarball):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# installing
log.warn('Installing Distribute')
if not _python_cmd('setup.py', 'install'):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
finally:
os.chdir(old_wd)
def _build_egg(egg, tarball, to_dir):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
tar = tarfile.open(tarball)
_extractall(tar)
tar.close()
# going in the directory
subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
os.chdir(subdir)
log.warn('Now working in %s', subdir)
# building an egg
log.warn('Building a Distribute egg in %s', to_dir)
_python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
finally:
os.chdir(old_wd)
# returning the result
log.warn(egg)
if not os.path.exists(egg):
raise IOError('Could not build the egg.')
def _do_download(version, download_base, to_dir, download_delay):
egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg'
% (version, sys.version_info[0], sys.version_info[1]))
if not os.path.exists(egg):
tarball = download_setuptools(version, download_base,
to_dir, download_delay)
_build_egg(egg, tarball, to_dir)
sys.path.insert(0, egg)
import setuptools
setuptools.bootstrap_install_from = egg
def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, download_delay=15, no_fake=True):
# making sure we use the absolute path
to_dir = os.path.abspath(to_dir)
was_imported = 'pkg_resources' in sys.modules or \
'setuptools' in sys.modules
try:
try:
import pkg_resources
if not hasattr(pkg_resources, '_distribute'):
if not no_fake:
_fake_setuptools()
raise ImportError
except ImportError:
return _do_download(version, download_base, to_dir, download_delay)
try:
pkg_resources.require("distribute>="+version)
return
except pkg_resources.VersionConflict:
e = sys.exc_info()[1]