Example #1
0
 def test_master_state(self):
     my_lock = Lock(self.lock_file)
     # Mailman is not running.
     state, lock = master.master_state(self.lock_file)
     self.assertEqual(state, master.WatcherState.none)
     # Acquire the lock as if another process had already started the
     # master.
     my_lock.lock()
     try:
         state, lock = master.master_state(self.lock_file)
     finally:
         my_lock.unlock()
     self.assertEqual(state, master.WatcherState.conflict)
Example #2
0
 def test_master_state(self):
     my_lock = Lock(self.lock_file)
     # Mailman is not running.
     state, lock = master.master_state(self.lock_file)
     self.assertEqual(state, master.WatcherState.none)
     # Acquire the lock as if another process had already started the
     # master.  Use a timeout to avoid this test deadlocking.
     my_lock.lock(timedelta(seconds=60))
     try:
         state, lock = master.master_state(self.lock_file)
     finally:
         my_lock.unlock()
     self.assertEqual(state, master.WatcherState.conflict)
Example #3
0
 def test_master_state(self):
     my_lock = Lock(self.lock_file)
     # Mailman is not running.
     state, lock = master.master_state(self.lock_file)
     self.assertEqual(state, master.WatcherState.none)
     # Acquire the lock as if another process had already started the
     # master.
     my_lock.lock()
     try:
         state, lock = master.master_state(self.lock_file)
     finally:
         my_lock.unlock()
     self.assertEqual(state, master.WatcherState.conflict)
Example #4
0
    def process(self, args):
        """See `ICLISubCommand`."""
        # Although there's a potential race condition here, it's a better user
        # experience for the parent process to refuse to start twice, rather
        # than having it try to start the master, which will error exit.
        status, lock = master_state()
        if status is WatcherState.conflict:
            self.parser.error(_('GNU Mailman is already running'))
        elif status in (WatcherState.stale_lock, WatcherState.host_mismatch):
            if args.force is None:
                self.parser.error(
                    _('A previous run of GNU Mailman did not exit '
                      'cleanly.  Try using --force.'))
        def log(message):                           # noqa
            if not args.quiet:
                print(message)
        # Try to find the path to a valid, existing configuration file, and
        # refuse to start if one cannot be found.
        if args.config is not None:
            config_path = args.config
        elif config.filename is not None:
            config_path = config.filename
        else:
            config_path = os.path.join(config.VAR_DIR, 'etc', 'mailman.cfg')
            if not os.path.exists(config_path):
                print(_("""\
No valid configuration file could be found, so Mailman will refuse to start.
Use -C/--config to specify a valid configuration file."""), file=sys.stderr)
                sys.exit(1)
        # Daemon process startup according to Stevens, Advanced Programming in
        # the UNIX Environment, Chapter 13.
        pid = os.fork()
        if pid:
            # parent
            log(_("Starting Mailman's master runner"))
            return
        # child: Create a new session and become the session leader, but since
        # we won't be opening any terminal devices, don't do the
        # ultra-paranoid suggestion of doing a second fork after the setsid()
        # call.
        os.setsid()
        # Instead of cd'ing to root, cd to the Mailman runtime directory.
        # However, before we do that, set an environment variable used by the
        # subprocesses to calculate their path to the $VAR_DIR.
        os.environ['MAILMAN_VAR_DIR'] = config.VAR_DIR
        os.chdir(config.VAR_DIR)
        # Exec the master watcher.
        execl_args = [
            sys.executable, sys.executable,
            os.path.join(config.BIN_DIR, 'master'),
            ]
        if args.force:
            execl_args.append('--force')
        # Always pass the config file path to the master projects, so there's
        # no confusion about which cfg is being used.
        execl_args.extend(['-C', config_path])
        qlog.debug('starting: %s', execl_args)
        os.execl(*execl_args)
        # We should never get here.
        raise RuntimeError('os.execl() failed')
Example #5
0
    def process(self, args):
        """See `ICLISubCommand`."""
        # Although there's a potential race condition here, it's a better user
        # experience for the parent process to refuse to start twice, rather
        # than having it try to start the master, which will error exit.
        status, lock = master_state()
        if status is WatcherState.conflict:
            self.parser.error(_('GNU Mailman is already running'))
        elif status in (WatcherState.stale_lock, WatcherState.host_mismatch):
            if args.force is None:
                self.parser.error(
                    _('A previous run of GNU Mailman did not exit '
                      'cleanly.  Try using --force.'))
        def log(message):
            if not args.quiet:
                print(message)
        # Try to find the path to a valid, existing configuration file, and
        # refuse to start if one cannot be found.
        if args.config is not None:
            config_path = args.config
        elif config.filename is not None:
            config_path = config.filename
        else:
            config_path = os.path.join(config.VAR_DIR, 'etc', 'mailman.cfg')
            if not os.path.exists(config_path):
                print(_("""\
No valid configuration file could be found, so Mailman will refuse to start.
Use -C/--config to specify a valid configuration file."""), file=sys.stderr)
                sys.exit(1)
        # Daemon process startup according to Stevens, Advanced Programming in
        # the UNIX Environment, Chapter 13.
        pid = os.fork()
        if pid:
            # parent
            log(_("Starting Mailman's master runner"))
            return
        # child: Create a new session and become the session leader, but since
        # we won't be opening any terminal devices, don't do the
        # ultra-paranoid suggestion of doing a second fork after the setsid()
        # call.
        os.setsid()
        # Instead of cd'ing to root, cd to the Mailman runtime directory.
        # However, before we do that, set an environment variable used by the
        # subprocesses to calculate their path to the $VAR_DIR.
        os.environ['MAILMAN_VAR_DIR'] = config.VAR_DIR
        os.chdir(config.VAR_DIR)
        # Exec the master watcher.
        execl_args = [
            sys.executable, sys.executable,
            os.path.join(config.BIN_DIR, 'master'),
            ]
        if args.force:
            execl_args.append('--force')
        # Always pass the config file path to the master projects, so there's
        # no confusion about which cfg is being used.
        execl_args.extend(['-C', config_path])
        qlog.debug('starting: %s', execl_args)
        os.execl(*execl_args)
        # We should never get here.
        raise RuntimeError('os.execl() failed')
