Add systemd notification support to heat

This mirrors work done in other OpenStack projects
to add systemd notification support to signal that
a given process is ready to accept requests.

The heat-api, heat-api-cfn, heat-engine, and
heat-api-cloudwatch processes are all covered by
a new, single, 'onready' configuration file option.

Additionally, the sample configuration file has been
updated to match.

Implements: blueprint systemd-integration

Change-Id: I90d2b915e2568a65ed9ed78923c9982e19f9c948
Signed-off-by: Lon Hohberger <lhh@redhat.com>
This commit is contained in:
Lon Hohberger 2014-02-18 13:44:56 -05:00
parent 7c2c54f04d
commit cceda95a35
8 changed files with 107 additions and 1 deletions

View File

@ -40,6 +40,7 @@ from oslo.config import cfg
from heat.common import config
from heat.common import wsgi
from heat.common import notify
from heat.openstack.common import log as logging
@ -62,6 +63,7 @@ if __name__ == '__main__':
LOG.info('Starting Heat ReST API on %s:%s' % (host, port))
server = wsgi.Server()
server.start(app, cfg.CONF.heat_api, default_port=port)
notify.startup_notify(cfg.CONF.onready)
server.wait()
except RuntimeError as e:
sys.exit("ERROR: %s" % e)

View File

@ -42,6 +42,7 @@ from oslo.config import cfg
from heat.common import config
from heat.common import wsgi
from heat.common import notify
from heat.openstack.common import log as logging
@ -64,6 +65,7 @@ if __name__ == '__main__':
LOG.info('Starting Heat API on %s:%s' % (host, port))
server = wsgi.Server()
server.start(app, cfg.CONF.heat_api_cfn, default_port=port)
notify.startup_notify(cfg.CONF.onready)
server.wait()
except RuntimeError as e:
sys.exit("ERROR: %s" % e)

View File

@ -42,6 +42,7 @@ from oslo.config import cfg
from heat.common import config
from heat.common import wsgi
from heat.common import notify
from heat.openstack.common import log as logging
@ -64,6 +65,7 @@ if __name__ == '__main__':
LOG.info('Starting Heat CloudWatch API on %s:%s' % (host, port))
server = wsgi.Server()
server.start(app, cfg.CONF.heat_api_cloudwatch, default_port=port)
notify.startup_notify(cfg.CONF.onready)
server.wait()
except RuntimeError as e:
sys.exit("ERROR: %s" % e)

View File

@ -41,6 +41,8 @@ gettextutils.install('heat', lazy=True)
from oslo.config import cfg
from heat.common import notify
from heat.openstack.common import log as logging
from heat.openstack.common import service
@ -64,4 +66,5 @@ if __name__ == '__main__':
srv = engine.EngineService(cfg.CONF.host, rpc_api.ENGINE_TOPIC)
launcher = service.launch(srv)
notify.startup_notify(cfg.CONF.onready)
launcher.wait()

View File

@ -58,6 +58,14 @@
# stack locking. (integer value)
#engine_life_check_timeout=2
# onready allows you to send a notification when the heat
# processes are ready to serve. This is either a module with
# the notify() method or a shell command. To enable
# notifications with systemd, one may use the 'systemd-notify
# --ready' shell command or the 'heat.common.systemd'
# notification module. (string value)
#onready=<None>
# Name of the engine node. This can be an opaque identifier.
# It is not necessarily a hostname, FQDN, or IP address.
# (string value)

View File

@ -118,7 +118,14 @@ engine_opts = [
cfg.IntOpt('engine_life_check_timeout',
default=2,
help=_('RPC timeout for the engine liveness check that is used'
' for stack locking.'))]
' for stack locking.')),
cfg.StrOpt('onready',
help=_('onready allows you to send a notification when the'
' heat processes are ready to serve. This is either a'
' module with the notify() method or a shell command. '
' To enable notifications with systemd, one may use'
' the \'systemd-notify --ready\' shell command or'
' the \'heat.common.systemd\' notification module.'))]
rpc_opts = [
cfg.StrOpt('host',

38
heat/common/notify.py Normal file
View File

@ -0,0 +1,38 @@
# Copyright 2014 Red Hat, Inc.
#
# 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.
"""
Startup notification using a shell script or systemd NOTIFY_SOCKET
style notification
"""
from heat.openstack.common import log as logging
from heat.openstack.common import importutils
from heat.openstack.common import processutils
logger = logging.getLogger(__name__)
def startup_notify(notify_param):
if not notify_param or notify_param == "":
return
try:
notifier = importutils.import_module(notify_param)
except ImportError:
try:
processutils.execute(notify_param, shell=True)
except Exception as e:
logger.error(_('Failed to execute onready command: %s') % str(e))
else:
notifier.notify()

44
heat/common/systemd.py Normal file
View File

@ -0,0 +1,44 @@
# Copyright 2012 Red Hat, Inc.
#
# 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.
"""
Helper module for systemd start-up completion notification.
Used for "onready" configuration parameter in heat.conf
"""
import os
import socket
from heat.openstack.common import log as logging
logger = logging.getLogger(__name__)
def _sd_notify(msg):
sysd = os.getenv('NOTIFY_SOCKET')
if sysd:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
if sysd.startswith('@'):
# abstract namespace socket
sysd = '\0%s' % sysd[1:]
sock.connect(sysd)
sock.sendall(msg)
sock.close()
else:
logger.warning(_('Unable to notify systemd of startup completion:'
' NOTIFY_SOCKET not set'))
def notify():
_sd_notify('READY=1')