Merge remote-tracking branch 'origin/pr/129'
[grml-debootstrap.git] / travis / serial-console-connection
1 #!/usr/bin/env python
2
3 from __future__ import print_function
4 import argparse
5 import pexpect
6 import serial
7 import sys
8 import time
9 from pexpect import fdpexpect
10
11 parser = argparse.ArgumentParser(description='Connect to serial console ' +
12                                  'to execute stuff')
13 parser.add_argument('--port', required=True,
14                     help='serial console device to connect ' +
15                     'to (e.g. /dev/pts/X)')
16 parser.add_argument('--hostname', default="stretch",
17                     help='hostname of the system for login process ' +
18                     '(default: stretch)')
19 parser.add_argument('--pipefile', default="./serial0",
20                     help='file name for named pipe file (for ' +
21                     'interacting between host + VM via QEMU ' +
22                     '(default: ./serial0)')
23 parser.add_argument('--vmoutput', default="vm-output.log",
24                     help='filename for VM output (default: vm-output.log)')
25 parser.add_argument('--user', default="root",
26                     help='user name to use for login (default: root)')
27 parser.add_argument('--password', default="grml",
28                     help='password for login (default: grml)')
29 args = parser.parse_args()
30
31
32 def execute(port, hostname, user, baudrate=115200, timeout=5):
33     ser = serial.Serial(port, baudrate)
34     ser.flushInput()
35     ser.flushOutput()
36     ser.write("\n")
37     ser.flush()
38
39     child = fdpexpect.fdspawn(ser.fileno())
40     child.sendline("")
41     try:
42         print("Begin of execution inside VM")
43         child.expect("%s@%s" % (user, hostname), timeout=timeout)
44         child.sendline("/usr/local/bin/goss --gossfile /root/goss.yaml " +
45                        "validate --format tap > /root/goss.tap ; " +
46                        "echo $? > /root/goss.exitcode\n")
47         # NOTE - the serial0 is hardcoded here
48         child.sendline("cat /root/goss.tap > /dev/virtio-ports/serial0\n")
49         child.sendline("grep -q '^0' /root/goss.exitcode && " +
50                        "echo clean_exit > /dev/virtio-ports/serial0\n")
51         child.sendline("grep -q '^0' /root/goss.exitcode || " +
52                        "echo failure_exit > /dev/virtio-ports/serial0\n")
53         child.sendline("poweroff\n")
54         print("End of execution inside VM")
55     except Exception as except_inst:
56         print("Execution inside VM failed: ", except_inst)
57
58
59 def login(port, hostname, user, password,
60           baudrate=115200, timeout=5):
61     ser = serial.Serial(port, baudrate)
62     ser.flushInput()
63     ser.flushOutput()
64
65     child = fdpexpect.fdspawn(ser.fileno())
66     child.sendline("\n")
67
68     try:
69         child.expect("root@%s" % hostname, timeout=timeout)
70         return
71     except:
72         pass
73
74     print("Checking for login prompt...")
75     child.expect("%s login:" % hostname, timeout=timeout)
76     ser.write("%s\n" % user)
77     ser.flush()
78     time.sleep(1)
79     ser.write("%s\n" % password)
80     ser.flush()
81     time.sleep(1)
82     print("login ok...")
83
84
85 if __name__ == "__main__":
86     hostname = args.hostname
87     password = args.password
88     pipefile = args.pipefile
89     port = args.port
90     user = args.user
91     vmoutput = args.vmoutput
92
93     with open(pipefile, 'r') as output_pipe:
94         success = False
95         for i in range(12):
96             try:
97                 print("Logging into {0} via serial "
98                       "console [try {1}]".format(port, i))
99                 login(port, hostname, user, password)
100                 success = True
101                 break
102             except Exception as except_inst:
103                 print("Login failure (try {0}):".format(i),
104                       except_inst, file=sys.stderr)
105                 time.sleep(5)
106
107         if success:
108             execute(port, hostname, user)
109             with open(vmoutput, 'w') as fp:
110                 output = output_pipe.read()
111                 print(output)
112                 fp.write(output)