diff --git a/README.md b/README.md index 7f5bc05..6e3fe5e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # Obsidian A set of python scripts for starting and working with Java processes with complex configurations in production and development. + +Installation: +python setup.py install diff --git a/cnf b/cnf index 8ec63da..bf69987 100644 --- a/cnf +++ b/cnf @@ -36,3 +36,6 @@ port = 9555 [hello] class = Hello classpath = java + +[tomcat] +file = /opt/tomcat/logs/catalina.out diff --git a/obsidian/ocommon.py b/obsidian/ocommon.py new file mode 100755 index 0000000..f8c43c0 --- /dev/null +++ b/obsidian/ocommon.py @@ -0,0 +1,53 @@ +#!/usr/bin/python + +import os + +# ./.obs.cnf and ~/.obs.cnf +project_conf_name = '.obs.cnf' +# /etc/obs.cnf +system_conf_name = '/etc/obsidian.cnf' + + +def find_conf_file(): + conf_file = find_in_parent_dir(project_conf_name) + if(conf_file): + return conf_file + + conf_file = os.path.expanduser(os.path.join('~', project_conf_name)) + if os.path.exists(conf_file): + return open(conf_file, 'r') + + if os.path.exists(system_conf_name): + return open(system_conf_name, 'r') + + return None + +def find_in_parent_dir(fname): + """ + Look in the current directory and then each parent + until root. + Inspired from 'findrepo()' in http://selenic.com/hg/file/2c9f5897d4b7/mercurial/cmdutil.py + """ + p = os.path.abspath(os.path.curdir) + + while not os.path.exists(os.path.join(p, project_conf_name)): + oldp, p = p, os.path.dirname(p) + if p == oldp: + return None + + return open(os.path.join(p, project_conf_name), 'r') + +""" +Sets the environment variables specified in the following format: +ENV_NAME1=loc1, ENV_NAME2=loc2 +""" +def set_env(env_str): + env_list = env_str.replace(" ","") + env_list = env_list.split(",") + for setting in env_list: + split = setting.split("=") + os.environ[split[0]] = os.path.expandvars(split[1]) + +class ConfigError(Exception): + def __init__(self, message): + self.message = message diff --git a/obsidian/ostart.py b/scripts/ostart old mode 100755 new mode 100644 similarity index 58% rename from obsidian/ostart.py rename to scripts/ostart index aa8d176..5e9be73 --- a/obsidian/ostart.py +++ b/scripts/ostart @@ -1,20 +1,13 @@ -#!/usr/bin/python - -import os - -# ./.obs.cnf and ~/.obs.cnf -project_conf_name = '.obs.cnf' -# /etc/obs.cnf -system_conf_name = '/etc/obsidian.cnf' - +#!/usr/bin/env python +from ocommon import * +import ConfigParser +from ConfigParser import NoOptionError +import sys +import argparse """ Starts a Java program defined by file 'cnf'. """ def ostart(): - import sys - import argparse - import ConfigParser - parser = argparse.ArgumentParser(description='Starts the process named by \'appid\'') parser.add_argument('appid', metavar='appid', type=str) parser.add_argument('--dry-run', '-d', action='store_true') @@ -53,8 +46,14 @@ def ostart(): java_cmd = config.get(appid, 'java_home') + "/bin/java" classpath = config.get(appid, 'classpath') class_ = config.get(appid, 'class') - - jvm_opts = config.get(appid, 'java_opts') + + #for compatability with flint, try both java_opts + #and opts. + jvm_opts = '' + if config.has_option(appid, 'java_opts'): + jvm_opts = config.get(appid,'java_opts') + elif config.has_option(appid, 'opts'): + jvm_opts = config.get(appid, 'opts') jvm_opts = jvm_opts.split(' ') if config.has_option(appid, 'system_opts'): @@ -63,63 +62,37 @@ def ostart(): else: system_opts = [] - if config.has_option(appid, 'conf'): - app_args = config.get(appid, 'conf') + if config.has_option(appid, 'args'): + app_args = config.get(appid, 'args') app_args = app_args.split(' ') else: app_args = [] + + if config.has_option(appid, 'env'): + env = config.get(appid, 'env') + set_env(env) + - c_args = [java_cmd] + c_args = [] + c_args.append(java_cmd) c_args.extend(jvm_opts) c_args.append("-classpath") c_args.append(classpath) c_args.extend(system_opts) c_args.append(class_) c_args.extend(app_args) - + #Expand environment variables + c_args = [os.path.expandvars(x) for x in c_args if x] #print " ".join(args) if args.dry_run: print " ".join(c_args) return - - os.execv(java_cmd, c_args) - -def find_conf_file(): - conf_file = find_in_parent_dir(project_conf_name) - if(conf_file): - return conf_file - - conf_file = os.path.expanduser(os.path.join('~', project_conf_name)) - if os.path.exists(conf_file): - return open(conf_file, 'r') - - if os.path.exists(system_conf_name): - return open(system_conf_name, 'r') - - return None - -def find_in_parent_dir(fname): - """ - Look in the current directory and then each parent - until root. - Inspired from 'findrepo()' in http://selenic.com/hg/file/2c9f5897d4b7/mercurial/cmdutil.py - """ - p = os.path.abspath(os.path.curdir) - - while not os.path.exists(os.path.join(p, project_conf_name)): - oldp, p = p, os.path.dirname(p) - if p == oldp: - return None - - return open(os.path.join(p, project_conf_name), 'r') - -class ConfigError(Exception): - def __init__(self, msg): - self.msg = msg + os.execv(c_args[0], c_args) if __name__ == "__main__": try: ostart() except ConfigError as e: - print e.msg - + print e.message + except NoOptionError as e: + print e.message diff --git a/scripts/otail b/scripts/otail new file mode 100644 index 0000000..eb631a2 --- /dev/null +++ b/scripts/otail @@ -0,0 +1,79 @@ +#!/usr/bin/env python +from ocommon import * +import ConfigParser +from ConfigParser import NoOptionError +import sys +import argparse +""" +Starts a Java program defined by file 'cnf'. +""" +def otail(): + parser = argparse.ArgumentParser(description='Starts the process named by \'appid\'') + parser.add_argument('appid', metavar='appid', type=str) + parser.add_argument('--dry-run', '-d', action='store_true') + parser.add_argument('--file', '-f', dest='conf_file', type=str) + + args = parser.parse_args() + appid = args.appid + conf_file = args.conf_file + + if conf_file: + conf_file = open(conf_file, 'r') + else: + conf_file = find_conf_file() + + if not conf_file: + raise ConfigError('could not find config file') + + if appid: + print "tailing [%s]" % appid + else: + print "appid required" + exit(1) + + config = ConfigParser.ConfigParser() + config.readfp(conf_file) + + # get the config file defaults out first, and recreate + # the config, providing those + defaults = dict(config.items('default')) + config = ConfigParser.ConfigParser(defaults) + + #readfp reads the whole file, must rewind + conf_file.seek(0) + config.readfp(conf_file) + + if config.has_option(appid, 'env'): + env = config.get(appid, 'env') + set_env(env) + tailFile = '' + if config.has_option(appid, 'file'): + tailFile = config.get(appid, 'file') + else: + print "Missing file, exiting" + return + + lines = '25' + if config.has_option(appid, 'lines'): + lines = config.get(appid, 'lines') + + c_args = ['/usr/bin/tail'] + c_args.append('-n') + c_args.append(lines) + c_args.append('-f') + c_args.append(tailFile) + #Expand environment variables + c_args = [os.path.expandvars(x) for x in c_args if x] + #print " ".join(args) + if args.dry_run: + print " ".join(c_args) + return + os.execv(c_args[0], c_args) + +if __name__ == "__main__": + try: + otail() + except ConfigError as e: + print e.message + except NoOptionError as e: + print e.message diff --git a/setup.py b/setup.py index 8d48d96..5926bd6 100644 --- a/setup.py +++ b/setup.py @@ -2,12 +2,13 @@ import sys sys.path.append('obsidian') -import ostart +import ocommon setup(name='ostart', version='0.1', author='Adam Lehenbauer', description='Start and manage Java processes declaratively', package_dir={'': 'obsidian'}, - py_modules=['ostart'] + py_modules=['ocommon'], + scripts=['scripts/ostart', 'scripts/otail'] )