Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-ci
Path: blob/main/scripts/test/run-tests.py
1130 views
1
# Copyright (c) 2014, Craig Rodrigues <[email protected]>
2
# All rights reserved.
3
#
4
# Redistribution and use in source and binary forms, with or without
5
# modification, are permitted provided that the following conditions
6
# are met:
7
# 1. Redistributions of source code must retain the above copyright
8
# notice unmodified, this list of conditions, and the following
9
# disclaimer.
10
# 2. Redistributions in binary form must reproduce the above copyright
11
# notice, this list of conditions and the following disclaimer in the
12
# documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25
#
26
#
27
# RUN KYUA TESTS INSIDE WITH BHYVE
28
#
29
# The following program::
30
# (1) takes a an image
31
# (2) boots it
32
# (3) runs tests in /usr/tests
33
#
34
from __future__ import print_function
35
from optparse import OptionParser
36
import atexit
37
import getopt
38
import json
39
import os
40
import os.path
41
import pexpect
42
import sys
43
import subprocess
44
import fabric.api
45
46
test_config = None
47
test_config_file = None
48
sentinel_file = None
49
50
def usage(argv):
51
print("Usage:")
52
print(" %s -f [JSON config file]" % argv[0])
53
54
55
def main(argv):
56
57
try:
58
opts, args = getopt.getopt(sys.argv[1:], "f:")
59
except getopt.GetoptError as err:
60
sys.exit(2)
61
62
global test_config
63
global test_config_file
64
65
for o, a in opts:
66
if o == "-f":
67
test_config_file = a
68
else:
69
assert False, "unhandled option"
70
71
if test_config_file is None:
72
usage(argv)
73
sys.exit(1)
74
75
config_file = open(test_config_file, "r")
76
test_config = json.load(config_file)
77
config_file.close()
78
checkpreReqBhyve()
79
runTest()
80
81
def runTest():
82
global test_config
83
global test_config_file
84
85
home = os.path.expanduser("~")
86
known_hosts = "%s/.ssh/known_hosts" % (home)
87
88
# Create the bridge interface if it does not exist.
89
# Configure the bridge with an IP address.
90
print(["ifconfig", test_config['bridge']])
91
ret = subprocess.call(["ifconfig", test_config['bridge']])
92
if ret != 0:
93
ret = subprocess.call(["ifconfig", test_config['bridge'], "create"])
94
if ret != 0:
95
sys.exit(ret)
96
ret = subprocess.call(["ifconfig", test_config['bridge'], "inet", "%s/24" % test_config['bridge_ip']])
97
if ret != 0:
98
sys.exit(ret)
99
100
# Create the tap interface if it does not exist.
101
# Add the tap interface to the bridge.
102
ret = subprocess.call(["ifconfig", test_config['tap']])
103
if ret != 0:
104
ret = subprocess.call(["ifconfig", test_config['tap'], "create"])
105
if ret != 0:
106
sys.exit(ret)
107
ret = subprocess.call(["ifconfig", test_config['bridge'], "addm", test_config['tap']])
108
if ret != 0:
109
sys.exit(ret)
110
111
cmd = "bhyvectl --destroy --vm=%s" % test_config['vm_name']
112
print("")
113
ret = os.system(cmd)
114
115
cmd = "bhyveload -m %s -d %s %s" % \
116
(test_config['ram'], test_config['disks'][0], test_config['vm_name'])
117
print(cmd)
118
child = pexpect.spawn(cmd)
119
child.logfile = sys.stdout
120
child.expect(pexpect.EOF, timeout=120)
121
122
macaddress = ""
123
if "mac" in test_config:
124
macaddress = ",mac=%s" % test_config['mac']
125
126
cmd = "bhyve -c 2 -m %s -AI -H -P -s 0:0,hostbridge " \
127
"-s 1:0,lpc -s 2:0,virtio-net,%s%s -s 3:0,ahci-hd,%s " \
128
"-l com1,stdio %s" % \
129
(test_config['ram'], test_config['tap'], macaddress, \
130
test_config['disks'][0], test_config['vm_name'])
131
print(cmd)
132
child2 = pexpect.spawn(cmd)
133
child2.logfile = sys.stdout
134
135
# Log into the VM via expect, and execute enough
136
# commands to figure out the IP address.
137
child2.expect(['login:'], timeout=1200)
138
child2.sendline("root")
139
child2.expect(['Password:'], timeout=1200)
140
child2.sendline("test")
141
child2.expect("# ")
142
143
# Change the prompt to something more unique
144
prompt = "kyuatestprompt # "
145
child2.sendline("set prompt=\"%s\"" % (prompt))
146
child2.expect(prompt)
147
child2.expect(prompt)
148
149
child2.sendline("ifconfig %s | grep 'inet '" % (test_config['interface']))
150
child2.before = None
151
child2.after = None
152
i = child2.expect([' inet ', prompt, pexpect.EOF])
153
ip_address = None
154
if i == 0:
155
# matched " inet 8.8.178.209 netmask 0xffffffe0 broadcast 8.8.178.223"
156
i1 = child2.expect(['netmask ', prompt, pexpect.EOF])
157
if i1 == 0:
158
# matched "netmask 0xffffffe0 broadcast 8.8.178.223"
159
ip_address = child2.before.strip()
160
print("\nFound IP address: %s" % (ip_address))
161
subprocess.call(["sed", "-i", "", "-e", "/%s/d" % (ip_address), known_hosts])
162
163
if ip_address is None:
164
print("\nDid not find IP address for %s" % (test_config['interface']))
165
child2.sendline("shutdown -p now")
166
child2.expect(pexpect.EOF, timeout=1000)
167
else:
168
# If at this point we have figured out the IP address for
169
# this host, then execute all subsequent commands over SSH
170
# using the Python Fabric library.
171
172
# Set global state used by Python Fabric library
173
fabric.api.env.host_string = ip_address
174
fabric.api.env.user = "root"
175
fabric.api.env.password = "test"
176
fabric.api.env.shell = "/bin/sh -c"
177
fabric.api.env.warn_only = True
178
179
# Execute commands over SSH. We can more easily
180
# grab the exit status code of executed commands over SSH,
181
# compared to expect.
182
with fabric.api.cd("/usr/tests"):
183
fabric.api.run("kyua test")
184
fabric.api.run("kyua report --verbose --results-filter passed,skipped,xfail,broken,failed --output test-report.txt")
185
fabric.api.run("kyua report-junit --output=test-report.xml")
186
fabric.api.run("shutdown -p now")
187
child2.expect(pexpect.EOF, timeout=1000)
188
189
def checkpreReqBhyve():
190
# Check if Bhyve module is loaded, and if we ran the script as superuser.
191
# If not, silently kill the application.
192
euid = os.geteuid()
193
if euid != 0:
194
raise EnvironmentError("this script need to be run as root")
195
ret = os.system("kldload -n vmm")
196
if ret != 0:
197
raise EnvironmentError("missing vmm.ko")
198
ret = os.system("kldload -n if_tap")
199
if ret != 0:
200
raise EnvironmentError("missing if_tap.ko")
201
202
def cleanup():
203
os.system("rm -f %s" % (sentinel_file))
204
205
if __name__ == "__main__":
206
atexit.register(cleanup)
207
main(sys.argv)
208
209