def main(args): import_data = yaml.safe_load(args.input) groups = {k['group']['name']:k['group'] for k in import_data if 'group' in k} programs = {k['program']['name']:k['program'] for k in import_data if 'program' in k} for group in groups.values(): group_dir = path.join(config.dirs.user_data_dir, 'groups') if not path.isdir(group_dir): os.makedirs(group_dir) group_path = path.join(group_dir, '%s.yaml' % group['name']) log.info("Writing group %s to %s" % (group['name'], group_path)) with open(group_path, 'w') as gf: yaml.safe_dump(group, gf, default_flow_style=False) for defn in programs.values(): if 'name' not in defn: raise errors.ChalmersError("Import definition requires a name field") prog = Program(defn['name']) if prog.exists(): log.warn("Program '%s' already exists, not importing" % defn['name']) continue prog.raw_data.update(defn) prog.mk_data()
def main(args): config.set_relative_dirs(path.abspath('.chalmers')) if not os.path.isfile(args.procfile): raise errors.ChalmersError("procfile '{}' does not exist".format( args.procfile)) with open(args.procfile) as fd: procs = yaml.load(fd) print('procs', procs) programs = [] for name, command in procs.items(): definition = { 'name': name, 'command': split(command), } program = Program(name) pprint(definition) program.raw_data.update(definition) programs.append(program) pool = MultiPlexIOPool(stream=True, use_color=args.color) for prog in programs: pool.append(prog) pool.join()
def add(cls, name, command, paused=False, cwd=None, stdout=None, stderr=None, daemon_log=None, redirect_stderr=None, env=None): """ Add a new program to run, This will not start the program, to start it run prog.start() """ program = cls(name) if program.exists(): raise errors.ChalmersError( "Program with name '{name}' already exists. \n" "Use the -n/--name option to change the name or \n" "Run 'chalmers remove {name}' to remove it \n" "or 'chalmers set' to update the parameters".format(name=name)) state = {'paused': paused} definition = create_definition(name, command) program.raw_data.update(definition) program.state.update(state) # Updated the data attribute from the raw data program.mk_data() return program
def __init__(self, target_user): if target_user is not False: # raise errors.ChalmersError( "You can not install a local service into another users account. " "To do this use the 'runas' windows command with chalmers") self.target_user = target_user
def get_crontab(): try: output = sp.check_output(['crontab', '-l']).strip() except sp.CalledProcessError as err: if err.returncode != 1: raise errors.ChalmersError("Could not read crontab") return [] return output.split('\n')
def check_output(self, command): if self.target_user: if os.getuid() != 0: raise errors.ChalmersError("Can not perform system install without root") log.info("Running command: %s" % ' '.join(command)) try: output = sp.check_output(command, stderr=sp.STDOUT) except OSError as err: raise errors.ChalmersError("Could not access program 'launchctl' required for osx service install") except sp.CalledProcessError as err: if err.returncode == 1: if 'Socket is not connected' in err.output: log.error(err.output) raise errors.ChalmersError("The user '%s' must be logged in via the osx gui to perform this operation" % self.target_user) raise return output
def remove(self): """ Remove this program definition """ if self.is_running: raise errors.ChalmersError( "Can not remove running program (must be stopped)") self.state.delete() self.raw_data.delete()
def handle_signals(self): # Called before keep_alive new_mask = self.data.get('umask') if new_mask: log.warning("Config var 'umask' will be ignored on win32") user = self.data.get('user') if user: raise errors.ChalmersError( "Can not yet run as program as a user on win32")
def __init__(self, name, load=True, force=False): self._name = name EventDispatcher.__init__(self) self.finished_event = Event() defn_filename = path.join(config.dirs.user_data_dir, 'programs', '%s.yaml' % self.name) state_filename = path.join(config.dirs.user_data_dir, 'state', '%s.yaml' % self.name) try: self.state = PersistentDict(state_filename) except yaml.error.YAMLError: log.error("Yaml parser error. could not parse state file %s" % state_filename) if force: log.warn("Removing state file and continuing") os.unlink(state_filename) self.state = PersistentDict(state_filename) else: msg = "Invalid state file. run `chalmers stop --force` to clear the state file" raise errors.ChalmersError(msg) try: self.raw_data = PersistentDict(defn_filename) except yaml.error.YAMLError: log.error("Yaml parser error. could not parse definition file %s" % defn_filename) if force: self.raw_data = PersistentDict(defn_filename, load=False) else: msg = "Invalid definition file. Run `chalmers edit %s` to fix the definition file" raise errors.ChalmersError(msg % (defn_filename)) self.data = {} self.mk_data() self._p0 = None self.pipe_output = False
def main(args): service = LocalService(False) if args.action == 'status': service.status() elif args.action == 'enable': service.install() elif args.action == 'disable': service.uninstall() else: raise errors.ChalmersError("Invalid action %s" % args.action)
def install(self): if not self.is_admin: raise errors.ChalmersError( "System services requires admin privleges. " "run this command as an administrator") log.info( "Your password is required by the windows service manager to launch " "the chalmers service at startup") password = getpass.getpass("Password for {}: ".format( self.target_user)) instart('.\\{}'.format(self.target_user), password)
def __init__(self, target_user): if target_user is not False: msg = ("Not implemented: chalmers can not detect " "the init system for your unix machine " "(upstart, systemd or sysv)") raise errors.ChalmersError(msg) self.target_user = target_user log = logging.getLogger('chalmers.cron_service') log.info('Platform: %s' % platform.linux_distribution()[0] or 'Unknown') log.info('Using posix crond @reboot command') log.info('Chalmers service for current user (does not require root)')
def main(args): if os.name == 'nt': from win32com.shell import shell if not shell.IsUserAnAdmin(): raise errors.ChalmersError( 'You must be an administrator to run this command') else: if os.getuid() != 0: raise errors.ChalmersError('You must be root to run this command') service = SystemService(args.target_user) if args.action == 'status': service.status() elif args.action == 'enable': service.install() elif args.action == 'disable': service.uninstall() else: raise errors.ChalmersError("Invalid action %s" % args.action)
def main(args): EDITOR = os.environ.get('EDITOR', None) if EDITOR is None: raise errors.ChalmersError( "Environment variable 'EDITOR' needs to be set") prog = Program(args.name, force=True) if prog and not prog.exists(): raise errors.ProgramNotFound("program '{}' not found".format( args.name)) cmd = '%s %s' % (EDITOR, pipes.quote(prog.raw_data.filename)) print(cmd) if subprocess.call(cmd, shell=True): raise errors.ChalmersError('Command "%s" exited with non zero status' % cmd) if prog.is_running: log.info("Changes to program %s will take effect on the next restart" % prog.name)
def main(args): if args.cmd and args.command: raise errors.ChalmersError('Unknow arguments %r' % args.command) elif not (args.cmd or args.command): raise errors.ChalmersError('Must specify a command to add') if args.cmd: args.command = args.cmd if not args.name: args.name = args.command[0] env = {} for env_var in args.save_env: if env_var in os.environ: env[env_var] = os.environ[env_var] else: log.warn( "Environment variable %s does not exist (from -e/--save-env)" % env_var) program = Program.add(args.name, args.command, paused=args.paused, cwd=args.cwd, stdout=args.stdout, stderr=args.stderr, daemon_log=args.daemon_log, redirect_stderr=args.redirect_stderr, env=env) log.info('Added program {args.name}'.format(args=args)) if args.run_now: log.info('Running program {args.name}'.format(args=args)) program.start(daemon=not args.wait)
def listener(self): "Return the multiprocessing Listener object" if self._listener is None: if self.FAMILY == 'AF_UNIX' and os.path.exists(self.addr): os.unlink(self.addr) try: log.debug("Listening to events from: %s" % self.addr) self._listener = Listener(self.addr, family=self.FAMILY) except socket.error as err: if err.errno == 48: msg = "Unix socket '%s' appears to be in use. Please stop this program." raise errors.ChalmersError(msg % self.addr) else: raise return self._listener
def _mk_lockfile(self): 'TODO: not implemented' lockfile = self._filename + '.lock' try: if self.exists(): os.link(self._filename, lockfile) else: os.mkdir(lockfile) except OSError as err: if err.errno == 17: msg = ("The file '%s' is locked by another process.\n" "If this process is not running, " "you can manually remove the lockfile\n\trm '%s'" % (self._filename, lockfile)) raise errors.ChalmersError(msg) raise
def dispatch_terminate(self, timeout=None): 'Action for event listener' children = self._stop() if not self.finished_event.wait(timeout): if self._p0: log.info('Process did not stop within %s seconds' % (timeout)) log.info('Hard killing process %s' % (self._p0.pid)) kill_tree(self._p0.pid) if not self.finished_event.wait(timeout): raise errors.ChalmersError( "Timed out waiting for program %s to finish" % self.name) else: for child in children: if child.is_running(): child.kill()
def use_if_not_root(cls, subcls, target_user): if target_user is False: if py3: return object.__new__(cls) else: return object.__new__(cls, target_user) else: if os.getuid() != 0: raise errors.ChalmersError( "You can not install a posix service for " "user %s without root privileges. " "Run this command again with sudo") if py3: return object.__new__(subcls) else: return object.__new__(subcls, target_user)
def uninstall(self): if not self.is_admin: raise errors.ChalmersError( "System services requires admin privileges. " "run this command as an administrator") if is_running(self.target_user): log.info("Service is running, stopping service {}".format( self.service_name)) StopService(self.service_name) if is_installed(self.target_user): RemoveService(self.service_name) log.info("Uninstalled windows service '{}'".format( self.service_name)) else: log.error("Windows service '{}' is not installed".format( self.service_name))
def restart_main(args): programs = cli.select_programs(args, filter_paused=True) if not (args.all or args.names): raise errors.ChalmersError( "Must specify at least one program to restart") if len(programs): print("Restarting programs %s" % ', '.join([p.name for p in programs])) print("") else: log.warn("No programs to restart") return for prog in programs: sys.stdout.flush() if prog.is_running: print("Stop program %-25s ... " % (prog.name[:25]), end='') try: prog.stop() except errors.StateError: print_colors('[ {=ERROR!c:red} ]') print_colors('[ {=OK!c:green} ]') time.sleep(.5) for prog in programs: prog.start() for prog in programs: print("Checking status of program %-25s ... " % (prog.name[:25]), end='') sys.stdout.flush() err = prog.wait_for_start() if err: print_colors('[{=ERROR!c:red} ]') else: print_colors('[ {=OK!c:green} ]')
def add_launchd(self): if self.target_user: username = '******' % self.target_user else: username = '' plist = self.template.format(python_exe=python_exe, chalmers=chalmers_script, label=self.label, username=username) with tempfile.NamedTemporaryFile('w', suffix='.plist', prefix='chalmers') as fd: fd.write(plist) fd.flush() try: command = ['launchctl', 'load', fd.name] self.check_output(command).strip() except sp.CalledProcessError as err: if err.returncode == 1: raise errors.ChalmersError("Chalmers service is already installed") raise
def main(args): proc = Program(args.name) if not proc.exists(): raise errors.ProgramNotFound("program '{}' not found".format( args.name)) if proc.is_running: log.warning( "Program is running: Updates will not be reflected until a restart is done" ) with proc.raw_data.transaction(): for key, value in args.items: if key == 'name': raise errors.ChalmersError("Can not set program name") set_nested_key(proc.raw_data, key, value) print("Set '%s' to %r for program %s" % (key, value, args.name)) print("done")
def send_action(name, action, *args, **kwargs): """ Send an action to a listener the listener must have a 'dispatch_{action}' method or this will raise a ChalmersError """ addr = get_addr(name) try: c = Client(addr, family=EventDispatcher.FAMILY) except (socket.error, WindowsError): raise errors.ConnectionError( "Could not connect to chalmers program %s" % name) try: c.send({'action': action, 'args': args, 'kwargs': kwargs}) res = c.recv() if res.get('error'): raise errors.ChalmersError(res.get('message', 'Unknown error')) return res.get('result') finally: c.close()
def dispatch_bg(self): raise errors.ChalmersError( "Can not yet move a win32 process to the background")
def __init__(self, target_user=None): supported_dists = platform._supported_dists + system_dist linux = platform.linux_distribution(supported_dists=supported_dists) raise errors.ChalmersError( "Could not detect system service for platform %s (tried systemd, sysv init and upstart)" % linux[0])