initial checkin

This commit is contained in:
gordon chung 2015-01-20 18:14:51 -05:00
parent 2ca24af1fb
commit 5a5dbbbee7
41 changed files with 1012 additions and 29 deletions

7
.coveragerc Normal file
View File

@ -0,0 +1,7 @@
[run]
branch = True
source = ceilometermiddleware
omit = ceilometermiddleware/tests/*
[report]
ignore-errors = True

3
.gitignore vendored
View File

@ -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
View File

@ -0,0 +1,4 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/ceilometermiddleware.git

4
.testr.conf Normal file
View 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

1
AUTHORS Normal file
View File

@ -0,0 +1 @@
gordon chung <gord@live.ca>

16
CONTRIBUTING.rst Normal file
View 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
ChangeLog Normal file
View File

@ -0,0 +1,4 @@
CHANGES
=======
* Initial Cookiecutter Commit

4
HACKING.rst Normal file
View File

@ -0,0 +1,4 @@
ceilometermiddleware Style Commandments
===============================================
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/

30
LICENSE
View File

@ -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
View File

@ -0,0 +1,6 @@
include AUTHORS
include ChangeLog
exclude .gitignore
exclude .gitreview
global-exclude *.pyc

15
README.rst Normal file
View 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

2
babel.cfg Normal file
View File

@ -0,0 +1,2 @@
[python: **.py]

View 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

View 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

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
{"is_release": false, "git_version": "e8cd146"}

View 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

View File

@ -0,0 +1 @@
ceilometermiddleware

View 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()

Binary file not shown.

View 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

Binary file not shown.

View File

Binary file not shown.

View 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."""

Binary file not shown.

View 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'])

Binary file not shown.

75
doc/source/conf.py Executable file
View 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}

View File

@ -0,0 +1,4 @@
============
Contributing
============
.. include:: ../../CONTRIBUTING.rst

25
doc/source/index.rst Normal file
View 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`

View 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
View File

@ -0,0 +1 @@
.. include:: ../../README.rst

7
doc/source/usage.rst Normal file
View File

@ -0,0 +1,7 @@
========
Usage
========
To use ceilometermiddleware in a project::
import ceilometermiddleware

6
openstack-common.conf Normal file
View 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
View 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
View 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
View 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
View 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
View 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