Merge branch 'master' into sfa-geni-v3
[tests.git] / qaapi / system-test.py
1 #!/usr/bin/python
2 import commands
3 import os
4 import sys
5 import traceback
6 from optparse import OptionParser
7 from random import Random
8 from time import localtime
9 from qa.sendmail import sendmail
10 from qa.utils import commands
11 from qa.logger import Logfile
12 from qa import utils 
13 from qa.Config import Config 
14 from qa.Step import Step
15 from qa.tests.vserver_create import vserver_create
16 from qa.tests.vserver_delete import vserver_delete
17 from qa.tests.plc_configure import plc_configure
18 from qa.tests.plc_stop import plc_stop
19 from qa.tests.plc_start import plc_start
20 from qa.tests.add_test_data import add_test_data
21 from qa.tests.api_unit_test import api_unit_test
22 from qa.tests.sync_person_key import sync_person_key
23 from qa.tests.boot_node import boot_node
24 from qa.tests.node_run_tests import node_run_tests
25
26 def create_vserver(vserver_name, vserver_home, mailto):
27     # create vserver for this system test if it doesnt already exist
28     if not os.path.isdir('%(vserver_home)s/%(vserver_name)s' % locals()):
29         vserver_create(config)(vserver_name, distro, mailto)
30
31 def stop_vservers(prefix = 'plc', exempt = []):
32         
33     # stop all running vservers
34     vserver_stat = "vserver-stat | grep %(prefix)s | awk '{print$8}'" % locals()
35     (stdin, stdout, stderr) = os.popen3(vserver_stat)
36     vservers = [line.strip() for line in stdout.readlines()]
37     vservers = filter(lambda x: x not in exempt, vservers)              
38     for vserver in vservers:
39         try: 
40             utils.header("Stopping %(vserver)s " % locals())
41             stop_cmd = "vserver %(vserver)s stop" % locals()
42             (status, output) = commands("vserver %(vserver)s stop" % locals())          
43         except: 
44             print "Failed to stop %(vserver)s" % locals()
45             utils.header("%s" % traceback.format_exc())
46
47 def cleanup_vservers(max_vservers, vserver_home, vserver_basename):
48     # only keep the newest MAX_VSERVERS 
49     vservers = os.listdir("%(vserver_home)s" % locals())
50     valid_vservers = lambda vserver: vserver.startswith(vserver_basename) and os.path.isdir(vserver)
51     vservers = filter(valid_vservers, vservers)
52     vservers.sort()
53     vservers.reverse()
54     expired_vservers = vservers[max_vservers:]
55     for vserver in expired_vservers:
56         utils.header("Deleting vserver: %(vserver)s" % locals(), logfile = config.logfile)
57         #vserver_delete()(vserver)
58
59 usage="""
60 Usage: %prog [options]   
61 """
62 parser = OptionParser(usage=usage,add_help_option = False)
63 parser.add_option("-v", "--vserver", help = "Vserver where tests should run")
64 parser.add_option("-d", "--distro", help = "Fedora distro to use")
65 parser.add_option("-p", "--plcname", help = "Which plc do we use (from config file)")
66 parser.add_option("-m", "--mailto", help = "Vserver build mailto address")
67
68 # Define globals
69 # Determine vserver name, distribution and mailto
70 # The distribution and current date will be part of of the vserver name  
71 MAX_VSERVERS =  3
72 VSERVER_HOME = '/vservers/'
73 VSERVER_BASENAME = 'plc'
74 distro = 'f8' 
75 # use todays date and defaults to determine which vservers to run tests in 
76 year, month, day = localtime()[:3]
77 YEAR, MONTH, DAY = [str(x) for x in [year,month,day]]
78 DATE = ".".join([YEAR, MONTH, DAY])
79 vserver_name = "%(VSERVER_BASENAME)s-%(distro)s-%(DATE)s" % locals()
80
81 (options, args) = parser.parse_args()
82 # choose which distros to use 
83 if options.distro is not None:  distros = [options.distro]
84 else: distros = ['f8']
85
86 # did the user specify a vserver or plc
87 vserver_names = []
88 if options.vserver is not None: 
89     vserver_name = options.vserver
90     vserver_names.append(vserver_name)
91           
92 if options.plcname is not None: plc_name = options.plcname
93 else: plc_name = 'TestPLC' 
94
95 # who gets emailed
96 if options.mailto is not None: mailto = options.mailto
97 else: mailto = 'tmack@cs.princeton.edu'     
98
99 if not options.vserver:
100     for distro in distros:
101         vserver_names.append("%(VSERVER_BASENAME)s-%(distro)s-%(DATE)s" % locals())
102         
103 stop_vservers(exempt = vserver_names)
104
105 for vserver_name in vserver_names:
106     try:        
107         # Setup configuration 
108         logfile_dir = "/var/log/qaapi/%(vserver_name)s" % locals()
109         config = Config(logdir = logfile_dir)
110         config.load("qa/qa_config.py")  
111         
112         config.plcs[plc_name]['vserver'] = vserver_name
113         config.plcs[plc_name]['host'] = config.hostname
114         config.plcs[plc_name]['ip'] = config.ip
115         config.plcs[plc_name].update_ip()
116         person_email = config.persons.values()[0]['email']
117
118         # Set plc configuration options
119         config_options = {}
120         for service in ['API', 'WWW', 'BOOT',' DB']:
121             config_options['PLC_'+service+'_HOST'] = config.plcs[plc_name]['ip']
122             config_options['PLC_'+service+'_IP'] = config.plcs[plc_name]['ip']  
123         config_options['PLC_ROOT_USER'] = 'root@localhost.localdomain'
124         config_options['PLC_ROOT_PASSWORD'] = 'root'
125         
126         # Set node configuration options
127         nodelist = ['vm1.paris.cs.princeton.edu']
128         node_tests = ['node_cpu_sched.py', 'pf2test.pl' ]
129         slice = config.slices['ts_slice1']
130         
131         steps = {}
132         steps[1] = Step("Create vserver %s" % vserver_name, create_vserver, 
133                         (vserver_name, VSERVER_HOME, mailto), config.logfile.filename)
134         steps[2] = Step("Mount plc %s " % plc_name,  config.plcs[plc_name].commands, 
135                         ("/sbin/service plc mount",), config.logfile.filename)
136         steps[3] = Step("Configure plc %s" % plc_name, plc_configure(config), (plc_name, config_options,),
137                         config.logfile.filename)
138         steps[4] = Step("Start plc %s " % plc_name, plc_start(config), (plc_name,),
139                         config.logfile.filename)
140         steps[5] = Step("Add test data", add_test_data(config), (plc_name,), config.logfile.filename)
141         steps[6] = Step("Sync person public key", sync_person_key(config), (person_email,),
142                         config.logfile.filename, False)
143         # XX fix logfile parameter
144         step_method = api_unit_test(config) 
145         #steps[7] = Step("API unit test", step_method, (plc_name,), step_method.logfile.filename, False)
146
147         for node in nodelist:
148             if not node in config.nodes.keys(): continue
149             node = config.nodes[node]   
150             node['vserver'] = vserver_name 
151             step_num = max(steps.keys()) + 1
152
153             # Boot node
154             steps[step_num] = Step("Boot node %s" % node['hostname'], boot_node(config),
155                                    (plc_name, node['hostname']), node.logfile.filename)
156             
157             # Check if node is fully booted
158             ready_step = Step("Check %s is ready" % node['hostname'], node.is_ready, (), node.logfile.filename)
159             steps[step_num].next_steps.append(ready_step)
160
161             # Download test scripts
162             download_scripts = Step("Download test scripts onto %s" % node['hostname'], node.download_testscripts,
163                                     (), config.logfile.filename)
164             steps[step_num].next_steps.append(download_scripts)
165
166                  
167             # XX fix logfile parameter
168             # XX node_run_tests should only run the test, download test on node before calling node_run_test
169             for test in node_tests:
170                 # Create a separate logfile for this script
171                 log_filename = "%s/%s-%s.log" % (config.logfile.dir, test, node['hostname'])
172                 test_logfile = Logfile(log_filename)
173                 step_method = node_run_tests(config, test_logfile) 
174                 test_step = Step("%s test on node %s" % (test, node['hostname']), 
175                                  step_method, (node['hostname'], plc_name, test), 
176                                  step_method.logfile.filename, False)
177                 steps[step_num].next_steps.append(test_step)    
178
179             # enter test slice
180             step_num = step_num + 1
181             steps[step_num] = Step("Enter slice %s on %s" % (slice['name'], node['hostname']),
182                                    node.slice_commands, ("echo `whoami`@`hostname`", slice['name']),
183                                    node.logfile.filename, False)
184                      
185             # Copy contents of /var/log
186             step_num = step_num + 1
187             steps[step_num] = Step("Get %s logs" % node['hostname'], node.get_logs, (),
188                                    node.logfile.filename, False)
189               
190         # Now that all the steps are defined, run them
191         order = steps.keys()
192         order.sort()
193         results = {}
194         for num in order:
195             steps[num].run()
196             steps[num].notify_contacts()
197             if steps[num].fatal and not steps[num].passed:
198                 break   
199         
200         # Generate summary email
201         to = ["qa@planet-lab.org"]
202         subject = "PLC - %(distro)s - %(DATE)s QA summary" % locals()
203         body = """
204         The following are the results of QA tests for %(DATE)s %(distro)s MyPLC.\n\n""" % locals()
205         
206         utils.header("Sending summary email")
207         # add results to summary body
208         for num in order:
209             step = steps[num]
210             body += step.get_results()
211          
212         sendmail(to, subject, body)     
213         sendmail(['tmack@cs.princeton.edu'], subject, body) 
214     except:
215         utils.header("ERROR %(vserver_name)s tests failed" % locals(), logfile = config.logfile)        
216         utils.header("%s" % traceback.format_exc(), logfile = config.logfile)
217