initial checkin
This commit is contained in:
parent
2ca24af1fb
commit
5a5dbbbee7
7
.coveragerc
Normal file
7
.coveragerc
Normal file
@ -0,0 +1,7 @@
|
||||
[run]
|
||||
branch = True
|
||||
source = ceilometermiddleware
|
||||
omit = ceilometermiddleware/tests/*
|
||||
|
||||
[report]
|
||||
ignore-errors = True
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -18,7 +18,7 @@ lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
*.egg-info
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
@ -35,6 +35,7 @@ pip-delete-this-directory.txt
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.testrespository
|
||||
.coverage
|
||||
.cache
|
||||
nosetests.xml
|
||||
|
4
.gitreview
Normal file
4
.gitreview
Normal file
@ -0,0 +1,4 @@
|
||||
[gerrit]
|
||||
host=review.openstack.org
|
||||
port=29418
|
||||
project=openstack/ceilometermiddleware.git
|
4
.testr.conf
Normal file
4
.testr.conf
Normal file
@ -0,0 +1,4 @@
|
||||
[DEFAULT]
|
||||
test_command=${PYTHON:-python} -m subunit.run discover -t ./ ./ceilometermiddleware/tests $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
16
CONTRIBUTING.rst
Normal file
16
CONTRIBUTING.rst
Normal file
@ -0,0 +1,16 @@
|
||||
If you would like to contribute to the development of OpenStack,
|
||||
you must follow the steps in this page:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html
|
||||
|
||||
Once those steps have been completed, changes to OpenStack
|
||||
should be submitted for review via the Gerrit tool, following
|
||||
the workflow documented at:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html#development-workflow
|
||||
|
||||
Pull requests submitted through GitHub will be ignored.
|
||||
|
||||
Bugs should be filed on Launchpad, not GitHub:
|
||||
|
||||
https://bugs.launchpad.net/ceilometermiddleware
|
4
HACKING.rst
Normal file
4
HACKING.rst
Normal file
@ -0,0 +1,4 @@
|
||||
ceilometermiddleware Style Commandments
|
||||
===============================================
|
||||
|
||||
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
|
30
LICENSE
30
LICENSE
@ -1,4 +1,5 @@
|
||||
Apache License
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
@ -173,30 +174,3 @@ Apache License
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
||||
|
||||
|
6
MANIFEST.in
Normal file
6
MANIFEST.in
Normal file
@ -0,0 +1,6 @@
|
||||
include AUTHORS
|
||||
include ChangeLog
|
||||
exclude .gitignore
|
||||
exclude .gitreview
|
||||
|
||||
global-exclude *.pyc
|
15
README.rst
Normal file
15
README.rst
Normal file
@ -0,0 +1,15 @@
|
||||
===============================
|
||||
ceilometermiddleware
|
||||
===============================
|
||||
|
||||
OpenStack Telemetry middleware for generating metrics
|
||||
|
||||
* Free software: Apache license
|
||||
* Documentation: http://docs.openstack.org/developer/ceilometermiddleware
|
||||
* Source: http://git.openstack.org/cgit/openstack/ceilometermiddleware
|
||||
* Bugs: http://bugs.launchpad.net/ceilometer
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* TODO
|
38
ceilometermiddleware.egg-info/PKG-INFO
Normal file
38
ceilometermiddleware.egg-info/PKG-INFO
Normal file
@ -0,0 +1,38 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: ceilometermiddleware
|
||||
Version: 0.0.0.post1
|
||||
Summary: OpenStack Telemetry middleware for generating metrics
|
||||
Home-page: http://www.openstack.org/
|
||||
Author: OpenStack
|
||||
Author-email: openstack-dev@lists.openstack.org
|
||||
License: UNKNOWN
|
||||
Description: ===============================
|
||||
ceilometermiddleware
|
||||
===============================
|
||||
|
||||
OpenStack Telemetry middleware for generating metrics
|
||||
|
||||
* Free software: Apache license
|
||||
* Documentation: http://docs.openstack.org/developer/ceilometermiddleware
|
||||
* Source: http://git.openstack.org/cgit/openstack/ceilometermiddleware
|
||||
* Bugs: http://bugs.launchpad.net/ceilometer
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* TODO
|
||||
|
||||
|
||||
Platform: UNKNOWN
|
||||
Classifier: Environment :: OpenStack
|
||||
Classifier: Intended Audience :: Information Technology
|
||||
Classifier: Intended Audience :: System Administrators
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Operating System :: POSIX :: Linux
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 2.6
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.3
|
||||
Classifier: Programming Language :: Python :: 3.4
|
35
ceilometermiddleware.egg-info/SOURCES.txt
Normal file
35
ceilometermiddleware.egg-info/SOURCES.txt
Normal file
@ -0,0 +1,35 @@
|
||||
.coveragerc
|
||||
.mailmap
|
||||
.testr.conf
|
||||
AUTHORS
|
||||
CONTRIBUTING.rst
|
||||
ChangeLog
|
||||
HACKING.rst
|
||||
LICENSE
|
||||
MANIFEST.in
|
||||
README.rst
|
||||
babel.cfg
|
||||
openstack-common.conf
|
||||
requirements.txt
|
||||
setup.cfg
|
||||
setup.py
|
||||
test-requirements.txt
|
||||
tox.ini
|
||||
ceilometermiddleware/__init__.py
|
||||
ceilometermiddleware/swift.py
|
||||
ceilometermiddleware.egg-info/PKG-INFO
|
||||
ceilometermiddleware.egg-info/SOURCES.txt
|
||||
ceilometermiddleware.egg-info/dependency_links.txt
|
||||
ceilometermiddleware.egg-info/not-zip-safe
|
||||
ceilometermiddleware.egg-info/pbr.json
|
||||
ceilometermiddleware.egg-info/requires.txt
|
||||
ceilometermiddleware.egg-info/top_level.txt
|
||||
ceilometermiddleware/tests/__init__.py
|
||||
ceilometermiddleware/tests/base.py
|
||||
ceilometermiddleware/tests/test_swift.py
|
||||
doc/source/conf.py
|
||||
doc/source/contributing.rst
|
||||
doc/source/index.rst
|
||||
doc/source/installation.rst
|
||||
doc/source/readme.rst
|
||||
doc/source/usage.rst
|
1
ceilometermiddleware.egg-info/dependency_links.txt
Normal file
1
ceilometermiddleware.egg-info/dependency_links.txt
Normal file
@ -0,0 +1 @@
|
||||
|
1
ceilometermiddleware.egg-info/not-zip-safe
Normal file
1
ceilometermiddleware.egg-info/not-zip-safe
Normal file
@ -0,0 +1 @@
|
||||
|
1
ceilometermiddleware.egg-info/pbr.json
Normal file
1
ceilometermiddleware.egg-info/pbr.json
Normal file
@ -0,0 +1 @@
|
||||
{"is_release": false, "git_version": "e8cd146"}
|
8
ceilometermiddleware.egg-info/requires.txt
Normal file
8
ceilometermiddleware.egg-info/requires.txt
Normal file
@ -0,0 +1,8 @@
|
||||
oslo.config>=1.6.0
|
||||
oslo.context>=0.1.0
|
||||
oslo.messaging>=1.4.0,!=1.5.0
|
||||
oslo.utils>=1.2.0
|
||||
pbr>=0.6,!=0.7,<1.0
|
||||
pycadf>=0.6.0
|
||||
six>=1.7.0
|
||||
Babel>=1.3
|
1
ceilometermiddleware.egg-info/top_level.txt
Normal file
1
ceilometermiddleware.egg-info/top_level.txt
Normal file
@ -0,0 +1 @@
|
||||
ceilometermiddleware
|
19
ceilometermiddleware/__init__.py
Normal file
19
ceilometermiddleware/__init__.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 pbr.version
|
||||
|
||||
|
||||
__version__ = pbr.version.VersionInfo(
|
||||
'ceilometermiddleware').version_string()
|
BIN
ceilometermiddleware/__init__.pyc
Normal file
BIN
ceilometermiddleware/__init__.pyc
Normal file
Binary file not shown.
225
ceilometermiddleware/swift.py
Normal file
225
ceilometermiddleware/swift.py
Normal file
@ -0,0 +1,225 @@
|
||||
#
|
||||
# Copyright 2012 eNovance <licensing@enovance.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Telemetry Middleware for Swift Proxy
|
||||
|
||||
Configuration:
|
||||
In /etc/swift/proxy-server.conf on the main pipeline add "ceilometer" just
|
||||
before "proxy-server" and add the following filter in the file:
|
||||
.. code-block:: python
|
||||
[filter:ceilometer]
|
||||
paste.filter_factory = ceilometermiddleware.swift:R
|
||||
# Some optional configuration this allow to publish additional metadata
|
||||
metadata_headers = X-TEST
|
||||
# Set reseller prefix (defaults to "AUTH_" if not set)
|
||||
reseller_prefix = AUTH_
|
||||
"""
|
||||
import functools
|
||||
import logging
|
||||
|
||||
import oslo.messaging
|
||||
from oslo_config import cfg
|
||||
from oslo_context import context
|
||||
from oslo_utils import timeutils
|
||||
from pycadf import event as cadf_event
|
||||
from pycadf import measurement as cadf_measurement
|
||||
from pycadf import metric as cadf_metric
|
||||
from pycadf import resource as cadf_resource
|
||||
import six
|
||||
import six.moves.urllib.parse as urlparse
|
||||
|
||||
_LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _log_and_ignore_error(fn):
|
||||
@functools.wraps(fn)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return fn(*args, **kwargs)
|
||||
except Exception as e:
|
||||
_LOG.exception('An exception occurred processing '
|
||||
'the API call: %s ', e)
|
||||
return wrapper
|
||||
|
||||
|
||||
class InputProxy(object):
|
||||
"""File-like object that counts bytes read.
|
||||
|
||||
To be swapped in for wsgi.input for accounting purposes.
|
||||
Borrowed from swift.common.utils. Duplicated here to avoid
|
||||
dependency on swift package.
|
||||
"""
|
||||
def __init__(self, wsgi_input):
|
||||
self.wsgi_input = wsgi_input
|
||||
self.bytes_received = 0
|
||||
|
||||
def read(self, *args, **kwargs):
|
||||
"""Pass read request to the underlying file-like object
|
||||
|
||||
Add bytes read to total.
|
||||
"""
|
||||
chunk = self.wsgi_input.read(*args, **kwargs)
|
||||
self.bytes_received += len(chunk)
|
||||
return chunk
|
||||
|
||||
def readline(self, *args, **kwargs):
|
||||
"""Pass readline request to the underlying file-like object
|
||||
|
||||
Add bytes read to total.
|
||||
"""
|
||||
line = self.wsgi_input.readline(*args, **kwargs)
|
||||
self.bytes_received += len(line)
|
||||
return line
|
||||
|
||||
|
||||
class Swift(object):
|
||||
"""Swift middleware used for counting requests."""
|
||||
|
||||
def __init__(self, app, conf):
|
||||
self._app = app
|
||||
|
||||
self._notifier = oslo.messaging.Notifier(
|
||||
oslo.messaging.get_transport(cfg.CONF),
|
||||
publisher_id='ceilometermiddleware')
|
||||
|
||||
self.metadata_headers = [h.strip().replace('-', '_').lower()
|
||||
for h in conf.get(
|
||||
"metadata_headers",
|
||||
"").split(",") if h.strip()]
|
||||
|
||||
self.reseller_prefix = conf.get('reseller_prefix', 'AUTH_')
|
||||
if self.reseller_prefix and self.reseller_prefix[-1] != '_':
|
||||
self.reseller_prefix += '_'
|
||||
|
||||
def __call__(self, env, start_response):
|
||||
start_response_args = [None]
|
||||
input_proxy = InputProxy(env['wsgi.input'])
|
||||
env['wsgi.input'] = input_proxy
|
||||
|
||||
def my_start_response(status, headers, exc_info=None):
|
||||
start_response_args[0] = (status, list(headers), exc_info)
|
||||
|
||||
def iter_response(iterable):
|
||||
iterator = iter(iterable)
|
||||
try:
|
||||
chunk = next(iterator)
|
||||
while not chunk:
|
||||
chunk = next(iterator)
|
||||
except StopIteration:
|
||||
chunk = ''
|
||||
|
||||
if start_response_args[0]:
|
||||
start_response(*start_response_args[0])
|
||||
bytes_sent = 0
|
||||
try:
|
||||
while chunk:
|
||||
bytes_sent += len(chunk)
|
||||
yield chunk
|
||||
chunk = next(iterator)
|
||||
finally:
|
||||
self.emit_event(env, input_proxy.bytes_received, bytes_sent)
|
||||
|
||||
try:
|
||||
iterable = self._app(env, my_start_response)
|
||||
except Exception:
|
||||
self.emit_event(env, input_proxy.bytes_received, 0, 'failure')
|
||||
raise
|
||||
else:
|
||||
return iter_response(iterable)
|
||||
|
||||
@_log_and_ignore_error
|
||||
def emit_event(self, env, bytes_received, bytes_sent, outcome='success'):
|
||||
path = urlparse.quote(env['PATH_INFO'])
|
||||
method = env['REQUEST_METHOD']
|
||||
headers = {}
|
||||
for header in env:
|
||||
if header.startswith('HTTP_') and env[header]:
|
||||
key = header[5:]
|
||||
if isinstance(env[header], six.text_type):
|
||||
headers[key] = env[header].encode('utf-8')
|
||||
else:
|
||||
headers[key] = str(env[header])
|
||||
|
||||
try:
|
||||
container = obj = None
|
||||
version, account, remainder = path.replace(
|
||||
'/', '', 1).split('/', 2)
|
||||
if not version or not account:
|
||||
raise ValueError('Invalid path: %s' % path)
|
||||
if remainder:
|
||||
if '/' in remainder:
|
||||
container, obj = remainder.split('/', 1)
|
||||
else:
|
||||
container = remainder
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
now = timeutils.utcnow().isoformat()
|
||||
|
||||
resource_metadata = {
|
||||
"path": path,
|
||||
"version": version,
|
||||
"container": container,
|
||||
"object": obj,
|
||||
}
|
||||
|
||||
for header in self.metadata_headers:
|
||||
if header.upper() in headers:
|
||||
resource_metadata['http_header_%s' % header] = headers.get(
|
||||
header.upper())
|
||||
|
||||
# build object store details
|
||||
target = cadf_resource.Resource(
|
||||
typeURI='service/storage/object',
|
||||
id=account.partition(self.reseller_prefix)[2])
|
||||
target.metadata = resource_metadata
|
||||
target.action = method.lower()
|
||||
|
||||
# build user details
|
||||
initiator = cadf_resource.Resource(
|
||||
typeURI='service/security/account/user',
|
||||
id=env.get('HTTP_X_USER_ID'))
|
||||
initiator.project_id = env.get('HTTP_X_TENANT_ID')
|
||||
|
||||
# build notification body
|
||||
event = cadf_event.Event(eventTime=now, outcome=outcome,
|
||||
initiator=initiator, target=target,
|
||||
observer=cadf_resource.Resource(id='target'))
|
||||
|
||||
# measurements
|
||||
if bytes_received:
|
||||
event.add_measurement(cadf_measurement.Measurement(
|
||||
result=bytes_received,
|
||||
metric=cadf_metric.Metric(
|
||||
name='storage.objects.incoming.bytes', unit='B')))
|
||||
if bytes_sent:
|
||||
event.add_measurement(cadf_measurement.Measurement(
|
||||
result=bytes_sent,
|
||||
metric=cadf_metric.Metric(
|
||||
name='storage.objects.outgoing.bytes', unit='B')))
|
||||
|
||||
self._notifier.info(context.get_admin_context().to_dict(),
|
||||
'objectstore.http.request', event.as_dict())
|
||||
|
||||
|
||||
def filter_factory(global_conf, **local_conf):
|
||||
conf = global_conf.copy()
|
||||
conf.update(local_conf)
|
||||
|
||||
def filter(app):
|
||||
return Swift(app, conf)
|
||||
return filter
|
BIN
ceilometermiddleware/swift.pyc
Normal file
BIN
ceilometermiddleware/swift.pyc
Normal file
Binary file not shown.
0
ceilometermiddleware/tests/__init__.py
Normal file
0
ceilometermiddleware/tests/__init__.py
Normal file
BIN
ceilometermiddleware/tests/__init__.pyc
Normal file
BIN
ceilometermiddleware/tests/__init__.pyc
Normal file
Binary file not shown.
23
ceilometermiddleware/tests/base.py
Normal file
23
ceilometermiddleware/tests/base.py
Normal file
@ -0,0 +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
|
||||
#
|
||||
# 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 oslotest import base
|
||||
|
||||
|
||||
class TestCase(base.BaseTestCase):
|
||||
|
||||
"""Test case base class for all unit tests."""
|
BIN
ceilometermiddleware/tests/base.pyc
Normal file
BIN
ceilometermiddleware/tests/base.pyc
Normal file
Binary file not shown.
330
ceilometermiddleware/tests/test_swift.py
Normal file
330
ceilometermiddleware/tests/test_swift.py
Normal file
@ -0,0 +1,330 @@
|
||||
#
|
||||
# Copyright 2012 eNovance <licensing@enovance.com>
|
||||
#
|
||||
# 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 oslo_config import cfg
|
||||
from oslo_utils import timeutils
|
||||
import six
|
||||
|
||||
from ceilometermiddleware import swift
|
||||
from ceilometermiddleware.tests import base as tests_base
|
||||
|
||||
|
||||
class FakeApp(object):
|
||||
def __init__(self, body=None):
|
||||
self.body = body or ['This string is 28 bytes long']
|
||||
|
||||
def __call__(self, env, start_response):
|
||||
yield
|
||||
start_response('200 OK', [
|
||||
('Content-Type', 'text/plain'),
|
||||
('Content-Length', str(sum(map(len, self.body))))
|
||||
])
|
||||
while env['wsgi.input'].read(5):
|
||||
pass
|
||||
for line in self.body:
|
||||
yield line
|
||||
|
||||
|
||||
class FakeRequest(object):
|
||||
"""A bare bones request object
|
||||
|
||||
The middleware will inspect this for request method,
|
||||
wsgi.input and headers.
|
||||
"""
|
||||
|
||||
def __init__(self, path, environ=None, headers=None):
|
||||
environ = environ or {}
|
||||
headers = headers or {}
|
||||
|
||||
environ['PATH_INFO'] = path
|
||||
|
||||
if 'wsgi.input' not in environ:
|
||||
environ['wsgi.input'] = six.moves.cStringIO('')
|
||||
|
||||
for header, value in headers.iteritems():
|
||||
environ['HTTP_%s' % header.upper()] = value
|
||||
self.environ = environ
|
||||
|
||||
|
||||
@mock.patch('oslo.messaging.get_transport', mock.MagicMock())
|
||||
class TestSwift(tests_base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestSwift, self).setUp()
|
||||
cfg.CONF([], project='ceilometermiddleware')
|
||||
self.addCleanup(cfg.CONF.reset)
|
||||
|
||||
@staticmethod
|
||||
def start_response(*args):
|
||||
pass
|
||||
|
||||
def test_get(self):
|
||||
app = swift.Swift(FakeApp(), {})
|
||||
req = FakeRequest('/1.0/account/container/obj',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
resp = app(req.environ, self.start_response)
|
||||
self.assertEqual(["This string is 28 bytes long"], list(resp))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
self.assertEqual(28, data[2]['measurements'][0]['result'])
|
||||
self.assertEqual('storage.objects.outgoing.bytes',
|
||||
data[2]['measurements'][0]['metric']['name'])
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertEqual('obj', metadata['object'])
|
||||
self.assertEqual('get', data[2]['target']['action'])
|
||||
|
||||
def test_put(self):
|
||||
app = swift.Swift(FakeApp(body=['']), {})
|
||||
req = FakeRequest(
|
||||
'/1.0/account/container/obj',
|
||||
environ={'REQUEST_METHOD': 'PUT',
|
||||
'wsgi.input':
|
||||
six.moves.cStringIO('some stuff')})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
self.assertEqual(10, data[2]['measurements'][0]['result'])
|
||||
self.assertEqual('storage.objects.incoming.bytes',
|
||||
data[2]['measurements'][0]['metric']['name'])
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertEqual('obj', metadata['object'])
|
||||
self.assertEqual('put', data[2]['target']['action'])
|
||||
|
||||
def test_post(self):
|
||||
app = swift.Swift(FakeApp(body=['']), {})
|
||||
req = FakeRequest(
|
||||
'/1.0/account/container/obj',
|
||||
environ={'REQUEST_METHOD': 'POST',
|
||||
'wsgi.input': six.moves.cStringIO('some other stuff')})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
self.assertEqual(16, data[2]['measurements'][0]['result'])
|
||||
self.assertEqual('storage.objects.incoming.bytes',
|
||||
data[2]['measurements'][0]['metric']['name'])
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertEqual('obj', metadata['object'])
|
||||
self.assertEqual('post', data[2]['target']['action'])
|
||||
|
||||
def test_head(self):
|
||||
app = swift.Swift(FakeApp(body=['']), {})
|
||||
req = FakeRequest('/1.0/account/container/obj',
|
||||
environ={'REQUEST_METHOD': 'HEAD'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
self.assertIsNone(data[2].get('measurements'))
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertEqual('obj', metadata['object'])
|
||||
self.assertEqual('head', data[2]['target']['action'])
|
||||
|
||||
def test_bogus_request(self):
|
||||
"""Test even for arbitrary request method, this will still work."""
|
||||
app = swift.Swift(FakeApp(body=['']), {})
|
||||
req = FakeRequest('/1.0/account/container/obj',
|
||||
environ={'REQUEST_METHOD': 'BOGUS'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
self.assertIsNone(data[2].get('measurements'))
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertEqual('obj', metadata['object'])
|
||||
self.assertEqual('bogus', data[2]['target']['action'])
|
||||
|
||||
def test_get_container(self):
|
||||
app = swift.Swift(FakeApp(), {})
|
||||
req = FakeRequest('/1.0/account/container',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
self.assertEqual(28, data[2]['measurements'][0]['result'])
|
||||
self.assertEqual('storage.objects.outgoing.bytes',
|
||||
data[2]['measurements'][0]['metric']['name'])
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertIsNone(metadata['object'])
|
||||
self.assertEqual('get', data[2]['target']['action'])
|
||||
|
||||
def test_no_metadata_headers(self):
|
||||
app = swift.Swift(FakeApp(), {})
|
||||
req = FakeRequest('/1.0/account/container',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertIsNone(metadata['object'])
|
||||
self.assertEqual('get', data[2]['target']['action'])
|
||||
http_headers = [k for k in metadata.keys()
|
||||
if k.startswith('http_header_')]
|
||||
self.assertEqual(0, len(http_headers))
|
||||
|
||||
def test_metadata_headers(self):
|
||||
app = swift.Swift(FakeApp(), {
|
||||
'metadata_headers': 'X_VAR1, x-var2, x-var3, token'
|
||||
})
|
||||
req = FakeRequest('/1.0/account/container',
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
headers={'X_VAR1': 'value1',
|
||||
'X_VAR2': 'value2',
|
||||
'TOKEN': 'token'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertIsNone(metadata['object'])
|
||||
self.assertEqual('get', data[2]['target']['action'])
|
||||
http_headers = [k for k in metadata.keys()
|
||||
if k.startswith('http_header_')]
|
||||
self.assertEqual(3, len(http_headers))
|
||||
self.assertEqual('value1', metadata['http_header_x_var1'])
|
||||
self.assertEqual('value2', metadata['http_header_x_var2'])
|
||||
self.assertEqual('token', metadata['http_header_token'])
|
||||
self.assertFalse('http_header_x_var3' in metadata)
|
||||
|
||||
def test_metadata_headers_unicode(self):
|
||||
app = swift.Swift(FakeApp(), {
|
||||
'metadata_headers': 'unicode'
|
||||
})
|
||||
uni = u'\xef\xbd\xa1\xef\xbd\xa5'
|
||||
req = FakeRequest('/1.0/account/container',
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
headers={'UNICODE': uni})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertIsNone(metadata['object'])
|
||||
self.assertEqual('get', data[2]['target']['action'])
|
||||
http_headers = [k for k in metadata.keys()
|
||||
if k.startswith('http_header_')]
|
||||
self.assertEqual(1, len(http_headers))
|
||||
self.assertEqual(uni.encode('utf-8'),
|
||||
metadata['http_header_unicode'])
|
||||
|
||||
def test_metadata_headers_on_not_existing_header(self):
|
||||
app = swift.Swift(FakeApp(), {
|
||||
'metadata_headers': 'x-var3'
|
||||
})
|
||||
req = FakeRequest('/1.0/account/container',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual('objectstore.http.request', data[1])
|
||||
metadata = data[2]['target']['metadata']
|
||||
self.assertEqual('1.0', metadata['version'])
|
||||
self.assertEqual('container', metadata['container'])
|
||||
self.assertIsNone(metadata['object'])
|
||||
self.assertEqual('get', data[2]['target']['action'])
|
||||
http_headers = [k for k in metadata.keys()
|
||||
if k.startswith('http_header_')]
|
||||
self.assertEqual(0, len(http_headers))
|
||||
|
||||
def test_bogus_path(self):
|
||||
app = swift.Swift(FakeApp(), {})
|
||||
req = FakeRequest('/5.0//',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(0, len(notify.call_args_list))
|
||||
|
||||
def test_missing_resource_id(self):
|
||||
app = swift.Swift(FakeApp(), {})
|
||||
req = FakeRequest('/v1/', environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(0, len(notify.call_args_list))
|
||||
|
||||
@mock.patch.object(timeutils, 'utcnow')
|
||||
def test_emit_event_fail(self, mocked_time):
|
||||
mocked_time.side_effect = Exception("a exception")
|
||||
app = swift.Swift(FakeApp(body=["test"]), {})
|
||||
req = FakeRequest('/1.0/account/container',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
resp = list(app(req.environ, self.start_response))
|
||||
self.assertEqual(0, len(notify.call_args_list))
|
||||
self.assertEqual(["test"], resp)
|
||||
|
||||
def test_reseller_prefix(self):
|
||||
app = swift.Swift(FakeApp(), {})
|
||||
req = FakeRequest('/1.0/AUTH_account/container/obj',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual("account", data[2]['target']['id'])
|
||||
|
||||
def test_custom_prefix(self):
|
||||
app = swift.Swift(FakeApp(), {'reseller_prefix': 'CUSTOM_'})
|
||||
req = FakeRequest('/1.0/CUSTOM_account/container/obj',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual("account", data[2]['target']['id'])
|
||||
|
||||
def test_invalid_reseller_prefix(self):
|
||||
# Custom reseller prefix set, but without trailing underscore
|
||||
app = swift.Swift(
|
||||
FakeApp(), {'reseller_prefix': 'CUSTOM'})
|
||||
req = FakeRequest('/1.0/CUSTOM_account/container/obj',
|
||||
environ={'REQUEST_METHOD': 'GET'})
|
||||
with mock.patch('oslo.messaging.Notifier.info') as notify:
|
||||
list(app(req.environ, self.start_response))
|
||||
self.assertEqual(1, len(notify.call_args_list))
|
||||
data = notify.call_args_list[0][0]
|
||||
self.assertEqual("account", data[2]['target']['id'])
|
BIN
ceilometermiddleware/tests/test_swift.pyc
Normal file
BIN
ceilometermiddleware/tests/test_swift.pyc
Normal file
Binary file not shown.
75
doc/source/conf.py
Executable file
75
doc/source/conf.py
Executable file
@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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 sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
#'sphinx.ext.intersphinx',
|
||||
'oslosphinx'
|
||||
]
|
||||
|
||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||
# text edit cycles.
|
||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'ceilometermiddleware'
|
||||
copyright = u'2013, OpenStack Foundation'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
# html_theme_path = ["."]
|
||||
# html_theme = '_theme'
|
||||
# html_static_path = ['static']
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index',
|
||||
'%s.tex' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'OpenStack Foundation', 'manual'),
|
||||
]
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
4
doc/source/contributing.rst
Normal file
4
doc/source/contributing.rst
Normal file
@ -0,0 +1,4 @@
|
||||
============
|
||||
Contributing
|
||||
============
|
||||
.. include:: ../../CONTRIBUTING.rst
|
25
doc/source/index.rst
Normal file
25
doc/source/index.rst
Normal file
@ -0,0 +1,25 @@
|
||||
.. ceilometermiddleware documentation master file, created by
|
||||
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to ceilometermiddleware's documentation!
|
||||
========================================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
readme
|
||||
installation
|
||||
usage
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
12
doc/source/installation.rst
Normal file
12
doc/source/installation.rst
Normal file
@ -0,0 +1,12 @@
|
||||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
At the command line::
|
||||
|
||||
$ pip install ceilometermiddleware
|
||||
|
||||
Or, if you have virtualenvwrapper installed::
|
||||
|
||||
$ mkvirtualenv ceilometermiddleware
|
||||
$ pip install ceilometermiddleware
|
1
doc/source/readme.rst
Normal file
1
doc/source/readme.rst
Normal file
@ -0,0 +1 @@
|
||||
.. include:: ../../README.rst
|
7
doc/source/usage.rst
Normal file
7
doc/source/usage.rst
Normal file
@ -0,0 +1,7 @@
|
||||
========
|
||||
Usage
|
||||
========
|
||||
|
||||
To use ceilometermiddleware in a project::
|
||||
|
||||
import ceilometermiddleware
|
6
openstack-common.conf
Normal file
6
openstack-common.conf
Normal file
@ -0,0 +1,6 @@
|
||||
[DEFAULT]
|
||||
|
||||
# The list of modules to copy from oslo-incubator.git
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=ceilometermiddleware
|
12
requirements.txt
Normal file
12
requirements.txt
Normal file
@ -0,0 +1,12 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
oslo.config>=1.6.0
|
||||
oslo.context>=0.1.0
|
||||
oslo.messaging>=1.4.0,!=1.5.0
|
||||
oslo.utils>=1.2.0
|
||||
pbr>=0.6,!=0.7,<1.0
|
||||
pycadf>=0.6.0
|
||||
six>=1.7.0
|
||||
Babel>=1.3
|
47
setup.cfg
Normal file
47
setup.cfg
Normal file
@ -0,0 +1,47 @@
|
||||
[metadata]
|
||||
name = ceilometermiddleware
|
||||
summary = OpenStack Telemetry middleware for generating metrics
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://www.openstack.org/
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Information Technology
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 2.6
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.3
|
||||
Programming Language :: Python :: 3.4
|
||||
|
||||
[files]
|
||||
packages =
|
||||
ceilometermiddleware
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
all_files = 1
|
||||
|
||||
[upload_sphinx]
|
||||
upload-dir = doc/build/html
|
||||
|
||||
[compile_catalog]
|
||||
directory = ceilometermiddleware/locale
|
||||
domain = ceilometermiddleware
|
||||
|
||||
[update_catalog]
|
||||
domain = ceilometermiddleware
|
||||
output_dir = ceilometermiddleware/locale
|
||||
input_file = ceilometermiddleware/locale/ceilometermiddleware.pot
|
||||
|
||||
[extract_messages]
|
||||
keywords = _ gettext ngettext l_ lazy_gettext
|
||||
mapping_file = babel.cfg
|
||||
output_file = ceilometermiddleware/locale/ceilometermiddleware.pot
|
22
setup.py
Executable file
22
setup.py
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
# 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
|
||||
#
|
||||
# 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 FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True)
|
15
test-requirements.txt
Normal file
15
test-requirements.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
hacking>=0.10.0,<0.11
|
||||
|
||||
coverage>=3.6
|
||||
discover
|
||||
python-subunit
|
||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
||||
oslosphinx>=2.2.0
|
||||
oslotest>=1.2.0
|
||||
testrepository>=0.0.18
|
||||
testscenarios>=0.4
|
||||
testtools>=0.9.36,!=1.2.0
|
37
tox.ini
Normal file
37
tox.ini
Normal file
@ -0,0 +1,37 @@
|
||||
[tox]
|
||||
minversion = 1.6
|
||||
envlist = py33,py34,py26,py27,pypy,pep8
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
install_command = pip install -U {opts} {packages}
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands = python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:pep8]
|
||||
commands = flake8
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:cover]
|
||||
commands = python setup.py testr --coverage --testr-args='{posargs}'
|
||||
|
||||
[testenv:docs]
|
||||
commands = python setup.py build_sphinx
|
||||
|
||||
[testenv:debug]
|
||||
commands = oslo_debug_helper {posargs}
|
||||
|
||||
[flake8]
|
||||
# H803 skipped on purpose per list discussion.
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
|
||||
show-source = True
|
||||
ignore = E123,E125,H803
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build
|
Loading…
Reference in New Issue
Block a user