Example #6
0
def start(ctx, force, generate_alias_file, run_as_user, quiet):
    # Although there's a potential race condition here, it's a better user
    # experience for the parent process to refuse to start twice, rather than
    # having it try to start the master, which will error exit.
    status, lock = master_state()
    if status is WatcherState.conflict:
        ctx.fail(_('GNU Mailman is already running'))
    elif status in (WatcherState.stale_lock, WatcherState.host_mismatch):
        if not force:
            ctx.fail(
                _('A previous run of GNU Mailman did not exit '
                  'cleanly ({}).  Try using --force'.format(status.name)))
    # Daemon process startup according to Stevens, Advanced Programming in the
    # UNIX Environment, Chapter 13.
    pid = os.fork()
    if pid:
        # parent
        if not quiet:
            print(_("Starting Mailman's master runner"))
        if generate_alias_file:
            if not quiet:
                print(_("Generating MTA alias maps"))
            call_name(config.mta.incoming).regenerate()
        return
    # child: Create a new session and become the session leader, but since we
    # won't be opening any terminal devices, don't do the ultra-paranoid
    # suggestion of doing a second fork after the setsid() call.
    os.setsid()
    # Instead of cd'ing to root, cd to the Mailman runtime directory.  However,
    # before we do that, set an environment variable used by the subprocesses
    # to calculate their path to the $VAR_DIR.
    os.environ['MAILMAN_VAR_DIR'] = config.VAR_DIR
    os.chdir(config.VAR_DIR)
    # Exec the master watcher.
    execl_args = [
        sys.executable,
        sys.executable,
        os.path.join(config.BIN_DIR, 'master'),
    ]
    if force:
        execl_args.append('--force')
    # Always pass the configuration file path to the master process, so there's
    # no confusion about which one is being used.
    execl_args.extend(['-C', config.filename])
    qlog.debug('starting: %s', execl_args)
    os.execl(*execl_args)
    # We should never get here.
    raise RuntimeError('os.execl() failed')
Example #7
0
def status():
    status, lock = master_state()
    if status is WatcherState.none:
        message = _('GNU Mailman is not running')
    elif status is WatcherState.conflict:
        hostname, pid, tempfile = lock.details
        message = _('GNU Mailman is running (master pid: $pid)')
    elif status is WatcherState.stale_lock:
        hostname, pid, tempfile = lock.details
        message = _('GNU Mailman is stopped (stale pid: $pid)')
    else:
        hostname, pid, tempfile = lock.details
        fqdn_name = socket.getfqdn()                         # noqa: F841
        assert status is WatcherState.host_mismatch, (
            'Invalid enum value: %s' % status)
        message = _('GNU Mailman is in an unexpected state '
                    '($hostname != $fqdn_name)')
    print(message)
    sys.exit(status.value)
Example #8
0
 def process(self, args):
     """See `ICLISubCommand`."""
     status, lock = master_state()
     if status is WatcherState.none:
         message = _('GNU Mailman is not running')
     elif status is WatcherState.conflict:
         hostname, pid, tempfile = lock.details
         message = _('GNU Mailman is running (master pid: $pid)')
     elif status is WatcherState.stale_lock:
         hostname, pid, tempfile = lock.details
         message = _('GNU Mailman is stopped (stale pid: $pid)')
     else:
         hostname, pid, tempfile = lock.details
         fqdn_name = socket.getfqdn()
         assert status is WatcherState.host_mismatch, (
             'Invalid enum value: %s' % status)
         message = _('GNU Mailman is in an unexpected state '
                     '($hostname != $fqdn_name)')
     print(message)
     return status.value
Example #9
0
 def process(self, args):
     """See `ICLISubCommand`."""
     status, lock = master_state()
     if status is WatcherState.none:
         message = _('GNU Mailman is not running')
     elif status is WatcherState.conflict:
         hostname, pid, tempfile = lock.details
         message = _('GNU Mailman is running (master pid: $pid)')
     elif status is WatcherState.stale_lock:
         hostname, pid, tempfile = lock.details
         message =_('GNU Mailman is stopped (stale pid: $pid)')
     else:
         hostname, pid, tempfile = lock.details
         fqdn_name = socket.getfqdn()
         assert status is WatcherState.host_mismatch, (
             'Invalid enum value: %s' % status)
         message = _('GNU Mailman is in an unexpected state '
                     '($hostname != $fqdn_name)')
     print(message)
     return status.value