Commit 00b4f1be authored by Faidon Liambotis's avatar Faidon Liambotis

Initial commit

parents
settings.py
*.pyc
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
#
# Copyright © 2010 Greek Research and Technology Network
#
from django.contrib.auth.models import User, AnonymousUser
from synnefo.api.faults import fault
# XXX: we need to add a Vary X-Auth-Token, somehow
# XXX: or use a standard auth middleware instead?
# but watch out for CSRF issues:
# http://andrew.io/weblog/2010/01/django-piston-and-handling-csrf-tokens/
class TokenAuthentication(object):
def is_authenticated(self, request):
token = request.META.get('HTTP_X_AUTH_TOKEN', None)
if not token:
return False
# XXX: lookup token in models and set request.user
if token:
request.user = AnonymousUser()
return True
def challenge(self):
return fault.unauthorized
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
#
# Copyright © 2010 Greek Research and Technology Network
#
from piston.resource import Resource as BaseResource
import re
_accept_re = re.compile(r'([^\s;,]+)(?:[^,]*?;\s*q=(\d*(?:\.\d+)?))?')
def parse_accept_header(value):
"""Parse an HTTP Accept header
Returns an ordered by quality list of tuples (value, quality)
"""
if not value:
return []
result = []
for match in _accept_re.finditer(value):
quality = match.group(2)
if not quality:
quality = 1
else:
quality = max(min(float(quality), 1), 0)
result.append((match.group(1), quality))
# sort by quality
result.sort(key=lambda x: x[1])
return result
# XXX: works as intended but not used since piston's XMLEmitter doesn't output
# XML according to our spec :(
class Resource(BaseResource):
def determine_emitter(self, request, *args, **kwargs):
"""
Override default emitter policy to account for Accept header
emitter_format (.json or .xml suffix in URL) always takes precedence.
After that, the Accept header is checked; if both JSON and XML are
equally preferred, use JSON.
If none of the two were provided, then use JSON as per the
specification.
"""
em = request.GET.get('format', 'xml')
if 'emitter_format' in kwargs:
em = kwargs.pop('emitter_format')
elif 'HTTP_ACCEPT' in request.META:
accepts = parse_accept_header(request.META['HTTP_ACCEPT'])
for content_type, quality in accepts:
if content_type == 'application/json':
break
elif content_type == 'application/xml':
em = request.GET.get('format', 'xml')
break
return em
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
#
# Copyright © 2010 Greek Research and Technology Network
#
from django.http import HttpResponse
from django.utils import simplejson
class _fault_factory(object):
"""
Openstack API Faults factory
"""
faults = {
'serviceUnavailable': {
'code': 503,
'message': 'Service Unavailable',
},
'unauthorized': {
'code': 401,
'message': 'Unauthorized',
},
'badRequest': {
'code': 400,
'message': 'Bad request',
},
'overLimit': {
'code': 413,
'message': 'Overlimit',
},
'badMediaType': {
'code': 415,
'message': 'Bad media type',
},
'badMethod': {
'code': 405,
'message': 'Bad method',
},
'itemNotFound': {
'code': 404,
'message': 'Not Found',
},
'buildInProgress': {
'code': 409,
'message': 'Build in progress',
},
'serverCapacityUnavailable': {
'code': 503,
'message': 'Server capacity unavailable',
},
'backupOrResizeInProgress': {
'code': 409,
'message': 'Backup or resize in progress',
},
'resizeNotAllowed': {
'code': 403,
'message': 'Resize not allowed',
},
'notImplemented': {
'code': 501,
'message': 'Not Implemented',
},
}
def __getattr__(self, attr):
try:
m = self.faults.get(attr)
except TypeError:
raise AttributeError(attr)
# XXX: piston > 0.2.2 does the serialization for us, but be compatible
message = simplejson.dumps({ attr: m }, ensure_ascii=False, indent=4)
code = m['code']
return HttpResponse(message, status=code)
fault = _fault_factory()
noContent = HttpResponse(status=204)
accepted = HttpResponse(status=202)
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
#
# Copyright © 2010 Greek Research and Technology Network
#
from piston.handler import BaseHandler, AnonymousBaseHandler
from synnefo.api.faults import fault, noContent, accepted
VERSIONS = [
{
"status": "CURRENT",
"id": "v1.0",
"docURL" : "http://docs.rackspacecloud.com/servers/api/v1.0/cs-devguide-20090714.pdf ",
"wadl" : "http://docs.rackspacecloud.com/servers/api/v1.0/application.wadl"
},
]
class VersionHandler(AnonymousBaseHandler):
allowed_methods = ('GET',)
def read(self, request, number=None):
if number is None:
versions = map(lambda v: {
"status": v["status"],
"id": v["id"],
}, VERSIONS)
return { "versions": versions }
else:
for version in VERSIONS:
if version["id"] == number:
return { "version": version }
return fault.itemNotFound
# XXX: incomplete
class ServerHandler(BaseHandler):
def read(self, request, id=None):
if id is None:
return self.read_all(request)
elif id is "detail":
return self.read_all(request, detail=True)
else:
return self.read_one(request, id)
def read_one(self, request, id):
print ("server info %s" % id)
return {}
def read_all(self, request, detail=False):
if not detail:
print "server info all"
else:
print "server info all detail"
return {}
def create(self, request):
return accepted
def update(self, request, id):
return noContent
def delete(self, request, id):
return accepted
class ServerAddressHandler(BaseHandler):
allowed_methods = ('GET', 'PUT', 'DELETE')
def read(self, request, id, type=None):
"""List IP addresses for a server"""
if type is None:
pass
elif type == "private":
pass
elif type == "public":
pass
return {}
def update(self, request, id, address):
"""Share an IP address to another in the group"""
return accepted
def delete(self, request, id, address):
"""Unshare an IP address"""
return accepted
class ServerActionHandler(BaseHandler):
allowed_methods = ('POST',)
def create(self, request, id):
"""Reboot, rebuild, resize, confirm resized, revert resized"""
print ("server action %s" % id)
return accepted
auth api
========
cloud api
=========
* auth
* version (DONE)
* faults (DONE)
* limits
* servers
+ list
- index: GET /servers
- detail: GET /servers/detail
+ create
- create: POST /servers
+ get details
- show: GET /servers/<id>
+ update password
- update: PUT /servers/<id>
+ delete servers
- delete: DELETE /servers/<id>
* addresses
+ list
+ list public
+ list private
+ share
+ unshare
* actions
+ reboot
+ rebuild
+ resize
+ confirm resized
+ revert resized
* flavors
+ list
+ get details
* images
+ list images
+ create an image
+ get details
+ delete image
* backup schedule
+ list
+ create/update
+ disable
* shared ip groups
+ list
+ create
+ get details
+ delete
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
#
# Copyright © 2010 Greek Research and Technology Network
#
from django.conf.urls.defaults import *
from piston.resource import Resource
from synnefo.api.handlers import *
from synnefo.api.authentication import TokenAuthentication
auth = TokenAuthentication()
server_handler = Resource(ServerHandler, auth)
server_address_handler = Resource(ServerAddressHandler, auth)
server_actions_handler = Resource(ServerActionHandler, auth)
v10patterns = patterns('',
url(r'^servers/(?P<id>[^/]+)?$', server_handler),
url(r'^servers/(?P<id>[^/]+)/action$', server_actions_handler),
url(r'^servers/(?P<id>[^/]+)/ips$', server_address_handler),
url(r'^servers/(?P<id>[^/]+)/ips/private$', server_address_handler),
url(r'^servers/(?P<id>[^/]+)/ips/public/(?P<address>[^/]+)$', server_address_handler),
)
version_handler = Resource(VersionHandler)
urlpatterns = patterns('',
url(r'^(?P<number>[^/]+)/$', version_handler),
url(r'^/?$', version_handler),
(r'^v1.0/', include(v10patterns)),
)
#!/usr/bin/python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)
# Django settings for synnefo project.
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': '', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# 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.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
# 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 = 'ly6)mw6a7x%n)-e#zzk4jo6f2=uqu!1o%)2-(7lo+f9yd^k^bg'
# 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',
# 'django.template.loaders.eggs.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
# 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
ROOT_URLCONF = 'synnefo.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.
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
# 'django.contrib.admin',
# 'django.contrib.admindocs',
'synnefo.api',
)
# vim: ts=4 sts=4 et ai sw=4 fileencoding=utf-8
#
# Copyright © 2010 Greek Research and Technology Network
#
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^api/', include('synnefo.api.urls')),
)
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