blob: 49643aee0512c9c96fb8fc5aca28be6e9136c9a4 [file] [log] [blame]
James E. Blair9f365192016-04-18 10:34:48 -07001#!/usr/bin/env python
2# Copyright 2012 Hewlett-Packard Development Company, L.P.
3# Copyright 2013-2014 OpenStack Foundation
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17import argparse
18import daemon
19import extras
20
21# as of python-daemon 1.6 it doesn't bundle pidlockfile anymore
22# instead it depends on lockfile-0.9.1 which uses pidfile.
23pid_file_module = extras.try_imports(['daemon.pidlockfile', 'daemon.pidfile'])
24
James E. Blair119acf32016-04-18 15:34:36 -070025import logging
James E. Blair9f365192016-04-18 10:34:48 -070026import os
James E. Blairc4b20412016-05-27 16:45:26 -070027import socket
James E. Blair9f365192016-04-18 10:34:48 -070028import sys
29import signal
30
31import zuul.cmd
James E. Blaira6a50042016-06-01 15:33:54 -070032import zuul.launcher.ansiblelaunchserver
James E. Blair9f365192016-04-18 10:34:48 -070033
James E. Blaira6a50042016-06-01 15:33:54 -070034# No zuul imports that pull in paramiko here; it must not be
James E. Blair9f365192016-04-18 10:34:48 -070035# imported until after the daemonization.
36# https://github.com/paramiko/paramiko/issues/59
37# Similar situation with gear and statsd.
38
39
40class Launcher(zuul.cmd.ZuulApp):
41
42 def parse_arguments(self):
43 parser = argparse.ArgumentParser(description='Zuul launch worker.')
44 parser.add_argument('-c', dest='config',
45 help='specify the config file')
46 parser.add_argument('-d', dest='nodaemon', action='store_true',
47 help='do not run as a daemon')
48 parser.add_argument('--version', dest='version', action='version',
49 version=self._get_version(),
50 help='show zuul version')
James E. Blairf87c5ce2016-05-25 08:43:37 -070051 parser.add_argument('--keep-jobdir', dest='keep_jobdir',
52 action='store_true',
53 help='keep local jobdirs after run completes')
James E. Blaira6a50042016-06-01 15:33:54 -070054 parser.add_argument('command',
55 choices=zuul.launcher.ansiblelaunchserver.COMMANDS,
James E. Blairc4b20412016-05-27 16:45:26 -070056 nargs='?')
57
James E. Blair9f365192016-04-18 10:34:48 -070058 self.args = parser.parse_args()
59
James E. Blairc4b20412016-05-27 16:45:26 -070060 def send_command(self, cmd):
61 if self.config.has_option('zuul', 'state_dir'):
62 state_dir = os.path.expanduser(
63 self.config.get('zuul', 'state_dir'))
64 else:
65 state_dir = '/var/lib/zuul'
66 path = os.path.join(state_dir, 'launcher.socket')
67 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
68 s.connect(path)
69 s.sendall('%s\n' % cmd)
James E. Blair119acf32016-04-18 15:34:36 -070070
James E. Blairc4b20412016-05-27 16:45:26 -070071 def exit_handler(self):
James E. Blair9f365192016-04-18 10:34:48 -070072 self.launcher.stop()
73 self.launcher.join()
74
James E. Blairc4b20412016-05-27 16:45:26 -070075 def main(self, daemon=True):
James E. Blair9f365192016-04-18 10:34:48 -070076 # See comment at top of file about zuul imports
James E. Blair9f365192016-04-18 10:34:48 -070077
78 self.setup_logging('launcher', 'log_config')
79
James E. Blair119acf32016-04-18 15:34:36 -070080 self.log = logging.getLogger("zuul.Launcher")
81
James E. Blair9f365192016-04-18 10:34:48 -070082 LaunchServer = zuul.launcher.ansiblelaunchserver.LaunchServer
James E. Blairf87c5ce2016-05-25 08:43:37 -070083 self.launcher = LaunchServer(self.config,
84 keep_jobdir=self.args.keep_jobdir)
James E. Blair9f365192016-04-18 10:34:48 -070085 self.launcher.start()
86
James E. Blair9f365192016-04-18 10:34:48 -070087 signal.signal(signal.SIGUSR2, zuul.cmd.stack_dump_handler)
James E. Blairc4b20412016-05-27 16:45:26 -070088 if daemon:
89 self.launcher.join()
90 else:
91 while True:
92 try:
93 signal.pause()
94 except KeyboardInterrupt:
Morgan Fainberg4c6a7742016-05-27 08:42:17 -070095 print("Ctrl + C: asking launcher to exit nicely...\n")
James E. Blairc4b20412016-05-27 16:45:26 -070096 self.exit_handler()
97 sys.exit(0)
James E. Blair9f365192016-04-18 10:34:48 -070098
99
100def main():
101 server = Launcher()
102 server.parse_arguments()
James E. Blair9f365192016-04-18 10:34:48 -0700103 server.read_config()
James E. Blairc4b20412016-05-27 16:45:26 -0700104
James E. Blaira6a50042016-06-01 15:33:54 -0700105 if server.args.command in zuul.launcher.ansiblelaunchserver.COMMANDS:
106 server.send_command(server.args.command)
James E. Blairc4b20412016-05-27 16:45:26 -0700107 sys.exit(0)
108
James E. Blair9f365192016-04-18 10:34:48 -0700109 server.configure_connections()
110
111 if server.config.has_option('launcher', 'pidfile'):
112 pid_fn = os.path.expanduser(server.config.get('launcher', 'pidfile'))
113 else:
114 pid_fn = '/var/run/zuul-launcher/zuul-launcher.pid'
115 pid = pid_file_module.TimeoutPIDLockFile(pid_fn, 10)
116
117 if server.args.nodaemon:
James E. Blairc4b20412016-05-27 16:45:26 -0700118 server.main(False)
James E. Blair9f365192016-04-18 10:34:48 -0700119 else:
120 with daemon.DaemonContext(pidfile=pid):
James E. Blairc4b20412016-05-27 16:45:26 -0700121 server.main(True)
James E. Blair9f365192016-04-18 10:34:48 -0700122
123
124if __name__ == "__main__":
125 sys.path.insert(0, '.')
126 main()