From 1486289a757c765f9d42916bb16469c1948486ef Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Tue, 26 Jul 2016 13:55:20 -0400 Subject: [PATCH] heat-all: all-in-one heat launcher This patch implements a new heat-all command that can be used to launch a single process version of the configured heat services. The end user can control which services are launched by setting 'enabled_services' in the heat config file: [heat_all] enabled_services = api,engine One use case for this launcher would be to launch a single process heat using rpc_backend = fake, connection=sqlite://heat.db, to have access to a minimal all in one Heat API/Engine for TripleO undercloud deployments via Heat templates. Change-Id: Ic35bdc455fe1397ac575522af0c8fca96dd95676 --- heat/cmd/all.py | 91 ++++++++++++++++++++++++++++++++++++++ heat/cmd/api.py | 41 ++++++++++------- heat/cmd/api_cfn.py | 39 +++++++++------- heat/cmd/api_cloudwatch.py | 41 ++++++++++------- heat/cmd/engine.py | 15 +++++-- setup.cfg | 1 + 6 files changed, 174 insertions(+), 54 deletions(-) create mode 100644 heat/cmd/all.py diff --git a/heat/cmd/all.py b/heat/cmd/all.py new file mode 100644 index 0000000000..d5ea33f4ea --- /dev/null +++ b/heat/cmd/all.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# +# 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. + +"""Heat All Server. + +An OpenStack Heat server that can run all services. +""" +import eventlet +eventlet.monkey_patch(os=False) + +import six + +import sys + +from heat.cmd import api +from heat.cmd import api_cfn +from heat.cmd import api_cloudwatch +from heat.cmd import engine +from heat.common import config +from heat.common import messaging +from heat import version +from oslo_config import cfg +import oslo_i18n as i18n +from oslo_log import log as logging +from oslo_service import systemd + +i18n.enable_lazy() + +LOG = logging.getLogger('heat.all') + +API_LAUNCH_OPTS = {'setup_logging': False} + +LAUNCH_SERVICES = { + 'engine': [engine.launch_engine, {'setup_logging': False}], + 'api': [api.launch_api, API_LAUNCH_OPTS], + 'api_cfn': [api_cfn.launch_cfn_api, API_LAUNCH_OPTS], + 'api_cloudwatch': [api_cloudwatch.launch_cloudwatch_api, API_LAUNCH_OPTS], +} + +services_opt = cfg.ListOpt( + 'enabled_services', + default=['engine', 'api', 'api_cfn'], + help='Specifies the heat services that are enabled when running heat-all. ' + 'Valid options are all or any combination of ' + 'api, engine, api_cfn, or api_cloudwatch.' +) + +cfg.CONF.register_opt(services_opt, group='heat_all') + + +def _start_service_threads(services): + threads = [] + for option in services: + launch_func = LAUNCH_SERVICES[option][0] + kwargs = LAUNCH_SERVICES[option][1] + threads.append(eventlet.spawn(launch_func, **kwargs)) + return threads + + +def launch_all(setup_logging=True): + if setup_logging: + logging.register_options(cfg.CONF) + cfg.CONF(project='heat', prog='heat-all', + version=version.version_info.version_string()) + if setup_logging: + logging.setup(cfg.CONF, 'heat-all') + config.set_config_defaults() + messaging.setup() + return _start_service_threads(set(cfg.CONF.heat_all.enabled_services)) + + +def main(): + try: + threads = launch_all() + services = [thread.wait() for thread in threads] + systemd.notify_once() + [service.wait() for service in services] + except RuntimeError as e: + msg = six.text_type(e) + sys.exit("ERROR: %s" % msg) diff --git a/heat/cmd/api.py b/heat/cmd/api.py index 52eddcedf0..bff97b4252 100644 --- a/heat/cmd/api.py +++ b/heat/cmd/api.py @@ -41,25 +41,32 @@ i18n.enable_lazy() LOG = logging.getLogger('heat.api') +def launch_api(setup_logging=True): + if setup_logging: + logging.register_options(cfg.CONF) + cfg.CONF(project='heat', prog='heat-api', + version=version.version_info.version_string()) + if setup_logging: + logging.setup(cfg.CONF, 'heat-api') + config.set_config_defaults() + messaging.setup() + + app = config.load_paste_app() + + port = cfg.CONF.heat_api.bind_port + host = cfg.CONF.heat_api.bind_host + LOG.info(_LI('Starting Heat REST API on %(host)s:%(port)s'), + {'host': host, 'port': port}) + profiler.setup('heat-api', host) + gmr.TextGuruMeditation.setup_autorun(version) + server = wsgi.Server('heat-api', cfg.CONF.heat_api) + server.start(app, default_port=port) + return server + + def main(): try: - logging.register_options(cfg.CONF) - cfg.CONF(project='heat', prog='heat-api', - version=version.version_info.version_string()) - logging.setup(cfg.CONF, 'heat-api') - config.set_config_defaults() - messaging.setup() - - app = config.load_paste_app() - - port = cfg.CONF.heat_api.bind_port - host = cfg.CONF.heat_api.bind_host - LOG.info(_LI('Starting Heat REST API on %(host)s:%(port)s'), - {'host': host, 'port': port}) - profiler.setup('heat-api', host) - gmr.TextGuruMeditation.setup_autorun(version) - server = wsgi.Server('heat-api', cfg.CONF.heat_api) - server.start(app, default_port=port) + server = launch_api() systemd.notify_once() server.wait() except RuntimeError as e: diff --git a/heat/cmd/api_cfn.py b/heat/cmd/api_cfn.py index 8089b78b81..f4b6315539 100644 --- a/heat/cmd/api_cfn.py +++ b/heat/cmd/api_cfn.py @@ -43,27 +43,34 @@ i18n.enable_lazy() LOG = logging.getLogger('heat.api.cfn') -def main(): - try: +def launch_cfn_api(setup_logging=True): + if setup_logging: logging.register_options(cfg.CONF) - cfg.CONF(project='heat', - prog='heat-api-cfn', - version=version.version_info.version_string()) + cfg.CONF(project='heat', + prog='heat-api-cfn', + version=version.version_info.version_string()) + if setup_logging: logging.setup(cfg.CONF, 'heat-api-cfn') logging.set_defaults() - config.set_config_defaults() - messaging.setup() + config.set_config_defaults() + messaging.setup() - app = config.load_paste_app() + app = config.load_paste_app() - port = cfg.CONF.heat_api_cfn.bind_port - host = cfg.CONF.heat_api_cfn.bind_host - LOG.info(_LI('Starting Heat API on %(host)s:%(port)s'), - {'host': host, 'port': port}) - profiler.setup('heat-api-cfn', host) - gmr.TextGuruMeditation.setup_autorun(version) - server = wsgi.Server('heat-api-cfn', cfg.CONF.heat_api_cfn) - server.start(app, default_port=port) + port = cfg.CONF.heat_api_cfn.bind_port + host = cfg.CONF.heat_api_cfn.bind_host + LOG.info(_LI('Starting Heat API on %(host)s:%(port)s'), + {'host': host, 'port': port}) + profiler.setup('heat-api-cfn', host) + gmr.TextGuruMeditation.setup_autorun(version) + server = wsgi.Server('heat-api-cfn', cfg.CONF.heat_api_cfn) + server.start(app, default_port=port) + return server + + +def main(): + try: + server = launch_cfn_api() systemd.notify_once() server.wait() except RuntimeError as e: diff --git a/heat/cmd/api_cloudwatch.py b/heat/cmd/api_cloudwatch.py index b68885665a..e8c720f75e 100644 --- a/heat/cmd/api_cloudwatch.py +++ b/heat/cmd/api_cloudwatch.py @@ -43,28 +43,35 @@ i18n.enable_lazy() LOG = logging.getLogger('heat.api.cloudwatch') -def main(): - try: +def launch_cloudwatch_api(setup_logging=True): + if setup_logging: logging.register_options(cfg.CONF) - cfg.CONF(project='heat', - prog='heat-api-cloudwatch', - version=version.version_info.version_string()) + cfg.CONF(project='heat', + prog='heat-api-cloudwatch', + version=version.version_info.version_string()) + if setup_logging: logging.setup(cfg.CONF, 'heat-api-cloudwatch') logging.set_defaults() - config.set_config_defaults() - messaging.setup() + config.set_config_defaults() + messaging.setup() - app = config.load_paste_app() + app = config.load_paste_app() - port = cfg.CONF.heat_api_cloudwatch.bind_port - host = cfg.CONF.heat_api_cloudwatch.bind_host - LOG.info(_LI('Starting Heat CloudWatch API on %(host)s:%(port)s'), - {'host': host, 'port': port}) - profiler.setup('heat-api-cloudwatch', host) - gmr.TextGuruMeditation.setup_autorun(version) - server = wsgi.Server('heat-api-cloudwatch', - cfg.CONF.heat_api_cloudwatch) - server.start(app, default_port=port) + port = cfg.CONF.heat_api_cloudwatch.bind_port + host = cfg.CONF.heat_api_cloudwatch.bind_host + LOG.info(_LI('Starting Heat CloudWatch API on %(host)s:%(port)s'), + {'host': host, 'port': port}) + profiler.setup('heat-api-cloudwatch', host) + gmr.TextGuruMeditation.setup_autorun(version) + server = wsgi.Server('heat-api-cloudwatch', + cfg.CONF.heat_api_cloudwatch) + server.start(app, default_port=port) + return server + + +def main(): + try: + server = launch_cloudwatch_api() systemd.notify_once() server.wait() except RuntimeError as e: diff --git a/heat/cmd/engine.py b/heat/cmd/engine.py index d3858943ac..41cf8008a6 100644 --- a/heat/cmd/engine.py +++ b/heat/cmd/engine.py @@ -44,12 +44,14 @@ i18n.enable_lazy() LOG = logging.getLogger('heat.engine') -def main(): - logging.register_options(cfg.CONF) +def launch_engine(setup_logging=True): + if setup_logging: + logging.register_options(cfg.CONF) cfg.CONF(project='heat', prog='heat-engine', version=version.version_info.version_string()) - logging.setup(cfg.CONF, 'heat-engine') - logging.set_defaults() + if setup_logging: + logging.setup(cfg.CONF, 'heat-engine') + logging.set_defaults() messaging.setup() config.startup_sanity_check() @@ -76,4 +78,9 @@ def main(): # We create the periodic tasks here, which mean they are created # only in the parent process when num_engine_workers>1 is specified srv.create_periodic_tasks() + return launcher + + +def main(): + launcher = launch_engine() launcher.wait() diff --git a/setup.cfg b/setup.cfg index ec4c0ca33f..73645930d4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,6 +30,7 @@ scripts = [entry_points] console_scripts = + heat-all = heat.cmd.all:main heat-api = heat.cmd.api:main heat-api-cfn = heat.cmd.api_cfn:main heat-api-cloudwatch = heat.cmd.api_cloudwatch:main