Sync Oslo service module to Ironic
New Oslo service code does correct stop Ironic conductor service from screen session on devstack (screen -S stack -p ir-cond -X kill), otherwise multiple conductors started on devstack after few unstack/rejoin-stack cycles. Change-Id: Ia8b4523e1288ca0817b94f85070f78237908a410
This commit is contained in:
parent
f843cdaaaa
commit
789ae2ea65
@ -1,5 +1,3 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
# Copyright 2010 United States Government as represented by the
|
# Copyright 2010 United States Government as represented by the
|
||||||
# Administrator of the National Aeronautics and Space Administration.
|
# Administrator of the National Aeronautics and Space Administration.
|
||||||
# Copyright 2011 Justin Santa Barbara
|
# Copyright 2011 Justin Santa Barbara
|
||||||
@ -27,12 +25,20 @@ import signal
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Importing just the symbol here because the io module does not
|
||||||
|
# exist in Python 2.6.
|
||||||
|
from io import UnsupportedOperation # noqa
|
||||||
|
except ImportError:
|
||||||
|
# Python 2.6
|
||||||
|
UnsupportedOperation = None
|
||||||
|
|
||||||
import eventlet
|
import eventlet
|
||||||
from eventlet import event
|
from eventlet import event
|
||||||
from oslo.config import cfg
|
from oslo.config import cfg
|
||||||
|
|
||||||
from ironic.openstack.common import eventlet_backdoor
|
from ironic.openstack.common import eventlet_backdoor
|
||||||
from ironic.openstack.common.gettextutils import _ # noqa
|
from ironic.openstack.common.gettextutils import _
|
||||||
from ironic.openstack.common import importutils
|
from ironic.openstack.common import importutils
|
||||||
from ironic.openstack.common import log as logging
|
from ironic.openstack.common import log as logging
|
||||||
from ironic.openstack.common import threadgroup
|
from ironic.openstack.common import threadgroup
|
||||||
@ -47,8 +53,32 @@ def _sighup_supported():
|
|||||||
return hasattr(signal, 'SIGHUP')
|
return hasattr(signal, 'SIGHUP')
|
||||||
|
|
||||||
|
|
||||||
def _is_sighup(signo):
|
def _is_daemon():
|
||||||
return _sighup_supported() and signo == signal.SIGHUP
|
# The process group for a foreground process will match the
|
||||||
|
# process group of the controlling terminal. If those values do
|
||||||
|
# not match, or ioctl() fails on the stdout file handle, we assume
|
||||||
|
# the process is running in the background as a daemon.
|
||||||
|
# http://www.gnu.org/software/bash/manual/bashref.html#Job-Control-Basics
|
||||||
|
try:
|
||||||
|
is_daemon = os.getpgrp() != os.tcgetpgrp(sys.stdout.fileno())
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.ENOTTY:
|
||||||
|
# Assume we are a daemon because there is no terminal.
|
||||||
|
is_daemon = True
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
except UnsupportedOperation:
|
||||||
|
# Could not get the fileno for stdout, so we must be a daemon.
|
||||||
|
is_daemon = True
|
||||||
|
return is_daemon
|
||||||
|
|
||||||
|
|
||||||
|
def _is_sighup_and_daemon(signo):
|
||||||
|
if not (_sighup_supported() and signo == signal.SIGHUP):
|
||||||
|
# Avoid checking if we are a daemon, because the signal isn't
|
||||||
|
# SIGHUP.
|
||||||
|
return False
|
||||||
|
return _is_daemon()
|
||||||
|
|
||||||
|
|
||||||
def _signo_to_signame(signo):
|
def _signo_to_signame(signo):
|
||||||
@ -162,7 +192,7 @@ class ServiceLauncher(Launcher):
|
|||||||
while True:
|
while True:
|
||||||
self.handle_signal()
|
self.handle_signal()
|
||||||
status, signo = self._wait_for_exit_or_signal(ready_callback)
|
status, signo = self._wait_for_exit_or_signal(ready_callback)
|
||||||
if not _is_sighup(signo):
|
if not _is_sighup_and_daemon(signo):
|
||||||
return status
|
return status
|
||||||
self.restart()
|
self.restart()
|
||||||
|
|
||||||
@ -176,10 +206,16 @@ class ServiceWrapper(object):
|
|||||||
|
|
||||||
|
|
||||||
class ProcessLauncher(object):
|
class ProcessLauncher(object):
|
||||||
def __init__(self):
|
def __init__(self, wait_interval=0.01):
|
||||||
|
"""Constructor.
|
||||||
|
|
||||||
|
:param wait_interval: The interval to sleep for between checks
|
||||||
|
of child process exit.
|
||||||
|
"""
|
||||||
self.children = {}
|
self.children = {}
|
||||||
self.sigcaught = None
|
self.sigcaught = None
|
||||||
self.running = True
|
self.running = True
|
||||||
|
self.wait_interval = wait_interval
|
||||||
rfd, self.writepipe = os.pipe()
|
rfd, self.writepipe = os.pipe()
|
||||||
self.readpipe = eventlet.greenio.GreenPipe(rfd, 'r')
|
self.readpipe = eventlet.greenio.GreenPipe(rfd, 'r')
|
||||||
self.handle_signal()
|
self.handle_signal()
|
||||||
@ -220,7 +256,7 @@ class ProcessLauncher(object):
|
|||||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
|
||||||
def _child_wait_for_exit_or_signal(self, launcher):
|
def _child_wait_for_exit_or_signal(self, launcher):
|
||||||
status = None
|
status = 0
|
||||||
signo = 0
|
signo = 0
|
||||||
|
|
||||||
# NOTE(johannes): All exceptions are caught to ensure this
|
# NOTE(johannes): All exceptions are caught to ensure this
|
||||||
@ -282,7 +318,7 @@ class ProcessLauncher(object):
|
|||||||
while True:
|
while True:
|
||||||
self._child_process_handle_signal()
|
self._child_process_handle_signal()
|
||||||
status, signo = self._child_wait_for_exit_or_signal(launcher)
|
status, signo = self._child_wait_for_exit_or_signal(launcher)
|
||||||
if not _is_sighup(signo):
|
if not _is_sighup_and_daemon(signo):
|
||||||
break
|
break
|
||||||
launcher.restart()
|
launcher.restart()
|
||||||
|
|
||||||
@ -337,7 +373,7 @@ class ProcessLauncher(object):
|
|||||||
# Yield to other threads if no children have exited
|
# Yield to other threads if no children have exited
|
||||||
# Sleep for a short time to avoid excessive CPU usage
|
# Sleep for a short time to avoid excessive CPU usage
|
||||||
# (see bug #1095346)
|
# (see bug #1095346)
|
||||||
eventlet.greenthread.sleep(.01)
|
eventlet.greenthread.sleep(self.wait_interval)
|
||||||
continue
|
continue
|
||||||
while self.running and len(wrap.children) < wrap.workers:
|
while self.running and len(wrap.children) < wrap.workers:
|
||||||
self._start_child(wrap)
|
self._start_child(wrap)
|
||||||
@ -354,7 +390,7 @@ class ProcessLauncher(object):
|
|||||||
if self.sigcaught:
|
if self.sigcaught:
|
||||||
signame = _signo_to_signame(self.sigcaught)
|
signame = _signo_to_signame(self.sigcaught)
|
||||||
LOG.info(_('Caught %s, stopping children'), signame)
|
LOG.info(_('Caught %s, stopping children'), signame)
|
||||||
if not _is_sighup(self.sigcaught):
|
if not _is_sighup_and_daemon(self.sigcaught):
|
||||||
break
|
break
|
||||||
|
|
||||||
for pid in self.children:
|
for pid in self.children:
|
||||||
@ -451,11 +487,12 @@ class Services(object):
|
|||||||
done.wait()
|
done.wait()
|
||||||
|
|
||||||
|
|
||||||
def launch(service, workers=None):
|
def launch(service, workers=1):
|
||||||
if workers:
|
if workers is None or workers == 1:
|
||||||
launcher = ProcessLauncher()
|
|
||||||
launcher.launch_service(service, workers=workers)
|
|
||||||
else:
|
|
||||||
launcher = ServiceLauncher()
|
launcher = ServiceLauncher()
|
||||||
launcher.launch_service(service)
|
launcher.launch_service(service)
|
||||||
|
else:
|
||||||
|
launcher = ProcessLauncher()
|
||||||
|
launcher.launch_service(service, workers=workers)
|
||||||
|
|
||||||
return launcher
|
return launcher
|
||||||
|
@ -26,6 +26,7 @@ module=policy
|
|||||||
module=processutils
|
module=processutils
|
||||||
module=py3kcompat
|
module=py3kcompat
|
||||||
module=rpc
|
module=rpc
|
||||||
|
module=service
|
||||||
module=setup
|
module=setup
|
||||||
module=strutils
|
module=strutils
|
||||||
module=timeutils
|
module=timeutils
|
||||||
|
Loading…
x
Reference in New Issue
Block a user