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/
|
parts/
|
||||||
sdist/
|
sdist/
|
||||||
var/
|
var/
|
||||||
*.egg-info/
|
*.egg-info
|
||||||
.installed.cfg
|
.installed.cfg
|
||||||
*.egg
|
*.egg
|
||||||
|
|
||||||
@ -35,6 +35,7 @@ pip-delete-this-directory.txt
|
|||||||
# Unit test / coverage reports
|
# Unit test / coverage reports
|
||||||
htmlcov/
|
htmlcov/
|
||||||
.tox/
|
.tox/
|
||||||
|
.testrespository
|
||||||
.coverage
|
.coverage
|
||||||
.cache
|
.cache
|
||||||
nosetests.xml
|
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
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
@ -173,30 +174,3 @@ Apache License
|
|||||||
incurred by, or claims asserted against, such Contributor by reason
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
of your accepting any such warranty or additional liability.
|
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