diff --git a/ekko/api/__init__.py b/ekko/api/__init__.py
deleted file mode 100644
index c5a60f3..0000000
--- a/ekko/api/__init__.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# 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.
-
-from oslo_config import cfg
-
-# TODO(pbourke): add i18n support
-_ = lambda x: x
-
-API_SERVICE_OPTS = [
- cfg.StrOpt('host_ip',
- default='0.0.0.0',
- help=_('The IP address on which ekko-api listens.')),
- cfg.PortOpt('port',
- default=6800,
- help=_('The TCP port on which ekko-api listens.')),
- cfg.IntOpt('max_limit',
- default=1000,
- help=_('The maximum number of items returned in a single '
- 'response from a collection resource.')),
- cfg.StrOpt('public_endpoint',
- default=None,
- # TODO(pbourke): decide on port for ekko
- help=_("Public URL to use when building the links to the API "
- "resources (for example, \"https://ekko.rocks:6800\")."
- " If None the links will be built using the request's "
- "host URL. If the API is operating behind a proxy, you "
- "will want to change this to represent the proxy's URL. "
- "Defaults to None.")),
- cfg.IntOpt('api_workers',
- help=_('Number of workers for OpenStack ekko API service. '
- 'The default is equal to the number of CPUs available '
- 'if that can be determined, else a default worker '
- 'count of 1 is returned.')),
- cfg.BoolOpt('enable_ssl_api',
- default=False,
- help=_("Enable the integrated stand-alone API to service "
- "requests via HTTPS instead of HTTP. If there is a "
- "front-end service performing HTTPS offloading from "
- "the service, this option should be False; note, you "
- "will want to change public API endpoint to represent "
- "SSL termination URL with 'public_endpoint' option.")),
-]
-
-CONF = cfg.CONF
-opt_group = cfg.OptGroup(name='api',
- title='Options for the ekko-api service')
-CONF.register_group(opt_group)
-CONF.register_opts(API_SERVICE_OPTS, opt_group)
diff --git a/ekko/api/app.py b/ekko/api/app.py
deleted file mode 100644
index 9871d87..0000000
--- a/ekko/api/app.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#
-# 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 pecan
-
-from oslo_config import cfg
-
-from ekko.api import config
-# TODO(pbourke): port hooks module
-# from ekko.api import hooks
-from ekko.api import middleware
-
-# TODO(pbourke): add i18n support
-_ = lambda x: x
-
-api_opts = [
- cfg.StrOpt(
- 'auth_strategy',
- default='keystone',
- help=_('Authentication strategy used by ekko-api: one of "keystone" '
- 'or "noauth". "noauth" should not be used in a production '
- 'environment because all authentication will be disabled.')),
- cfg.BoolOpt('debug_tracebacks_in_api',
- default=False,
- help=_('Return server tracebacks in the API response for any '
- 'error responses. WARNING: this is insecure '
- 'and should not be used in a production environment.')),
- cfg.BoolOpt('pecan_debug',
- default=False,
- help=_('Enable pecan debug mode. WARNING: this is insecure '
- 'and should not be used in a production environment.')),
-]
-
-CONF = cfg.CONF
-CONF.register_opts(api_opts)
-
-
-def get_pecan_config():
- # Set up the pecan configuration
- filename = config.__file__.replace('.pyc', '.py')
- return pecan.configuration.conf_from_file(filename)
-
-
-def setup_app(pecan_config=None, extra_hooks=None):
- # TODO(pbourke): port hooks module
- # app_hooks = [hooks.ConfigHook(),
- # hooks.DBHook(),
- # hooks.ContextHook(pecan_config.app.acl_public_routes),
- # hooks.RPCHook(),
- # hooks.NoExceptionTracebackHook(),
- # hooks.PublicUrlHook()]
- # if extra_hooks:
- # app_hooks.extend(extra_hooks)
-
- if not pecan_config:
- pecan_config = get_pecan_config()
-
- # if pecan_config.app.enable_acl:
- # app_hooks.append(hooks.TrustedCallHook())
-
- pecan.configuration.set_config(dict(pecan_config), overwrite=True)
-
- app = pecan.make_app(
- pecan_config.app.root,
- static_root=pecan_config.app.static_root,
- debug=CONF.pecan_debug,
- force_canonical=getattr(pecan_config.app, 'force_canonical', True),
- # hooks=app_hooks,
- wrap_app=middleware.ParsableErrorMiddleware,
- )
-
- # if pecan_config.app.enable_acl:
- # app = acl.install(app, cfg.CONF, pecan_config.app.acl_public_routes)
-
- return app
-
-
-class VersionSelectorApplication(object):
- def __init__(self):
- pc = get_pecan_config()
- pc.app.enable_acl = (CONF.auth_strategy == 'keystone')
- self.v1 = setup_app(pecan_config=pc)
-
- def __call__(self, environ, start_response):
- return self.v1(environ, start_response)
diff --git a/ekko/api/config.py b/ekko/api/config.py
deleted file mode 100644
index f738d42..0000000
--- a/ekko/api/config.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# 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.
-
-# Server Specific Configurations
-# See https://pecan.readthedocs.org/en/latest/configuration.html#server-configuration # noqa
-server = {
- 'port': '6800',
- 'host': '0.0.0.0'
-}
-
-# Pecan Application Configurations
-# See https://pecan.readthedocs.org/en/latest/configuration.html#application-configuration # noqa
-app = {
- 'root': 'ekko.api.controllers.root.RootController',
- 'modules': ['ekko.api'],
- 'static_root': '%(confdir)s/public',
- 'debug': False,
- 'enable_acl': True,
- 'acl_public_routes': [
- '/',
- '/v1',
- ],
-}
-
-# WSME Configurations
-# See https://wsme.readthedocs.org/en/latest/integrate.html#configuration
-wsme = {
- 'debug': False,
-}
diff --git a/ekko/api/controllers/__init__.py b/ekko/api/controllers/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/ekko/api/controllers/base.py b/ekko/api/controllers/base.py
deleted file mode 100644
index ff2832a..0000000
--- a/ekko/api/controllers/base.py
+++ /dev/null
@@ -1,112 +0,0 @@
-#
-# 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 datetime
-import functools
-
-from webob import exc
-import wsme
-from wsme import types as wtypes
-
-# TODO(pbourke): add i18n support
-_ = lambda x: x
-
-
-class APIBase(wtypes.Base):
-
- created_at = wsme.wsattr(datetime.datetime, readonly=True)
- """The time in UTC at which the object is created"""
-
- updated_at = wsme.wsattr(datetime.datetime, readonly=True)
- """The time in UTC at which the object is updated"""
-
- def as_dict(self):
- """Render this object as a dict of its fields."""
- return dict((k, getattr(self, k))
- for k in self.fields
- if hasattr(self, k) and
- getattr(self, k) != wsme.Unset)
-
- def unset_fields_except(self, except_list=None):
- """Unset fields so they don't appear in the message body.
-
- :param except_list: A list of fields that won't be touched.
-
- """
- if except_list is None:
- except_list = []
-
- for k in self.as_dict():
- if k not in except_list:
- setattr(self, k, wsme.Unset)
-
-
-@functools.total_ordering
-class Version(object):
- """API Version object."""
-
- string = 'X-OpenStack-Ekko-API-Version'
- """HTTP Header string carrying the requested version"""
-
- min_string = 'X-OpenStack-Ekko-API-Minimum-Version'
- """HTTP response header"""
-
- max_string = 'X-OpenStack-Ekko-API-Maximum-Version'
- """HTTP response header"""
-
- def __init__(self, headers, default_version, latest_version):
- """Create an API Version object from the supplied headers.
-
- :param headers: webob headers
- :param default_version: version to use if not specified in headers
- :param latest_version: version to use if latest is requested
- :raises: webob.HTTPNotAcceptable
- """
- (self.major, self.minor) = Version.parse_headers(
- headers, default_version, latest_version)
-
- def __repr__(self):
- return '%s.%s' % (self.major, self.minor)
-
- @staticmethod
- def parse_headers(headers, default_version, latest_version):
- """Determine the API version requested based on the headers supplied.
-
- :param headers: webob headers
- :param default_version: version to use if not specified in headers
- :param latest_version: version to use if latest is requested
- :returns: a tupe of (major, minor) version numbers
- :raises: webob.HTTPNotAcceptable
- """
- version_str = headers.get(Version.string, default_version)
-
- if version_str.lower() == 'latest':
- parse_str = latest_version
- else:
- parse_str = version_str
-
- try:
- version = tuple(int(i) for i in parse_str.split('.'))
- except ValueError:
- version = ()
-
- if len(version) != 2:
- raise exc.HTTPNotAcceptable(_(
- "Invalid value for %s header") % Version.string)
- return version
-
- def __gt__(a, b):
- return (a.major, a.minor) > (b.major, b.minor)
-
- def __eq__(a, b):
- return (a.major, a.minor) == (b.major, b.minor)
diff --git a/ekko/api/controllers/root.py b/ekko/api/controllers/root.py
deleted file mode 100644
index a3df428..0000000
--- a/ekko/api/controllers/root.py
+++ /dev/null
@@ -1,111 +0,0 @@
-#
-# 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 pecan
-from pecan import rest
-from wsme import types as wtypes
-
-from ekko.api.controllers import base
-from ekko.api.controllers import v1
-from ekko.api.controllers.v1 import versions
-from ekko.api import expose
-
-ID_VERSION1 = 'v1'
-
-
-class Version(base.APIBase):
- """An API version representation.
-
- This class represents an API version, including the minimum and
- maximum minor versions that are supported within the major version.
- """
-
- id = wtypes.text
- """The ID of the (major) version, also acts as the release number"""
-
- status = wtypes.text
- """Status of the version.
-
- One of:
- * CURRENT - the latest version of API,
- * SUPPORTED - supported, but not latest, version of API,
- * DEPRECATED - supported, but deprecated, version of API.
- """
-
- version = wtypes.text
- """The current, maximum supported (major.minor) version of API."""
-
- min_version = wtypes.text
- """Minimum supported (major.minor) version of API."""
-
- def __init__(self, id, min_version, version, status='CURRENT'):
- self.id = id
- self.status = status
- self.version = version
- self.min_version = min_version
-
-
-class Root(base.APIBase):
-
- name = wtypes.text
- """The name of the API"""
-
- description = wtypes.text
- """Some information about this API"""
-
- versions = [Version]
- """Links to all the versions available in this API"""
-
- default_version = Version
- """A link to the default version of the API"""
-
- @staticmethod
- def convert():
- root = Root()
- root.name = "OpenStack Ekko API"
- root.description = ("Block-based backups stored in object-storage.")
- root.default_version = Version(ID_VERSION1,
- versions.MIN_VERSION_STRING,
- versions.MAX_VERSION_STRING)
- root.versions = [root.default_version]
- return root
-
-
-class RootController(rest.RestController):
-
- _versions = [ID_VERSION1]
- """All supported API versions"""
-
- _default_version = ID_VERSION1
- """The default API version"""
-
- v1 = v1.Controller()
-
- @expose.expose(Root)
- def get(self):
- # NOTE: The reason why convert() it's being called for every
- # request is because we need to get the host url from
- # the request object to make the links.
- return Root.convert()
-
- @pecan.expose()
- def _route(self, args):
- """Overrides the default routing behavior.
-
- It redirects the request to the default version of the ekko API
- if the version number is not specified in the url.
- """
-
- if args[0] and args[0] not in self._versions:
- args = [self._default_version] + args
- return super(RootController, self)._route(args)
diff --git a/ekko/api/controllers/v1/__init__.py b/ekko/api/controllers/v1/__init__.py
deleted file mode 100644
index eeeebed..0000000
--- a/ekko/api/controllers/v1/__init__.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# 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 pecan
-from pecan import rest
-from webob import exc
-from wsme import types as wtypes
-
-from ekko.api.controllers import base
-from ekko.api.controllers.v1 import versions
-from ekko.api import expose
-
-# TODO(pbourke): add i18n support
-_ = lambda x: x
-
-BASE_VERSION = versions.BASE_VERSION
-
-MIN_VER = base.Version(
- {base.Version.string: versions.MIN_VERSION_STRING},
- versions.MIN_VERSION_STRING, versions.MAX_VERSION_STRING)
-MAX_VER = base.Version(
- {base.Version.string: versions.MAX_VERSION_STRING},
- versions.MIN_VERSION_STRING, versions.MAX_VERSION_STRING)
-
-
-class MediaType(base.APIBase):
- """A media type representation."""
-
- base = wtypes.text
- type = wtypes.text
-
- def __init__(self, base, type):
- self.base = base
- self.type = type
-
-
-class V1(base.APIBase):
- """The representation of the version 1 of the API."""
-
- id = wtypes.text
- """The ID of the version, also acts as the release number"""
-
- media_types = [MediaType]
- """An array of supported media types for this version"""
-
- @staticmethod
- def convert():
- v1 = V1()
- v1.id = "v1"
-
- v1.media_types = [MediaType('application/json',
- 'application/vnd.openstack.ekko.v1+json')]
-
- return v1
-
-
-class Controller(rest.RestController):
- """Version 1 API controller root."""
-
- @expose.expose(V1)
- def get(self):
- # NOTE: The reason why convert() it's being called for every
- # request is because we need to get the host url from
- # the request object to make the links.
- return V1.convert()
-
- def _check_version(self, version, headers=None):
- if headers is None:
- headers = {}
- # ensure that major version in the URL matches the header
- if version.major != BASE_VERSION:
- raise exc.HTTPNotAcceptable(_(
- "Mutually exclusive versions requested. Version %(ver)s "
- "requested but not supported by this service. The supported "
- "version range is: [%(min)s, %(max)s].") %
- {'ver': version, 'min': versions.MIN_VERSION_STRING,
- 'max': versions.MAX_VERSION_STRING},
- headers=headers)
- # ensure the minor version is within the supported range
- if version < MIN_VER or version > MAX_VER:
- raise exc.HTTPNotAcceptable(_(
- "Version %(ver)s was requested but the minor version is not "
- "supported by this service. The supported version range is: "
- "[%(min)s, %(max)s].") %
- {'ver': version, 'min': versions.MIN_VERSION_STRING,
- 'max': versions.MAX_VERSION_STRING},
- headers=headers)
-
- @pecan.expose()
- def _route(self, args):
- v = base.Version(pecan.request.headers, versions.MIN_VERSION_STRING,
- versions.MAX_VERSION_STRING)
-
- # Always set the min and max headers
- pecan.response.headers[base.Version.min_string] = (
- versions.MIN_VERSION_STRING)
- pecan.response.headers[base.Version.max_string] = (
- versions.MAX_VERSION_STRING)
-
- # assert that requested version is supported
- self._check_version(v, pecan.response.headers)
- pecan.response.headers[base.Version.string] = str(v)
- pecan.request.version = v
-
- return super(Controller, self)._route(args)
-
-
-__all__ = (Controller)
diff --git a/ekko/api/controllers/v1/versions.py b/ekko/api/controllers/v1/versions.py
deleted file mode 100644
index c2b9d84..0000000
--- a/ekko/api/controllers/v1/versions.py
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# 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.
-
-# This is the version 1 API
-BASE_VERSION = 1
-
-# Here goes a short log of changes in every version.
-# Refer to doc/source/webapi/v1.rst for a detailed explanation of what
-# each version contains.
-#
-# v1.0: Initial version of the Ekko API
-
-MINOR_0_INITIAL_VERSION = 0
-
-# When adding another version, update MINOR_MAX_VERSION and also update
-# doc/source/webapi/v1.rst with a detailed explanation of what the version has
-# changed.
-MINOR_MAX_VERSION = MINOR_0_INITIAL_VERSION
-
-# String representations of the minor and maximum versions
-MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_0_INITIAL_VERSION)
-MAX_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_MAX_VERSION)
diff --git a/ekko/api/expose.py b/ekko/api/expose.py
deleted file mode 100644
index 9412211..0000000
--- a/ekko/api/expose.py
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# 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 wsmeext.pecan as wsme_pecan
-
-
-def expose(*args, **kwargs):
- """Ensure that only JSON, and not XML, is supported."""
- if 'rest_content_types' not in kwargs:
- kwargs['rest_content_types'] = ('json',)
- return wsme_pecan.wsexpose(*args, **kwargs)
diff --git a/ekko/api/middleware/__init__.py b/ekko/api/middleware/__init__.py
deleted file mode 100644
index 5266385..0000000
--- a/ekko/api/middleware/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# 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.
-
-from ekko.api.middleware import auth_token
-from ekko.api.middleware import parsable_error
-
-
-ParsableErrorMiddleware = parsable_error.ParsableErrorMiddleware
-AuthTokenMiddleware = auth_token.AuthTokenMiddleware
-
-__all__ = (ParsableErrorMiddleware,
- AuthTokenMiddleware)
diff --git a/ekko/api/middleware/auth_token.py b/ekko/api/middleware/auth_token.py
deleted file mode 100644
index 484bd57..0000000
--- a/ekko/api/middleware/auth_token.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#
-# 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 re
-
-from keystonemiddleware import auth_token
-from oslo_log import log
-
-from ekko.common import exception
-
-LOG = log.getLogger(__name__)
-
-# TODO(pbourke): add i18n support
-_ = lambda x: x
-
-
-class AuthTokenMiddleware(auth_token.AuthProtocol):
- """A wrapper on Keystone auth_token middleware.
-
- Does not perform verification of authentication tokens
- for public routes in the API.
-
- """
- def __init__(self, app, conf, public_api_routes=[]):
- self._ekko_app = app
- # TODO(mrda): Remove .xml and ensure that doesn't result in a
- # 401 Authentication Required instead of 404 Not Found
- route_pattern_tpl = '%s(\.json|\.xml)?$'
-
- try:
- self.public_api_routes = [re.compile(route_pattern_tpl % route_tpl)
- for route_tpl in public_api_routes]
- except re.error as e:
- msg = _('Cannot compile public API routes: %s') % e
-
- LOG.error(msg)
- raise exception.ConfigInvalid(error_msg=msg)
-
- super(AuthTokenMiddleware, self).__init__(app, conf)
-
- def __call__(self, env, start_response):
- # TODO(pbourke): ironic uses a utils.safe_rstrip function here.
- path = env.get('PATH_INFO').rstrip('/')
-
- # The information whether the API call is being performed against the
- # public API is required for some other components. Saving it to the
- # WSGI environment is reasonable thereby.
- env['is_public_api'] = any(map(lambda pattern: re.match(pattern, path),
- self.public_api_routes))
-
- if env['is_public_api']:
- return self._ekko_app(env, start_response)
-
- return super(AuthTokenMiddleware, self).__call__(env, start_response)
diff --git a/ekko/api/middleware/parsable_error.py b/ekko/api/middleware/parsable_error.py
deleted file mode 100644
index 40c5d61..0000000
--- a/ekko/api/middleware/parsable_error.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#
-# 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.
-
-"""
-Middleware to replace the plain text message body of an error
-response with one formatted so the client can parse it.
-
-Based on pecan.middleware.errordocument
-"""
-
-import json
-from xml import etree as et
-
-from oslo_log import log
-import six
-import webob
-
-
-LOG = log.getLogger(__name__)
-
-# TODO(pbourke): add i18n support
-_ = _LE = lambda x: x
-
-
-class ParsableErrorMiddleware(object):
- """Replace error body with something the client can parse."""
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- # Request for this state, modified by replace_start_response()
- # and used when an error is being reported.
- state = {}
-
- def replacement_start_response(status, headers, exc_info=None):
- """Overrides the default response to make errors parsable."""
- try:
- status_code = int(status.split(' ')[0])
- state['status_code'] = status_code
- except (ValueError, TypeError): # pragma: nocover
- raise Exception(_(
- 'ErrorDocumentMiddleware received an invalid '
- 'status %s') % status)
- else:
- if (state['status_code'] // 100) not in (2, 3):
- # Remove some headers so we can replace them later
- # when we have the full error message and can
- # compute the length.
- headers = [(h, v)
- for (h, v) in headers
- if h not in ('Content-Length', 'Content-Type')
- ]
- # Save the headers in case we need to modify them.
- state['headers'] = headers
- return start_response(status, headers, exc_info)
-
- app_iter = self.app(environ, replacement_start_response)
- if (state['status_code'] // 100) not in (2, 3):
- req = webob.Request(environ)
- if (req.accept.best_match(['application/json', 'application/xml'])
- == 'application/xml'):
- try:
- # simple check xml is valid
- body = [et.ElementTree.tostring(
- et.ElementTree.fromstring(''
- + '\n'.join(app_iter)
- + ''))]
- except et.ElementTree.ParseError as err:
- LOG.error(_LE('Error parsing HTTP response: %s'), err)
- body = ['%s' % state['status_code']
- + '']
- state['headers'].append(('Content-Type', 'application/xml'))
- else:
- if six.PY3:
- app_iter = [i.decode('utf-8') for i in app_iter]
- body = [json.dumps({'error_message': '\n'.join(app_iter)})]
- if six.PY3:
- body = [item.encode('utf-8') for item in body]
- state['headers'].append(('Content-Type', 'application/json'))
- state['headers'].append(('Content-Length', str(len(body[0]))))
- else:
- body = app_iter
- return body
diff --git a/ekko/cmd/__init__.py b/ekko/cmd/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/ekko/cmd/api.py b/ekko/cmd/api.py
deleted file mode 100644
index bd4a0a5..0000000
--- a/ekko/cmd/api.py
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# 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 sys
-
-from oslo_config import cfg
-
-from ekko.common import service as ekko_service
-
-CONF = cfg.CONF
-
-
-def main():
- # Parse config file and command line options, then start logging
- ekko_service.prepare_service(sys.argv)
-
- # Build and start the WSGI app
- launcher = ekko_service.process_launcher()
- server = ekko_service.WSGIService('ekko_api', CONF.api.enable_ssl_api)
- launcher.launch_service(server, workers=server.workers)
- launcher.wait()
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/ekko/common/__init__.py b/ekko/common/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/ekko/common/config.py b/ekko/common/config.py
deleted file mode 100644
index 5a34570..0000000
--- a/ekko/common/config.py
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# 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.
-
-from oslo_config import cfg
-
-# from ekko.common import rpc
-# from ekko import version
-
-
-def parse_args(argv, default_config_files=None):
- # rpc.set_defaults(control_exchange='ekko')
- cfg.CONF(argv[1:],
- project='ekko',
- # version=version.version_info.release_string(),
- default_config_files=default_config_files)
- # rpc.init(cfg.CONF)
diff --git a/ekko/common/exception.py b/ekko/common/exception.py
deleted file mode 100644
index 064461b..0000000
--- a/ekko/common/exception.py
+++ /dev/null
@@ -1,131 +0,0 @@
-#
-# 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.
-
-from oslo_config import cfg
-from oslo_log import log as logging
-import six
-from six.moves import http_client
-
-# TODO(pbourke): add i18n support
-_ = _LE = _LW = lambda x: x
-
-
-LOG = logging.getLogger(__name__)
-
-exc_log_opts = [
- cfg.BoolOpt('fatal_exception_format_errors',
- default=False,
- help=_('Used if there is a formatting error when generating '
- 'an exception message (a programming error). If True, '
- 'raise an exception; if False, use the unformatted '
- 'message.')),
-]
-
-CONF = cfg.CONF
-CONF.register_opts(exc_log_opts)
-
-
-class EkkoException(Exception):
- """Base Ekko Exception
-
- To correctly use this class, inherit from it and define
- a '_msg_fmt' property. That message will get printf'd
- with the keyword arguments provided to the constructor.
-
- If you need to access the message from an exception you should use
- six.text_type(exc)
-
- """
- _msg_fmt = _("An unknown exception occurred.")
- code = http_client.INTERNAL_SERVER_ERROR
- headers = {}
- safe = False
-
- def __init__(self, message=None, **kwargs):
- self.kwargs = kwargs
-
- if 'code' not in self.kwargs:
- try:
- self.kwargs['code'] = self.code
- except AttributeError:
- pass
-
- if not message:
- # Check if class is using deprecated 'message' attribute.
- if (hasattr(self, 'message') and self.message):
- LOG.warning(_LW("Exception class: %s Using the 'message' "
- "attribute in an exception has been "
- "deprecated. The exception class should be "
- "modified to use the '_msg_fmt' "
- "attribute."), self.__class__.__name__)
- self._msg_fmt = self.message
-
- try:
- message = self._msg_fmt % kwargs
-
- except Exception as e:
- # kwargs doesn't match a variable in self._msg_fmt
- # log the issue and the kwargs
- LOG.exception(_LE('Exception in string format operation'))
- for name, value in kwargs.items():
- LOG.error("%s: %s" % (name, value))
-
- if CONF.fatal_exception_format_errors:
- raise e
- else:
- # at least get the core self._msg_fmt out if something
- # happened
- message = self._msg_fmt
-
- super(EkkoException, self).__init__(message)
-
- def __str__(self):
- """Encode to utf-8 then wsme api can consume it as well."""
- if not six.PY3:
- return unicode(self.args[0]).encode('utf-8')
-
- return self.args[0]
-
- def __unicode__(self):
- """Return a unicode representation of the exception message."""
- return unicode(self.args[0])
-
-
-class NotAuthorized(EkkoException):
- _msg_fmt = _("Not authorized.")
- code = http_client.FORBIDDEN
-
-
-class OperationNotPermitted(NotAuthorized):
- _msg_fmt = _("Operation not permitted.")
-
-
-class Invalid(EkkoException):
- _msg_fmt = _("Unacceptable parameters.")
- code = http_client.BAD_REQUEST
-
-
-class Conflict(EkkoException):
- _msg_fmt = _('Conflict.')
- code = http_client.CONFLICT
-
-
-class TemporaryFailure(EkkoException):
- _msg_fmt = _("Resource temporarily unavailable, please retry.")
- code = http_client.SERVICE_UNAVAILABLE
-
-
-class NotAcceptable(EkkoException):
- # TODO(deva): We need to set response headers in the API for this exception
- _msg_fmt = _("Request not acceptable.")
- code = http_client.NOT_ACCEPTABLE
diff --git a/ekko/common/service.py b/ekko/common/service.py
deleted file mode 100644
index be2b2d9..0000000
--- a/ekko/common/service.py
+++ /dev/null
@@ -1,109 +0,0 @@
-#
-# 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 socket
-
-from oslo_concurrency import processutils
-from oslo_config import cfg
-from oslo_log import log
-from oslo_service import service
-from oslo_service import wsgi
-
-from ekko.api import app
-from ekko.common import config
-
-# TODO(pbourke): add i18n support
-_ = lambda x: x
-
-
-service_opts = [
- cfg.IntOpt('periodic_interval',
- default=60,
- help=_('Seconds between running periodic tasks.')),
- cfg.StrOpt('host',
- default=socket.getfqdn(),
- help=_('Name of this node. This can be an opaque identifier. '
- 'It is not necessarily a hostname, FQDN, or IP address. '
- 'However, the node name must be valid within '
- 'an AMQP key, and if using ZeroMQ, a valid '
- 'hostname, FQDN, or IP address.')),
-]
-
-
-CONF = cfg.CONF
-LOG = log.getLogger(__name__)
-
-CONF.register_opts(service_opts)
-
-
-def prepare_service(argv=[]):
- log.register_options(CONF)
- config.parse_args(argv)
- log.setup(CONF, 'ekko')
-
-
-def process_launcher():
- return service.ProcessLauncher(CONF)
-
-
-class WSGIService(service.ServiceBase):
- """Provides ability to launch ekko API from wsgi app."""
-
- def __init__(self, name, use_ssl=False):
- """Initialize, but do not start the WSGI server.
-
- :param name: The name of the WSGI server given to the loader.
- :param use_ssl: Wraps the socket in an SSL context if True.
- :returns: None
- """
- self.name = name
- self.app = app.VersionSelectorApplication()
- self.workers = (CONF.api.api_workers or
- processutils.get_worker_count())
- if self.workers and self.workers < 1:
- raise Exception(
- _("api_workers value of %d is invalid, "
- "must be greater than 0.") % self.workers)
-
- self.server = wsgi.Server(CONF, name, self.app,
- host=CONF.api.host_ip,
- port=CONF.api.port,
- use_ssl=use_ssl)
-
- def start(self):
- """Start serving this service using loaded configuration.
-
- :returns: None
- """
- self.server.start()
-
- def stop(self):
- """Stop serving this API.
-
- :returns: None
- """
- self.server.stop()
-
- def wait(self):
- """Wait for the service to stop serving this API.
-
- :returns: None
- """
- self.server.wait()
-
- def reset(self):
- """Reset server greenpool size to default.
-
- :returns: None
- """
- self.server.reset()
diff --git a/ekko/tests/base.py b/ekko/tests/base.py
index bc07e11..1c30cdb 100644
--- a/ekko/tests/base.py
+++ b/ekko/tests/base.py
@@ -1,142 +1,23 @@
+# -*- coding: utf-8 -*-
+
+# Copyright 2010-2011 OpenStack Foundation
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
-# 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
+# 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
+# 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.
+# 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.
-"""Base classes for our unit tests.
-
-Allows overriding of config for use of fakes, and some black magic for
-inline callbacks.
-
-"""
-
-# import copy
-import os
-import sys
-# import tempfile
-
-import eventlet
-eventlet.monkey_patch(os=False)
-import fixtures
-from oslo_config import cfg
-from oslo_context import context as ekko_context
-from oslo_log import log as logging
-import testtools
-
-# from ekko.objects import base as objects_base
-from ekko.tests.unit import conf_fixture
-# from ekko.tests.unit import policy_fixture
+from oslotest import base
-CONF = cfg.CONF
-logging.register_options(CONF)
-CONF.set_override('use_stderr', False)
+class TestCase(base.BaseTestCase):
-logging.setup(CONF, 'ekko')
-
-
-class ReplaceModule(fixtures.Fixture):
- """Replace a module with a fake module."""
-
- def __init__(self, name, new_value):
- self.name = name
- self.new_value = new_value
-
- def _restore(self, old_value):
- sys.modules[self.name] = old_value
-
- def setUp(self):
- super(ReplaceModule, self).setUp()
- old_value = sys.modules.get(self.name)
- sys.modules[self.name] = self.new_value
- self.addCleanup(self._restore, old_value)
-
-
-class TestingException(Exception):
- pass
-
-
-class TestCase(testtools.TestCase):
"""Test case base class for all unit tests."""
-
- def setUp(self):
- """Run before each test method to initialize test environment."""
- super(TestCase, self).setUp()
- self.context = ekko_context.get_admin_context()
- test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
- try:
- test_timeout = int(test_timeout)
- except ValueError:
- # If timeout value is invalid do not set a timeout.
- test_timeout = 0
- if test_timeout > 0:
- self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
- self.useFixture(fixtures.NestedTempfile())
- self.useFixture(fixtures.TempHomeDir())
- # self.config(tempdir=tempfile.tempdir)
-
- if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
- os.environ.get('OS_STDOUT_CAPTURE') == '1'):
- stdout = self.useFixture(fixtures.StringStream('stdout')).stream
- self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
- if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
- os.environ.get('OS_STDERR_CAPTURE') == '1'):
- stderr = self.useFixture(fixtures.StringStream('stderr')).stream
- self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
-
- self.log_fixture = self.useFixture(fixtures.FakeLogger())
- self.useFixture(conf_fixture.ConfFixture(CONF))
-
- # NOTE(danms): Make sure to reset us back to non-remote objects
- # for each test to avoid interactions. Also, backup the object
- # registry
- # objects_base.EkkoObject.indirection_api = None
- # self._base_test_obj_backup = copy.copy(
- # objects_base.EkkoObjectRegistry.obj_classes())
- # self.addCleanup(self._restore_obj_registry)
-
- self.addCleanup(self._clear_attrs)
- self.useFixture(fixtures.EnvironmentVariable('http_proxy'))
- # self.policy = self.useFixture(policy_fixture.PolicyFixture())
- # CONF.set_override('fatal_exception_format_errors', True)
-
- # def _restore_obj_registry(self):
- # objects_base.EkkoObjectRegistry._registry._obj_classes = (
- # self._base_test_obj_backup)
-
- def _clear_attrs(self):
- # Delete attributes that don't start with _ so they don't pin
- # memory around unnecessarily for the duration of the test
- # suite
- for key in [k for k in self.__dict__.keys() if k[0] != '_']:
- del self.__dict__[key]
-
- def config(self, **kw):
- """Override config options for a test."""
- group = kw.pop('group', None)
- for k, v in kw.items():
- CONF.set_override(k, v, group)
-
- def path_get(self, project_file=None):
- """Get the absolute path to a file. Used for testing the API.
-
- :param project_file: File whose path to return. Default: None.
- :returns: path to the specified file, or path to project root.
- """
- root = os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..',
- '..',
- )
- )
- if project_file:
- return os.path.join(root, project_file)
- else:
- return root
diff --git a/ekko/tests/unit/__init__.py b/ekko/tests/unit/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/ekko/tests/unit/api/__init__.py b/ekko/tests/unit/api/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/ekko/tests/unit/api/base.py b/ekko/tests/unit/api/base.py
deleted file mode 100644
index 620a5db..0000000
--- a/ekko/tests/unit/api/base.py
+++ /dev/null
@@ -1,237 +0,0 @@
-#
-# 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.
-
-# NOTE: Ported from ceilometer/tests/api.py (subsequently moved to
-# ceilometer/tests/api/__init__.py). This should be oslo'ified:
-# https://bugs.launchpad.net/ekko/+bug/1255115.
-
-import mock
-from oslo_config import cfg
-import pecan
-import pecan.testing
-from six.moves.urllib import parse as urlparse
-
-# from ekko.tests.unit.db import base
-from ekko.tests import base
-
-PATH_PREFIX = '/v1'
-
-cfg.CONF.import_group('keystone_authtoken', 'keystonemiddleware.auth_token')
-
-
-# class BaseApiTest(base.DbTestCase):
-class BaseApiTest(base.TestCase):
- """Pecan controller functional testing class.
-
- Used for functional tests of Pecan controllers where you need to
- test your literal application and its integration with the
- framework.
- """
-
- SOURCE_DATA = {'test_source': {'somekey': '666'}}
-
- def setUp(self):
- super(BaseApiTest, self).setUp()
- cfg.CONF.set_override("auth_version", "v2.0",
- group='keystone_authtoken')
- cfg.CONF.set_override("admin_user", "admin",
- group='keystone_authtoken')
- self.app = self._make_app()
-
- def reset_pecan():
- pecan.set_config({}, overwrite=True)
-
- self.addCleanup(reset_pecan)
-
- p = mock.patch('ekko.api.controllers.v1.Controller._check_version')
- self._check_version = p.start()
- self.addCleanup(p.stop)
-
- def _make_app(self, enable_acl=False):
- # Determine where we are so we can set up paths in the config
- root_dir = self.path_get()
-
- self.config = {
- 'app': {
- 'root': 'ekko.api.controllers.root.RootController',
- 'modules': ['ekko.api'],
- 'static_root': '%s/public' % root_dir,
- 'template_path': '%s/api/templates' % root_dir,
- 'enable_acl': enable_acl,
- 'acl_public_routes': ['/', '/v1'],
- },
- }
-
- return pecan.testing.load_test_app(self.config)
-
- def _request_json(self, path, params, expect_errors=False, headers=None,
- method="post", extra_environ=None, status=None,
- path_prefix=PATH_PREFIX):
- """Sends simulated HTTP request to Pecan test app.
-
- :param path: url path of target service
- :param params: content for wsgi.input of request
- :param expect_errors: Boolean value; whether an error is expected based
- on request
- :param headers: a dictionary of headers to send along with the request
- :param method: Request method type. Appropriate method function call
- should be used rather than passing attribute in.
- :param extra_environ: a dictionary of environ variables to send along
- with the request
- :param status: expected status code of response
- :param path_prefix: prefix of the url path
- """
- full_path = path_prefix + path
- print('%s: %s %s' % (method.upper(), full_path, params))
- response = getattr(self.app, "%s_json" % method)(
- str(full_path),
- params=params,
- headers=headers,
- status=status,
- extra_environ=extra_environ,
- expect_errors=expect_errors
- )
- print('GOT:%s' % response)
- return response
-
- def put_json(self, path, params, expect_errors=False, headers=None,
- extra_environ=None, status=None):
- """Sends simulated HTTP PUT request to Pecan test app.
-
- :param path: url path of target service
- :param params: content for wsgi.input of request
- :param expect_errors: Boolean value; whether an error is expected based
- on request
- :param headers: a dictionary of headers to send along with the request
- :param extra_environ: a dictionary of environ variables to send along
- with the request
- :param status: expected status code of response
- """
- return self._request_json(path=path, params=params,
- expect_errors=expect_errors,
- headers=headers, extra_environ=extra_environ,
- status=status, method="put")
-
- def post_json(self, path, params, expect_errors=False, headers=None,
- extra_environ=None, status=None):
- """Sends simulated HTTP POST request to Pecan test app.
-
- :param path: url path of target service
- :param params: content for wsgi.input of request
- :param expect_errors: Boolean value; whether an error is expected based
- on request
- :param headers: a dictionary of headers to send along with the request
- :param extra_environ: a dictionary of environ variables to send along
- with the request
- :param status: expected status code of response
- """
- return self._request_json(path=path, params=params,
- expect_errors=expect_errors,
- headers=headers, extra_environ=extra_environ,
- status=status, method="post")
-
- def patch_json(self, path, params, expect_errors=False, headers=None,
- extra_environ=None, status=None):
- """Sends simulated HTTP PATCH request to Pecan test app.
-
- :param path: url path of target service
- :param params: content for wsgi.input of request
- :param expect_errors: Boolean value; whether an error is expected based
- on request
- :param headers: a dictionary of headers to send along with the request
- :param extra_environ: a dictionary of environ variables to send along
- with the request
- :param status: expected status code of response
- """
- return self._request_json(path=path, params=params,
- expect_errors=expect_errors,
- headers=headers, extra_environ=extra_environ,
- status=status, method="patch")
-
- def delete(self, path, expect_errors=False, headers=None,
- extra_environ=None, status=None, path_prefix=PATH_PREFIX):
- """Sends simulated HTTP DELETE request to Pecan test app.
-
- :param path: url path of target service
- :param expect_errors: Boolean value; whether an error is expected based
- on request
- :param headers: a dictionary of headers to send along with the request
- :param extra_environ: a dictionary of environ variables to send along
- with the request
- :param status: expected status code of response
- :param path_prefix: prefix of the url path
- """
- full_path = path_prefix + path
- print('DELETE: %s' % (full_path))
- response = self.app.delete(str(full_path),
- headers=headers,
- status=status,
- extra_environ=extra_environ,
- expect_errors=expect_errors)
- print('GOT:%s' % response)
- return response
-
- def get_json(self, path, expect_errors=False, headers=None,
- extra_environ=None, q=[], path_prefix=PATH_PREFIX, **params):
- """Sends simulated HTTP GET request to Pecan test app.
-
- :param path: url path of target service
- :param expect_errors: Boolean value;whether an error is expected based
- on request
- :param headers: a dictionary of headers to send along with the request
- :param extra_environ: a dictionary of environ variables to send along
- with the request
- :param q: list of queries consisting of: field, value, op, and type
- keys
- :param path_prefix: prefix of the url path
- :param params: content for wsgi.input of request
- """
- full_path = path_prefix + path
- query_params = {'q.field': [],
- 'q.value': [],
- 'q.op': [],
- }
- for query in q:
- for name in ['field', 'op', 'value']:
- query_params['q.%s' % name].append(query.get(name, ''))
- all_params = {}
- all_params.update(params)
- if q:
- all_params.update(query_params)
- print('GET: %s %r' % (full_path, all_params))
- response = self.app.get(full_path,
- params=all_params,
- headers=headers,
- extra_environ=extra_environ,
- expect_errors=expect_errors)
- if not expect_errors:
- response = response.json
- print('GOT:%s' % response)
- return response
-
- def validate_link(self, link, bookmark=False):
- """Checks if the given link can get correct data."""
- # removes the scheme and net location parts of the link
- url_parts = list(urlparse.urlparse(link))
- url_parts[0] = url_parts[1] = ''
-
- # bookmark link should not have the version in the URL
- if bookmark and url_parts[2].startswith(PATH_PREFIX):
- return False
-
- full_path = urlparse.urlunparse(url_parts)
- try:
- self.get_json(full_path, path_prefix='')
- return True
- except Exception:
- return False
diff --git a/ekko/tests/unit/api/test_base.py b/ekko/tests/unit/api/test_base.py
deleted file mode 100644
index 4de5ebd..0000000
--- a/ekko/tests/unit/api/test_base.py
+++ /dev/null
@@ -1,117 +0,0 @@
-#
-# 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 mock
-from six.moves import http_client
-from webob import exc
-
-from ekko.api.controllers import base as cbase
-from ekko.tests.unit.api import base
-
-
-class TestBase(base.BaseApiTest):
-
- def test_api_setup(self):
- pass
-
- def test_bad_uri(self):
- response = self.get_json('/bad/path',
- expect_errors=True,
- headers={"Accept": "application/json"})
- self.assertEqual(http_client.NOT_FOUND, response.status_int)
- self.assertEqual("application/json", response.content_type)
- self.assertTrue(response.json['error_message'])
-
-
-class TestVersion(base.BaseApiTest):
-
- @mock.patch('ekko.api.controllers.base.Version.parse_headers')
- def test_init(self, mock_parse):
- a = mock.Mock()
- b = mock.Mock()
- mock_parse.return_value = (a, b)
- v = cbase.Version('test', 'foo', 'bar')
-
- mock_parse.assert_called_with('test', 'foo', 'bar')
- self.assertEqual(a, v.major)
- self.assertEqual(b, v.minor)
-
- @mock.patch('ekko.api.controllers.base.Version.parse_headers')
- def test_repr(self, mock_parse):
- mock_parse.return_value = (123, 456)
- v = cbase.Version('test', mock.ANY, mock.ANY)
- result = "%s" % v
- self.assertEqual('123.456', result)
-
- @mock.patch('ekko.api.controllers.base.Version.parse_headers')
- def test_repr_with_strings(self, mock_parse):
- mock_parse.return_value = ('abc', 'def')
- v = cbase.Version('test', mock.ANY, mock.ANY)
- result = "%s" % v
- self.assertEqual('abc.def', result)
-
- def test_parse_headers_ok(self):
- version = cbase.Version.parse_headers(
- {cbase.Version.string: '123.456'}, mock.ANY, mock.ANY)
- self.assertEqual((123, 456), version)
-
- def test_parse_headers_latest(self):
- for s in ['latest', 'LATEST']:
- version = cbase.Version.parse_headers(
- {cbase.Version.string: s}, mock.ANY, '1.9')
- self.assertEqual((1, 9), version)
-
- def test_parse_headers_bad_length(self):
- self.assertRaises(
- exc.HTTPNotAcceptable,
- cbase.Version.parse_headers,
- {cbase.Version.string: '1'},
- mock.ANY,
- mock.ANY)
- self.assertRaises(
- exc.HTTPNotAcceptable,
- cbase.Version.parse_headers,
- {cbase.Version.string: '1.2.3'},
- mock.ANY,
- mock.ANY)
-
- def test_parse_no_header(self):
- # this asserts that the minimum version string of "1.1" is applied
- version = cbase.Version.parse_headers({}, '1.1', '1.5')
- self.assertEqual((1, 1), version)
-
- def test_equals(self):
- ver_1 = cbase.Version(
- {cbase.Version.string: '123.456'}, mock.ANY, mock.ANY)
- ver_2 = cbase.Version(
- {cbase.Version.string: '123.456'}, mock.ANY, mock.ANY)
- self.assertTrue(hasattr(ver_1, '__eq__'))
- self.assertTrue(ver_1 == ver_2)
-
- def test_greaterthan(self):
- ver_1 = cbase.Version(
- {cbase.Version.string: '123.457'}, mock.ANY, mock.ANY)
- ver_2 = cbase.Version(
- {cbase.Version.string: '123.456'}, mock.ANY, mock.ANY)
- self.assertTrue(hasattr(ver_1, '__gt__'))
- self.assertTrue(ver_1 > ver_2)
-
- def test_lessthan(self):
- # __lt__ is created by @functools.total_ordering, make sure it exists
- # and works
- ver_1 = cbase.Version(
- {cbase.Version.string: '123.456'}, mock.ANY, mock.ANY)
- ver_2 = cbase.Version(
- {cbase.Version.string: '123.457'}, mock.ANY, mock.ANY)
- self.assertTrue(hasattr(ver_1, '__lt__'))
- self.assertTrue(ver_1 < ver_2)
diff --git a/ekko/tests/unit/conf_fixture.py b/ekko/tests/unit/conf_fixture.py
deleted file mode 100644
index 7770c0b..0000000
--- a/ekko/tests/unit/conf_fixture.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# 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 fixtures
-from oslo_config import cfg
-
-from ekko.common import config
-
-CONF = cfg.CONF
-CONF.import_opt('host', 'ekko.common.service')
-
-
-class ConfFixture(fixtures.Fixture):
- """Fixture to manage global conf settings."""
-
- def __init__(self, conf):
- self.conf = conf
-
- def setUp(self):
- super(ConfFixture, self).setUp()
-
- self.conf.set_default('host', 'fake-mini')
- # self.conf.set_default('connection', "sqlite://", group='database')
- # self.conf.set_default('sqlite_synchronous', False, group='database')
- self.conf.set_default('verbose', True)
- config.parse_args([], default_config_files=[])
- self.addCleanup(self.conf.reset)
diff --git a/requirements.txt b/requirements.txt
index d0448f3..13ef382 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,10 +6,3 @@ pbr>=1.6 # Apache-2.0
six>=1.9.0 # MIT
oslo.utils>=3.11.0 # Apache-2.0
stevedore>=1.10.0 # Apache-2.0
-oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config>=3.10.0 # Apache-2.0
-oslo.log>=1.14.0 # Apache-2.0
-oslo.service>=1.10.0 # Apache-2.0
-pecan>=1.0.0 # BSD
-WSME>=0.8 # MIT
-keystonemiddleware!=4.1.0,!=4.5.0,>=4.0.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index 7fee618..9aaceed 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -33,8 +33,6 @@ ekko.storage.compression_drivers =
zlib = ekko.storage._compression_drivers.zlib_:ZlibCompression
ekko.storage.encryption_drivers =
noop = ekko.storage._encryption_drivers.noop:NoopEncryption
-console_scripts =
- ekko-api = ekko.cmd.api:main
[files]
packages =
diff --git a/tox.ini b/tox.ini
index 304b7a0..771c126 100644
--- a/tox.ini
+++ b/tox.ini
@@ -10,7 +10,6 @@ install_command =
pip install -U {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
- TESTS_DIR=./ekko/tests/unit/
deps = -r{toxinidir}/test-requirements.txt
commands = python setup.py testr --slowest --testr-args='{posargs}'