# HG changeset patch # User Atul Varma # Date 1205884885 0 # Node ID f64af329930f9220ac9dbcbe78ba04f3a70a2f38 # Parent 6d1dc2d106f61fbd56179b40894b9ce47a3d4e94 Any user can now use ProcessManager to manage processes--root is no longer required. However, an error will be displayed if the user doesn't have privileges to manage a process because a user/group change is required. diff -r 6d1dc2d106f6 -r f64af329930f ProcessManager.py --- a/ProcessManager.py Tue Mar 18 23:08:58 2008 +0000 +++ b/ProcessManager.py Wed Mar 19 00:01:25 2008 +0000 @@ -51,10 +51,6 @@ # TODO's # # * Document the public methods better. -# -# * Don't require ProcessManager to be run as root, but do raise -# exceptions if the user tries to control a process that requires -# changing the user ID and it can't be done. # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- @@ -162,8 +158,8 @@ program, args, workingDir, - uid, - gid, + uid = None, + gid = None, stopSignal = None ): """ Creates a process with the given name/identifier, description, @@ -184,12 +180,46 @@ self.args.extend( args ) self.workingDir = workingDir self.stopSignal = stopSignal - - import grp - import pwd + + if gid and uid: + import grp + import pwd + + self.gid = grp.getgrnam( gid )[2] + self.uid = pwd.getpwnam( uid )[2] + elif gid or uid: + raise ValueError( + "For process '%s', either gid or uid must both be None, " + "or both must be set." % self.name + ) + else: + self.gid = None + self.uid = None - self.gid = grp.getgrnam( gid )[2] - self.uid = pwd.getpwnam( uid )[2] + def canCurrentUserManage( self ): + """ + Returns whether the current user has the ability to manage this + process. + """ + + if os.getuid() == 0: + # we're running as root, so all is good. + result = True + elif self.uid is None: + # We don't need to change the user to manage the + # process, so all is good. + result = True + elif self.uid == os.getuid() and self.gid == os.getgid(): + # uid and gid are specified, but they're the + # current user, so all is good. + result = True + else: + # uid and gid are specified, they're different from + # the current user, and we're not root, so this + # isn't good. + result = False + + return result def _pidfile( self ): """ @@ -249,7 +279,8 @@ print "Process '%s' is already running!" % self.name return else: - print "Hmm. Process '%s' seems to have died prematurely." % self.name + print ( "Hmm. Process '%s' seems to have " + "died prematurely." % self.name ) # Start the process now. leftColumnText = "Launching %s..." % self.name @@ -267,8 +298,10 @@ forkResult = os.fork() if forkResult == 0: # We're the child process. - os.setgid( self.gid ) - os.setuid( self.uid ) + if self.uid is not None: + assert self.gid is not None + os.setgid( self.gid ) + os.setuid( self.uid ) os.chdir( self.workingDir ) @@ -327,7 +360,8 @@ else: print "FAILED" elif warnCrashed: - print "Hmm. Process '%s' seems to have died prematurely." % self.name + print ( "Hmm. Process '%s' seems to have " + "died prematurely." % self.name ) os.remove( self._pidfile() ) else: print "Process '%s' is not running." % self.name @@ -389,6 +423,31 @@ pass +def _runCommandOnProcesses( command, processes ): + """ + Runs the given command on the given Process objects and + returns True if successful, False if an error occurred. + """ + + success = True + + if command != "status": + for process in processes: + if not process.canCurrentUserManage(): + print ( "The process '%s' cannot be managed " + "by the current user." % process.name ) + success = False + + if success: + for process in processes: + method = getattr( process, command ) + try: + method() + except ProcessStartupError: + success = False + + return success + def _runCommandOnTarget( command, target ): """ Runs the given command on the given target. @@ -399,33 +458,12 @@ print "Please use ProcessManager.init()." sys.exit( -1 ) - errorOccurred = False - if target == "all": - for process in _processes.values(): - method = getattr( process, command ) - try: - method() - except ProcessStartupError: - errorOccurred = True + processes = [ process for process in _processes.values() ] else: - method = getattr( _processes[target], command ) - try: - method() - except ProcessStartupError: - errorOccurred = True - - if errorOccurred: - sys.exit( -1 ) + processes = [_processes[target]] -def _checkPrivileges(): - """ - Checks to ensure that the current user has the proper privileges - to run the ProcessManager; exits the program if not. - """ - - if os.getuid() != 0: - print "ERROR: This script must be run as root." + if not _runCommandOnProcesses( command, processes ): sys.exit( -1 ) def _generateTargetHelpText(): @@ -458,8 +496,6 @@ first command-line parameter determines the command. """ - _checkPrivileges() - target = os.path.split( sys.argv[0] )[1] if not _processes.has_key( target ): # If we're in a rc.d directory, we may have 3 characters @@ -546,8 +582,6 @@ command-line arguments and acts on them. """ - _checkPrivileges() - usageTextDict = { "scriptName" : os.path.split( sys.argv[0] )[1], "targets" : _generateTargetHelpText(),