#!/usr/bin/python3 # SPDX-License-Identifier: LGPL-2.1-or-later # pylint: disable=broad-except import argparse import logging import signal import sys import time import pexpect def run(args): ret = 1 logger = logging.getLogger("test-shutdown") logfile = None if args.logfile: logger.debug("Logging pexpect IOs to %s", args.logfile) logfile = open(args.logfile, 'w') elif args.verbose: logfile = sys.stdout logger.info("spawning test") console = pexpect.spawn(args.command, args.arg, logfile=logfile, env={ "TERM": "dumb", }, encoding='utf-8', timeout=60) logger.debug("child pid %d", console.pid) try: logger.info("waiting for login prompt") console.expect('H login: ', 10) logger.info("log in and start screen") console.sendline('root') console.expect('bash.*# ', 10) console.sendline('screen') console.expect('screen0 ', 10) console.sendcontrol('a') console.send('c') console.expect('screen1 ', 10) logger.info('wait for the machine to fully boot') console.sendline('systemctl is-system-running --wait') console.expect(r'\b(running|degraded)\b', 60) # console.interact() console.sendline('tty') console.expect(r'/dev/(pts/\d+)') pty = console.match.group(1) logger.info("window 1 at tty %s", pty) logger.info("schedule reboot") console.sendline('shutdown -r') console.expect("Reboot scheduled for (?P.*), use 'shutdown -c' to cancel", 2) date = console.match.group('date') logger.info("reboot scheduled for %s", date) console.sendcontrol('a') console.send('0') logger.info("verify broadcast message") console.expect(f'Broadcast message from root@H on {pty}', 2) console.expect(f'The system will reboot at {date}', 2) logger.info("check show output") console.sendline('shutdown --show') console.expect(f"Reboot scheduled for {date}, use 'shutdown -c' to cancel", 2) logger.info("cancel shutdown") console.sendline('shutdown -c') console.sendcontrol('a') console.send('1') console.expect('System shutdown has been cancelled', 2) logger.info("call for reboot") console.sendline('sleep 10; shutdown -r now') console.sendcontrol('a') console.send('0') console.expect("The system will reboot now!", 12) logger.info("waiting for reboot") console.expect('H login: ', 60) console.sendline('root') console.expect('bash.*# ', 10) console.sendline('> /testok') logger.info("power off") console.sendline('poweroff') logger.info("expect termination now") console.expect(pexpect.EOF) ret = 0 except Exception as e: logger.error(e) logger.info("killing child pid %d", console.pid) # Ask systemd-nspawn to stop and release the container's resources properly. console.kill(signal.SIGTERM) for _ in range(10): if not console.isalive(): break time.sleep(1) else: # We haven't exited the loop early, so check if the process is # still alive - if so, force-kill it. if console.isalive(): console.terminate(force=True) return ret def main(): parser = argparse.ArgumentParser(description='test logind shutdown feature') parser.add_argument("-v", "--verbose", action="store_true", help="verbose") parser.add_argument("--logfile", metavar='FILE', help="Save all test input/output to the given path") parser.add_argument("command", help="command to run") parser.add_argument("arg", nargs='*', help="args for command") args = parser.parse_args() if args.verbose: level = logging.DEBUG else: level = logging.INFO logging.basicConfig(level=level) return run(args) if __name__ == '__main__': sys.exit(main()) # vim: sw=4 et