Files
zuul/zuul/cmd/executor.py
T
James E. Blair 7e6e0a1f68 Change jobroot_dir to job_dir in executor config
And document it.

Naming this parameter is surprisingly difficult, since, ultimately
it's the "root directory for the job directories".  We call the
job directories jobdirs.  So it's the jobdir root.  But other
directory names in zuul config files have a dir suffix.
jobdir_dir doesn't sound right.  jobroot_dir is what we went
with since it's the most correct thing that matches the existing
style (even though it's confusing for internal zuul devs because
it maps to a variable called jobdir_root).

Instead of that, just call it "job_dir", which again, isn't technically
the most accurate from a Zuul internals perspective, but conveys
what needs to be conveyed to someone installing zuul.

Change-Id: I1494258c12eda5d566bc7154a2e0746090d0eecd
2017-07-25 11:13:36 -07:00

181 lines
6.0 KiB
Python
Executable File

#!/usr/bin/env python
# Copyright 2012 Hewlett-Packard Development Company, L.P.
# Copyright 2013-2014 OpenStack Foundation
#
# 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.
import argparse
import daemon
import extras
# as of python-daemon 1.6 it doesn't bundle pidlockfile anymore
# instead it depends on lockfile-0.9.1 which uses pidfile.
pid_file_module = extras.try_imports(['daemon.pidlockfile', 'daemon.pidfile'])
import logging
import os
import pwd
import socket
import sys
import signal
import tempfile
import zuul.cmd
import zuul.executor.server
from zuul.lib.config import get_default
# No zuul imports that pull in paramiko here; it must not be
# imported until after the daemonization.
# https://github.com/paramiko/paramiko/issues/59
# Similar situation with gear and statsd.
class Executor(zuul.cmd.ZuulApp):
def parse_arguments(self):
parser = argparse.ArgumentParser(description='Zuul executor.')
parser.add_argument('-c', dest='config',
help='specify the config file')
parser.add_argument('-d', dest='nodaemon', action='store_true',
help='do not run as a daemon')
parser.add_argument('--version', dest='version', action='version',
version=self._get_version(),
help='show zuul version')
parser.add_argument('--keep-jobdir', dest='keep_jobdir',
action='store_true',
help='keep local jobdirs after run completes')
parser.add_argument('command',
choices=zuul.executor.server.COMMANDS,
nargs='?')
self.args = parser.parse_args()
def send_command(self, cmd):
state_dir = get_default(self.config, 'executor', 'state_dir',
'/var/lib/zuul', expand_user=True)
path = os.path.join(state_dir, 'executor.socket')
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(path)
cmd = '%s\n' % cmd
s.sendall(cmd.encode('utf8'))
def exit_handler(self):
self.executor.stop()
self.executor.join()
def start_log_streamer(self):
pipe_read, pipe_write = os.pipe()
child_pid = os.fork()
if child_pid == 0:
os.close(pipe_write)
import zuul.lib.log_streamer
self.log.info("Starting log streamer")
streamer = zuul.lib.log_streamer.LogStreamer(
self.user, '0.0.0.0', self.finger_port, self.job_dir)
# Keep running until the parent dies:
pipe_read = os.fdopen(pipe_read)
pipe_read.read()
self.log.info("Stopping log streamer")
streamer.stop()
os._exit(0)
else:
os.close(pipe_read)
self.log_streamer_pid = child_pid
def change_privs(self):
'''
Drop our privileges to the zuul user.
'''
if os.getuid() != 0:
return
pw = pwd.getpwnam(self.user)
os.setgroups([])
os.setgid(pw.pw_gid)
os.setuid(pw.pw_uid)
os.umask(0o022)
def main(self, daemon=True):
# See comment at top of file about zuul imports
self.user = get_default(self.config, 'executor', 'user', 'zuul')
if self.config.has_option('executor', 'job_dir'):
self.job_dir = os.path.expanduser(
self.config.get('executor', 'job_dir'))
if not os.path.isdir(self.job_dir):
print("Invalid job_dir: {job_dir}".format(
job_dir=self.job_dir))
sys.exit(1)
else:
self.job_dir = tempfile.gettempdir()
self.setup_logging('executor', 'log_config')
self.log = logging.getLogger("zuul.Executor")
self.finger_port = int(
get_default(self.config, 'executor', 'finger_port',
zuul.executor.server.DEFAULT_FINGER_PORT)
)
self.start_log_streamer()
self.change_privs()
ExecutorServer = zuul.executor.server.ExecutorServer
self.executor = ExecutorServer(self.config, self.connections,
jobdir_root=self.job_dir,
keep_jobdir=self.args.keep_jobdir,
log_streaming_port=self.finger_port)
self.executor.start()
signal.signal(signal.SIGUSR2, zuul.cmd.stack_dump_handler)
if daemon:
self.executor.join()
else:
while True:
try:
signal.pause()
except KeyboardInterrupt:
print("Ctrl + C: asking executor to exit nicely...\n")
self.exit_handler()
sys.exit(0)
def main():
server = Executor()
server.parse_arguments()
server.read_config()
if server.args.command in zuul.executor.server.COMMANDS:
server.send_command(server.args.command)
sys.exit(0)
server.configure_connections(source_only=True)
pid_fn = get_default(server.config, 'executor', 'pidfile',
'/var/run/zuul-executor/zuul-executor.pid',
expand_user=True)
pid = pid_file_module.TimeoutPIDLockFile(pid_fn, 10)
if server.args.nodaemon:
server.main(False)
else:
with daemon.DaemonContext(pidfile=pid):
server.main(True)
if __name__ == "__main__":
sys.path.insert(0, '.')
main()