def testClosesFds(self, _mock_exit, _mock_chdir, _mock_dup2, _mock_open, mock_close, _mock_setsid, _mock_fork): daemon.become_daemon() self.assertEqual(2048, mock_close.call_count) self.assertEqual([((i,),) for i in reversed(range(2048))], mock_close.call_args_list)
def testClosesFdWithExceptions( self, _mock_exit, _mock_chdir, _mock_dup2, _mock_open, mock_close, _mock_setsid, _mock_fork ): daemon.become_daemon(keep_fds={42}) self.assertEqual(2047, mock_close.call_count) self.assertEqual([((i,),) for i in reversed(range(2048)) if i != 42], mock_close.call_args_list)
def testOpensDevNull(self, _mock_exit, _mock_chdir, mock_dup2, mock_open, _mock_close, _mock_setsid, _mock_fork): handle = object() mock_open.return_value = handle daemon.become_daemon() self.assertEqual([((handle, 0),), ((handle, 1),), ((handle, 2),)], mock_dup2.call_args_list)
def _start_child(self, control_fh): """The part of start() that runs in the child process. Daemonises the current process, writes the new PID to the pipe, and execs the service executable. """ # Detach from the parent but keep FDs open so we can write to the log still. daemon.become_daemon(keep_fds=True) # Write our new PID to the pipe and close it. json.dump({'pid': os.getpid()}, control_fh) control_fh.close() # Start cloudtail. This needs to be done after become_daemon so it's a # child of the service itself, not service_manager. # Cloudtail's stdout and stderr will go to /dev/null. output_fh = self._open_output_fh({'close_fds': True}) # Pipe our stdout and stderr to cloudtail if configured. Close all other # FDs. os.dup2(output_fh.fileno(), 1) os.dup2(output_fh.fileno(), 2) daemon.close_all_fds(keep_fds={1, 2}) # Exec the service. os.execv(self.service.cmd[0], self.service.cmd)
def testClosesInvalidFds(self, _mock_exit, _mock_chdir, _mock_dup2, _mock_open, mock_close, _mock_setsid, _mock_fork): mock_close.side_effect = EnvironmentError(errno.EIO, '') with self.assertRaises(EnvironmentError): daemon.become_daemon() mock_close.side_effect = EnvironmentError(errno.EBADF, '') daemon.become_daemon()
def testClosesFdWithExceptions(self, _mock_exit, _mock_chdir, _mock_dup2, _mock_open, mock_close, _mock_setsid, _mock_fork): daemon.become_daemon(keep_fds={42}) self.assertEqual(2047, mock_close.call_count) self.assertEqual([((i,),) for i in reversed(range(2048)) if i != 42], mock_close.call_args_list)
def testForkExitsParent(self, mock_exit, _mock_chdir, _mock_dup2, _mock_open, _mock_close, _mock_setsid, mock_fork): mock_fork.return_value = 0 daemon.become_daemon() self.assertFalse(mock_exit.called) mock_fork.return_value = 123 daemon.become_daemon() self.assertTrue(mock_exit.called)
def testClosesInvalidFds( self, _mock_exit, _mock_chdir, _mock_dup2, _mock_open, mock_close, _mock_setsid, _mock_fork ): mock_close.side_effect = EnvironmentError(errno.EIO, "") with self.assertRaises(EnvironmentError): daemon.become_daemon() mock_close.side_effect = EnvironmentError(errno.EBADF, "") daemon.become_daemon()
def testOpensDevNull(self, _mock_exit, _mock_chdir, mock_dup2, mock_open, _mock_close, _mock_setsid, _mock_fork): handle = object() mock_open.return_value = handle daemon.become_daemon() self.assertEqual([ ((handle, 0),), ((handle, 1),), ((handle, 2),), ], mock_dup2.call_args_list)
def _start_child(self, pipe): """The part of start() that runs in the child process. Daemonises the current process, writes the new PID to the pipe, and execs the service executable. """ # Detach from the parent and close all FDs except that of the pipe. daemon.become_daemon(keep_fds={pipe.fileno()}) # Write our new PID to the pipe and close it. json.dump({'pid': os.getpid()}, pipe) pipe.close() # Exec the service. runpy = os.path.join(self.service.root_directory, 'run.py') os.execv(runpy, [runpy, self.service.tool] + self.service.args)
def _start_child(self, pipe): """The part of start() that runs in the child process. Daemonises the current process, writes the new PID to the pipe, and execs the service executable. """ # Detach from the parent and close all FDs except that of the pipe. daemon.become_daemon(keep_fds={pipe.fileno()}) # Write our new PID to the pipe and close it. json.dump({'pid': os.getpid()}, pipe) pipe.close() # Exec the service. runpy = os.path.join(self.root_directory, 'run.py') os.execv(runpy, [runpy, self.tool] + self.args)
def _start_child(self, control_fh): """The part of start() that runs in the child process. Daemonises the current process, writes the new PID to the pipe, and execs the service executable. """ # Detach from the parent but keep FDs open so we can write to the log still. daemon.become_daemon(keep_fds=True) # Change the current working directory if specified. if self.service.working_directory: os.chdir(self.service.working_directory) # Write our new PID to the pipe and close it. json.dump({'pid': os.getpid()}, control_fh) control_fh.close() # Start cloudtail. This needs to be done after become_daemon so it's a # child of the service itself, not service_manager. # Cloudtail's stdout and stderr will go to /dev/null. output_fh = self._open_output_fh({'close_fds': True}) # Pipe our stdout and stderr to cloudtail if configured. Close all other # FDs. os.dup2(output_fh.fileno(), 1) os.dup2(output_fh.fileno(), 2) daemon.close_all_fds(keep_fds={1, 2}) # Set environment variables and resource limits if given. environment = os.environ.copy() if self.service.environment: environment.update(self.service.environment) if self.service.resources: self._setrlimits(self.service.resources) # Exec the service. os.execve(self.service.cmd[0], self.service.cmd, environment)
def testChangesToRoot(self, _mock_exit, mock_chdir, _mock_dup2, _mock_open, _mock_close, _mock_setsid, _mock_fork): daemon.become_daemon() mock_chdir.assert_called_with("/")
def testClosesFdsKeepingAll(self, _mock_exit, _mock_chdir, _mock_dup2, _mock_open, mock_close, _mock_setsid, _mock_fork): daemon.become_daemon(keep_fds=True) self.assertEqual(0, mock_close.call_count)
def testChangesToRoot(self, _mock_exit, mock_chdir, _mock_dup2, _mock_open, _mock_close, _mock_setsid, _mock_fork): daemon.become_daemon() mock_chdir.assert_called_with('/')