blob: 4c934444637ac895265ec1b866087496b45d7648 [file] [log] [blame]
jamesrenc3940222010-02-19 21:57:37 +00001import common
2import os
3from autotest_lib.frontend.afe import models as afe_models, model_logic
jamesren3e9f6092010-03-11 21:32:10 +00004from autotest_lib.frontend.planner import models, model_attributes
jamesren4be631f2010-04-08 23:01:22 +00005from autotest_lib.frontend.planner import failure_actions
jamesren0cde1eb2010-04-09 20:45:49 +00006from autotest_lib.client.common_lib import global_config, utils, global_config
jamesrenc3940222010-02-19 21:57:37 +00007
8
9PLANNER_LABEL_PREFIX = 'planner_'
10PLANNER_ATOMIC_GROUP_NAME = 'planner_global_atomic_group'
11SERVER = global_config.global_config.get_config_value('SERVER', 'hostname')
12LAZY_LOADED_FILES = {}
13
14
15def create_plan_label(plan):
16 """
17 Creates the host label to apply on the plan hosts
18 """
19 group, _ = afe_models.AtomicGroup.objects.get_or_create(
20 name=PLANNER_ATOMIC_GROUP_NAME)
21 if group.invalid:
22 group.invalid = False
23 group.save()
24
25 name = PLANNER_LABEL_PREFIX + plan.name
26 if bool(afe_models.Label.valid_objects.filter(name=name)):
27 raise model_logic.ValidationError('Label %s already exists, '
28 'cannot start plan' % name)
29 label = afe_models.Label(name=name, atomic_group=group)
30 label.save()
31
32 return label
33
34
35def start_plan(plan, label):
36 """
37 Takes the necessary steps to start a test plan in Autotest
38 """
jamesren0cde1eb2010-04-09 20:45:49 +000039 timeout = global_config.global_config.get_config_value(
40 'PLANNER', 'execution_engine_timeout')
jamesren30f06c72010-04-12 18:23:56 +000041 control = _get_execution_engine_control(server=SERVER,
42 plan_id=plan.id,
43 label_name=label.name)
jamesren3e9f6092010-03-11 21:32:10 +000044 options = {'name': plan.name + '_execution_engine',
45 'priority': afe_models.Job.Priority.MEDIUM,
jamesren30f06c72010-04-12 18:23:56 +000046 'control_file': control,
jamesren3e9f6092010-03-11 21:32:10 +000047 'control_type': afe_models.Job.ControlType.SERVER,
48 'synch_count': None,
jamesren0cde1eb2010-04-09 20:45:49 +000049 'timeout': timeout,
jamesren16e1bbb2010-04-12 18:23:46 +000050 'max_runtime_hrs': timeout,
jamesren3e9f6092010-03-11 21:32:10 +000051 'run_verify': False,
52 'reboot_before': False,
53 'reboot_after': False,
jamesrenab9e11b2010-04-16 23:44:51 +000054 'dependencies': ()}
jamesren3e9f6092010-03-11 21:32:10 +000055 job = afe_models.Job.create(owner=afe_models.User.current_user().login,
56 options=options, hosts=())
57 job.queue(hosts=())
jamesrenc3940222010-02-19 21:57:37 +000058
59
jamesren30f06c72010-04-12 18:23:56 +000060def _get_execution_engine_control(server, plan_id, label_name):
jamesrenc3940222010-02-19 21:57:37 +000061 """
62 Gets the control file to run the execution engine
63 """
jamesren30f06c72010-04-12 18:23:56 +000064 control = lazy_load(os.path.join(os.path.dirname(__file__),
65 'execution_engine_control.srv'))
66 return control % dict(server=server, plan_id=plan_id, label_name=label_name)
jamesrenc3940222010-02-19 21:57:37 +000067
68
69def lazy_load(path):
70 """
71 Lazily loads the file indicated by the path given, and caches the result
72 """
73 if path not in LAZY_LOADED_FILES:
74 LAZY_LOADED_FILES[path] = utils.read_file(path)
75
76 return LAZY_LOADED_FILES[path]
jamesren3e9f6092010-03-11 21:32:10 +000077
78
79def update_hosts_table(plan):
80 """
81 Resolves the host labels into host objects
82
83 Adds or removes hosts from the planner Hosts model based on changes to the
84 host label
85 """
86 label_hosts = set()
87
88 for label in plan.host_labels.all():
89 for afe_host in label.host_set.all():
90 host, created = models.Host.objects.get_or_create(plan=plan,
91 host=afe_host)
92 if created:
93 host.added_by_label = True
94 host.save()
95
96 label_hosts.add(host.host.id)
97
98 deleted_hosts = models.Host.objects.filter(
99 plan=plan, added_by_label=True).exclude(host__id__in=label_hosts)
100 deleted_hosts.delete()
101
102
103def compute_next_test_config(plan, host):
104 """
105 Gets the next test config that should be run for this plan and host
106
107 Returns None if the host is already running a job. Also sets the host's
108 complete bit if the host is finished running tests.
109 """
110 if host.blocked:
111 return None
112
113 test_configs = plan.testconfig_set.order_by('execution_order')
114 for test_config in test_configs:
115 afe_jobs = plan.job_set.filter(test_config=test_config)
116 afe_job_ids = afe_jobs.values_list('afe_job', flat=True)
117 hqes = afe_models.HostQueueEntry.objects.filter(job__id__in=afe_job_ids,
118 host=host.host)
jamesrendbeebf82010-04-08 22:58:26 +0000119 if not hqes and not bool(test_config.skipped_hosts.filter(host=host)):
120 return test_config
jamesren3e9f6092010-03-11 21:32:10 +0000121 for hqe in hqes:
122 if not hqe.complete:
123 # HostQueueEntry still active for this host,
124 # should not run another test
125 return None
126
127 # All HQEs related to this host are complete
128 host.complete = True
129 host.save()
130 return None
131
132
133def check_for_completion(plan):
134 """
135 Checks if a plan is actually complete. Sets complete=True if so
136 """
137 if not models.Host.objects.filter(plan=plan, complete=False):
138 plan.complete = True
139 plan.save()
140
141
142def compute_test_run_status(status):
143 """
144 Converts a TKO test status to a Planner test run status
145 """
146 Status = model_attributes.TestRunStatus
147 if status == 'GOOD':
148 return Status.PASSED
149 if status == 'RUNNING':
150 return Status.ACTIVE
151 return Status.FAILED
152
153
154def add_test_run(plan, planner_job, tko_test, hostname, status):
155 """
156 Adds a TKO test to the Planner Test Run tables
157 """
158 host = afe_models.Host.objects.get(hostname=hostname)
159
160 planner_host = models.Host.objects.get(plan=plan, host=host)
161 test_run, _ = models.TestRun.objects.get_or_create(plan=plan,
162 test_job=planner_job,
163 tko_test=tko_test,
164 host=planner_host)
165 test_run.status = status
166 test_run.save()
jamesren4be631f2010-04-08 23:01:22 +0000167
168
169def _site_process_host_action_dummy(host, action):
170 return False
171
172
173def process_host_action(host, action):
174 """
175 Takes the specified action on the host
176 """
177 HostAction = failure_actions.HostAction
178 if action not in HostAction.values:
179 raise ValueError('Unexpected host action %s' % action)
180
181 site_process = utils.import_site_function(
182 __file__, 'autotest_lib.frontend.planner.site_rpc_utils',
183 'site_process_host_action', _site_process_host_action_dummy)
184
185 if not site_process(host, action):
186 # site_process_host_action returns True and and only if it matched a
187 # site-specific processing option
188 if action == HostAction.BLOCK:
189 host.blocked = True
190 elif action == HostAction.UNBLOCK:
191 host.blocked = False
192 else:
193 assert action == HostAction.REINSTALL
194 raise NotImplemented('TODO: implement reinstall')
195
196 host.save()
197
198
199def process_test_action(planner_job, action):
200 """
201 Takes the specified action for this planner job
202 """
203 TestAction = failure_actions.TestAction
204 if action not in TestAction.values:
205 raise ValueError('Unexpected test action %s' % action)
206
207 if action == TestAction.SKIP:
208 # Do nothing
209 pass
210 else:
211 assert action == TestAction.RERUN
212 planner_job.requires_rerun = True
213 planner_job.save()