diff --git a/bin/ceilometer-api b/bin/ceilometer-api index fc6da7300..ffe24a465 100755 --- a/bin/ceilometer-api +++ b/bin/ceilometer-api @@ -18,17 +18,38 @@ # under the License. """Set up the development API server. """ +import os import sys +from wsgiref import simple_server from oslo.config import cfg -from ceilometer.api.v1 import app +from ceilometer.api import app from ceilometer import service if __name__ == '__main__': - # Parse config file and command line options, - # then configure logging. + # Parse OpenStack config file and command line options, then + # configure logging. service.prepare_service(sys.argv) - root = app.make_app(cfg.CONF) - root.run(host='0.0.0.0', port=cfg.CONF.metering_api_port) + + # Build the WSGI app + root = app.VersionSelectorApplication() + + # Create the WSGI server and start it + host, port = '0.0.0.0', int(cfg.CONF.metering_api_port) + srv = simple_server.make_server(host, port, root) + + print 'Starting server in PID %s' % os.getpid() + + if host == '0.0.0.0': + print 'serving on 0.0.0.0:%s, view at http://127.0.0.1:%s' % \ + (port, port) + else: + print "serving on http://%s:%s" % (host, port) + + try: + srv.serve_forever() + except KeyboardInterrupt: + # allow CTRL+C to shutdown without an error + pass diff --git a/bin/ceilometer-api-v2 b/bin/ceilometer-api-v2 deleted file mode 100755 index a1b99df4a..000000000 --- a/bin/ceilometer-api-v2 +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# -*- encoding: utf-8 -*- -# -# Copyright © 2012 New Dream Network, LLC (DreamHost) -# -# Author: Doug Hellmann -# -# 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. -"""Set up the development API server. -""" -import os -import sys -from wsgiref import simple_server - -from oslo.config import cfg - -from ceilometer.api import app -from ceilometer import service -from ceilometer.openstack.common import log as logging - - -if __name__ == '__main__': - # Parse OpenStack config file and command line options, then - # configure logging. - service.prepare_service(sys.argv) - - # Build the WSGI app - root = app.setup_app() - - # Create the WSGI server and start it - host, port = '0.0.0.0', int(cfg.CONF.metering_api_port) - srv = simple_server.make_server(host, port, root) - - print 'Starting server in PID %s' % os.getpid() - - if host == '0.0.0.0': - print 'serving on 0.0.0.0:%s, view at http://127.0.0.1:%s' % \ - (port, port) - else: - print "serving on http://%s:%s" % (host, port) - - try: - srv.serve_forever() - except KeyboardInterrupt: - # allow CTRL+C to shutdown without an error - pass diff --git a/ceilometer/api/app.py b/ceilometer/api/app.py index 8ae09f7ef..5004171f3 100644 --- a/ceilometer/api/app.py +++ b/ceilometer/api/app.py @@ -23,6 +23,17 @@ from ceilometer.api import acl from ceilometer.api import config as api_config from ceilometer.api import hooks from ceilometer.api import middleware +from ceilometer.api.v1 import app as v1app + + +auth_opts = [ + cfg.StrOpt('auth_strategy', + default='keystone', + help='The strategy to use for auth: noauth or keystone.'), +] + +CONF = cfg.CONF +CONF.register_opts(auth_opts) def get_pecan_config(): @@ -61,3 +72,17 @@ def setup_app(pecan_config=None, extra_hooks=None): return acl.install(app, cfg.CONF) return app + + +class VersionSelectorApplication(object): + def __init__(self): + pc = get_pecan_config() + pc.app.debug = CONF.debug + pc.app.enable_acl = (CONF.auth_strategy == 'keystone') + self.v1 = v1app.make_app(cfg.CONF, enable_acl=pc.app.enable_acl) + self.v2 = setup_app(pecan_config=pc) + + def __call__(self, environ, start_response): + if environ['PATH_INFO'].startswith('/v1/'): + return self.v1(environ, start_response) + return self.v2(environ, start_response) diff --git a/etc/ceilometer/ceilometer.conf.sample b/etc/ceilometer/ceilometer.conf.sample index a4f952c96..4a5dfe5f3 100644 --- a/etc/ceilometer/ceilometer.conf.sample +++ b/etc/ceilometer/ceilometer.conf.sample @@ -74,6 +74,8 @@ # metering_api_port=8777 #### (IntOpt) The port for the ceilometer API server +# auth_strategy=keystone +### (StrOpt) one of keystone or noauth ######## defined in ceilometer.central.manager ######## diff --git a/tests/test_bin.py b/tests/test_bin.py index 240c5435c..4d6757b88 100644 --- a/tests/test_bin.py +++ b/tests/test_bin.py @@ -17,10 +17,14 @@ # License for the specific language governing permissions and limitations # under the License. -import subprocess -import unittest -import tempfile +import httplib2 +import json import os +import socket +import subprocess +import tempfile +import time +import unittest class BinDbsyncTestCase(unittest.TestCase): @@ -58,3 +62,49 @@ class BinSendCounterTestCase(unittest.TestCase): def tearDown(self): os.unlink(self.tempfile) + + +class BinApiTestCase(unittest.TestCase): + + def setUp(self): + self.api_port = 8777 + self.http = httplib2.Http() + self.tempfile = tempfile.mktemp() + with open(self.tempfile, 'w') as tmp: + tmp.write("[DEFAULT]\n") + tmp.write( + "rpc_backend=ceilometer.openstack.common.rpc.impl_fake\n") + tmp.write("database_connection=log://localhost\n") + tmp.write( + "auth_strategy=noauth\n") + tmp.write( + "debug=true\n") + self.subp = subprocess.Popen(["../bin/ceilometer-api", + "--config-file=%s" % self.tempfile]) + + def tearDown(self): + os.unlink(self.tempfile) + self.subp.kill() + self.subp.wait() + + def get_response(self, path): + url = 'http://%s:%d/%s' % ('127.0.0.1', self.api_port, path) + + for x in range(10): + try: + r, c = self.http.request(url, 'GET') + except socket.error: + time.sleep(.3) + self.assertEqual(self.subp.poll(), None) + else: + return r, c + + def test_v1(self): + response, content = self.get_response('v1/meters') + self.assertEqual(response.status, 200) + self.assertEqual(json.loads(content), {'meters': []}) + + def test_v2(self): + response, content = self.get_response('v2/meters') + self.assertEqual(response.status, 200) + self.assertEqual(json.loads(content), [])