Updated initial version of portas-api
This commit is contained in:
parent
b9d60d50bd
commit
0e8c965b88
90
api/setup.py
90
api/setup.py
@ -1,90 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 OpenStack LLC.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
from setuptools.command.sdist import sdist
|
||||
|
||||
from windc import version
|
||||
|
||||
|
||||
if os.path.isdir('.bzr'):
|
||||
with open("windc/vcsversion.py", 'w') as version_file:
|
||||
vcs_cmd = subprocess.Popen(["bzr", "version-info", "--python"],
|
||||
stdout=subprocess.PIPE)
|
||||
vcsversion = vcs_cmd.communicate()[0]
|
||||
version_file.write(vcsversion)
|
||||
|
||||
|
||||
class local_sdist(sdist):
|
||||
"""Customized sdist hook - builds the ChangeLog file from VC first"""
|
||||
|
||||
def run(self):
|
||||
if os.path.isdir('.bzr'):
|
||||
# We're in a bzr branch
|
||||
|
||||
log_cmd = subprocess.Popen(["bzr", "log", "--gnu"],
|
||||
stdout=subprocess.PIPE)
|
||||
changelog = log_cmd.communicate()[0]
|
||||
with open("ChangeLog", "w") as changelog_file:
|
||||
changelog_file.write(changelog)
|
||||
sdist.run(self)
|
||||
|
||||
cmdclass = {'sdist': local_sdist}
|
||||
|
||||
# If Sphinx is installed on the box running setup.py,
|
||||
# enable setup.py to build the documentation, otherwise,
|
||||
# just ignore it
|
||||
try:
|
||||
from sphinx.setup_command import BuildDoc
|
||||
|
||||
class local_BuildDoc(BuildDoc):
|
||||
def run(self):
|
||||
for builder in ['html', 'man']:
|
||||
self.builder = builder
|
||||
self.finalize_options()
|
||||
BuildDoc.run(self)
|
||||
cmdclass['build_sphinx'] = local_BuildDoc
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
setup(
|
||||
name='windc',
|
||||
version=version.canonical_version_string(),
|
||||
description='The WinDC project provides a simple WSGI server for Windows Environment Management',
|
||||
license='Apache License (2.0)',
|
||||
author='OpenStack',
|
||||
author_email='openstack@lists.launchpad.net',
|
||||
url='http://windc.openstack.org/',
|
||||
packages=find_packages(exclude=['tests', 'bin']),
|
||||
test_suite='nose.collector',
|
||||
cmdclass=cmdclass,
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Operating System :: POSIX :: Linux',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Environment :: No Input/Output (Daemon)',
|
||||
],
|
||||
scripts=['bin/windc',
|
||||
'bin/windc-api'])
|
2
portas/.gitignore
vendored
2
portas/.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
##IntelJ Idea
|
||||
#IntelJ Idea
|
||||
.idea/
|
||||
|
||||
#virtualenv
|
||||
|
@ -19,29 +19,32 @@ import gettext
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
# If ../portas/__init__.py exists, add ../ to Python search path, so that
|
||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||
|
||||
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
||||
os.pardir,
|
||||
os.pardir))
|
||||
if os.path.exists(os.path.join(possible_topdir, 'portas', '__init__.py')):
|
||||
sys.path.insert(0, possible_topdir)
|
||||
|
||||
gettext.install('portas', './portas/locale', unicode=1)
|
||||
|
||||
from portas.common import config
|
||||
from portas.openstack.common import log
|
||||
from portas.openstack.common import wsgi
|
||||
from portas.openstack.common import service
|
||||
|
||||
gettext.install('portas', './portas/locale', unicode=1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
config.parse_args()
|
||||
log.setup('portas')
|
||||
|
||||
server = wsgi.Server()
|
||||
server.start(config.load_paste_app(), default_port=8181)
|
||||
server.wait()
|
||||
api_service = wsgi.Service(config.load_paste_app(),
|
||||
port=config.CONF.bind_port,
|
||||
host=config.CONF.bind_host)
|
||||
launcher = service.Launcher()
|
||||
launcher.run_service(api_service)
|
||||
except RuntimeError, e:
|
||||
sys.stderr.write("ERROR: %s\n" % e)
|
||||
sys.exit(1)
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2010 OpenStack Foundation.
|
||||
#
|
||||
@ -15,8 +16,8 @@
|
||||
# limitations under the License.
|
||||
|
||||
#
|
||||
# Glance documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue May 18 13:50:15 2010.
|
||||
# Portas documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue February 28 13:50:15 2013.
|
||||
#
|
||||
# This file is execfile()'d with the current directory set to its containing
|
||||
# dir.
|
||||
@ -33,7 +34,7 @@ import sys
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path = [os.path.abspath('../../glance'),
|
||||
sys.path = [os.path.abspath('../../portas'),
|
||||
os.path.abspath('../..'),
|
||||
os.path.abspath('../../bin')
|
||||
] + sys.path
|
||||
@ -65,19 +66,19 @@ source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Glance'
|
||||
copyright = u'2010, OpenStack Foundation.'
|
||||
project = u'Portas'
|
||||
copyright = u'2013, Mirantis, Inc.'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
from glance.version import version_info as glance_version
|
||||
from portas.version import version_info as portas_version
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = glance_version.version_string_with_vcs()
|
||||
release = portas_version.version_string_with_vcs()
|
||||
# The short X.Y version.
|
||||
version = glance_version.canonical_version_string()
|
||||
version = portas_version.canonical_version_string()
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@ -114,7 +115,7 @@ show_authors = True
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
modindex_common_prefix = ['glance.']
|
||||
modindex_common_prefix = ['portas.']
|
||||
|
||||
# -- Options for man page output --------------------------------------------
|
||||
|
||||
@ -122,25 +123,7 @@ modindex_common_prefix = ['glance.']
|
||||
# List of tuples 'sourcefile', 'target', u'title', u'Authors name', 'manual'
|
||||
|
||||
man_pages = [
|
||||
('man/glance', 'glance', u'Glance CLI',
|
||||
[u'OpenStack'], 1),
|
||||
('man/glanceapi', 'glance-api', u'Glance API Server',
|
||||
[u'OpenStack'], 1),
|
||||
('man/glancecachecleaner', 'glance-cache-cleaner', u'Glance Cache Cleaner',
|
||||
[u'OpenStack'], 1),
|
||||
('man/glancecachemanage', 'glance-cache-manage', u'Glance Cache Manager',
|
||||
[u'OpenStack'], 1),
|
||||
('man/glancecacheprefetcher', 'glance-cache-prefetcher',
|
||||
u'Glance Cache Pre-fetcher', [u'OpenStack'], 1),
|
||||
('man/glancecachepruner', 'glance-cache-pruner', u'Glance Cache Pruner',
|
||||
[u'OpenStack'], 1),
|
||||
('man/glancecontrol', 'glance-control', u'Glance Daemon Control Helper ',
|
||||
[u'OpenStack'], 1),
|
||||
('man/glancemanage', 'glance-manage', u'Glance Management Utility',
|
||||
[u'OpenStack'], 1),
|
||||
('man/glanceregistry', 'glance-registry', u'Glance Registry Server',
|
||||
[u'OpenStack'], 1),
|
||||
('man/glancescrubber', 'glance-scrubber', u'Glance Scrubber Service',
|
||||
('man/portasapi', 'portas-api', u'Portas API Server',
|
||||
[u'OpenStack'], 1)
|
||||
]
|
||||
|
||||
@ -219,7 +202,7 @@ html_use_index = False
|
||||
#html_file_suffix = ''
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'glancedoc'
|
||||
htmlhelp_basename = 'portasdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ------------------------------------------------
|
||||
@ -234,8 +217,8 @@ htmlhelp_basename = 'glancedoc'
|
||||
# (source start file, target name, title, author,
|
||||
# documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'Glance.tex', u'Glance Documentation',
|
||||
u'Glance Team', 'manual'),
|
||||
('index', 'Portas.tex', u'Portas Documentation',
|
||||
u'Keero Team', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
@ -256,6 +239,4 @@ latex_documents = [
|
||||
#latex_use_modindex = True
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/', None),
|
||||
'nova': ('http://nova.openstack.org', None),
|
||||
'swift': ('http://swift.openstack.org', None)}
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/', None)}
|
||||
|
@ -14,70 +14,7 @@
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Welcome to Glance's documentation!
|
||||
Welcome to Portas's documentation!
|
||||
==================================
|
||||
|
||||
The Glance project provides services for discovering, registering, and
|
||||
retrieving virtual machine images. Glance has a RESTful API that allows
|
||||
querying of VM image metadata as well as retrieval of the actual image.
|
||||
|
||||
VM images made available through Glance can be stored in a variety of
|
||||
locations from simple filesystems to object-storage systems like the
|
||||
OpenStack Swift project.
|
||||
|
||||
Glance, as with all OpenStack projects, is written with the following design
|
||||
guidelines in mind:
|
||||
|
||||
* **Component based architecture**: Quickly add new behaviors
|
||||
* **Highly available**: Scale to very serious workloads
|
||||
* **Fault tolerant**: Isolated processes avoid cascading failures
|
||||
* **Recoverable**: Failures should be easy to diagnose, debug, and rectify
|
||||
* **Open standards**: Be a reference implementation for a community-driven api
|
||||
|
||||
This documentation is generated by the Sphinx toolkit and lives in the source
|
||||
tree. Additional documentation on Glance and other components of OpenStack can
|
||||
be found on the `OpenStack wiki`_.
|
||||
|
||||
.. _`OpenStack wiki`: http://wiki.openstack.org
|
||||
|
||||
Concepts
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
identifiers
|
||||
statuses
|
||||
formats
|
||||
common-image-properties
|
||||
|
||||
Installing/Configuring Glance
|
||||
=============================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
installing
|
||||
configuring
|
||||
authentication
|
||||
policies
|
||||
|
||||
Operating Glance
|
||||
================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
controllingservers
|
||||
db
|
||||
cache
|
||||
notifications
|
||||
|
||||
Using Glance
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
glanceapi
|
||||
glanceclient
|
||||
We rule the world!
|
@ -1,57 +1,5 @@
|
||||
[DEFAULT]
|
||||
# Show more verbose log output (sets INFO log level output)
|
||||
verbose = True
|
||||
# Show debugging output in logs (sets DEBUG log level output)
|
||||
debug = True
|
||||
# Address to bind the server to
|
||||
bind_host = 0.0.0.0
|
||||
# Port the bind the server to
|
||||
bind_port = 8082
|
||||
# Log to this file. Make sure the user running skeleton-api has
|
||||
# permissions to write to this file!
|
||||
log_file = /tmp/api.log
|
||||
# Orchestration Adapter Section
|
||||
#
|
||||
#provider - Cloud provider to use (openstack, amazon, dummy)
|
||||
provider = openstack
|
||||
|
||||
# Heat specific parameters
|
||||
#heat_url - url for the heat service
|
||||
# [auto] - find in the keystone
|
||||
heat_url = auto
|
||||
|
||||
#heat_api_version - version of the API to use
|
||||
#
|
||||
heat_api_version = 1
|
||||
|
||||
|
||||
[pipeline:windc-api]
|
||||
[pipeline:portas-api]
|
||||
pipeline = apiv1app
|
||||
# NOTE: use the following pipeline for keystone
|
||||
#pipeline = authtoken context apiv1app
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = windc.common.wsgi:app_factory
|
||||
windc.app_factory = windc.api.v1.router:API
|
||||
|
||||
[filter:context]
|
||||
paste.filter_factory = windc.common.wsgi:filter_factory
|
||||
windc.filter_factory = windc.common.context:ContextMiddleware
|
||||
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystone.middleware.auth_token:filter_factory
|
||||
auth_host = 172.18.67.57
|
||||
auth_port = 35357
|
||||
auth_protocol = http
|
||||
auth_uri = http://172.18.67.57:5000/v2.0/
|
||||
admin_tenant_name = service
|
||||
admin_user = windc
|
||||
admin_password = 000
|
||||
|
||||
[filter:auth-context]
|
||||
paste.filter_factory = windc.common.wsgi:filter_factory
|
||||
windc.filter_factory = keystone.middleware.balancer_auth_token:KeystoneContextMiddleware
|
||||
|
||||
[rabbitmq]
|
||||
host = 10.0.0.1
|
||||
vhost = keero
|
||||
paste.app_factory = portas.api.v1.router:API.factory
|
@ -13,22 +13,7 @@ bind_port = 8082
|
||||
|
||||
# Log to this file. Make sure the user running skeleton-api has
|
||||
# permissions to write to this file!
|
||||
log_file = /tmp/api.log
|
||||
log_file = /tmp/portas-api.log
|
||||
|
||||
[pipeline:windc-api]
|
||||
pipeline = versionnegotiation context apiv1app
|
||||
|
||||
[pipeline:versions]
|
||||
pipeline = versionsapp
|
||||
|
||||
[app:versionsapp]
|
||||
paste.app_factory = windc.api.versions:app_factory
|
||||
|
||||
[app:apiv1app]
|
||||
paste.app_factory = windc.api.v1:app_factory
|
||||
|
||||
[filter:versionnegotiation]
|
||||
paste.filter_factory = windc.api.middleware.version_negotiation:filter_factory
|
||||
|
||||
[filter:context]
|
||||
paste.filter_factory = openstack.common.middleware.context:filter_factory
|
||||
#A valid SQLAlchemy connection string for the metadata database
|
||||
sql_connection = sqlite:///portas.sqlite
|
@ -1,7 +1,7 @@
|
||||
[DEFAULT]
|
||||
|
||||
# The list of modules to copy from openstack-common
|
||||
modules=setup,wsgi,config,exception,gettextutilsl,jsonutils,log,xmlutils,sslutils,service,notifier,local,install_venv_common
|
||||
modules=setup,wsgi,config,exception,gettextutils,importutils,jsonutils,log,xmlutils,sslutils,service,notifier,local,install_venv_common,version,timeutils,eventlet_backdoor,threadgroup,loopingcall,uuidutils
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=portas
|
@ -0,0 +1,30 @@
|
||||
from portas.db.api import EnvironmentRepository
|
||||
from portas.openstack.common import wsgi
|
||||
from portas.openstack.common import log as logging
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Controller(object):
|
||||
repository = EnvironmentRepository()
|
||||
|
||||
def index(self, request):
|
||||
log.debug(_("Display list of environments"))
|
||||
return {"environments": [env.to_dict() for env in self.repository.list()]}
|
||||
|
||||
def create(self, request, body):
|
||||
return self.repository.add(body).to_dict()
|
||||
|
||||
# def delete(self, request, datacenter_id):
|
||||
# log.debug("Got delete request. Request: %s", req)
|
||||
# self.repository., datacenter_id)
|
||||
#
|
||||
# def update(self, req, tenant_id, datacenter_id, body):
|
||||
# log.debug("Got update request. Request: %s", req)
|
||||
# core_api.update_dc(self.conf, tenant_id, datacenter_id, body)
|
||||
# return {'datacenter': {'id': dc_id}}
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(Controller())
|
@ -14,37 +14,17 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from glance.api.v1 import images
|
||||
from glance.api.v1 import members
|
||||
from glance.common import wsgi
|
||||
import routes
|
||||
from portas.openstack.common import wsgi
|
||||
from portas.api.v1 import environments
|
||||
|
||||
|
||||
class API(wsgi.Router):
|
||||
|
||||
"""WSGI router for Glance v1 API requests."""
|
||||
@classmethod
|
||||
def factory(cls, global_conf, **local_conf):
|
||||
return cls(routes.Mapper())
|
||||
|
||||
def __init__(self, mapper):
|
||||
images_resource = images.create_resource()
|
||||
|
||||
mapper.resource("image", "images", controller=images_resource,
|
||||
collection={'detail': 'GET'})
|
||||
mapper.connect("/", controller=images_resource, action="index")
|
||||
mapper.connect("/images/{id}", controller=images_resource,
|
||||
action="meta", conditions=dict(method=["HEAD"]))
|
||||
|
||||
members_resource = members.create_resource()
|
||||
|
||||
mapper.resource("member", "members", controller=members_resource,
|
||||
parent_resource=dict(member_name='image',
|
||||
collection_name='images'))
|
||||
mapper.connect("/shared-images/{id}",
|
||||
controller=members_resource,
|
||||
action="index_shared_images")
|
||||
mapper.connect("/images/{image_id}/members",
|
||||
controller=members_resource,
|
||||
action="update_all",
|
||||
conditions=dict(method=["PUT"]))
|
||||
|
||||
environments_resource = environments.create_resource()
|
||||
mapper.resource("environment", "environments", controller=environments_resource)
|
||||
super(API, self).__init__(mapper)
|
||||
|
@ -29,71 +29,40 @@ import sys
|
||||
from oslo.config import cfg
|
||||
from paste import deploy
|
||||
|
||||
from glance.version import version_info as version
|
||||
from portas.version import version_info as version
|
||||
|
||||
paste_deploy_opts = [
|
||||
cfg.StrOpt('flavor'),
|
||||
cfg.StrOpt('config_file'),
|
||||
]
|
||||
common_opts = [
|
||||
cfg.BoolOpt('allow_additional_image_properties', default=True,
|
||||
help=_('Whether to allow users to specify image properties '
|
||||
'beyond what the image schema provides')),
|
||||
cfg.StrOpt('data_api', default='glance.db.sqlalchemy.api',
|
||||
help=_('Python module path of data access API')),
|
||||
cfg.IntOpt('limit_param_default', default=25,
|
||||
help=_('Default value for the number of items returned by a '
|
||||
'request if not specified explicitly in the request')),
|
||||
cfg.IntOpt('api_limit_max', default=1000,
|
||||
help=_('Maximum permissible number of items that could be '
|
||||
'returned by a request')),
|
||||
cfg.BoolOpt('show_image_direct_url', default=False,
|
||||
help=_('Whether to include the backend image storage location '
|
||||
'in image properties. Revealing storage location can be a '
|
||||
'security risk, so use this setting with caution!')),
|
||||
cfg.IntOpt('image_size_cap', default=1099511627776,
|
||||
help=_("Maximum size of image a user can upload in bytes. "
|
||||
"Defaults to 1099511627776 bytes (1 TB).")),
|
||||
cfg.BoolOpt('enable_v1_api', default=True,
|
||||
help=_("Deploy the v1 OpenStack Images API. ")),
|
||||
cfg.BoolOpt('enable_v2_api', default=True,
|
||||
help=_("Deploy the v2 OpenStack Images API. ")),
|
||||
cfg.StrOpt('pydev_worker_debug_host', default=None,
|
||||
help=_('The hostname/IP of the pydev process listening for '
|
||||
'debug connections')),
|
||||
cfg.IntOpt('pydev_worker_debug_port', default=5678,
|
||||
help=_('The port on which a pydev process is listening for '
|
||||
'connections.')),
|
||||
|
||||
bind_opts = [
|
||||
cfg.StrOpt('bind_host', default='localhost'),
|
||||
cfg.IntOpt('bind_port'),
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opts(paste_deploy_opts, group='paste_deploy')
|
||||
CONF.register_opts(common_opts)
|
||||
CONF.register_opts(bind_opts)
|
||||
|
||||
CONF.import_opt('verbose', 'glance.openstack.common.log')
|
||||
CONF.import_opt('debug', 'glance.openstack.common.log')
|
||||
CONF.import_opt('log_dir', 'glance.openstack.common.log')
|
||||
CONF.import_opt('log_file', 'glance.openstack.common.log')
|
||||
CONF.import_opt('log_config', 'glance.openstack.common.log')
|
||||
CONF.import_opt('log_format', 'glance.openstack.common.log')
|
||||
CONF.import_opt('log_date_format', 'glance.openstack.common.log')
|
||||
CONF.import_opt('use_syslog', 'glance.openstack.common.log')
|
||||
CONF.import_opt('syslog_log_facility', 'glance.openstack.common.log')
|
||||
CONF.import_opt('verbose', 'portas.openstack.common.log')
|
||||
CONF.import_opt('debug', 'portas.openstack.common.log')
|
||||
CONF.import_opt('log_dir', 'portas.openstack.common.log')
|
||||
CONF.import_opt('log_file', 'portas.openstack.common.log')
|
||||
CONF.import_opt('log_config', 'portas.openstack.common.log')
|
||||
CONF.import_opt('log_format', 'portas.openstack.common.log')
|
||||
CONF.import_opt('log_date_format', 'portas.openstack.common.log')
|
||||
CONF.import_opt('use_syslog', 'portas.openstack.common.log')
|
||||
CONF.import_opt('syslog_log_facility', 'portas.openstack.common.log')
|
||||
|
||||
|
||||
def parse_args(args=None, usage=None, default_config_files=None):
|
||||
CONF(args=args,
|
||||
project='glance',
|
||||
project='portas',
|
||||
version=version.cached_version_string(),
|
||||
usage=usage,
|
||||
default_config_files=default_config_files)
|
||||
|
||||
|
||||
def parse_cache_args(args=None):
|
||||
config_files = cfg.find_config_files(project='glance', prog='glance-cache')
|
||||
parse_args(args=args, default_config_files=config_files)
|
||||
|
||||
|
||||
def setup_logging():
|
||||
"""
|
||||
Sets up the logging options for a log with supplied name
|
||||
|
@ -16,21 +16,14 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Glance exception subclasses"""
|
||||
|
||||
import urlparse
|
||||
"""Portas exception subclasses"""
|
||||
|
||||
_FATAL_EXCEPTION_FORMAT_ERRORS = False
|
||||
|
||||
|
||||
class RedirectException(Exception):
|
||||
def __init__(self, url):
|
||||
self.url = urlparse.urlparse(url)
|
||||
|
||||
|
||||
class GlanceException(Exception):
|
||||
class PortasException(Exception):
|
||||
"""
|
||||
Base Glance Exception
|
||||
Base Portas Exception
|
||||
|
||||
To correctly use this class, inherit from it and define
|
||||
a 'message' property. That message will get printf'd
|
||||
@ -50,223 +43,14 @@ class GlanceException(Exception):
|
||||
# at least get the core message out if something happened
|
||||
pass
|
||||
|
||||
super(GlanceException, self).__init__(message)
|
||||
super(PortasException, self).__init__(message)
|
||||
|
||||
|
||||
class MissingArgumentError(GlanceException):
|
||||
message = _("Missing required argument.")
|
||||
|
||||
|
||||
class MissingCredentialError(GlanceException):
|
||||
message = _("Missing required credential: %(required)s")
|
||||
|
||||
|
||||
class BadAuthStrategy(GlanceException):
|
||||
message = _("Incorrect auth strategy, expected \"%(expected)s\" but "
|
||||
"received \"%(received)s\"")
|
||||
|
||||
|
||||
class NotFound(GlanceException):
|
||||
message = _("An object with the specified identifier was not found.")
|
||||
|
||||
|
||||
class UnknownScheme(GlanceException):
|
||||
message = _("Unknown scheme '%(scheme)s' found in URI")
|
||||
|
||||
|
||||
class BadStoreUri(GlanceException):
|
||||
message = _("The Store URI was malformed.")
|
||||
|
||||
|
||||
class Duplicate(GlanceException):
|
||||
message = _("An object with the same identifier already exists.")
|
||||
|
||||
|
||||
class StorageFull(GlanceException):
|
||||
message = _("There is not enough disk space on the image storage media.")
|
||||
|
||||
|
||||
class StorageWriteDenied(GlanceException):
|
||||
message = _("Permission to write image storage media denied.")
|
||||
|
||||
|
||||
class AuthBadRequest(GlanceException):
|
||||
message = _("Connect error/bad request to Auth service at URL %(url)s.")
|
||||
|
||||
|
||||
class AuthUrlNotFound(GlanceException):
|
||||
message = _("Auth service at URL %(url)s not found.")
|
||||
|
||||
|
||||
class AuthorizationFailure(GlanceException):
|
||||
message = _("Authorization failed.")
|
||||
|
||||
|
||||
class NotAuthenticated(GlanceException):
|
||||
message = _("You are not authenticated.")
|
||||
|
||||
|
||||
class Forbidden(GlanceException):
|
||||
message = _("You are not authorized to complete this action.")
|
||||
|
||||
|
||||
class ForbiddenPublicImage(Forbidden):
|
||||
message = _("You are not authorized to complete this action.")
|
||||
|
||||
|
||||
class ProtectedImageDelete(Forbidden):
|
||||
message = _("Image %(image_id)s is protected and cannot be deleted.")
|
||||
|
||||
|
||||
#NOTE(bcwaldon): here for backwards-compatability, need to deprecate.
|
||||
class NotAuthorized(Forbidden):
|
||||
message = _("You are not authorized to complete this action.")
|
||||
|
||||
|
||||
class Invalid(GlanceException):
|
||||
message = _("Data supplied was not valid.")
|
||||
|
||||
|
||||
class InvalidSortKey(Invalid):
|
||||
message = _("Sort key supplied was not valid.")
|
||||
|
||||
|
||||
class InvalidFilterRangeValue(Invalid):
|
||||
message = _("Unable to filter using the specified range.")
|
||||
|
||||
|
||||
class ReadonlyProperty(Forbidden):
|
||||
message = _("Attribute '%(property)s' is read-only.")
|
||||
|
||||
|
||||
class ReservedProperty(Forbidden):
|
||||
message = _("Attribute '%(property)s' is reserved.")
|
||||
|
||||
|
||||
class AuthorizationRedirect(GlanceException):
|
||||
message = _("Redirecting to %(uri)s for authorization.")
|
||||
|
||||
|
||||
class DatabaseMigrationError(GlanceException):
|
||||
message = _("There was an error migrating the database.")
|
||||
|
||||
|
||||
class ClientConnectionError(GlanceException):
|
||||
message = _("There was an error connecting to a server")
|
||||
|
||||
|
||||
class ClientConfigurationError(GlanceException):
|
||||
message = _("There was an error configuring the client.")
|
||||
|
||||
|
||||
class MultipleChoices(GlanceException):
|
||||
message = _("The request returned a 302 Multiple Choices. This generally "
|
||||
"means that you have not included a version indicator in a "
|
||||
"request URI.\n\nThe body of response returned:\n%(body)s")
|
||||
|
||||
|
||||
class LimitExceeded(GlanceException):
|
||||
message = _("The request returned a 413 Request Entity Too Large. This "
|
||||
"generally means that rate limiting or a quota threshold was "
|
||||
"breached.\n\nThe response body:\n%(body)s")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.retry_after = (int(kwargs['retry']) if kwargs.get('retry')
|
||||
else None)
|
||||
super(LimitExceeded, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class ServiceUnavailable(GlanceException):
|
||||
message = _("The request returned 503 Service Unavilable. This "
|
||||
"generally occurs on service overload or other transient "
|
||||
"outage.")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.retry_after = (int(kwargs['retry']) if kwargs.get('retry')
|
||||
else None)
|
||||
super(ServiceUnavailable, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class ServerError(GlanceException):
|
||||
message = _("The request returned 500 Internal Server Error.")
|
||||
|
||||
|
||||
class UnexpectedStatus(GlanceException):
|
||||
message = _("The request returned an unexpected status: %(status)s."
|
||||
"\n\nThe response body:\n%(body)s")
|
||||
|
||||
|
||||
class InvalidContentType(GlanceException):
|
||||
message = _("Invalid content type %(content_type)s")
|
||||
|
||||
|
||||
class BadRegistryConnectionConfiguration(GlanceException):
|
||||
message = _("Registry was not configured correctly on API server. "
|
||||
"Reason: %(reason)s")
|
||||
|
||||
|
||||
class BadStoreConfiguration(GlanceException):
|
||||
message = _("Store %(store_name)s could not be configured correctly. "
|
||||
"Reason: %(reason)s")
|
||||
|
||||
|
||||
class BadDriverConfiguration(GlanceException):
|
||||
message = _("Driver %(driver_name)s could not be configured correctly. "
|
||||
"Reason: %(reason)s")
|
||||
|
||||
|
||||
class StoreDeleteNotSupported(GlanceException):
|
||||
message = _("Deleting images from this store is not supported.")
|
||||
|
||||
|
||||
class StoreAddDisabled(GlanceException):
|
||||
message = _("Configuration for store failed. Adding images to this "
|
||||
"store is disabled.")
|
||||
|
||||
|
||||
class InvalidNotifierStrategy(GlanceException):
|
||||
message = _("'%(strategy)s' is not an available notifier strategy.")
|
||||
|
||||
|
||||
class MaxRedirectsExceeded(GlanceException):
|
||||
message = _("Maximum redirects (%(redirects)s) was exceeded.")
|
||||
|
||||
|
||||
class InvalidRedirect(GlanceException):
|
||||
message = _("Received invalid HTTP redirect.")
|
||||
|
||||
|
||||
class NoServiceEndpoint(GlanceException):
|
||||
message = _("Response from Keystone does not contain a Glance endpoint.")
|
||||
|
||||
|
||||
class RegionAmbiguity(GlanceException):
|
||||
message = _("Multiple 'image' service matches for region %(region)s. This "
|
||||
"generally means that a region is required and you have not "
|
||||
"supplied one.")
|
||||
|
||||
|
||||
class WorkerCreationFailure(GlanceException):
|
||||
message = _("Server worker creation failed: %(reason)s.")
|
||||
|
||||
|
||||
class SchemaLoadError(GlanceException):
|
||||
class SchemaLoadError(PortasException):
|
||||
message = _("Unable to load schema: %(reason)s")
|
||||
|
||||
|
||||
class InvalidObject(GlanceException):
|
||||
class InvalidObject(PortasException):
|
||||
message = _("Provided object does not match schema "
|
||||
"'%(schema)s': %(reason)s")
|
||||
|
||||
|
||||
class UnsupportedHeaderFeature(GlanceException):
|
||||
message = _("Provided header feature is unsupported: %(feature)s")
|
||||
|
||||
|
||||
class InUseByStore(GlanceException):
|
||||
message = _("The image cannot be deleted because it is in use through "
|
||||
"the backend store outside of Glance.")
|
||||
|
||||
|
||||
class ImageSizeLimitExceeded(GlanceException):
|
||||
message = _("The provided image is too large.")
|
||||
|
@ -1 +1,12 @@
|
||||
__author__ = 'sad'
|
||||
from oslo.config import cfg
|
||||
|
||||
sql_connection_opt = cfg.StrOpt('sql_connection',
|
||||
default='sqlite:///portas.sqlite',
|
||||
secret=True,
|
||||
metavar='CONNECTION',
|
||||
help='A valid SQLAlchemy connection '
|
||||
'string for the metadata database. '
|
||||
'Default: %(default)s')
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.register_opt(sql_connection_opt)
|
@ -1 +1,18 @@
|
||||
__author__ = 'sad'
|
||||
from portas.db.models import Environment
|
||||
from portas.db.session import get_session
|
||||
|
||||
|
||||
class EnvironmentRepository(object):
|
||||
def list(self):
|
||||
session = get_session()
|
||||
return session.query(Environment).all()
|
||||
|
||||
def add(self, values):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
env = Environment()
|
||||
env.update(values)
|
||||
session.add(env)
|
||||
return env
|
||||
|
||||
# def update(self, env):
|
@ -1,7 +1,7 @@
|
||||
[db_settings]
|
||||
# Used to identify which repository this database is versioned under.
|
||||
# You can use the name of your project.
|
||||
repository_id=Glance Migrations
|
||||
repository_id=Portas Migrations
|
||||
|
||||
# The name of the database table used to track the schema version.
|
||||
# This name shouldn't already be used by your project.
|
||||
|
@ -1,36 +1,29 @@
|
||||
from sqlalchemy.schema import MetaData, Table, Column, ForeignKey
|
||||
from sqlalchemy.types import Integer, String, Text, DateTime
|
||||
from sqlalchemy.types import String, Text, DateTime
|
||||
|
||||
|
||||
meta = MetaData()
|
||||
|
||||
Table('datacenter', meta,
|
||||
Column('id', String(32), primary_key=True),
|
||||
Column('name', String(255)),
|
||||
Column('type', String(255)),
|
||||
Column('version', String(255)),
|
||||
Column('tenant_id',String(100)),
|
||||
Column('KMS', String(80)),
|
||||
Column('WSUS', String(80)),
|
||||
Column('extra', Text()),
|
||||
Table('environment', meta,
|
||||
Column('id', String(32), primary_key=True),
|
||||
Column('name', String(255)),
|
||||
Column('created', DateTime(), nullable=False),
|
||||
Column('updated', DateTime(), nullable=False),
|
||||
Column('tenant_id', String(36)),
|
||||
Column('description', Text()),
|
||||
)
|
||||
|
||||
Table('service', meta,
|
||||
Column('id', String(32), primary_key=True),
|
||||
Column('datacenter_id', String(32), ForeignKey('datacenter.id')),
|
||||
Column('name', String(255)),
|
||||
Column('type', String(40)),
|
||||
Column('status', String(255)),
|
||||
Column('tenant_id', String(40)),
|
||||
Column('created_at', DateTime, nullable=False),
|
||||
Column('updated_at', DateTime, nullable=False),
|
||||
Column('deployed', String(40)),
|
||||
Column('vm_id',String(40)),
|
||||
Column('extra', Text()),
|
||||
Column('id', String(32), primary_key=True),
|
||||
Column('name', String(255)),
|
||||
Column('type', String(40)),
|
||||
Column('environment_id', String(32), ForeignKey('environment.id')),
|
||||
Column('created', DateTime, nullable=False),
|
||||
Column('updated', DateTime, nullable=False),
|
||||
Column('description', Text()),
|
||||
)
|
||||
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta.bind = migrate_engine
|
||||
meta.create_all()
|
||||
|
@ -1 +0,0 @@
|
||||
# template repository default versions module
|
@ -17,19 +17,20 @@
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
SQLAlchemy models for glance data
|
||||
SQLAlchemy models for portas data
|
||||
"""
|
||||
import anyjson
|
||||
|
||||
from sqlalchemy import Column, Integer, String, BigInteger
|
||||
from sqlalchemy import Column, String, BigInteger, TypeDecorator, ForeignKey
|
||||
from sqlalchemy.ext.compiler import compiles
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import ForeignKey, DateTime, Boolean, Text
|
||||
from sqlalchemy import DateTime, Text
|
||||
from sqlalchemy.orm import relationship, backref, object_mapper
|
||||
from sqlalchemy import UniqueConstraint
|
||||
|
||||
import glance.db.sqlalchemy.api
|
||||
from glance.openstack.common import timeutils
|
||||
from glance.openstack.common import uuidutils
|
||||
from portas.openstack.common import timeutils
|
||||
from portas.openstack.common import uuidutils
|
||||
|
||||
from portas.db.session import get_session
|
||||
|
||||
BASE = declarative_base()
|
||||
|
||||
@ -40,22 +41,16 @@ def compile_big_int_sqlite(type_, compiler, **kw):
|
||||
|
||||
|
||||
class ModelBase(object):
|
||||
"""Base class for Nova and Glance Models"""
|
||||
__table_args__ = {'mysql_engine': 'InnoDB'}
|
||||
__table_initialized__ = False
|
||||
__protected_attributes__ = set([
|
||||
"created_at", "updated_at", "deleted_at", "deleted"])
|
||||
__protected_attributes__ = {"created", "updated"}
|
||||
|
||||
created_at = Column(DateTime, default=timeutils.utcnow,
|
||||
nullable=False)
|
||||
updated_at = Column(DateTime, default=timeutils.utcnow,
|
||||
nullable=False, onupdate=timeutils.utcnow)
|
||||
deleted_at = Column(DateTime)
|
||||
deleted = Column(Boolean, nullable=False, default=False)
|
||||
created = Column(DateTime, default=timeutils.utcnow,
|
||||
nullable=False)
|
||||
updated = Column(DateTime, default=timeutils.utcnow,
|
||||
nullable=False, onupdate=timeutils.utcnow)
|
||||
|
||||
def save(self, session=None):
|
||||
"""Save this object"""
|
||||
session = session or glance.db.sqlalchemy.api.get_session()
|
||||
session = session or get_session()
|
||||
session.add(self)
|
||||
session.flush()
|
||||
|
||||
@ -94,80 +89,55 @@ class ModelBase(object):
|
||||
return self.__dict__.items()
|
||||
|
||||
def to_dict(self):
|
||||
return self.__dict__.copy()
|
||||
dictionary = self.__dict__.copy()
|
||||
return {k: v for k, v in dictionary.iteritems() if k != '_sa_instance_state'}
|
||||
|
||||
|
||||
class Image(BASE, ModelBase):
|
||||
"""Represents an image in the datastore"""
|
||||
__tablename__ = 'images'
|
||||
class JsonBlob(TypeDecorator):
|
||||
impl = Text
|
||||
|
||||
def process_bind_param(self, value, dialect):
|
||||
return anyjson.serialize(value)
|
||||
|
||||
def process_result_value(self, value, dialect):
|
||||
return anyjson.deserialize(value)
|
||||
|
||||
|
||||
class Environment(BASE, ModelBase):
|
||||
"""Represents a Environment in the metadata-store"""
|
||||
__tablename__ = 'environment'
|
||||
|
||||
id = Column(String(36), primary_key=True, default=uuidutils.generate_uuid)
|
||||
name = Column(String(255))
|
||||
disk_format = Column(String(20))
|
||||
container_format = Column(String(20))
|
||||
size = Column(BigInteger)
|
||||
status = Column(String(30), nullable=False)
|
||||
is_public = Column(Boolean, nullable=False, default=False)
|
||||
checksum = Column(String(32))
|
||||
min_disk = Column(Integer(), nullable=False, default=0)
|
||||
min_ram = Column(Integer(), nullable=False, default=0)
|
||||
owner = Column(String(255))
|
||||
protected = Column(Boolean, nullable=False, default=False)
|
||||
tenant_id = Column(String(36))
|
||||
description = Column(JsonBlob())
|
||||
|
||||
|
||||
class ImageProperty(BASE, ModelBase):
|
||||
"""Represents an image properties in the datastore"""
|
||||
__tablename__ = 'image_properties'
|
||||
__table_args__ = (UniqueConstraint('image_id', 'name'), {})
|
||||
class Service(BASE, ModelBase):
|
||||
"""
|
||||
Represents an instance of service.
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
image_id = Column(String(36), ForeignKey('images.id'),
|
||||
nullable=False)
|
||||
image = relationship(Image, backref=backref('properties'))
|
||||
:var name: string
|
||||
:var type: string - type of service (e.g. Active Directory)
|
||||
"""
|
||||
|
||||
__tablename__ = 'service'
|
||||
|
||||
id = Column(String(36), primary_key=True, default=uuidutils.generate_uuid)
|
||||
name = Column(String(255), index=True, nullable=False)
|
||||
value = Column(Text)
|
||||
|
||||
|
||||
class ImageTag(BASE, ModelBase):
|
||||
"""Represents an image tag in the datastore"""
|
||||
__tablename__ = 'image_tags'
|
||||
|
||||
id = Column(Integer, primary_key=True, nullable=False)
|
||||
image_id = Column(String(36), ForeignKey('images.id'), nullable=False)
|
||||
value = Column(String(255), nullable=False)
|
||||
|
||||
|
||||
class ImageLocation(BASE, ModelBase):
|
||||
"""Represents an image location in the datastore"""
|
||||
__tablename__ = 'image_locations'
|
||||
|
||||
id = Column(Integer, primary_key=True, nullable=False)
|
||||
image_id = Column(String(36), ForeignKey('images.id'), nullable=False)
|
||||
image = relationship(Image, backref=backref('locations'))
|
||||
value = Column(Text(), nullable=False)
|
||||
|
||||
|
||||
class ImageMember(BASE, ModelBase):
|
||||
"""Represents an image members in the datastore"""
|
||||
__tablename__ = 'image_members'
|
||||
__table_args__ = (UniqueConstraint('image_id', 'member'), {})
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
image_id = Column(String(36), ForeignKey('images.id'),
|
||||
nullable=False)
|
||||
image = relationship(Image, backref=backref('members'))
|
||||
|
||||
member = Column(String(255), nullable=False)
|
||||
can_share = Column(Boolean, nullable=False, default=False)
|
||||
status = Column(String(20), nullable=False, default="pending")
|
||||
type = Column(String(255), index=True, nullable=False)
|
||||
environment_id = Column(String(36), ForeignKey('environment.id'))
|
||||
environment = relationship(Environment,
|
||||
backref=backref('service', order_by=id),
|
||||
uselist=False)
|
||||
description = Column(JsonBlob())
|
||||
|
||||
|
||||
def register_models(engine):
|
||||
"""
|
||||
Creates database tables for all models with the given engine
|
||||
"""
|
||||
models = (Image, ImageProperty, ImageMember)
|
||||
models = (Environment, Service)
|
||||
for model in models:
|
||||
model.metadata.create_all(engine)
|
||||
|
||||
@ -176,6 +146,6 @@ def unregister_models(engine):
|
||||
"""
|
||||
Drops database tables for all models with the given engine
|
||||
"""
|
||||
models = (Image, ImageProperty)
|
||||
models = (Environment, Service)
|
||||
for model in models:
|
||||
model.metadata.drop_all(engine)
|
||||
|
@ -30,15 +30,10 @@ from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.pool import NullPool
|
||||
from sqlalchemy.exc import DisconnectionError
|
||||
|
||||
from windc.common import cfg
|
||||
from windc.db import migrate_repo
|
||||
from portas.common.config import CONF as conf
|
||||
|
||||
from portas.db import migrate_repo
|
||||
|
||||
DB_GROUP_NAME = 'sql'
|
||||
DB_OPTIONS = (
|
||||
cfg.IntOpt('idle_timeout', default=3600),
|
||||
cfg.StrOpt('connection', default='sqlite:///windc.sqlite'),
|
||||
)
|
||||
|
||||
MAKER = None
|
||||
ENGINE = None
|
||||
@ -73,27 +68,26 @@ class MySQLPingListener(object):
|
||||
raise
|
||||
|
||||
|
||||
def get_session(conf, autocommit=True, expire_on_commit=False):
|
||||
def get_session(autocommit=True, expire_on_commit=False):
|
||||
"""Return a SQLAlchemy session."""
|
||||
global MAKER
|
||||
|
||||
if MAKER is None:
|
||||
MAKER = sessionmaker(autocommit=autocommit,
|
||||
expire_on_commit=expire_on_commit)
|
||||
engine = get_engine(conf)
|
||||
engine = get_engine()
|
||||
MAKER.configure(bind=engine)
|
||||
session = MAKER()
|
||||
return session
|
||||
|
||||
|
||||
def get_engine(conf):
|
||||
def get_engine():
|
||||
"""Return a SQLAlchemy engine."""
|
||||
global ENGINE
|
||||
|
||||
register_conf_opts(conf)
|
||||
connection_url = make_url(conf.sql.connection)
|
||||
connection_url = make_url(conf.sql_connection)
|
||||
if ENGINE is None or not ENGINE.url == connection_url:
|
||||
engine_args = {'pool_recycle': conf.sql.idle_timeout,
|
||||
engine_args = {'pool_recycle': 3600,
|
||||
'echo': False,
|
||||
'convert_unicode': True
|
||||
}
|
||||
@ -101,22 +95,16 @@ def get_engine(conf):
|
||||
engine_args['poolclass'] = NullPool
|
||||
if 'mysql' in connection_url.drivername:
|
||||
engine_args['listeners'] = [MySQLPingListener()]
|
||||
ENGINE = create_engine(conf.sql.connection, **engine_args)
|
||||
ENGINE = create_engine(conf.sql_connection, **engine_args)
|
||||
|
||||
sync()
|
||||
return ENGINE
|
||||
|
||||
|
||||
def register_conf_opts(conf, options=DB_OPTIONS, group=DB_GROUP_NAME):
|
||||
"""Register database options."""
|
||||
|
||||
conf.register_group(cfg.OptGroup(name=group))
|
||||
conf.register_opts(options, group=group)
|
||||
|
||||
|
||||
def sync(conf):
|
||||
register_conf_opts(conf)
|
||||
def sync():
|
||||
repo_path = os.path.abspath(os.path.dirname(migrate_repo.__file__))
|
||||
try:
|
||||
versioning_api.upgrade(conf.sql.connection, repo_path)
|
||||
versioning_api.upgrade(conf.sql_connection, repo_path)
|
||||
except versioning_exceptions.DatabaseNotControlledError:
|
||||
versioning_api.version_control(conf.sql.connection, repo_path)
|
||||
versioning_api.upgrade(conf.sql.connection, repo_path)
|
||||
versioning_api.version_control(conf.sql_connection, repo_path)
|
||||
versioning_api.upgrade(conf.sql_connection, repo_path)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,21 +44,6 @@ class Schema(object):
|
||||
def _filter_func(properties, key):
|
||||
return key in properties
|
||||
|
||||
def merge_properties(self, properties):
|
||||
# Ensure custom props aren't attempting to override base props
|
||||
original_keys = set(self.properties.keys())
|
||||
new_keys = set(properties.keys())
|
||||
intersecting_keys = original_keys.intersection(new_keys)
|
||||
conflicting_keys = [k for k in intersecting_keys
|
||||
if self.properties[k] != properties[k]]
|
||||
if len(conflicting_keys) > 0:
|
||||
props = ', '.join(conflicting_keys)
|
||||
reason = _("custom properties (%(props)s) conflict "
|
||||
"with base properties")
|
||||
raise exception.SchemaLoadError(reason=reason % {'props': props})
|
||||
|
||||
self.properties.update(properties)
|
||||
|
||||
def raw(self):
|
||||
raw = {
|
||||
'name': self.name,
|
||||
@ -70,17 +55,6 @@ class Schema(object):
|
||||
return raw
|
||||
|
||||
|
||||
class PermissiveSchema(Schema):
|
||||
@staticmethod
|
||||
def _filter_func(properties, key):
|
||||
return True
|
||||
|
||||
def raw(self):
|
||||
raw = super(PermissiveSchema, self).raw()
|
||||
raw['additionalProperties'] = {'type': 'string'}
|
||||
return raw
|
||||
|
||||
|
||||
class CollectionSchema(object):
|
||||
|
||||
def __init__(self, name, item_schema):
|
||||
|
@ -3,4 +3,4 @@ import unittest
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
def test(self):
|
||||
assert False
|
||||
assert True
|
||||
|
@ -15,6 +15,6 @@
|
||||
# under the License.
|
||||
|
||||
|
||||
from glance.openstack.common import version as common_version
|
||||
from portas.openstack.common import version as common_version
|
||||
|
||||
version_info = common_version.VersionInfo('glance')
|
||||
version_info = common_version.VersionInfo('portas')
|
||||
|
@ -28,8 +28,8 @@ function process_option {
|
||||
-P|--no-pep8) let no_pep8=1;;
|
||||
-f|--force) let force=1;;
|
||||
-u|--update) update=1;;
|
||||
--unittests-only) noseopts="$noseopts --exclude-dir=glance/tests/functional";;
|
||||
-c|--coverage) noseopts="$noseopts --with-coverage --cover-package=glance";;
|
||||
--unittests-only) noseopts="$noseopts --exclude-dir=portas/tests/functional";;
|
||||
-c|--coverage) noseopts="$noseopts --with-coverage --cover-package=portas";;
|
||||
-*) noseopts="$noseopts $1";;
|
||||
*) noseargs="$noseargs $1"
|
||||
esac
|
||||
|
@ -7,3 +7,27 @@ source-dir = doc/source
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
||||
|
||||
[compile_catalog]
|
||||
directory = portas/locale
|
||||
domain = portas
|
||||
|
||||
[update_catalog]
|
||||
domain = portas
|
||||
output_dir = portas/locale
|
||||
input_file = portas/locale/portas.pot
|
||||
|
||||
[extract_messages]
|
||||
keywords = _ gettext ngettext l_ lazy_gettext
|
||||
mapping_file = babel.cfg
|
||||
output_file = portas/locale/portas.pot
|
||||
|
||||
[nosetests]
|
||||
# NOTE(jkoelker) To run the test suite under nose install the following
|
||||
# coverage http://pypi.python.org/pypi/coverage
|
||||
# tissue http://pypi.python.org/pypi/tissue (pep8 checker)
|
||||
# openstack-nose https://github.com/jkoelker/openstack-nose
|
||||
verbosity=2
|
||||
cover-package = portas
|
||||
cover-html = true
|
||||
cover-erase = true
|
@ -25,7 +25,8 @@ project = 'portas'
|
||||
setuptools.setup(
|
||||
name=project,
|
||||
version=setup.get_version(project, '2013.1'),
|
||||
description='The Portas project provides a simple WSGI server for Windows Environment Management',
|
||||
description='The Portas project provides a simple WSGI server for Windows '
|
||||
'Environment Management',
|
||||
license='Apache License (2.0)',
|
||||
author='OpenStack',
|
||||
author_email='openstack@lists.launchpad.net',
|
||||
@ -43,6 +44,7 @@ setuptools.setup(
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Environment :: No Input/Output (Daemon)',
|
||||
'Environment :: OpenStack',
|
||||
],
|
||||
],
|
||||
scripts=['bin/portas-api'],
|
||||
py_modules=[])
|
||||
py_modules=[]
|
||||
)
|
||||
|
@ -1,23 +1,30 @@
|
||||
# The greenlet package must be compiled with gcc and needs
|
||||
# the Python.h headers. Make sure you install the python-dev
|
||||
# package to get the right headers...
|
||||
greenlet>=0.3.1
|
||||
|
||||
SQLAlchemy<=0.7.9
|
||||
Babel
|
||||
SQLAlchemy>=0.7,<=0.7.9
|
||||
anyjson
|
||||
eventlet>=0.9.12
|
||||
PasteDeploy
|
||||
Routes
|
||||
webob==1.0.8
|
||||
routes
|
||||
WebOb>=1.2
|
||||
wsgiref
|
||||
argparse
|
||||
sqlalchemy-migrate>=0.7.2
|
||||
boto
|
||||
sqlalchemy-migrate>=0.7
|
||||
httplib2
|
||||
kombu
|
||||
pycrypto>=2.1.0alpha1
|
||||
iso8601>=0.1.4
|
||||
PyChef
|
||||
|
||||
# Note you will need gcc buildtools installed and must
|
||||
# have installed libxml headers for lxml to be successfully
|
||||
# installed using pip, therefore you will need to install the
|
||||
# libxml2-dev and libxslt-dev Ubuntu packages.
|
||||
lxml
|
||||
|
||||
# For paste.util.template used in keystone.common.template
|
||||
Paste
|
||||
|
||||
passlib
|
||||
puka
|
||||
jsonschema
|
||||
python-keystoneclient>=0.2.0
|
||||
|
||||
http://tarballs.openstack.org/oslo-config/oslo-config-2013.1b4.tar.gz#egg=oslo-config
|
||||
|
@ -0,0 +1,19 @@
|
||||
# Packages needed for dev testing
|
||||
distribute>=0.6.24
|
||||
|
||||
# Needed for testing
|
||||
coverage
|
||||
fixtures>=0.3.12
|
||||
mox
|
||||
nose
|
||||
nose-exclude
|
||||
openstack.nose_plugin>=0.7
|
||||
nosehtmloutput>=0.0.3
|
||||
pep8==1.3.3
|
||||
sphinx>=1.1.2
|
||||
requests
|
||||
testtools>=0.9.22
|
||||
|
||||
# Optional packages that should be installed when testing
|
||||
xattr>=0.6.0
|
||||
pysendfile==2.0.0
|
Loading…
x
Reference in New Issue
Block a user