Refactor service readiness notification

import and apply Oslo systemd module
drop old keystone.common.systemd
drop onready configuration parameter
 - systemd notification is no-op when not running inside systemd

Oslo commit 53e1214c092f09e3851b1a1b55289a93a72b09ec

Change-Id: I80f325c9be9c171c2dc8d5526570bf64f0f87c78
This commit is contained in:
Alan Pevec 2014-03-09 23:27:46 +01:00
parent e954942d44
commit c045ea108d
6 changed files with 107 additions and 65 deletions

View File

@ -48,7 +48,7 @@ from keystone.common import sql
from keystone.common import utils
from keystone import config
from keystone.openstack.common.gettextutils import _
from keystone.openstack.common import importutils
from keystone.openstack.common import systemd
CONF = config.CONF
@ -83,15 +83,7 @@ def serve(*servers):
raise
# notify calling process we are ready to serve
if CONF.onready:
try:
notifier = importutils.import_module(CONF.onready)
notifier.notify()
except ImportError:
try:
utils.check_output(CONF.onready.split())
except Exception:
logging.exception('Failed to execute onready command')
systemd.notify_once()
for name, server in servers:
server.wait()

View File

@ -54,13 +54,6 @@
# server. (string value)
#admin_endpoint=<None>
# onready allows you to send a notification when the process
# is ready to serve. For example, to have it notify using
# systemd, one could set shell command: "onready = systemd-
# notify --ready" or a module with notify() method: "onready =
# keystone.common.systemd". (string value)
#onready=<None>
# Enforced by optional sizelimit middleware
# (keystone.middleware:RequestBodySizeLimiter). (integer
# value)

View File

@ -69,13 +69,6 @@ FILE_OPTIONS = {
'to set this value if the base URL contains a path '
'(e.g. /prefix/v2.0) or the endpoint should be found '
'on a different server.'),
cfg.StrOpt('onready',
help='onready allows you to send a notification when the '
'process is ready to serve. For example, to have it '
'notify using systemd, one could set shell command: '
'"onready = systemd-notify --ready" or a module '
'with notify() method: '
'"onready = keystone.common.systemd".'),
# default max request size is 112k
cfg.IntOpt('max_request_body_size', default=114688,
help='Enforced by optional sizelimit middleware '

View File

@ -1,41 +0,0 @@
# 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 keystone.conf
"""
import os
import socket
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()
def notify():
_sd_notify('READY=1')
if __name__ == '__main__':
notify()

View File

@ -0,0 +1,104 @@
# Copyright 2012-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.
"""
Helper module for systemd service readiness notification.
"""
import os
import socket
import sys
from keystone.openstack.common import log as logging
LOG = logging.getLogger(__name__)
def _abstractify(socket_name):
if socket_name.startswith('@'):
# abstract namespace socket
socket_name = '\0%s' % socket_name[1:]
return socket_name
def _sd_notify(unset_env, msg):
notify_socket = os.getenv('NOTIFY_SOCKET')
if notify_socket:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
try:
sock.connect(_abstractify(notify_socket))
sock.sendall(msg)
if unset_env:
del os.environ['NOTIFY_SOCKET']
except EnvironmentError:
LOG.debug("Systemd notification failed", exc_info=True)
finally:
sock.close()
def notify():
"""Send notification to Systemd that service is ready.
For details see
http://www.freedesktop.org/software/systemd/man/sd_notify.html
"""
_sd_notify(False, 'READY=1')
def notify_once():
"""Send notification once to Systemd that service is ready.
Systemd sets NOTIFY_SOCKET environment variable with the name of the
socket listening for notifications from services.
This method removes the NOTIFY_SOCKET environment variable to ensure
notification is sent only once.
"""
_sd_notify(True, 'READY=1')
def onready(notify_socket, timeout):
"""Wait for systemd style notification on the socket.
:param notify_socket: local socket address
:type notify_socket: string
:param timeout: socket timeout
:type timeout: float
:returns: 0 service ready
1 service not ready
2 timeout occured
"""
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.settimeout(timeout)
sock.bind(_abstractify(notify_socket))
try:
msg = sock.recv(512)
except socket.timeout:
return 2
finally:
sock.close()
if 'READY=1' in msg:
return 0
else:
return 1
if __name__ == '__main__':
# simple CLI for testing
if len(sys.argv) == 1:
notify()
elif len(sys.argv) >= 2:
timeout = float(sys.argv[1])
notify_socket = os.getenv('NOTIFY_SOCKET')
if notify_socket:
retval = onready(notify_socket, timeout)
sys.exit(retval)

View File

@ -13,6 +13,7 @@ module=jsonutils
module=log
module=policy
module=strutils
module=systemd
module=timeutils
module=versionutils