From 20df85f4385cab39c41007fd686ccdbee21f8dda Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 14 Nov 2019 18:30:12 +0100 Subject: [PATCH 01/31] Autocomplete with argcomplete --- procServUtils/manage.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 7874a5f..b496ca8 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -253,6 +253,7 @@ def writeprocs(conf, args): def getargs(args=None): from argparse import ArgumentParser, REMAINDER + import argcomplete P = ArgumentParser() P.add_argument('--user', action='store_true', default=os.geteuid()!=0, help='Consider user config') @@ -307,6 +308,7 @@ def getargs(args=None): S.add_argument('extra', nargs=REMAINDER, help='extra args for telnet') S.set_defaults(func=attachproc) + argcomplete.autocomplete(P) A = P.parse_args(args=args) if not hasattr(A, 'func'): P.print_help() From 26de0a11f33c266370d97af0249c4e6c02103aed Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Fri, 15 Nov 2019 00:40:12 +0100 Subject: [PATCH 02/31] Autocomplete instances names --- manage-procs | 1 + procServUtils/manage.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/manage-procs b/manage-procs index 169227d..13e2e49 100755 --- a/manage-procs +++ b/manage-procs @@ -1,4 +1,5 @@ #!/usr/bin/python3 +# PYTHON_ARGCOMPLETE_OK from procServUtils.manage import getargs, main main(getargs()) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index b496ca8..11083d6 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -251,9 +251,12 @@ def writeprocs(conf, args): else: sys.stdout.write('# systemctl %s reload conserver-server.service\n'%argusersys) +def instances_completer(**kwargs): + return getconf(user=False).sections() + getconf(user=True).sections() + def getargs(args=None): from argparse import ArgumentParser, REMAINDER - import argcomplete + from argcomplete import autocomplete P = ArgumentParser() P.add_argument('--user', action='store_true', default=os.geteuid()!=0, help='Consider user config') @@ -287,7 +290,7 @@ def getargs(args=None): S = SP.add_parser('remove', help='Remove a procServ instance') S.add_argument('-f','--force', action='store_true', default=False) - S.add_argument('name', help='Instance name') + S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=delproc) S = SP.add_parser('write-procs-cf', help='Write conserver config') @@ -296,19 +299,19 @@ def getargs(args=None): S.set_defaults(func=writeprocs) S = SP.add_parser('start', help='Start a procServ instance') - S.add_argument('name', help='Instance name') + S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=startproc) S = SP.add_parser('stop', help='Stop a procServ instance') - S.add_argument('name', help='Instance name') + S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=stopproc) S = SP.add_parser('attach', help='Attach to a procServ instance') - S.add_argument("name", help='Instance name') + S.add_argument("name", help='Instance name').completer = instances_completer S.add_argument('extra', nargs=REMAINDER, help='extra args for telnet') S.set_defaults(func=attachproc) - argcomplete.autocomplete(P) + autocomplete(P) A = P.parse_args(args=args) if not hasattr(A, 'func'): P.print_help() From e3bf0a60b2ec185667e2383056b97978390bdb39 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Fri, 15 Nov 2019 12:01:06 +0100 Subject: [PATCH 03/31] Get user configuration during autocomplete --- procServUtils/manage.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 11083d6..c73121a 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -252,7 +252,10 @@ def writeprocs(conf, args): sys.stdout.write('# systemctl %s reload conserver-server.service\n'%argusersys) def instances_completer(**kwargs): - return getconf(user=False).sections() + getconf(user=True).sections() + user = True + if 'parsed_args' in kwargs: + user = kwargs['parsed_args'].user + return getconf(user=user).sections() def getargs(args=None): from argparse import ArgumentParser, REMAINDER From 25be63079e9529c9d5adef9d84c958f648784c35 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Fri, 15 Nov 2019 13:25:24 +0100 Subject: [PATCH 04/31] Adding logs and restart commands to manage-procs --- procServUtils/manage.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index c73121a..2832f5e 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -19,6 +19,7 @@ ] systemctl = '/bin/systemctl' +journalctl = '/bin/journalctl' def status(conf, args, fp=None): rundir=getrundir(user=args.user) @@ -90,6 +91,24 @@ def stopproc(conf, args): '--user' if args.user else '--system', 'stop', 'procserv-%s.service'%args.name]) +def restartproc(conf, args): + _log.info("Restarting service procserv-%s.service", args.name) + SP.call([systemctl, + '--user' if args.user else '--system', + 'restart', 'procserv-%s.service'%args.name]) + +def showlogs(conf, args): + _log.info("Opening logs of service procserv-%s.service", args.name) + command = [journalctl, + '--user-unit' if args.user else '--unit', + 'procserv-%s.service'%args.name] + if args.follow: + command.append('-f') + try: + SP.call(command) + except KeyboardInterrupt: + pass + def attachproc(conf, args): from .attach import attach attach(args) @@ -309,6 +328,15 @@ def getargs(args=None): S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=stopproc) + S = SP.add_parser('restart', help='Restart a procServ instance') + S.add_argument('name', help='Instance name').completer = instances_completer + S.set_defaults(func=restartproc) + + S = SP.add_parser('logs', help='Open logs of a procServ instance') + S.add_argument('-f','--follow', action='store_true', default=False) + S.add_argument('name', help='Instance name').completer = instances_completer + S.set_defaults(func=showlogs) + S = SP.add_parser('attach', help='Attach to a procServ instance') S.add_argument("name", help='Instance name').completer = instances_completer S.add_argument('extra', nargs=REMAINDER, help='extra args for telnet') From 551a76a6ea560106461cd2f6a29b1dab1792218c Mon Sep 17 00:00:00 2001 From: Giovanni Savarese Date: Tue, 28 Jan 2020 15:49:05 +0100 Subject: [PATCH 05/31] Reset a failed procServ instance --- procServUtils/manage.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 2832f5e..97d320d 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -91,6 +91,12 @@ def stopproc(conf, args): '--user' if args.user else '--system', 'stop', 'procserv-%s.service'%args.name]) +def resetfailedproc(conf, args): + _log.info("Resetting service procserv-%s.service", args.name) + SP.call([systemctl, + '--user' if args.user else '--system', + 'reset-failed', 'procserv-%s.service'%args.name]) + def restartproc(conf, args): _log.info("Restarting service procserv-%s.service", args.name) SP.call([systemctl, @@ -328,6 +334,10 @@ def getargs(args=None): S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=stopproc) + S = SP.add_parser('reset-failed', help='Reset a failed procServ instance') + S.add_argument('name', help='Instance name').completer = instances_completer + S.set_defaults(func=resetfailedproc) + S = SP.add_parser('restart', help='Restart a procServ instance') S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=restartproc) From bbc7f1ae09a6b44a73ac57ccb1a9e4a695de6217 Mon Sep 17 00:00:00 2001 From: Giovanni Savarese Date: Wed, 29 Jan 2020 10:04:52 +0100 Subject: [PATCH 06/31] Insert reset-failed in remove func --- procServUtils/manage.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 97d320d..1f467ee 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -91,12 +91,6 @@ def stopproc(conf, args): '--user' if args.user else '--system', 'stop', 'procserv-%s.service'%args.name]) -def resetfailedproc(conf, args): - _log.info("Resetting service procserv-%s.service", args.name) - SP.call([systemctl, - '--user' if args.user else '--system', - 'reset-failed', 'procserv-%s.service'%args.name]) - def restartproc(conf, args): _log.info("Restarting service procserv-%s.service", args.name) SP.call([systemctl, @@ -235,6 +229,23 @@ def delproc(conf, args): 'disable', "procserv-%s.service"%args.name]) + _log.info("Resetting service procserv-%s.service", args.name) + occurences = 0 + check_service = SP.Popen([systemctl, + '--user' if args.user else '--system', + 'list-units', + '--all', + 'procserv-%s.service'%args.name], stdout=SP.PIPE) + output = check_service.communicate()[0].split('\n') + for row in output: + if 'loaded units listed' in row: + occurences = int(row[0]) + if occurences != 0: + SP.check_call([systemctl, + '--user' if args.user else '--system', + 'reset-failed', + 'procserv-%s.service'%args.name]) + _log.info('Triggering systemd reload') SP.check_call([systemctl, '--user' if args.user else '--system', @@ -334,10 +345,6 @@ def getargs(args=None): S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=stopproc) - S = SP.add_parser('reset-failed', help='Reset a failed procServ instance') - S.add_argument('name', help='Instance name').completer = instances_completer - S.set_defaults(func=resetfailedproc) - S = SP.add_parser('restart', help='Restart a procServ instance') S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=restartproc) From 61e75863f3390b37b268749df6364ea0798f4ff7 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Wed, 29 Jan 2020 16:24:24 +0100 Subject: [PATCH 07/31] Improving unit removal, fixing some exceptions --- procServUtils/manage.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 1f467ee..510f206 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -224,24 +224,13 @@ def delproc(conf, args): stopproc(conf, args) _log.info("Disabling service procserv-%s.service", args.name) - SP.check_call([systemctl, + SP.call([systemctl, '--user' if args.user else '--system', 'disable', "procserv-%s.service"%args.name]) _log.info("Resetting service procserv-%s.service", args.name) - occurences = 0 - check_service = SP.Popen([systemctl, - '--user' if args.user else '--system', - 'list-units', - '--all', - 'procserv-%s.service'%args.name], stdout=SP.PIPE) - output = check_service.communicate()[0].split('\n') - for row in output: - if 'loaded units listed' in row: - occurences = int(row[0]) - if occurences != 0: - SP.check_call([systemctl, + SP.call([systemctl, '--user' if args.user else '--system', 'reset-failed', 'procserv-%s.service'%args.name]) From 8f05ae4531f52744fec58d7ee44244f99dcc7854 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Wed, 18 Mar 2020 15:59:37 +0100 Subject: [PATCH 08/31] Pretty table on manage-procs status --- procServUtils/manage.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 510f206..50aa33f 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -4,6 +4,8 @@ import sys, os, errno import subprocess as SP +from tabulate import tabulate +from termcolor import colored from .conf import getconf, getrundir, getgendir @@ -25,11 +27,12 @@ def status(conf, args, fp=None): rundir=getrundir(user=args.user) fp = fp or sys.stdout + table = [] for name in conf.sections(): if not conf.getboolean(name, 'instance'): continue - fp.write('%s '%name) - + instance = ['%s '%name] + pid = None ports = [] infoname = os.path.join(rundir, 'procserv-%s'%name, 'info') @@ -63,14 +66,18 @@ def status(conf, args, fp=None): _log.debug("Can't say if PID exists or not") else: _log.exception("Testing PID %s", pid) - fp.write('Running' if running else 'Dead') + instance.append(colored('Running', 'green') if running else colored('Dead', attrs=['bold'])) if running: - fp.write('\t'+' '.join(ports)) + instance.append(' '.join(ports)) else: - fp.write('Stopped') - - fp.write('\n') + instance.append(colored('Stopped', 'red')) + + table.append(instance) + + # Print results table + headers = ['PROCESS', 'STATE', 'PORT'] + fp.write(tabulate(sorted(table), headers=headers, tablefmt="github")+ '\n') def syslist(conf, args): SP.check_call([systemctl, @@ -200,7 +207,7 @@ def delproc(conf, args): if not args.force and sys.stdin.isatty(): while True: - sys.stdout.write("Remove section '%s' from %s ? [yN]"%(args.name, cfile)) + sys.stdout.write("Remove section '%s' from %s ? [yN] "%(args.name, cfile)) sys.stdout.flush() L = sys.stdin.readline().strip().upper() if L=='Y': From 9118005745b57e17bb33ff8135ce6eee25710e2a Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Wed, 18 Mar 2020 19:48:46 +0100 Subject: [PATCH 09/31] Renameprocs --- procServUtils/conf.py | 24 ++++++++++++++++++++- procServUtils/manage.py | 47 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/procServUtils/conf.py b/procServUtils/conf.py index b2b60fb..508047a 100644 --- a/procServUtils/conf.py +++ b/procServUtils/conf.py @@ -2,7 +2,7 @@ import logging _log = logging.getLogger(__name__) -import os +import os, sys, errno from functools import reduce from glob import glob @@ -53,6 +53,28 @@ def getconffiles(user=False): # reduce by concatination into a single list return reduce(list.__add__, map(glob, files), []) +def addconf(name, conf, user=False, force=False): + outdir = getgendir(user) + cfile = os.path.join(outdir, '%s.conf'%name) + + if os.path.exists(cfile) and not force: + _log.error("Instance already exists @ %s", cfile) + sys.exit(1) + + try: + os.makedirs(outdir) + except OSError as e: + if e.errno!=errno.EEXIST: + _log.exception('Creating directory "%s"', outdir) + raise + + _log.info("Writing: %s", cfile) + with open(cfile, 'w') as F: + conf.write(F) + +def delconf(name): + pass + _defaults = { 'user':'nobody', 'group':'nogroup', diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 50aa33f..4771d5f 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -7,7 +7,7 @@ from tabulate import tabulate from termcolor import colored -from .conf import getconf, getrundir, getgendir +from .conf import getconf, getrundir, getgendir, ConfigParser, addconf, delconf try: import shlex @@ -121,7 +121,7 @@ def attachproc(conf, args): attach(args) def addproc(conf, args): - from .generator import run, write_service + from .generator import run outdir = getgendir(user=args.user) cfile = os.path.join(outdir, '%s.conf'%args.name) @@ -256,6 +256,41 @@ def delproc(conf, args): #sys.stdout.write("# systemctl stop procserv-%s.service\n"%args.name) +def renameproc(conf, args): + from .generator import run + + # copy settings from previous conf + items = conf.items(args.name) + new_conf = ConfigParser() + new_conf.add_section(args.new_name) + for item in items: + new_conf.set(args.new_name, item[0], item[1]) + + # create new conf file with old settings + addconf(args.new_name, new_conf, args.user, args.force) + + # delete previous proc + delproc(conf, args) + + outdir = getgendir(args.user) + argusersys = '--user' if args.user else '--system' + run(outdir, user=args.user) + SP.check_call([systemctl, + argusersys, + 'enable', + "%s/procserv-%s.service"%(outdir, args.new_name)]) + + _log.info('Trigger systemd reload') + SP.check_call([systemctl, + argusersys, + 'daemon-reload'], shell=False) + + if args.autostart: + args.name = args.new_name + startproc(conf, args) + else: + sys.stdout.write("# manage-procs %s start %s\n"%(argusersys,args.new_name)) + def writeprocs(conf, args): argusersys = '--user' if args.user else '--system' opts = { @@ -328,6 +363,14 @@ def getargs(args=None): S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=delproc) + S = SP.add_parser('rename', help='Rename a procServ instance') + S.add_argument('-f','--force', action='store_true', default=False) + S.add_argument('-A','--autostart',action='store_true', default=False, + help='Automatically start after renaming') + S.add_argument('name', help='Current instance name').completer = instances_completer + S.add_argument('new_name', help='Desired instance name') + S.set_defaults(func=renameproc) + S = SP.add_parser('write-procs-cf', help='Write conserver config') S.add_argument('-f','--out',default='/etc/conserver/procs.cf') S.add_argument('-R','--reload', action='store_true', default=False) From ccdc042f9e1d0375f367d9c61f800901abc33b86 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Wed, 18 Mar 2020 20:15:01 +0100 Subject: [PATCH 10/31] Addproc with new addconf utility --- procServUtils/manage.py | 72 +++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 4771d5f..5046a0e 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -123,63 +123,43 @@ def attachproc(conf, args): def addproc(conf, args): from .generator import run - outdir = getgendir(user=args.user) - cfile = os.path.join(outdir, '%s.conf'%args.name) - argusersys = '--user' if args.user else '--system' - - if os.path.exists(cfile) and not args.force: - _log.error("Instance already exists @ %s", cfile) - sys.exit(1) - - #if conf.has_section(args.name): - # _log.error("Instance already exists") - # sys.exit(1) - - try: - os.makedirs(outdir) - except OSError as e: - if e.errno!=errno.EEXIST: - _log.exception('Creating directory "%s"', outdir) - raise - - _log.info("Writing: %s", cfile) - # ensure chdir and env_file are absolute paths - args.chdir = os.path.abspath(os.path.join(os.getcwd(), args.chdir)) + chdir = os.path.abspath(os.path.join(os.getcwd(), args.chdir)) if args.env_file: args.env_file = os.path.abspath(os.path.join(os.getcwd(), args.env_file)) if not os.path.exists(args.env_file): _log.error('File not found: "%s"', args.env_file) sys.exit(1) - args.command = os.path.abspath(os.path.join(args.chdir, args.command)) - - opts = { - 'name':args.name, - 'command':args.command + ' ' + ' '.join(map(shlex.quote, args.args)), - 'chdir':args.chdir, - } - - with open(cfile+'.tmp', 'w') as F: - F.write(""" -[%(name)s] -command = %(command)s -chdir = %(chdir)s -"""%opts) - - if args.username: F.write("user = %s\n"%args.username) - if args.group: F.write("group = %s\n"%args.group) - if args.port: F.write("port = %s\n"%args.port) - if args.environment: F.write("environment = %s\n"%' '.join(args.environment)) - if args.env_file: F.write("env_file = %s\n"%args.env_file) - - os.rename(cfile+'.tmp', cfile) + # command is relative to chdir + command = os.path.abspath(os.path.join(args.chdir, args.command)) + command = command + ' ' + ' '.join(map(shlex.quote, args.args)) + # set conf paramers + new_conf = ConfigParser() + conf_name = args.name + new_conf.add_section(conf_name) + new_conf.set(conf_name, "command", command) + new_conf.set(conf_name, "chdir", chdir) + if args.username: new_conf.set(conf_name, "user", args.username) + if args.group: new_conf.set(conf_name, "group", args.group) + if args.port: new_conf.set(conf_name, "port", args.port) + if args.environment: new_conf.set(conf_name, "environment", ' '.join(args.environment)) + if args.env_file: new_conf.set(conf_name, "env_file", args.env_file) + + # write conf file + addconf(conf_name, new_conf, args.user, args.force) + + # generate service files + outdir = getgendir(args.user) run(outdir, user=args.user) + + # register systemd service + argusersys = '--user' if args.user else '--system' SP.check_call([systemctl, argusersys, 'enable', - "%s/procserv-%s.service"%(outdir, args.name)]) + "%s/procserv-%s.service"%(outdir, conf_name)]) _log.info('Trigger systemd reload') SP.check_call([systemctl, @@ -189,7 +169,7 @@ def addproc(conf, args): if args.autostart: startproc(conf, args) else: - sys.stdout.write("# manage-procs %s start %s\n"%(argusersys,args.name)) + sys.stdout.write("# manage-procs %s start %s\n"%(argusersys, conf_name)) def delproc(conf, args): from .conf import getconffiles, ConfigParser From 1de88db09a41f3de5c3e3c90d0977a2241675e5e Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Wed, 18 Mar 2020 21:05:38 +0100 Subject: [PATCH 11/31] Fix rename on unknown process --- procServUtils/manage.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 5046a0e..bb7b54f 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -240,6 +240,9 @@ def renameproc(conf, args): from .generator import run # copy settings from previous conf + if args.name not in conf.sections(): + _log.error('Unknown process: "%s"', args.name) + sys.exit(1) items = conf.items(args.name) new_conf = ConfigParser() new_conf.add_section(args.new_name) From 656305cdca70d31208659a30516e4773c7aeb75d Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 14:51:53 +0100 Subject: [PATCH 12/31] Check existence of requested proc --- procServUtils/manage.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index bb7b54f..fd9f753 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -4,8 +4,6 @@ import sys, os, errno import subprocess as SP -from tabulate import tabulate -from termcolor import colored from .conf import getconf, getrundir, getgendir, ConfigParser, addconf, delconf @@ -23,7 +21,15 @@ systemctl = '/bin/systemctl' journalctl = '/bin/journalctl' +def check_req(conf, args): + if args.name not in conf.sections(): + _log.error(' "%s" is not an active %s procServ.', args.name, 'user' if args.user else 'system') + sys.exit(1) + def status(conf, args, fp=None): + from tabulate import tabulate + from termcolor import colored + rundir=getrundir(user=args.user) fp = fp or sys.stdout @@ -87,24 +93,28 @@ def syslist(conf, args): 'procserv-*']) def startproc(conf, args): + check_req(conf, args) _log.info("Starting service procserv-%s.service", args.name) SP.call([systemctl, '--user' if args.user else '--system', 'start', 'procserv-%s.service'%args.name]) def stopproc(conf, args): + check_req(conf, args) _log.info("Stopping service procserv-%s.service", args.name) SP.call([systemctl, '--user' if args.user else '--system', 'stop', 'procserv-%s.service'%args.name]) def restartproc(conf, args): + check_req(conf, args) _log.info("Restarting service procserv-%s.service", args.name) SP.call([systemctl, '--user' if args.user else '--system', 'restart', 'procserv-%s.service'%args.name]) def showlogs(conf, args): + check_req(conf, args) _log.info("Opening logs of service procserv-%s.service", args.name) command = [journalctl, '--user-unit' if args.user else '--unit', @@ -117,6 +127,7 @@ def showlogs(conf, args): pass def attachproc(conf, args): + check_req(conf, args) from .attach import attach attach(args) @@ -172,6 +183,8 @@ def addproc(conf, args): sys.stdout.write("# manage-procs %s start %s\n"%(argusersys, conf_name)) def delproc(conf, args): + check_req(conf, args) + from .conf import getconffiles, ConfigParser for cfile in getconffiles(user=args.user): _log.debug('delproc processing %s', cfile) @@ -219,6 +232,7 @@ def delproc(conf, args): _log.info("Resetting service procserv-%s.service", args.name) SP.call([systemctl, '--user' if args.user else '--system', + '--quiet', 'reset-failed', 'procserv-%s.service'%args.name]) @@ -237,12 +251,10 @@ def delproc(conf, args): #sys.stdout.write("# systemctl stop procserv-%s.service\n"%args.name) def renameproc(conf, args): + check_req(conf, args) from .generator import run # copy settings from previous conf - if args.name not in conf.sections(): - _log.error('Unknown process: "%s"', args.name) - sys.exit(1) items = conf.items(args.name) new_conf = ConfigParser() new_conf.add_section(args.new_name) @@ -253,11 +265,15 @@ def renameproc(conf, args): addconf(args.new_name, new_conf, args.user, args.force) # delete previous proc + args.force = True delproc(conf, args) + # generate service files outdir = getgendir(args.user) - argusersys = '--user' if args.user else '--system' run(outdir, user=args.user) + + # register systemd service + argusersys = '--user' if args.user else '--system' SP.check_call([systemctl, argusersys, 'enable', From f21c49b9b51332e6352ddb4b777c3d09e4a3c548 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 15:03:02 +0100 Subject: [PATCH 13/31] Comment with dependencies --- procServUtils/conf.py | 3 --- setup.py | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/procServUtils/conf.py b/procServUtils/conf.py index 508047a..3c62b8e 100644 --- a/procServUtils/conf.py +++ b/procServUtils/conf.py @@ -72,9 +72,6 @@ def addconf(name, conf, user=False, force=False): with open(cfile, 'w') as F: conf.write(F) -def delconf(name): - pass - _defaults = { 'user':'nobody', 'group':'nogroup', diff --git a/setup.py b/setup.py index ad1e609..0280bd3 100755 --- a/setup.py +++ b/setup.py @@ -29,4 +29,5 @@ def run(self): ('lib/systemd/user-generators', ['systemd-procserv-generator-user']), ], cmdclass = { 'install_data': custom_install_data }, + #install_requires=['argcomplete', 'tabulate', 'termcolor'], ) From 91038e1692372f2776e8cf61cd9a857a4db91d6e Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 15:24:23 +0100 Subject: [PATCH 14/31] Double import --- procServUtils/manage.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 0938df7..64478b5 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -5,7 +5,7 @@ import sys, os, errno import subprocess as SP -from .conf import getconf, getrundir, getgendir, ConfigParser, addconf, delconf +from .conf import getconf, getrundir, getgendir, ConfigParser, addconf, getconffiles try: import shlex @@ -185,8 +185,7 @@ def addproc(conf, args): def delproc(conf, args): check_req(conf, args) - - from .conf import getconffiles, ConfigParser + for cfile in getconffiles(user=args.user): _log.debug('delproc processing %s', cfile) From ece589e3f1f88f0f8214c12f3bcba9756b0d3547 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 16:42:00 +0100 Subject: [PATCH 15/31] Adding procServUtils docs --- procServUtils/README.md | 98 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 procServUtils/README.md diff --git a/procServUtils/README.md b/procServUtils/README.md new file mode 100644 index 0000000..221580d --- /dev/null +++ b/procServUtils/README.md @@ -0,0 +1,98 @@ +# procServUtils + +`manage-procs` is a script to run procServ instances as systemd services. +It allows to completely manage the service with its command line interface. +See below for the available commands. + +## Installation + +Python prerequisites: +``` +sudo pip install tabulate termcolor argcomplete +``` +Activate global arcomplete completion: +``` +sudo activate-global-python-argcomplete +``` +Then proceed to install procServ with the `--with-systemd-utils` configuration +option. + +## Using manage-procs + +See `manage-procs --help` for all the commands. + +### User or system services + +All the `manage-procs` support one option to specify the destination of the service: + +- `manage-procs --system` will manage system-wide services. This is the default options +when running as root. +- `manage-procs --user` will manage user-level services. It is the equivalent +of `systemctl --user`. This is the default when running as a non-privileged user. + +**NOTE:** Not all linux distributions support user level systemd (eg: Centos 7). In those cases you should always use `--system`. + +### Add a service + +Let's add a service: +``` +manage-procs add service_name some_command [command_args...] +``` +This will install a new service called `service_name` which will run the specified command +with its args. + +With the optional arguments one can specify the working directory, the user +running the process and also add some environment variables. For example: +``` +manage-procs add -C /path/to/some_folder -U user_name -G user_group -e "FOO=foo" -e "BAR=bar" service_name some_command [command_args...] +``` +Alternatively one can write an environment file like: +``` +FOO=foo +BAR=bar +``` +And run: +``` +manage-procs add -C /path/to/some_folder -U user_name -G user_group -E /path/to/env_file service_name some_command [command_args...] +``` +See `manage-procs add -h` for all the options. + +### List services +``` +manage-procs status +``` +will list all the services installed with `manage-procs add` and their status. +``` +manage-procs list +``` +will show the underlying systemd services. + +### Start, stop, restart service exection +``` +manage-procs start service_name +manage-procs stop service_name +manage-procs restart service_name +``` + +### Remove or rename a service +To uninstall a service: +``` +manage-procs remove service_name +``` +To rename a service: +``` +manage-procs rename service_name +``` + +### Attach to a service +`procServ` enables the user to see the output of the inner command and, eventually, interact with it through a telent port or a domain socket. +``` +manage-procs attach service_name +``` +This will automatically open the right port for the desired service. + +### Open service log files +All the output of the service is saved to the systemd log files. To open them run: +``` +manage-procs logs [--follow] service_name +``` From 32f904a7f14ddc988eca0089341b9e420e5f4c4f Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 16:46:14 +0100 Subject: [PATCH 16/31] Link new readmi --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db79caf..f8daee0 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ start and stop configured procServ instances, generate lists of the instances known on the current host and report their status. -For more details, check the manpage and use the script's `-h` option. +For more details, see its [README](procServUtils/README.md) or check the manpage and use the script's `-h` option. For older systems using SysV-style rc scripts, you can look at the [Debian packaging](http://epics.nsls2.bnl.gov/debian/) or From 35665219fdfbd2b023e3fa5302598f5b34b5b9a1 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 16:52:52 +0100 Subject: [PATCH 17/31] Typos --- procServUtils/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/procServUtils/README.md b/procServUtils/README.md index 221580d..eb6460e 100644 --- a/procServUtils/README.md +++ b/procServUtils/README.md @@ -23,7 +23,7 @@ See `manage-procs --help` for all the commands. ### User or system services -All the `manage-procs` support one option to specify the destination of the service: +All the `manage-procs` commands support one option to specify the destination of the service: - `manage-procs --system` will manage system-wide services. This is the default options when running as root. @@ -94,5 +94,5 @@ This will automatically open the right port for the desired service. ### Open service log files All the output of the service is saved to the systemd log files. To open them run: ``` -manage-procs logs [--follow] service_name +manage-procs logs [--follow] service_name ``` From b22c3ca211e2ab36eb2277dc79a0513f2c6139c2 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 18:24:12 +0100 Subject: [PATCH 18/31] Fix code review --- procServUtils/README.md | 31 ++++++++++++++++--------------- procServUtils/manage.py | 28 +++++++++++++--------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/procServUtils/README.md b/procServUtils/README.md index eb6460e..c1aada1 100644 --- a/procServUtils/README.md +++ b/procServUtils/README.md @@ -7,11 +7,11 @@ See below for the available commands. ## Installation Python prerequisites: -``` +```bash sudo pip install tabulate termcolor argcomplete ``` Activate global arcomplete completion: -``` +```bash sudo activate-global-python-argcomplete ``` Then proceed to install procServ with the `--with-systemd-utils` configuration @@ -25,9 +25,10 @@ See `manage-procs --help` for all the commands. All the `manage-procs` commands support one option to specify the destination of the service: -- `manage-procs --system` will manage system-wide services. This is the default options +- `manage-procs --system` will manage system-wide services. This is the default options when running as root. -- `manage-procs --user` will manage user-level services. It is the equivalent + +- `manage-procs --user` will manage user-level services. It is the equivalent of `systemctl --user`. This is the default when running as a non-privileged user. **NOTE:** Not all linux distributions support user level systemd (eg: Centos 7). In those cases you should always use `--system`. @@ -35,7 +36,7 @@ of `systemctl --user`. This is the default when running as a non-privileged user ### Add a service Let's add a service: -``` +```bash manage-procs add service_name some_command [command_args...] ``` This will install a new service called `service_name` which will run the specified command @@ -43,32 +44,32 @@ with its args. With the optional arguments one can specify the working directory, the user running the process and also add some environment variables. For example: -``` +```bash manage-procs add -C /path/to/some_folder -U user_name -G user_group -e "FOO=foo" -e "BAR=bar" service_name some_command [command_args...] ``` Alternatively one can write an environment file like: -``` +```bash FOO=foo BAR=bar ``` And run: -``` +```bash manage-procs add -C /path/to/some_folder -U user_name -G user_group -E /path/to/env_file service_name some_command [command_args...] ``` See `manage-procs add -h` for all the options. ### List services -``` +```bash manage-procs status ``` will list all the services installed with `manage-procs add` and their status. -``` +```bash manage-procs list ``` will show the underlying systemd services. ### Start, stop, restart service exection -``` +```bash manage-procs start service_name manage-procs stop service_name manage-procs restart service_name @@ -76,23 +77,23 @@ manage-procs restart service_name ### Remove or rename a service To uninstall a service: -``` +```bash manage-procs remove service_name ``` To rename a service: -``` +```bash manage-procs rename service_name ``` ### Attach to a service `procServ` enables the user to see the output of the inner command and, eventually, interact with it through a telent port or a domain socket. -``` +```bash manage-procs attach service_name ``` This will automatically open the right port for the desired service. ### Open service log files All the output of the service is saved to the systemd log files. To open them run: -``` +```bash manage-procs logs [--follow] service_name ``` diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 64478b5..7091f1c 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -82,7 +82,7 @@ def status(conf, args, fp=None): table.append(instance) # Print results table - headers = ['PROCESS', 'STATE', 'PORT'] + headers = ['PROCESS', 'STATUS', 'PORT'] fp.write(tabulate(sorted(table), headers=headers, tablefmt="github")+ '\n') def syslist(conf, args): @@ -116,15 +116,13 @@ def restartproc(conf, args): def showlogs(conf, args): check_req(conf, args) _log.info("Opening logs of service procserv-%s.service", args.name) - command = [journalctl, - '--user-unit' if args.user else '--unit', - 'procserv-%s.service'%args.name] - if args.follow: - command.append('-f') try: - SP.call(command) + SP.call([journalctl, + '--user-unit' if args.user else '--unit', + 'procserv-%s.service'%args.name] + + (['-f'] if args.follow else [])) except KeyboardInterrupt: - pass + pass def attachproc(conf, args): check_req(conf, args) @@ -155,19 +153,19 @@ def addproc(conf, args): if args.username: new_conf.set(conf_name, "user", args.username) if args.group: new_conf.set(conf_name, "group", args.group) if args.port: new_conf.set(conf_name, "port", args.port) - if args.environment: + if args.environment: new_conf.set(conf_name, "environment", ' '.join("\"%s\""%e for e in args.environment)) if args.env_file: new_conf.set(conf_name, "env_file", args.env_file) # write conf file addconf(conf_name, new_conf, args.user, args.force) - # generate service files + # generate service files outdir = getgendir(args.user) run(outdir, user=args.user) # register systemd service - argusersys = '--user' if args.user else '--system' + argusersys = '--user' if args.user else '--system' SP.check_call([systemctl, argusersys, 'enable', @@ -185,7 +183,7 @@ def addproc(conf, args): def delproc(conf, args): check_req(conf, args) - + for cfile in getconffiles(user=args.user): _log.debug('delproc processing %s', cfile) @@ -233,7 +231,7 @@ def delproc(conf, args): SP.call([systemctl, '--user' if args.user else '--system', '--quiet', - 'reset-failed', + 'reset-failed', 'procserv-%s.service'%args.name]) _log.info('Triggering systemd reload') @@ -267,8 +265,8 @@ def renameproc(conf, args): # delete previous proc args.force = True delproc(conf, args) - - # generate service files + + # generate service files outdir = getgendir(args.user) run(outdir, user=args.user) From ea360cf3c8d9e2dc81ff3b92d3264c1cdf1b482e Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 18:35:26 +0100 Subject: [PATCH 19/31] Fix travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b6ff8e6..bd6eab1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,10 +19,10 @@ jobs: - os: linux language: python python: 2.7 - install: pip install nose + install: pip install nose argcomplete termcolor tabulate script: python -m nose procServUtils - os: linux language: python python: 3.6 - install: pip install nose + install: pip install nose argcomplete termcolor tabulate script: python -m nose procServUtils From cb602e7155939095c7c7bb51c286668ce81c2368 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 18:50:48 +0100 Subject: [PATCH 20/31] Slightly different conf file spacing --- procServUtils/test/test_manage.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/procServUtils/test/test_manage.py b/procServUtils/test/test_manage.py index 0ce9539..2d889c3 100644 --- a/procServUtils/test/test_manage.py +++ b/procServUtils/test/test_manage.py @@ -19,10 +19,11 @@ def test_add(self): with open(confname, 'r') as F: content = F.read() - self.assertEqual(content, """ -[instname] + self.assertEqual(content, +"""[instname] command = /bin/sh -c blah chdir = /somedir + """) main(getargs(['add', @@ -37,34 +38,37 @@ def test_add(self): with open(confname, 'r') as F: content = F.read() - self.assertEqual(content, """ -[other] + self.assertEqual(content, +"""[other] command = /bin/sh -c blah chdir = /somedir user = someone group = controls + """) def test_remove(self): with TestDir() as t: # we won't remove this config, so it should not be touched with open(t.dir+'/procServ.d/other.conf', 'w') as F: - F.write(""" -[other] + F.write( +"""[other] command = /bin/sh -c blah chdir = /somedir user = someone group = controls + """) confname = t.dir+'/procServ.d/blah.conf' with open(confname, 'w') as F: - F.write(""" -[blah] + F.write( +"""[blah] command = /bin/sh -c blah chdir = /somedir user = someone group = controls + """) main(getargs(['remove', '-f', 'blah']), test=True) @@ -74,8 +78,8 @@ def test_remove(self): confname = t.dir+'/procServ.d/blah.conf' with open(confname, 'w') as F: - F.write(""" -[blah] + F.write( +"""[blah] command = /bin/sh -c blah chdir = /somedir user = someone From 3f4bb3770869c45ad348e2206d3520a81fbede9d Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Thu, 19 Mar 2020 18:57:51 +0100 Subject: [PATCH 21/31] Whitespaces --- procServUtils/manage.py | 4 ++-- procServUtils/test/test_manage.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 7091f1c..44f3916 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -38,7 +38,7 @@ def status(conf, args, fp=None): if not conf.getboolean(name, 'instance'): continue instance = ['%s '%name] - + pid = None ports = [] infoname = os.path.join(rundir, 'procserv-%s'%name, 'info') @@ -80,7 +80,7 @@ def status(conf, args, fp=None): instance.append(colored('Stopped', 'red')) table.append(instance) - + # Print results table headers = ['PROCESS', 'STATUS', 'PORT'] fp.write(tabulate(sorted(table), headers=headers, tablefmt="github")+ '\n') diff --git a/procServUtils/test/test_manage.py b/procServUtils/test/test_manage.py index 2d889c3..bfee265 100644 --- a/procServUtils/test/test_manage.py +++ b/procServUtils/test/test_manage.py @@ -38,7 +38,7 @@ def test_add(self): with open(confname, 'r') as F: content = F.read() - self.assertEqual(content, + self.assertEqual(content, """[other] command = /bin/sh -c blah chdir = /somedir From 78b76b3cc5242d03ad14b7ee173410d590dd7ca4 Mon Sep 17 00:00:00 2001 From: Davide Marcato <26935676+darcato@users.noreply.github.com> Date: Fri, 27 Mar 2020 14:36:42 +0100 Subject: [PATCH 22/31] Fix manage-procs rename docs --- procServUtils/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procServUtils/README.md b/procServUtils/README.md index c1aada1..27107f6 100644 --- a/procServUtils/README.md +++ b/procServUtils/README.md @@ -82,7 +82,7 @@ manage-procs remove service_name ``` To rename a service: ```bash -manage-procs rename service_name +manage-procs rename service_name new_service_name ``` ### Attach to a service From d44c6013135a23083938d6f4ca79bd8f0ce93b1d Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Fri, 6 Nov 2020 14:46:32 +0100 Subject: [PATCH 23/31] Conditional usage of python packages termcolor, tabulate and argcomplete --- procServUtils/fallbacks.py | 19 +++++++++++++++++++ procServUtils/manage.py | 20 ++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 procServUtils/fallbacks.py diff --git a/procServUtils/fallbacks.py b/procServUtils/fallbacks.py new file mode 100644 index 0000000..0e71ca1 --- /dev/null +++ b/procServUtils/fallbacks.py @@ -0,0 +1,19 @@ +""" +Fallback functions when termcolor or tabulate packes are not available +""" + + +def colored(s, *args, **kwargs): + return s + + +def tabulate(table, headers, **kwargs): + s = "" + for header in headers: + s += "%s " % header.strip() + s += "\n" + for line in table: + for elem in line: + s += "%s " % elem.strip() + s += "\n" + return s[:-1] \ No newline at end of file diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 44f3916..1e951f1 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -27,9 +27,16 @@ def check_req(conf, args): sys.exit(1) def status(conf, args, fp=None): - from tabulate import tabulate - from termcolor import colored + try: + from tabulate import tabulate + except ImportError: + from .fallbacks import tabulate + try: + from termcolor import colored + except ImportError: + from .fallbacks import colored + rundir=getrundir(user=args.user) fp = fp or sys.stdout @@ -323,7 +330,7 @@ def instances_completer(**kwargs): def getargs(args=None): from argparse import ArgumentParser, REMAINDER - from argcomplete import autocomplete + P = ArgumentParser() P.add_argument('--user', action='store_true', default=os.geteuid()!=0, help='Consider user config') @@ -395,7 +402,12 @@ def getargs(args=None): S.add_argument('extra', nargs=REMAINDER, help='extra args for telnet') S.set_defaults(func=attachproc) - autocomplete(P) + try: + from argcomplete import autocomplete + autocomplete(P) + except ImportError: + pass + A = P.parse_args(args=args) if not hasattr(A, 'func'): P.print_help() From 5bb72a566cbb8c8cabd313b5c119ad8beb0cba9d Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Mon, 9 Nov 2020 11:58:28 +0100 Subject: [PATCH 24/31] Fix systemctl call order --- procServUtils/manage.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 1e951f1..0da5454 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -173,15 +173,15 @@ def addproc(conf, args): # register systemd service argusersys = '--user' if args.user else '--system' - SP.check_call([systemctl, - argusersys, - 'enable', - "%s/procserv-%s.service"%(outdir, conf_name)]) - _log.info('Trigger systemd reload') SP.check_call([systemctl, argusersys, 'daemon-reload'], shell=False) + + SP.check_call([systemctl, + argusersys, + 'enable', + "%s/procserv-%s.service"%(outdir, conf_name)]) if args.autostart: startproc(conf, args) @@ -237,9 +237,8 @@ def delproc(conf, args): _log.info("Resetting service procserv-%s.service", args.name) SP.call([systemctl, '--user' if args.user else '--system', - '--quiet', 'reset-failed', - 'procserv-%s.service'%args.name]) + 'procserv-%s.service'%args.name], stderr=SP.DEVNULL) _log.info('Triggering systemd reload') SP.check_call([systemctl, @@ -279,15 +278,15 @@ def renameproc(conf, args): # register systemd service argusersys = '--user' if args.user else '--system' - SP.check_call([systemctl, - argusersys, - 'enable', - "%s/procserv-%s.service"%(outdir, args.new_name)]) - _log.info('Trigger systemd reload') SP.check_call([systemctl, argusersys, 'daemon-reload'], shell=False) + + SP.check_call([systemctl, + argusersys, + 'enable', + "%s/procserv-%s.service"%(outdir, args.new_name)]) if args.autostart: args.name = args.new_name From 433540117edbcd85bdb4cd3f5fc5f5024788485e Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Mon, 9 Nov 2020 13:04:27 +0100 Subject: [PATCH 25/31] Revert check call on systemctl disable --- procServUtils/manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 0da5454..603101a 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -229,7 +229,7 @@ def delproc(conf, args): stopproc(conf, args) _log.info("Disabling service procserv-%s.service", args.name) - SP.call([systemctl, + SP.check_call([systemctl, '--user' if args.user else '--system', 'disable', "procserv-%s.service"%args.name]) From ae2c6d91e5df41428950856289c3599309ecb4ee Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Mon, 9 Nov 2020 13:08:22 +0100 Subject: [PATCH 26/31] Updating procServUtils doc --- procServUtils/README.md | 64 +++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/procServUtils/README.md b/procServUtils/README.md index 27107f6..d75033f 100644 --- a/procServUtils/README.md +++ b/procServUtils/README.md @@ -4,18 +4,31 @@ It allows to completely manage the service with its command line interface. See below for the available commands. -## Installation +## Installation from source Python prerequisites: + ```bash sudo pip install tabulate termcolor argcomplete ``` -Activate global arcomplete completion: + +Then proceed to build and install procServ with the `--with-systemd-utils` configuration option. For example: + +```bash +cd procserv +make +./configure --disable-doc --with-systemd-utils +make +sudo make install +``` + +**[OPTIONAL]** If you want to activate bash autocompletion run the following command: + ```bash -sudo activate-global-python-argcomplete +sudo activate-global-python-argcomplete ``` -Then proceed to install procServ with the `--with-systemd-utils` configuration -option. + +This will activate global argcomplete completion. See [argcomplete documentation](https://pypi.org/project/argcomplete/#activating-global-completion) for more details. ## Using manage-procs @@ -25,50 +38,68 @@ See `manage-procs --help` for all the commands. All the `manage-procs` commands support one option to specify the destination of the service: -- `manage-procs --system` will manage system-wide services. This is the default options -when running as root. +- `manage-procs --system` will manage system-wide services. This is the default options when running as root. -- `manage-procs --user` will manage user-level services. It is the equivalent -of `systemctl --user`. This is the default when running as a non-privileged user. +- `manage-procs --user` will manage user-level services. It is the equivalent + of `systemctl --user`. This is the default when running as a non-privileged user. **NOTE:** Not all linux distributions support user level systemd (eg: Centos 7). In those cases you should always use `--system`. ### Add a service Let's add a service: + ```bash manage-procs add service_name some_command [command_args...] ``` + This will install a new service called `service_name` which will run the specified command with its args. With the optional arguments one can specify the working directory, the user running the process and also add some environment variables. For example: + ```bash -manage-procs add -C /path/to/some_folder -U user_name -G user_group -e "FOO=foo" -e "BAR=bar" service_name some_command [command_args...] +manage-procs add -C /path/to/some_folder \ + -U user_name -G user_group \ + -e "FOO=foo" -e "BAR=bar" \ + service_name some_command [command_args...] ``` + Alternatively one can write an environment file like: + ```bash FOO=foo BAR=bar ``` + And run: + ```bash -manage-procs add -C /path/to/some_folder -U user_name -G user_group -E /path/to/env_file service_name some_command [command_args...] +manage-procs add -C /path/to/some_folder \ + -U user_name -G user_group \ + -E /path/to/env_file \ + service_name some_command [command_args...] ``` + See `manage-procs add -h` for all the options. ### List services + ```bash manage-procs status ``` + will list all the services installed with `manage-procs add` and their status. + ```bash manage-procs list ``` + will show the underlying systemd services. ### Start, stop, restart service exection + ```bash manage-procs start service_name manage-procs stop service_name @@ -76,24 +107,33 @@ manage-procs restart service_name ``` ### Remove or rename a service + To uninstall a service: + ```bash manage-procs remove service_name ``` + To rename a service: + ```bash manage-procs rename service_name new_service_name ``` ### Attach to a service -`procServ` enables the user to see the output of the inner command and, eventually, interact with it through a telent port or a domain socket. + +`procServ` enables the user to see the output of the inner command and, eventually, interact with it through a telent port or a domain socket. + ```bash manage-procs attach service_name ``` + This will automatically open the right port for the desired service. ### Open service log files + All the output of the service is saved to the systemd log files. To open them run: + ```bash manage-procs logs [--follow] service_name ``` From b3c6f6819cf61805eed5f5615bc1c6a53c5d7282 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Mon, 9 Nov 2020 13:23:56 +0100 Subject: [PATCH 27/31] Whitespaces --- procServUtils/manage.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 603101a..b208c73 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -31,7 +31,7 @@ def status(conf, args, fp=None): from tabulate import tabulate except ImportError: from .fallbacks import tabulate - + try: from termcolor import colored except ImportError: @@ -85,7 +85,7 @@ def status(conf, args, fp=None): instance.append(' '.join(ports)) else: instance.append(colored('Stopped', 'red')) - + table.append(instance) # Print results table @@ -177,7 +177,7 @@ def addproc(conf, args): SP.check_call([systemctl, argusersys, 'daemon-reload'], shell=False) - + SP.check_call([systemctl, argusersys, 'enable', @@ -282,7 +282,7 @@ def renameproc(conf, args): SP.check_call([systemctl, argusersys, 'daemon-reload'], shell=False) - + SP.check_call([systemctl, argusersys, 'enable', @@ -329,7 +329,7 @@ def instances_completer(**kwargs): def getargs(args=None): from argparse import ArgumentParser, REMAINDER - + P = ArgumentParser() P.add_argument('--user', action='store_true', default=os.geteuid()!=0, help='Consider user config') @@ -375,7 +375,7 @@ def getargs(args=None): S.set_defaults(func=renameproc) S = SP.add_parser('write-procs-cf', help='Write conserver config') - S.add_argument('-f','--out',default='/etc/conserver/procs.cf') + S.add_argument('-f','--out',default='/etc/conserver/procs.cf') S.add_argument('-R','--reload', action='store_true', default=False) S.set_defaults(func=writeprocs) From 65153f23f76729b61024425614919308a65eeb23 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Mon, 9 Nov 2020 13:35:16 +0100 Subject: [PATCH 28/31] Fix devnull for python2 --- procServUtils/manage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index b208c73..2ab953b 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -235,10 +235,11 @@ def delproc(conf, args): "procserv-%s.service"%args.name]) _log.info("Resetting service procserv-%s.service", args.name) + devnull = open(os.devnull, 'w') SP.call([systemctl, '--user' if args.user else '--system', 'reset-failed', - 'procserv-%s.service'%args.name], stderr=SP.DEVNULL) + 'procserv-%s.service'%args.name], stderr=devnull) _log.info('Triggering systemd reload') SP.check_call([systemctl, From 15f3dba034e92e514d3009f6f34eca2979d0a488 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Mon, 9 Nov 2020 15:31:20 +0100 Subject: [PATCH 29/31] Add test for rename command --- procServUtils/test/test_manage.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/procServUtils/test/test_manage.py b/procServUtils/test/test_manage.py index bfee265..cccf986 100644 --- a/procServUtils/test/test_manage.py +++ b/procServUtils/test/test_manage.py @@ -93,3 +93,26 @@ def test_remove(self): self.assertTrue(os.path.isfile(confname)) self.assertTrue(os.path.isfile(t.dir+'/procServ.d/other.conf')) + + def test_rename(self): + with TestDir() as t: + main(getargs(['add', '-C', '/somedir', '-U', 'foo', '-G', 'bar', \ + 'firstname', '--', '/bin/sh', '-c', 'blah']), test=True) + main(getargs(['rename', 'firstname', 'secondname']), test=True) + + confname = t.dir+'/procServ.d/secondname.conf' + + self.assertTrue(os.path.isfile(confname)) + with open(confname, 'r') as F: + content = F.read() + + self.assertEqual(content, +"""[secondname] +user = foo +group = bar +chdir = /somedir +port = 0 +instance = 1 +command = /bin/sh -c blah + +""") From 182fd78edfe360f3515478519ca499b656079283 Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Mon, 9 Nov 2020 16:19:40 +0100 Subject: [PATCH 30/31] Ask before stopping service to rename --- procServUtils/README.md | 2 ++ procServUtils/manage.py | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/procServUtils/README.md b/procServUtils/README.md index d75033f..47ebc14 100644 --- a/procServUtils/README.md +++ b/procServUtils/README.md @@ -120,6 +120,8 @@ To rename a service: manage-procs rename service_name new_service_name ``` +Note that this command will stop the service if it's running. + ### Attach to a service `procServ` enables the user to see the output of the inner command and, eventually, interact with it through a telent port or a domain socket. diff --git a/procServUtils/manage.py b/procServUtils/manage.py index 2ab953b..a57d1b4 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -257,6 +257,19 @@ def delproc(conf, args): def renameproc(conf, args): check_req(conf, args) + + if not args.force and sys.stdin.isatty(): + while True: + sys.stdout.write("This will stop the service '%s' if it's running. Continue? [yN] "%(args.name)) + sys.stdout.flush() + L = sys.stdin.readline().strip().upper() + if L=='Y': + break + elif L in ('N',''): + sys.exit(1) + else: + sys.stdout.write('\n') + from .generator import run # copy settings from previous conf @@ -367,7 +380,7 @@ def getargs(args=None): S.add_argument('name', help='Instance name').completer = instances_completer S.set_defaults(func=delproc) - S = SP.add_parser('rename', help='Rename a procServ instance') + S = SP.add_parser('rename', help='Rename a procServ instance. The instance will be stopped.') S.add_argument('-f','--force', action='store_true', default=False) S.add_argument('-A','--autostart',action='store_true', default=False, help='Automatically start after renaming') From bf8bd0a103c5630065cf36d908732534f912694f Mon Sep 17 00:00:00 2001 From: Davide Marcato Date: Mon, 9 Nov 2020 16:40:37 +0100 Subject: [PATCH 31/31] Fix test errors --- procServUtils/manage.py | 4 ++-- procServUtils/test/test_manage.py | 25 ++++++++++++------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/procServUtils/manage.py b/procServUtils/manage.py index a57d1b4..0e91892 100644 --- a/procServUtils/manage.py +++ b/procServUtils/manage.py @@ -235,8 +235,8 @@ def delproc(conf, args): "procserv-%s.service"%args.name]) _log.info("Resetting service procserv-%s.service", args.name) - devnull = open(os.devnull, 'w') - SP.call([systemctl, + with open(os.devnull, 'w') as devnull: + SP.call([systemctl, '--user' if args.user else '--system', 'reset-failed', 'procserv-%s.service'%args.name], stderr=devnull) diff --git a/procServUtils/test/test_manage.py b/procServUtils/test/test_manage.py index cccf986..49515c2 100644 --- a/procServUtils/test/test_manage.py +++ b/procServUtils/test/test_manage.py @@ -98,21 +98,20 @@ def test_rename(self): with TestDir() as t: main(getargs(['add', '-C', '/somedir', '-U', 'foo', '-G', 'bar', \ 'firstname', '--', '/bin/sh', '-c', 'blah']), test=True) - main(getargs(['rename', 'firstname', 'secondname']), test=True) + main(getargs(['rename', '-f', 'firstname', 'secondname']), test=True) confname = t.dir+'/procServ.d/secondname.conf' self.assertTrue(os.path.isfile(confname)) with open(confname, 'r') as F: - content = F.read() - - self.assertEqual(content, -"""[secondname] -user = foo -group = bar -chdir = /somedir -port = 0 -instance = 1 -command = /bin/sh -c blah - -""") + content = F.readlines() + + self.assertIn("[secondname]\n", content) + self.assertIn("user = foo\n", content) + self.assertIn("group = bar\n", content) + self.assertIn("chdir = /somedir\n", content) + self.assertIn("port = 0\n", content) + self.assertIn("instance = 1\n", content) + self.assertIn("command = /bin/sh -c blah\n", content) + self.assertIn("\n", content) + self.assertEqual(len(content), 8)