#!/usr/bin/env python # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright (c) 2011 OpenStack, LLC. # # 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. """ Helper script for starting/stopping/reloading Glance server programs. Thanks for some of the code, Swifties ;) """ from __future__ import with_statement import errno import os import optparse import resource import signal import sys import time possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]), os.pardir, os.pardir, os.pardir)) if os.path.exists(os.path.join(possible_topdir, 'keystone', '__init__.py')): sys.path.insert(0, possible_topdir) from keystone import version from keystone.common import config ALL_COMMANDS = ['start', 'stop', 'restart'] MAX_DESCRIPTORS = 32768 MAX_MEMORY = (1024 * 1024 * 1024) * 1 # 2 GB USAGE = """%prog [options] keystone [CONFPATH] And command is one of: start, stop, restart And CONFPATH is the optional configuration file to use.""" def pid_files(server, options): pid_files = [] if options['pid_file']: if os.path.exists(os.path.abspath(options['pid_file'])): pid_files = [os.path.abspath(options['pid_file'])] else: if os.path.exists('/var/run/keystone/%s.pid' % server): pid_files = ['/var/run/keystone/%s.pid' % server] for pid_file in pid_files: pid = int(open(pid_file).read().strip()) yield pid_file, pid def do_start(server, options, args): for pid_file, pid in pid_files(server, options): if os.path.exists('/proc/%s' % pid): print "%s appears to already be running: %s" % (server, pid_file) return else: print "Removing stale pid file %s" % pid_file os.unlink(pid_file) try: resource.setrlimit(resource.RLIMIT_NOFILE, (MAX_DESCRIPTORS, MAX_DESCRIPTORS)) resource.setrlimit(resource.RLIMIT_DATA, (MAX_MEMORY, MAX_MEMORY)) except ValueError: print "Unable to increase file descriptor limit. Running as non-root?" os.environ['PYTHON_EGG_CACHE'] = '/tmp' def write_pid_file(pid_file, pid): dir, file = os.path.split(pid_file) if not os.path.exists(dir): try: os.makedirs(dir) except OSError, err: if err.errno == errno.EACCES: sys.exit('Unable to create %s. Running as non-root?' % dir) fp = open(pid_file, 'w') fp.write('%d\n' % pid) fp.close() def launch(ini_file, pid_file): args = [server, ini_file] print 'Starting %s with %s' % (server, ini_file) pid = os.fork() if pid == 0: os.setsid() with open(os.devnull, 'r+b') as nullfile: for desc in (0, 1, 2): # close stdio try: os.dup2(nullfile.fileno(), desc) except OSError: pass try: os.execlp('%s' % server, server, ini_file) except OSError, e: sys.exit('unable to launch %s. Got error: %s' % (server, str(e))) sys.exit(0) else: write_pid_file(pid_file, pid) if not options['pid_file']: pid_file = '/var/run/keystone/%s.pid' % server else: pid_file = os.path.abspath(options['pid_file']) conf_file = config.find_config_file(options, args) if not conf_file: sys.exit("Could not find any configuration file to use!") launch_args = [(conf_file, pid_file)] # start all servers for conf_file, pid_file in launch_args: launch(conf_file, pid_file) def do_stop(server, options, args, graceful=False): if graceful and server in GRACEFUL_SHUTDOWN_SERVERS: sig = signal.SIGHUP else: sig = signal.SIGTERM did_anything = False pfiles = pid_files(server, options) for pid_file, pid in pfiles: did_anything = True try: print 'Stopping %s pid: %s signal: %s' % (server, pid, sig) os.kill(pid, sig) except OSError: print "Process %d not running" % pid try: os.unlink(pid_file) except OSError: pass for pid_file, pid in pfiles: for _junk in xrange(150): # 15 seconds if not os.path.exists('/proc/%s' % pid): break time.sleep(0.1) else: print 'Waited 15 seconds for pid %s (%s) to die; giving up' % \ (pid, pid_file) if not did_anything: print 'No %s running' % server if __name__ == '__main__': oparser = optparse.OptionParser(usage=USAGE, version='%%prog %s' % version.version_string()) oparser.add_option('--pid-file', default=None, metavar="PATH", help="File to use as pid file. Default: " "/var/run/keysonte/keystone.pid") config.add_common_options(oparser) (options, args) = config.parse_options(oparser) if len(args) < 1: oparser.print_usage() sys.exit(1) server = 'keystone' command = args.pop(0).lower() if command not in ALL_COMMANDS: command_list = ", ".join(ALL_COMMANDS) msg = ("Unknown command %(command)s specified. Please specify a " "command in this list: %(command_list)s" % locals()) sys.exit(msg) if command == 'start': do_start(server, options, args) if command == 'stop': do_stop(server, options, args) if command == 'restart': do_stop(server, options, args) do_start(server, options, args)