Merge "Factor out common code between cli utilities"
diff --git a/tests/test_stack_dump.py b/tests/test_stack_dump.py
index cc8cf8f..824e04c 100644
--- a/tests/test_stack_dump.py
+++ b/tests/test_stack_dump.py
@@ -17,7 +17,7 @@
import signal
import testtools
-import zuul.cmd.server
+import zuul.cmd
class TestStackDump(testtools.TestCase):
@@ -29,6 +29,6 @@
def test_stack_dump_logs(self):
"Test that stack dumps end up in logs."
- zuul.cmd.server.stack_dump_handler(signal.SIGUSR2, None)
+ zuul.cmd.stack_dump_handler(signal.SIGUSR2, None)
self.assertIn("Thread", self.log_fixture.output)
self.assertIn("test_stack_dump_logs", self.log_fixture.output)
diff --git a/zuul/cmd/__init__.py b/zuul/cmd/__init__.py
index e69de29..e17ad5b 100644
--- a/zuul/cmd/__init__.py
+++ b/zuul/cmd/__init__.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# Copyright 2012 Hewlett-Packard Development Company, L.P.
+# Copyright 2013 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 ConfigParser
+import logging
+import logging.config
+import os
+import signal
+import sys
+import traceback
+
+# No zuul imports here because they pull in paramiko which must not be
+# imported until after the daemonization.
+# https://github.com/paramiko/paramiko/issues/59
+# Similar situation with gear and statsd.
+
+
+def stack_dump_handler(signum, frame):
+ signal.signal(signal.SIGUSR2, signal.SIG_IGN)
+ log_str = ""
+ for thread_id, stack_frame in sys._current_frames().items():
+ log_str += "Thread: %s\n" % thread_id
+ log_str += "".join(traceback.format_stack(stack_frame))
+ log = logging.getLogger("zuul.stack_dump")
+ log.debug(log_str)
+ signal.signal(signal.SIGUSR2, stack_dump_handler)
+
+
+class ZuulApp(object):
+
+ def __init__(self):
+ self.args = None
+ self.config = None
+
+ def _get_version(self):
+ from zuul.version import version_info as zuul_version_info
+ return "Zuul version: %s" % zuul_version_info.version_string()
+
+ def read_config(self):
+ self.config = ConfigParser.ConfigParser()
+ if self.args.config:
+ locations = [self.args.config]
+ else:
+ locations = ['/etc/zuul/zuul.conf',
+ '~/zuul.conf']
+ for fp in locations:
+ if os.path.exists(os.path.expanduser(fp)):
+ self.config.read(os.path.expanduser(fp))
+ return
+ raise Exception("Unable to locate config file in %s" % locations)
+
+ def setup_logging(self, section, parameter):
+ if self.config.has_option(section, parameter):
+ fp = os.path.expanduser(self.config.get(section, parameter))
+ if not os.path.exists(fp):
+ raise Exception("Unable to read logging config file at %s" %
+ fp)
+ logging.config.fileConfig(fp)
+ else:
+ logging.basicConfig(level=logging.DEBUG)
diff --git a/zuul/cmd/client.py b/zuul/cmd/client.py
index 147fade..766a4ef 100644
--- a/zuul/cmd/client.py
+++ b/zuul/cmd/client.py
@@ -16,26 +16,20 @@
import argparse
import babel.dates
-import ConfigParser
import datetime
import logging
-import logging.config
-import os
import prettytable
import sys
import time
+
import zuul.rpcclient
+import zuul.cmd
-class Client(object):
+class Client(zuul.cmd.ZuulApp):
log = logging.getLogger("zuul.Client")
- def __init__(self):
- self.args = None
- self.config = None
- self.gear_server_pid = None
-
def parse_arguments(self):
parser = argparse.ArgumentParser(
description='Zuul Project Gating System Client.')
@@ -89,24 +83,8 @@
self.args = parser.parse_args()
- def _get_version(self):
- from zuul.version import version_info as zuul_version_info
- return "Zuul version: %s" % zuul_version_info.version_string()
-
- def read_config(self):
- self.config = ConfigParser.ConfigParser()
- if self.args.config:
- locations = [self.args.config]
- else:
- locations = ['/etc/zuul/zuul.conf',
- '~/zuul.conf']
- for fp in locations:
- if os.path.exists(os.path.expanduser(fp)):
- self.config.read(os.path.expanduser(fp))
- return
- raise Exception("Unable to locate config file in %s" % locations)
-
def setup_logging(self):
+ """Client logging does not rely on conf file"""
if self.args.verbose:
logging.basicConfig(level=logging.DEBUG)
diff --git a/zuul/cmd/merger.py b/zuul/cmd/merger.py
index edf8da9..dc3484a 100644
--- a/zuul/cmd/merger.py
+++ b/zuul/cmd/merger.py
@@ -15,7 +15,6 @@
# under the License.
import argparse
-import ConfigParser
import daemon
import extras
@@ -23,12 +22,11 @@
# instead it depends on lockfile-0.9.1 which uses pidfile.
pid_file_module = extras.try_imports(['daemon.pidlockfile', 'daemon.pidfile'])
-import logging
-import logging.config
import os
import sys
import signal
-import traceback
+
+import zuul.cmd
# No zuul imports here because they pull in paramiko which must not be
# imported until after the daemonization.
@@ -36,21 +34,7 @@
# Similar situation with gear and statsd.
-def stack_dump_handler(signum, frame):
- signal.signal(signal.SIGUSR2, signal.SIG_IGN)
- log_str = ""
- for thread_id, stack_frame in sys._current_frames().items():
- log_str += "Thread: %s\n" % thread_id
- log_str += "".join(traceback.format_stack(stack_frame))
- log = logging.getLogger("zuul.stack_dump")
- log.debug(log_str)
- signal.signal(signal.SIGUSR2, stack_dump_handler)
-
-
-class Merger(object):
- def __init__(self):
- self.args = None
- self.config = None
+class Merger(zuul.cmd.ZuulApp):
def parse_arguments(self):
parser = argparse.ArgumentParser(description='Zuul merge worker.')
@@ -58,33 +42,11 @@
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='store_true',
+ parser.add_argument('--version', dest='version', action='version',
+ version=self._get_version(),
help='show zuul version')
self.args = parser.parse_args()
- def read_config(self):
- self.config = ConfigParser.ConfigParser()
- if self.args.config:
- locations = [self.args.config]
- else:
- locations = ['/etc/zuul/zuul.conf',
- '~/zuul.conf']
- for fp in locations:
- if os.path.exists(os.path.expanduser(fp)):
- self.config.read(os.path.expanduser(fp))
- return
- raise Exception("Unable to locate config file in %s" % locations)
-
- def setup_logging(self, section, parameter):
- if self.config.has_option(section, parameter):
- fp = os.path.expanduser(self.config.get(section, parameter))
- if not os.path.exists(fp):
- raise Exception("Unable to read logging config file at %s" %
- fp)
- logging.config.fileConfig(fp)
- else:
- logging.basicConfig(level=logging.DEBUG)
-
def exit_handler(self, signum, frame):
signal.signal(signal.SIGUSR1, signal.SIG_IGN)
self.merger.stop()
@@ -100,7 +62,7 @@
self.merger.start()
signal.signal(signal.SIGUSR1, self.exit_handler)
- signal.signal(signal.SIGUSR2, stack_dump_handler)
+ signal.signal(signal.SIGUSR2, zuul.cmd.stack_dump_handler)
while True:
try:
signal.pause()
@@ -113,11 +75,6 @@
server = Merger()
server.parse_arguments()
- if server.args.version:
- from zuul.version import version_info as zuul_version_info
- print "Zuul version: %s" % zuul_version_info.version_string()
- sys.exit(0)
-
server.read_config()
if server.config.has_option('zuul', 'state_dir'):
diff --git a/zuul/cmd/server.py b/zuul/cmd/server.py
index 8caa1fd..06ea780 100755
--- a/zuul/cmd/server.py
+++ b/zuul/cmd/server.py
@@ -15,7 +15,6 @@
# under the License.
import argparse
-import ConfigParser
import daemon
import extras
@@ -24,11 +23,11 @@
pid_file_module = extras.try_imports(['daemon.pidlockfile', 'daemon.pidfile'])
import logging
-import logging.config
import os
import sys
import signal
-import traceback
+
+import zuul.cmd
# No zuul imports here because they pull in paramiko which must not be
# imported until after the daemonization.
@@ -36,21 +35,9 @@
# Similar situation with gear and statsd.
-def stack_dump_handler(signum, frame):
- signal.signal(signal.SIGUSR2, signal.SIG_IGN)
- log_str = ""
- for thread_id, stack_frame in sys._current_frames().items():
- log_str += "Thread: %s\n" % thread_id
- log_str += "".join(traceback.format_stack(stack_frame))
- log = logging.getLogger("zuul.stack_dump")
- log.debug(log_str)
- signal.signal(signal.SIGUSR2, stack_dump_handler)
-
-
-class Server(object):
+class Server(zuul.cmd.ZuulApp):
def __init__(self):
- self.args = None
- self.config = None
+ super(Server, self).__init__()
self.gear_server_pid = None
def parse_arguments(self):
@@ -71,33 +58,6 @@
help='show zuul version')
self.args = parser.parse_args()
- def _get_version(self):
- from zuul.version import version_info as zuul_version_info
- return "Zuul version: %s" % zuul_version_info.version_string()
-
- def read_config(self):
- self.config = ConfigParser.ConfigParser()
- if self.args.config:
- locations = [self.args.config]
- else:
- locations = ['/etc/zuul/zuul.conf',
- '~/zuul.conf']
- for fp in locations:
- if os.path.exists(os.path.expanduser(fp)):
- self.config.read(os.path.expanduser(fp))
- return
- raise Exception("Unable to locate config file in %s" % locations)
-
- def setup_logging(self, section, parameter):
- if self.config.has_option(section, parameter):
- fp = os.path.expanduser(self.config.get(section, parameter))
- if not os.path.exists(fp):
- raise Exception("Unable to read logging config file at %s" %
- fp)
- logging.config.fileConfig(fp)
- else:
- logging.basicConfig(level=logging.DEBUG)
-
def reconfigure_handler(self, signum, frame):
signal.signal(signal.SIGHUP, signal.SIG_IGN)
self.read_config()
@@ -235,7 +195,7 @@
signal.signal(signal.SIGHUP, self.reconfigure_handler)
signal.signal(signal.SIGUSR1, self.exit_handler)
- signal.signal(signal.SIGUSR2, stack_dump_handler)
+ signal.signal(signal.SIGUSR2, zuul.cmd.stack_dump_handler)
signal.signal(signal.SIGTERM, self.term_handler)
while True:
try: