Merge "Add API endpoint to query build information"

This commit is contained in:
Jenkins 2013-12-03 21:58:04 +00:00 committed by Gerrit Code Review
commit 070258bb10
7 changed files with 140 additions and 1 deletions

View File

@ -983,3 +983,16 @@
#insecure=false
[revision]
#
# Options defined in heat.common.config
#
# Heat build revision. If you would prefer to manage your
# build revision separately you can move this section to a
# different file and add it as another config option (string
# value)
#heat_revision=unknown

View File

@ -19,6 +19,7 @@ from heat.api.openstack.v1 import stacks
from heat.api.openstack.v1 import resources
from heat.api.openstack.v1 import events
from heat.api.openstack.v1 import actions
from heat.api.openstack.v1 import build_info
from heat.common import wsgi
from heat.openstack.common import log as logging
@ -36,8 +37,8 @@ class API(wsgi.Router):
self.conf = conf
mapper = routes.Mapper()
# Stacks
stacks_resource = stacks.create_resource(conf)
with mapper.submapper(controller=stacks_resource,
path_prefix="/{tenant_id}") as stack_mapper:
# Template handling
@ -164,4 +165,14 @@ class API(wsgi.Router):
action="action",
conditions={'method': 'POST'})
# Info
info_resource = build_info.create_resource(conf)
with mapper.submapper(controller=info_resource,
path_prefix="/{tenant_id}") as info_mapper:
info_mapper.connect('build_info',
'/build_info',
action='build_info',
conditions={'method': 'GET'})
super(API, self).__init__(mapper)

View File

@ -0,0 +1,51 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo.config import cfg
from heat.api.openstack.v1 import util
from heat.common import wsgi
from heat.rpc import client as rpc_client
class BuildInfoController(object):
"""
WSGI controller for BuildInfo in Heat v1 API
Returns build information for current app
"""
def __init__(self, options):
self.options = options
self.engine = rpc_client.EngineClient()
@util.tenant_local
def build_info(self, req):
engine_revision = self.engine.get_revision(req.context)
build_info = {
'api': {'revision': cfg.CONF.revision['heat_revision']},
'engine': {'revision': engine_revision}
}
return build_info
def create_resource(options):
"""
BuildInfo factory method.
"""
deserializer = wsgi.JSONRequestDeserializer()
serializer = wsgi.JSONResponseSerializer()
return wsgi.Resource(BuildInfoController(options), deserializer,
serializer)

View File

@ -150,6 +150,15 @@ def register_clients_opts():
cfg.CONF.register_opts(opts_copy, group=client_specific_group)
revision_group = cfg.OptGroup('revision')
revision_opts = [
cfg.StrOpt('heat_revision',
default='unknown',
help=_('Heat build revision. '
'If you would prefer to manage your build revision '
'separately you can move this section to a different '
'file and add it as another config option'))]
cfg.CONF.register_opts(engine_opts)
cfg.CONF.register_opts(service_opts)
cfg.CONF.register_opts(rpc_opts)
@ -157,6 +166,8 @@ cfg.CONF.register_group(paste_deploy_group)
cfg.CONF.register_opts(paste_deploy_opts, group=paste_deploy_group)
cfg.CONF.register_group(auth_password_group)
cfg.CONF.register_opts(auth_password_opts, group=auth_password_group)
cfg.CONF.register_group(revision_group)
cfg.CONF.register_opts(revision_opts, group=revision_group)
register_clients_opts()

View File

@ -199,6 +199,9 @@ class EngineService(service.Service):
return [format_stack_detail(s) for s in stacks]
def get_revision(self, cnxt):
return cfg.CONF.revision['heat_revision']
@request_context
def list_stacks(self, cnxt, limit=None, marker=None, sort_keys=None,
sort_dir=None, filters=None):

View File

@ -322,3 +322,6 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy):
return self.call(ctxt, self.make_msg('set_watch_state',
watch_name=watch_name,
state=state))
def get_revision(self, ctxt):
return self.call(ctxt, self.make_msg('get_revision'))

View File

@ -33,6 +33,7 @@ import heat.api.openstack.v1.stacks as stacks
import heat.api.openstack.v1.resources as resources
import heat.api.openstack.v1.events as events
import heat.api.openstack.v1.actions as actions
import heat.api.openstack.v1.build_info as build_info
from heat.tests import utils
import heat.api.middleware.fault as fault
@ -2432,6 +2433,16 @@ class RoutesTest(HeatTestCase):
'event_id': 'dddd'
})
def test_build_info(self):
self.assertRoute(
self.m,
'/fake_tenant/build_info',
'GET',
'build_info',
'BuildInfoController',
{'tenant_id': 'fake_tenant'}
)
class ActionControllerTest(ControllerTest, HeatTestCase):
'''
@ -2595,3 +2606,39 @@ class ActionControllerTest(ControllerTest, HeatTestCase):
stack_id=stack_identity.stack_id,
body=body)
self.m.VerifyAll()
class BuildInfoControllerTest(HeatTestCase):
def test_theres_a_default_api_build_revision(self):
req = mock.Mock()
controller = build_info.BuildInfoController({})
controller.engine = mock.Mock()
response = controller.build_info(req, tenant_id='tenant_id')
self.assertIn('api', response)
self.assertIn('revision', response['api'])
self.assertEqual('unknown', response['api']['revision'])
@mock.patch.object(build_info.cfg, 'CONF')
def test_response_api_build_revision_from_config_file(self, mock_conf):
req = mock.Mock()
controller = build_info.BuildInfoController({})
mock_engine = mock.Mock()
mock_engine.get_revision.return_value = 'engine_revision'
controller.engine = mock_engine
mock_conf.revision = {'heat_revision': 'test'}
response = controller.build_info(req, tenant_id='tenant_id')
self.assertEqual('test', response['api']['revision'])
def test_retrieves_build_revision_from_the_engine(self):
req = mock.Mock()
controller = build_info.BuildInfoController({})
mock_engine = mock.Mock()
mock_engine.get_revision.return_value = 'engine_revision'
controller.engine = mock_engine
response = controller.build_info(req, tenant_id='tenant_id')
self.assertIn('engine', response)
self.assertIn('revision', response['engine'])
self.assertEqual('engine_revision', response['engine']['revision'])