Commit 3d500a10 authored by Kostas Papadimitriou's avatar Kostas Papadimitriou

Merge commit 'v0.9.0' into packaging

Conflicts:
	pithos/__init__.py
	pithos/api/management/commands/__init__.py
	pithos/backends/lib/rabbitmq/__init__.py
	pithos/backends/lib/rabbitmq/queue.py
	pithos/lib/user.py
	pithos/middleware/user.py
	pithos/settings.py
	pithos/ui/__init__.py
	pithos/ui/urls.py
	pithos/ui/views.py
	snf-pithos-app/pithos/api/settings.py
	snf-pithos-app/pithos/middleware/log.py
	snf-pithos-app/pithos/middleware/user.py
	snf-pithos-app/pithos/ui/settings.py
	snf-pithos-app/pithos/ui/templates/feedback_mail.txt
	snf-pithos-app/pithos/ui/views.py
	snf-pithos-lib/pithos/lib/__init__.py
	snf-pithos-tools/pithos/__init__.py
	snf-pithos-tools/pithos/tools/dispatcher.py
parents 58f20127 a672ba67
......@@ -63,3 +63,7 @@ UPGRADE
mysql> alter table versions add column `uuid` varchar(64) DEFAULT '' NOT NULL after `muser`;
mysql> update versions v, tmp_uuids u set v.`uuid` = u.`uuid` where v.`node` = u.`node`;
mysql> create index idx_versions_node_uuid on versions(uuid);
0.8.2 -> 0.9.0
--------------
* No upgrade path provided. Please reinstall and reconfigure.
......@@ -64,6 +64,16 @@ Edit ``/etc/apache2/sites-available/pithos`` (change the ``ServerName`` directiv
CustomLog ${APACHE_LOG_DIR}/pithos.access.log combined
</VirtualHost>
To disable non-SSL connections, ``/etc/apache2/sites-available/pithos`` should be::
<VirtualHost *:80>
ServerAdmin webmaster@pithos.dev.grnet.gr
ServerName pithos.dev.grnet.gr
RewriteEngine On
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
Edit ``/etc/apache2/sites-available/pithos-ssl`` (assuming files in ``/etc/ssl/private/pithos.dev.grnet.gr.key`` and ``/etc/ssl/certs/pithos.dev.grnet.gr.crt`` - change the ``ServerName`` directive)::
<IfModule mod_ssl.c>
......
This diff is collapsed.
......@@ -24,6 +24,15 @@
<link rel="stylesheet" href="site_media/css/site.css">
<script src="site_media/js/libs/modernizr-1.7.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
var CLOUDBAR_ACTIVE_SERVICE = 'cloud';
var CLOUDBAR_LOCATION = "/im/static/im/cloudbar/";
$(document).ready(function(){
$.getScript(CLOUDBAR_LOCATION + 'cloudbar.js');
})
</script>
</head>
<body id="index">
<div class="container">
......@@ -48,7 +57,7 @@
</div>
<div class="inner-bottom">
<a class="gotoapp"
href="/login?next=/ui"
href="/ui"
title="Enter Pithos+">Είσοδος</a>
</div>
<div class="downloads clearfix">
......
<!doctype html>
<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
<!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]-->
<!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
Remove this if you use the .htaccess -->
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>~okeanos</title>
<meta name="description" content="Pithos+ GRNet Service">
<meta name="author" content="Kostas Papadimitriou <kpap@grnet.gr>">
<!-- Mobile viewport optimized: j.mp/bplateviewport -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<!-- Place favicon.ico & apple-touch-icon.png
in the root of your domain and delete these references -->
<link rel="shortcut icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="stylesheet" href="site_media/css/site.css">
<script src="site_media/js/libs/modernizr-1.7.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
var CLOUDBAR_ACTIVE_SERVICE = 'okeanos';
var CLOUDBAR_LOCATION = "/im/static/im/cloudbar/";
$(document).ready(function(){
$.getScript(CLOUDBAR_LOCATION + 'cloudbar.js');
})
</script>
</head>
<body id="index" style="background-position: 0px -200px">
<div class="container">
<div class="logo">
<a href="#" title="Pithos+"><img
src="site_media/images/okeanos-logo-alpha.png"
alt="~okeanos"
title="~okeanos" /></a>
</div>
<div class="inner box-round-mid box-shadow-mid clearfix">
<div class="cols clearfix">
<div class="main-content">
<div class="intro-text page text">
<p>
Η έκδοση alpha 2 της υπηρεσίας ~okeanos θα είναι σύντομα διαθέσιμη.<br /><br />
Αν έχετε λογαριασμό θα λάβετε ενημερωτικό μήνυμα στο email σας.<br />
Αν δεν έχετε, φτιάξτε έναν <a href="/im">τώρα</a>!
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="bottom-text">
<p>&copy; 2011 <a target="_blank" href="http://www.grnet.gr/">Εθνικό Δίκτυο Έρευνας και Τεχνολογίας</a></p>
</div>
</div>
<script src="site_media/js/libs/jquery-1.5.1.min.js"></script>
<script src="site_media/js/libs/jquery.cookie.js"></script>
<script src="site_media/js/intro-hover.js"></script>
<script src="site_media/js/main.js"></script>
<!--[if lt IE 7 ]>
<script src="site_media/js/libs/dd_belatedpng.js"></script>
<script>DD_belatedPNG.fix('img, .png_bg');</script>
<![endif]-->
</body>
</html>
......@@ -136,7 +136,7 @@ body.alt {
.container {
width: 870px;
margin: 0 auto;
margin-top: 30px;
margin-top: 20px;
}
.inner {
margin-top: 2.5em;
......@@ -2805,7 +2805,6 @@ body, html {
}
.container {
width: 670px;
margin-top: 0;
}
.container .logo img {
margin: 0;
......
This diff is collapsed.
# Copyright 2012 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.
from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
from pithos.api.settings import (BACKEND_DB_MODULE, BACKEND_DB_CONNECTION,
BACKEND_BLOCK_MODULE, BACKEND_BLOCK_PATH,
BACKEND_QUEUE_MODULE, BACKEND_QUEUE_CONNECTION,
BACKEND_QUOTA, BACKEND_VERSIONING)
from pithos.backends import connect_backend
class Command(BaseCommand):
args = "<user>"
help = "Get/set a user's quota"
option_list = BaseCommand.option_list + (
make_option('--set-quota',
dest='quota',
metavar='BYTES',
help="Set user's quota"),
)
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("Please provide a user")
user = args[0]
quota = options.get('quota')
if quota is not None:
try:
quota = int(quota)
except ValueError:
raise CommandError("Invalid quota")
backend = connect_backend(db_module=BACKEND_DB_MODULE,
db_connection=BACKEND_DB_CONNECTION,
block_module=BACKEND_BLOCK_MODULE,
block_path=BACKEND_BLOCK_PATH,
queue_module=BACKEND_QUEUE_MODULE,
queue_connection=BACKEND_QUEUE_CONNECTION)
backend.default_policy['quota'] = BACKEND_QUOTA
backend.default_policy['versioning'] = BACKEND_VERSIONING
if quota is not None:
backend.update_account_policy(user, user, {'quota': quota})
else:
self.stdout.write("Quota for %s: %s\n" % (user, backend.get_account_policy(user, user)['quota']))
backend.close()
......@@ -34,18 +34,24 @@
import logging
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from pithos.lib.user import get_user
from pithos.api.faults import (Fault, BadRequest, ItemNotFound)
from pithos.api.util import (put_object_headers, update_manifest_meta,
validate_modification_preconditions, validate_matching_preconditions,
object_data_response, api_method)
from pithos.api.short_url import decode_url
from pithos.api.settings import AUTHENTICATION_URL, AUTHENTICATION_USERS
logger = logging.getLogger(__name__)
@csrf_exempt
def public_demux(request, v_public):
get_user(request, AUTHENTICATION_URL, AUTHENTICATION_USERS)
if request.method == 'HEAD':
return public_meta(request, v_public)
elif request.method == 'GET':
......
#coding=utf8
from django.conf import settings
from os.path import abspath, dirname, join
USE_X_FORWARDED_HOST = False
PROJECT_PATH = getattr(settings, 'PROJECT_PATH', dirname(dirname(abspath(__file__))))
# Either set local users here, or a remote host.
# To disable local users set to None.
AUTHENTICATION_USERS = {
# Set local users, or a remote host. To disable local users set them to None.
sample_users = {
'0000': 'test',
'0001': 'verigak',
'0002': 'chazapis',
......@@ -17,7 +18,22 @@ AUTHENTICATION_USERS = {
'0009': 'διογένης'
}
# Where astakos is hosted.
AUTHENTICATION_HOST = '127.0.0.1:10000'
AUTHENTICATION_URL = getattr(settings, 'PITHOS_AUTHENTICATION_URL', 'http://127.0.0.1:8000/im/authenticate')
AUTHENTICATION_USERS = getattr(settings, 'PITHOS_AUTHENTICATION_USERS', sample_users)
# SQLAlchemy (choose SQLite/MySQL/PostgreSQL).
BACKEND_DB_MODULE = getattr(settings, 'PITHOS_BACKEND_DB_MODULE', 'pithos.backends.lib.sqlalchemy')
BACKEND_DB_CONNECTION = getattr(settings, 'PITHOS_BACKEND_DB_CONNECTION', 'sqlite:///' + join(PROJECT_PATH, 'backend.db'))
# Block storage.
BACKEND_BLOCK_MODULE = getattr(settings, 'PITHOS_BACKEND_BLOCK_MODULE', 'pithos.backends.lib.hashfiler')
BACKEND_BLOCK_PATH = getattr(settings, 'PITHOS_BACKEND_BLOCK_PATH', join(PROJECT_PATH, 'data/'))
# Queue for billing.
BACKEND_QUEUE_MODULE = getattr(settings, 'PITHOS_BACKEND_QUEUE_MODULE', None) # Example: 'pithos.backends.lib.rabbitmq'
BACKEND_QUEUE_CONNECTION = getattr(settings, 'PITHOS_BACKEND_QUEUE_CONNECTION', None) # Example: 'rabbitmq://guest:guest@localhost:5672/pithos'
# Default setting for new accounts.
BACKEND_QUOTA = getattr(settings, 'PITHOS_BACKEND_QUOTA', 50 * 1024 * 1024 * 1024)
BACKEND_VERSIONING = getattr(settings, 'PITHOS_BACKEND_VERSIONING', 'auto')
TEST = False
#coding=utf8
# Django settings for pithos project.
from os.path import abspath, dirname, exists, join
PROJECT_PATH = dirname(abspath(__file__))
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': join(PROJECT_PATH, 'pithos.db')
}
}
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'UTC'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True
# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = ''
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = ''
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/media/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = '$j0cdrfm*0sc2j+e@@2f-&3-_@2=^!z#+b-8o4_i10@2%ev7si'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
#'django.contrib.sessions.middleware.SessionMiddleware',
#'django.contrib.auth.middleware.AuthenticationMiddleware',
#'django.contrib.messages.middleware.MessageMiddleware',
'pithos.middleware.LoggingConfigMiddleware',
'pithos.middleware.SecureMiddleware'
)
ROOT_URLCONF = 'pithos.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
# Setup logging (use this name for the setting to avoid conflicts with django > 1.2.x).
LOGGING_SETUP = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'simple': {
'format': '%(message)s'
},
'verbose': {
'format': '%(asctime)s [%(levelname)s] %(name)s %(message)s'
},
},
'handlers': {
'null': {
'class': 'logging.NullHandler',
},
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose'
},
'file': {
'class': 'logging.FileHandler',
'formatter': 'verbose'
},
},
'loggers': {
'pithos': {
'handlers': ['console'],
'level': 'DEBUG' if DEBUG else 'INFO'
},
}
}
# The server is behind a proxy (apache and gunicorn setup).
USE_X_FORWARDED_HOST = False
# Set umask (needed for gunicorn setup).
#umask(0077)
conf = join(PROJECT_PATH, 'settings.local')
if exists(conf):
execfile(conf)
elif exists('/etc/pithos/settings.local'):
execfile('/etc/pithos/settings.local')
INSTALLED_APPS = (
'pithos.api',
)
......@@ -31,12 +31,19 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from django.conf.urls.defaults import *
from django.conf.urls.defaults import include, patterns
# TODO: This only works when in this order.
urlpatterns = patterns('pithos.api.functions',
api_urlpatterns = patterns('pithos.api.functions',
(r'^$', 'top_demux'),
(r'^(?P<v_account>.+?)/(?P<v_container>.+?)/(?P<v_object>.+?)$', 'object_demux'),
(r'^(?P<v_account>.+?)/(?P<v_container>.+?)/?$', 'container_demux'),
(r'^(?P<v_account>.+?)/?$', 'account_demux')
)
urlpatterns = patterns('',
(r'^v1(?:$|/)', include(api_urlpatterns)),
(r'^v1\.0(?:$|/)', include(api_urlpatterns)),
(r'^public/(?P<v_public>.+?)/?$', 'pithos.api.public.public_demux'),
(r'^login/?$', 'pithos.api.login.redirect_to_login_service')
)
This diff is collapsed.
from log import LoggingConfigMiddleware
from secure import SecureMiddleware
from user import UserMiddleware
......@@ -3,16 +3,16 @@
# 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
......@@ -34,17 +34,31 @@
from django.conf import settings
from django.core.exceptions import MiddlewareNotUsed
from pithos.lib.dictconfig import dictConfig
import logging
class NullHandler(logging.Handler):
def emit(self, record):
pass
class LoggingConfigMiddleware:
def __init__(self):
'''Initialise the logging setup from settings, called on first request.'''
args = {}
args['level'] = logging.DEBUG if getattr(settings, 'DEBUG', False) else logging.INFO
if getattr(settings, 'LOGFILE', None):
args['filename'] = settings.LOGFILE
args['format'] = '%(asctime)s [%(levelname)s] %(name)s %(message)s'
args['datefmt'] = '%Y-%m-%d %H:%M:%S'
logging.basicConfig(**args)
logging_setting = getattr(settings, 'LOGGING_SETUP', None)
if logging_setting:
# Disable handlers that are not used by any logger.
active_handlers = set()
loggers = logging_setting.get('loggers', {})
for logger in loggers.values():
active_handlers.update(logger.get('handlers', []))
handlers = logging_setting.get('handlers', {})
for handler in handlers:
if handler not in active_handlers:
handlers[handler] = {'class': 'logging.NullHandler'}
logging.NullHandler = NullHandler
dictConfig(logging_setting)
raise MiddlewareNotUsed('Logging setup only.')
Feedback message:
{{ message }}
User info:
ID: {{ request.user.id }}
Email: {{ request.user.uniq }}
User application data:
{{ data|safe }}
......@@ -35,9 +35,5 @@ from django.conf.urls.defaults import include, patterns
urlpatterns = patterns('',
(r'^v1(?:$|/)', include('pithos.api.urls')),
(r'^v1\.0(?:$|/)', include('pithos.api.urls')),
(r'^public/(?P<v_public>.+?)/?$', 'pithos.api.public.public_demux'),
(r'^login/?$', 'pithos.api.login.redirect_to_login_service'),
(r'^ui', include('pithos.ui.urls'))
(r'', include('pithos.api.urls')),
)
......@@ -74,7 +74,7 @@ class BaseBackend(object):
"""
return []
def get_account_meta(self, user, account, domain, until=None):
def get_account_meta(self, user, account, domain, until=None, include_user_defined=True):
"""Return a dictionary with the account metadata for the domain.
The keys returned are all user-defined, except:
......@@ -185,7 +185,17 @@ class BaseBackend(object):
"""
return []
def get_container_meta(self, user, account, container, domain, until=None):
def list_container_meta(self, user, account, container, domain, until=None):
"""Return a list with all the container's object meta keys for the domain.
Raises:
NotAllowedError: Operation not permitted
NameError: Container does not exist
"""
return []
def get_container_meta(self, user, account, container, domain, until=None, include_user_defined=True):
"""Return a dictionary with the container metadata for the domain.
The keys returned are all user-defined, except:
......@@ -310,8 +320,11 @@ class BaseBackend(object):
"""
return []
def list_object_meta(self, user, account, container, domain, until=None):
"""Return a list with all the container's object meta keys for the domain.
def list_object_meta(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, domain=None, keys=[], shared=False, until=None, size_range=None):
"""Return a list of object metadata dicts existing under a container.
Same parameters with list_objects. Returned dicts have no user-defined
metadata and, if until is not None, a None 'modified' timestamp.
Raises:
NotAllowedError: Operation not permitted
......@@ -320,7 +333,19 @@ class BaseBackend(object):
"""
return []
def get_object_meta(self, user, account, container, name, domain, version=None):
def list_object_permissions(self, user, account, container, prefix=''):
"""Return a list of paths that enforce permissions under a container.
Raises:
NotAllowedError: Operation not permitted
"""
return []
def list_object_public(self, user, account, container, prefix=''):
"""Return a dict mapping paths to public ids for objects that are public under a container."""
return {}
def get_object_meta(self, user, account, container, name, domain, version=None, include_user_defined=True):
"""Return a dictionary with the object metadata for the domain.
The keys returned are all user-defined, except:
......@@ -328,6 +353,8 @@ class BaseBackend(object):