Last active
August 29, 2015 14:15
-
-
Save corystone/92714263f55bb60009a6 to your computer and use it in GitHub Desktop.
Cinder service maintenance mode patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/cinder/service.py b/cinder/service.py | |
index 6c557e8..60b4ce8 100644 | |
--- a/cinder/service.py | |
+++ b/cinder/service.py | |
@@ -153,11 +153,23 @@ class ProcessLauncher(object): | |
self.totalwrap = 0 | |
self.failedwrap = 0 | |
self.running = True | |
+ self.maintenance = False | |
rfd, self.writepipe = os.pipe() | |
self.readpipe = eventlet.greenio.GreenPipe(rfd, 'r') | |
signal.signal(signal.SIGTERM, self._handle_signal) | |
signal.signal(signal.SIGINT, self._handle_signal) | |
+ signal.signal(signal.SIGUSR1, self._handle_sigusr1) | |
+ | |
+ def _handle_sigusr1(self, signo, frame): | |
+ self.maintenance = True | |
+ for pid in self.children: | |
+ # Pass USR1 on to our children. | |
+ try: | |
+ os.kill(pid, signal.SIGUSR1) | |
+ except OSError as exc: | |
+ if exc.errno != errno.ESRCH: | |
+ raise | |
def _handle_signal(self, signo, frame): | |
self.sigcaught = signo | |
@@ -302,6 +314,9 @@ class ProcessLauncher(object): | |
eventlet.greenthread.sleep(.01) | |
continue | |
+ if self.maintenance: | |
+ break | |
+ | |
LOG.info(_('wait wrap.failed %s'), wrap.failed) | |
while (self.running and len(wrap.children) < wrap.workers | |
and not wrap.failed): | |
@@ -312,12 +327,12 @@ class ProcessLauncher(object): | |
signal.SIGINT: 'SIGINT'}[self.sigcaught] | |
LOG.info(_('Caught %s, stopping children'), signame) | |
- for pid in self.children: | |
- try: | |
- os.kill(pid, signal.SIGTERM) | |
- except OSError as exc: | |
- if exc.errno != errno.ESRCH: | |
- raise | |
+ for pid in self.children: | |
+ try: | |
+ os.kill(pid, signal.SIGTERM) | |
+ except OSError as exc: | |
+ if exc.errno != errno.ESRCH: | |
+ raise | |
# Wait for children to die | |
if self.children: | |
@@ -352,6 +367,35 @@ class Service(object): | |
self.saved_args, self.saved_kwargs = args, kwargs | |
self.timers = [] | |
+ def maintenance_periodic(self): | |
+ """If no eventlet timers exist, assume done, so shut down.""" | |
+ LOG.info(_('Maintenance, waiting for all eventlets to finish')) | |
+ hub = eventlet.hubs.get_hub() | |
+ if len(hub.timers) == 0: | |
+ LOG.info(_('No eventlet timers, exiting')) | |
+ self.stop() | |
+ | |
+ def _handle_sigusr1(self, signo, frame): | |
+ """Handle SIGUSR1 to enter maintenance mode. | |
+ | |
+ Stop processing new rpc messages. Stop running periodic tasks. The | |
+ service will keep running until it has no more RPC calls executing, | |
+ then it will cleanly exit. | |
+ """ | |
+ try: | |
+ self.conn.close() | |
+ except Exception: | |
+ pass | |
+ for x in self.timers: | |
+ try: | |
+ x.stop() | |
+ except Exception: | |
+ pass | |
+ # This periodic task just exists to keep the manager running. | |
+ periodic = utils.LoopingCall(self.maintenance_periodic) | |
+ periodic.start(interval=10, initial_delay=0) | |
+ self.timers.append(periodic) | |
+ | |
def start(self): | |
version_string = version.version_string() | |
LOG.audit(_('Starting %(topic)s node (version %(version_string)s)'), | |
@@ -401,6 +445,8 @@ class Service(object): | |
initial_delay=initial_delay) | |
self.timers.append(periodic) | |
+ signal.signal(signal.SIGUSR1, self._handle_sigusr1) | |
+ | |
def _create_service_ref(self, context): | |
zone = CONF.storage_availability_zone | |
service_ref = db.service_create(context, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment