def boot_and_login(self): self.console = remote.boot_and_login(self.domain, self.console) test_directory = self.domain.guest_path(self.console, host_path=self.test.directory) if not test_directory: abspath = os.path.abspath(self.test.directory) self.logger.error("directory %s not mounted on %s", abspath, self.domain) raise Exception("directory '%s' not mounted on %s" % (abspath, self.domain)) self.logger.info("'cd' to %s", test_directory) self.console.chdir(test_directory)
def main(): # If SIGUSR1, backtrace all threads; hopefully this is early # enough. faulthandler.register(signal.SIGUSR1) parser = argparse.ArgumentParser(description="Connect to and run a shell command on a virtual machine domain", epilog="If no command or file is specified an interactive shell is created. SIGUSR1 will dump all thread stacks") parser.add_argument("--timeout", type=argutil.timeout, default=None, help=("maximum runtime for the command" "; -1 for no timeout" " (default: no timeout)")) argutil.add_redirect_argument(parser, "re-direct console output from stdout to %(metavar)s", "--output", "-o", default=sys.stdout, metavar="FILE") parser.add_argument("--chdir", default=None, action="store", metavar="PATH", help=("first change directory to %(metavar)s on the remote" " domain and update prompt-match logic to expect" " that directory" "; an absolute %(metavar)s is used unmodified" "; a relative %(metavar)s, which is interpreted" " as relative to the current local working directory" ", is converted to an absolute remote path before use" " (default: leave directory unchanged)")) parser.add_argument("--boot", default=None, action="store", type=Boot, choices=[e for e in Boot], help=("force the domain to boot" "; 'cold': power-off any existing domain" "; 'warm': reboot any existing domain" " (default: leave existing domain running)")) parser.add_argument("--shutdown", default=False, action="store_true", help=("on-completion shut down the domain" " (default: leave the domain running)")) parser.add_argument("--mode", default=None, choices=set(["interactive", "batch"]), help=("enter mode" " (default: if there is no command enter interactive mode)")) parser.add_argument("--host-name", default=None, help="The virtual machine's host name") parser.add_argument("domain", action="store", metavar="DOMAIN", help="virtual machine (domain) to connect to") parser.add_argument("command", nargs=argparse.REMAINDER, metavar="COMMAND", help="run shell command non-interactively; WARNING#1: this simply concatenates remaining arguments with spaces; WARNING#2: this does not try to escape arguments before passing them onto the domain's shell") logutil.add_arguments(parser) # These three calls go together args = parser.parse_args() logutil.config(args, sys.stderr) logger = logutil.getLogger("kvmsh") # Get things started domain = virsh.Domain(domain_name=args.domain, host_name=args.host_name) # Find a reason to log-in and interact with the console. batch = args.mode == "batch" or args.command interactive = args.mode == "interactive" or (not args.command and args.boot == None and not args.shutdown) # Get the current console, this will be None if the machine is # shutoff (and forced to none if a cold boot) console = domain.console() if args.boot is Boot.cold and console: remote.shutdown(domain, console) console = None status = 0 if args.boot and not (interactive or batch): console = remote.boot_to_login_prompt(domain, console) elif interactive or batch: if console: remote.login(domain, console) else: console = remote.boot_and_login(domain, console) if args.chdir and os.path.isabs(args.chdir): chdir = args.chdir elif args.chdir: chdir = domain.guest_path(console, host_path=args.chdir) else: chdir = None if chdir: domain.logger.info("'cd' to %s", chdir) console.chdir(chdir) if args.command: if interactive: logger.info("info: option --output disabled as it makes pexpect crash when in interactive mode.") else: console.redirect_output(args.output) console.run("") status = console.run(' '.join(args.command), timeout=args.timeout) print() if interactive: print() if args.debug: logger.info("info: pexpect ignores --debug in interactive mode!") logger.info("Escape character is ^]") # Hack so that the prompt appears console.redirect_output(sys.stdout) console.run("") console.redirect_output(None) # Get this terminals properties. columns, rows = os.get_terminal_size() # Normal mode console.stty_sane(term=os.getenv("TERM"), rows=rows, columns=columns) console.interact() if args.shutdown: shutdown_status = remote.shutdown(domain) status = status or shutdown_status sys.exit(status)