Merge "Add API endpoint to query build information"
This commit is contained in:
commit
070258bb10
@ -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
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
51
heat/api/openstack/v1/build_info.py
Normal file
51
heat/api/openstack/v1/build_info.py
Normal 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)
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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'))
|
||||
|
@ -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'])
|
||||
|
Loading…
Reference in New Issue
Block a user