Update RPM specs to v. 2014.1.1
[openstack-build/neutron-build.git] / rpm / SOURCES / 0004-Sync-service-and-systemd-modules-from-oslo-incubator.patch
1 From f0bbb2c80e84848967885599d8b57f0710d7d44c Mon Sep 17 00:00:00 2001
2 From: Jakub Libosvar <libosvar@redhat.com>
3 Date: Mon, 17 Mar 2014 16:36:01 +0100
4 Subject: [PATCH] Sync service and systemd modules from oslo-incubator
5
6 This patch make systemd know when neutron-service was started. This is
7 needed in HA environment, previously systemd returned success even
8 before neutron-server was able to handle requests.
9
10 Current oslo-incubator commit on HEAD:
11 b7ad6ddab8b1d61bf4f52ccaa461a9d68809747b
12
13 Implements: blueprint service-readiness
14 Change-Id: Ic9e4abd11b614a896fbd7454b9a604a69a248d0f
15 ---
16  neutron/openstack/common/service.py |  72 +++++++++++++------------
17  neutron/openstack/common/systemd.py | 104 ++++++++++++++++++++++++++++++++++++
18  openstack-common.conf               |   1 +
19  3 files changed, 144 insertions(+), 33 deletions(-)
20  create mode 100644 neutron/openstack/common/systemd.py
21
22 diff --git a/neutron/openstack/common/service.py b/neutron/openstack/common/service.py
23 index b8144bb..627dda4 100644
24 --- a/neutron/openstack/common/service.py
25 +++ b/neutron/openstack/common/service.py
26 @@ -38,9 +38,10 @@ from eventlet import event
27  from oslo.config import cfg
28  
29  from neutron.openstack.common import eventlet_backdoor
30 -from neutron.openstack.common.gettextutils import _
31 +from neutron.openstack.common.gettextutils import _LE, _LI, _LW
32  from neutron.openstack.common import importutils
33  from neutron.openstack.common import log as logging
34 +from neutron.openstack.common import systemd
35  from neutron.openstack.common import threadgroup
36  
37  
38 @@ -163,7 +164,7 @@ class ServiceLauncher(Launcher):
39          status = None
40          signo = 0
41  
42 -        LOG.debug(_('Full set of CONF:'))
43 +        LOG.debug('Full set of CONF:')
44          CONF.log_opt_values(LOG, std_logging.DEBUG)
45  
46          try:
47 @@ -172,7 +173,7 @@ class ServiceLauncher(Launcher):
48              super(ServiceLauncher, self).wait()
49          except SignalExit as exc:
50              signame = _signo_to_signame(exc.signo)
51 -            LOG.info(_('Caught %s, exiting'), signame)
52 +            LOG.info(_LI('Caught %s, exiting'), signame)
53              status = exc.code
54              signo = exc.signo
55          except SystemExit as exc:
56 @@ -184,7 +185,7 @@ class ServiceLauncher(Launcher):
57                      rpc.cleanup()
58                  except Exception:
59                      # We're shutting down, so it doesn't matter at this point.
60 -                    LOG.exception(_('Exception during rpc cleanup.'))
61 +                    LOG.exception(_LE('Exception during rpc cleanup.'))
62  
63          return status, signo
64  
65 @@ -235,7 +236,7 @@ class ProcessLauncher(object):
66          # dies unexpectedly
67          self.readpipe.read()
68  
69 -        LOG.info(_('Parent process has died unexpectedly, exiting'))
70 +        LOG.info(_LI('Parent process has died unexpectedly, exiting'))
71  
72          sys.exit(1)
73  
74 @@ -266,13 +267,13 @@ class ProcessLauncher(object):
75              launcher.wait()
76          except SignalExit as exc:
77              signame = _signo_to_signame(exc.signo)
78 -            LOG.info(_('Caught %s, exiting'), signame)
79 +            LOG.info(_LI('Caught %s, exiting'), signame)
80              status = exc.code
81              signo = exc.signo
82          except SystemExit as exc:
83              status = exc.code
84          except BaseException:
85 -            LOG.exception(_('Unhandled exception'))
86 +            LOG.exception(_LE('Unhandled exception'))
87              status = 2
88          finally:
89              launcher.stop()
90 @@ -305,7 +306,7 @@ class ProcessLauncher(object):
91              # start up quickly but ensure we don't fork off children that
92              # die instantly too quickly.
93              if time.time() - wrap.forktimes[0] < wrap.workers:
94 -                LOG.info(_('Forking too fast, sleeping'))
95 +                LOG.info(_LI('Forking too fast, sleeping'))
96                  time.sleep(1)
97  
98              wrap.forktimes.pop(0)
99 @@ -324,7 +325,7 @@ class ProcessLauncher(object):
100  
101              os._exit(status)
102  
103 -        LOG.info(_('Started child %d'), pid)
104 +        LOG.info(_LI('Started child %d'), pid)
105  
106          wrap.children.add(pid)
107          self.children[pid] = wrap
108 @@ -334,7 +335,7 @@ class ProcessLauncher(object):
109      def launch_service(self, service, workers=1):
110          wrap = ServiceWrapper(service, workers)
111  
112 -        LOG.info(_('Starting %d workers'), wrap.workers)
113 +        LOG.info(_LI('Starting %d workers'), wrap.workers)
114          while self.running and len(wrap.children) < wrap.workers:
115              self._start_child(wrap)
116  
117 @@ -351,15 +352,15 @@ class ProcessLauncher(object):
118  
119          if os.WIFSIGNALED(status):
120              sig = os.WTERMSIG(status)
121 -            LOG.info(_('Child %(pid)d killed by signal %(sig)d'),
122 +            LOG.info(_LI('Child %(pid)d killed by signal %(sig)d'),
123                       dict(pid=pid, sig=sig))
124          else:
125              code = os.WEXITSTATUS(status)
126 -            LOG.info(_('Child %(pid)s exited with status %(code)d'),
127 +            LOG.info(_LI('Child %(pid)s exited with status %(code)d'),
128                       dict(pid=pid, code=code))
129  
130          if pid not in self.children:
131 -            LOG.warning(_('pid %d not in child list'), pid)
132 +            LOG.warning(_LW('pid %d not in child list'), pid)
133              return None
134  
135          wrap = self.children.pop(pid)
136 @@ -381,22 +382,25 @@ class ProcessLauncher(object):
137      def wait(self):
138          """Loop waiting on children to die and respawning as necessary."""
139  
140 -        LOG.debug(_('Full set of CONF:'))
141 +        LOG.debug('Full set of CONF:')
142          CONF.log_opt_values(LOG, std_logging.DEBUG)
143  
144 -        while True:
145 -            self.handle_signal()
146 -            self._respawn_children()
147 -            if self.sigcaught:
148 -                signame = _signo_to_signame(self.sigcaught)
149 -                LOG.info(_('Caught %s, stopping children'), signame)
150 -            if not _is_sighup_and_daemon(self.sigcaught):
151 -                break
152 -
153 -            for pid in self.children:
154 -                os.kill(pid, signal.SIGHUP)
155 -            self.running = True
156 -            self.sigcaught = None
157 +        try:
158 +            while True:
159 +                self.handle_signal()
160 +                self._respawn_children()
161 +                if self.sigcaught:
162 +                    signame = _signo_to_signame(self.sigcaught)
163 +                    LOG.info(_LI('Caught %s, stopping children'), signame)
164 +                if not _is_sighup_and_daemon(self.sigcaught):
165 +                    break
166 +
167 +                for pid in self.children:
168 +                    os.kill(pid, signal.SIGHUP)
169 +                self.running = True
170 +                self.sigcaught = None
171 +        except eventlet.greenlet.GreenletExit:
172 +            LOG.info(_LI("Wait called after thread killed.  Cleaning up."))
173  
174          for pid in self.children:
175              try:
176 @@ -407,7 +411,7 @@ class ProcessLauncher(object):
177  
178          # Wait for children to die
179          if self.children:
180 -            LOG.info(_('Waiting on %d children to exit'), len(self.children))
181 +            LOG.info(_LI('Waiting on %d children to exit'), len(self.children))
182              while self.children:
183                  self._wait_child()
184  
185 @@ -484,14 +488,16 @@ class Services(object):
186  
187          """
188          service.start()
189 +        systemd.notify_once()
190          done.wait()
191  
192  
193 -def launch(service, workers=None):
194 -    if workers:
195 -        launcher = ProcessLauncher()
196 -        launcher.launch_service(service, workers=workers)
197 -    else:
198 +def launch(service, workers=1):
199 +    if workers is None or workers == 1:
200          launcher = ServiceLauncher()
201          launcher.launch_service(service)
202 +    else:
203 +        launcher = ProcessLauncher()
204 +        launcher.launch_service(service, workers=workers)
205 +
206      return launcher
207 diff --git a/neutron/openstack/common/systemd.py b/neutron/openstack/common/systemd.py
208 new file mode 100644
209 index 0000000..e1ba656
210 --- /dev/null
211 +++ b/neutron/openstack/common/systemd.py
212 @@ -0,0 +1,104 @@
213 +# Copyright 2012-2014 Red Hat, Inc.
214 +#
215 +#    Licensed under the Apache License, Version 2.0 (the "License"); you may
216 +#    not use this file except in compliance with the License. You may obtain
217 +#    a copy of the License at
218 +#
219 +#         http://www.apache.org/licenses/LICENSE-2.0
220 +#
221 +#    Unless required by applicable law or agreed to in writing, software
222 +#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
223 +#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
224 +#    License for the specific language governing permissions and limitations
225 +#    under the License.
226 +
227 +"""
228 +Helper module for systemd service readiness notification.
229 +"""
230 +
231 +import os
232 +import socket
233 +import sys
234 +
235 +from neutron.openstack.common import log as logging
236 +
237 +
238 +LOG = logging.getLogger(__name__)
239 +
240 +
241 +def _abstractify(socket_name):
242 +    if socket_name.startswith('@'):
243 +        # abstract namespace socket
244 +        socket_name = '\0%s' % socket_name[1:]
245 +    return socket_name
246 +
247 +
248 +def _sd_notify(unset_env, msg):
249 +    notify_socket = os.getenv('NOTIFY_SOCKET')
250 +    if notify_socket:
251 +        sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
252 +        try:
253 +            sock.connect(_abstractify(notify_socket))
254 +            sock.sendall(msg)
255 +            if unset_env:
256 +                del os.environ['NOTIFY_SOCKET']
257 +        except EnvironmentError:
258 +            LOG.debug("Systemd notification failed", exc_info=True)
259 +        finally:
260 +            sock.close()
261 +
262 +
263 +def notify():
264 +    """Send notification to Systemd that service is ready.
265 +    For details see
266 +      http://www.freedesktop.org/software/systemd/man/sd_notify.html
267 +    """
268 +    _sd_notify(False, 'READY=1')
269 +
270 +
271 +def notify_once():
272 +    """Send notification once to Systemd that service is ready.
273 +    Systemd sets NOTIFY_SOCKET environment variable with the name of the
274 +    socket listening for notifications from services.
275 +    This method removes the NOTIFY_SOCKET environment variable to ensure
276 +    notification is sent only once.
277 +    """
278 +    _sd_notify(True, 'READY=1')
279 +
280 +
281 +def onready(notify_socket, timeout):
282 +    """Wait for systemd style notification on the socket.
283 +
284 +    :param notify_socket: local socket address
285 +    :type notify_socket:  string
286 +    :param timeout:       socket timeout
287 +    :type timeout:        float
288 +    :returns:             0 service ready
289 +                          1 service not ready
290 +                          2 timeout occured
291 +    """
292 +    sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
293 +    sock.settimeout(timeout)
294 +    sock.bind(_abstractify(notify_socket))
295 +    try:
296 +        msg = sock.recv(512)
297 +    except socket.timeout:
298 +        return 2
299 +    finally:
300 +        sock.close()
301 +    if 'READY=1' in msg:
302 +        return 0
303 +    else:
304 +        return 1
305 +
306 +
307 +if __name__ == '__main__':
308 +    # simple CLI for testing
309 +    if len(sys.argv) == 1:
310 +        notify()
311 +    elif len(sys.argv) >= 2:
312 +        timeout = float(sys.argv[1])
313 +        notify_socket = os.getenv('NOTIFY_SOCKET')
314 +        if notify_socket:
315 +            retval = onready(notify_socket, timeout)
316 +            sys.exit(retval)
317 diff --git a/openstack-common.conf b/openstack-common.conf
318 index 9523f9c..395576f 100644
319 --- a/openstack-common.conf
320 +++ b/openstack-common.conf
321 @@ -26,6 +26,7 @@ module=processutils
322  module=rpc
323  module=service
324  module=sslutils
325 +module=systemd
326  module=threadgroup
327  module=timeutils
328  module=uuidutils