blob: 0ce17b50f2b2354a65389345a84951de1319a536 [file] [log] [blame]
showardce38e0c2008-05-29 19:36:16 +00001#!/usr/bin/python
2
showard8fe93b52008-11-18 17:53:22 +00003import unittest, time, subprocess, os, StringIO, tempfile, datetime, shutil
showardce38e0c2008-05-29 19:36:16 +00004import MySQLdb
5import common
showard364fe862008-10-17 02:01:16 +00006from autotest_lib.frontend import setup_django_environment
7from autotest_lib.frontend import setup_test_environment
jadmanskifb7cfb12008-07-09 14:13:21 +00008from autotest_lib.client.common_lib import global_config, host_protections
jadmanski3d161b02008-06-06 15:43:36 +00009from autotest_lib.client.common_lib.test_utils import mock
showard442e71e2008-10-06 10:05:20 +000010from autotest_lib.database import database_connection, migrate
showard21baa452008-10-21 00:08:39 +000011from autotest_lib.frontend import thread_local
showardb1e51872008-10-07 11:08:18 +000012from autotest_lib.frontend.afe import models
showard364fe862008-10-17 02:01:16 +000013from autotest_lib.scheduler import monitor_db
showardce38e0c2008-05-29 19:36:16 +000014
15_DEBUG = False
16
showard04c82c52008-05-29 19:38:12 +000017class Dummy(object):
jadmanski0afbb632008-06-06 21:10:57 +000018 'Dummy object that can have attribute assigned to it'
showard04c82c52008-05-29 19:38:12 +000019
showard56193bb2008-08-13 20:07:41 +000020
21class IsRow(mock.argument_comparator):
22 def __init__(self, row_id):
23 self.row_id = row_id
showardce38e0c2008-05-29 19:36:16 +000024
25
showard56193bb2008-08-13 20:07:41 +000026 def is_satisfied_by(self, parameter):
27 return list(parameter)[0] == self.row_id
28
29
30 def __str__(self):
31 return 'row with id %s' % self.row_id
32
33
showardb2e2c322008-10-14 17:33:55 +000034class BaseSchedulerTest(unittest.TestCase):
showard50c0e712008-09-22 16:20:37 +000035 _config_section = 'AUTOTEST_WEB'
showardb1e51872008-10-07 11:08:18 +000036 _test_db_initialized = False
showardce38e0c2008-05-29 19:36:16 +000037
jadmanski0afbb632008-06-06 21:10:57 +000038 def _do_query(self, sql):
showardb1e51872008-10-07 11:08:18 +000039 self._database.execute(sql)
showardce38e0c2008-05-29 19:36:16 +000040
41
showardb1e51872008-10-07 11:08:18 +000042 @classmethod
43 def _initialize_test_db(cls):
44 if cls._test_db_initialized:
45 return
46 temp_fd, cls._test_db_file = tempfile.mkstemp(suffix='.monitor_test')
47 os.close(temp_fd)
showard364fe862008-10-17 02:01:16 +000048 setup_test_environment.set_test_database(cls._test_db_file)
49 setup_test_environment.run_syncdb()
50 cls._test_db_backup = setup_test_environment.backup_test_database()
showardb1e51872008-10-07 11:08:18 +000051 cls._test_db_initialized = True
showardce38e0c2008-05-29 19:36:16 +000052
53
showard50c0e712008-09-22 16:20:37 +000054 def _open_test_db(self):
showardb1e51872008-10-07 11:08:18 +000055 self._initialize_test_db()
showard364fe862008-10-17 02:01:16 +000056 setup_test_environment.restore_test_database(self._test_db_backup)
showardb1e51872008-10-07 11:08:18 +000057 self._database = (
58 database_connection.DatabaseConnection.get_test_database(
59 self._test_db_file))
60 self._database.connect()
61 self._database.debug = _DEBUG
showardce38e0c2008-05-29 19:36:16 +000062
63
jadmanski0afbb632008-06-06 21:10:57 +000064 def _close_test_db(self):
showardb1e51872008-10-07 11:08:18 +000065 self._database.disconnect()
showardce38e0c2008-05-29 19:36:16 +000066
67
showard56193bb2008-08-13 20:07:41 +000068 def _set_monitor_stubs(self):
showardb1e51872008-10-07 11:08:18 +000069 monitor_db._db = self._database
showard56193bb2008-08-13 20:07:41 +000070
71
jadmanski0afbb632008-06-06 21:10:57 +000072 def _fill_in_test_data(self):
showardb1e51872008-10-07 11:08:18 +000073 user = models.User.objects.create(login='my_user')
74 acl_group = models.AclGroup.objects.create(name='my_acl')
75 acl_group.users.add(user)
76
77 hosts = [models.Host.objects.create(hostname=hostname) for hostname in
78 ('host1', 'host2', 'host3', 'host4')]
79 acl_group.hosts = hosts
showard98863972008-10-29 21:14:56 +000080 models.AclGroup.smart_get('Everyone').hosts = []
showardb1e51872008-10-07 11:08:18 +000081
82 labels = [models.Label.objects.create(name=name) for name in
83 ('label1', 'label2', 'label3')]
84 labels[2].only_if_needed = True
85 labels[2].save()
86 hosts[0].labels.add(labels[0])
87 hosts[1].labels.add(labels[1])
showardce38e0c2008-05-29 19:36:16 +000088
89
showard21baa452008-10-21 00:08:39 +000090 def _setup_dummy_user(self):
91 user = models.User.objects.create(login='dummy', access_level=100)
92 thread_local.set_user(user)
93
94
showard56193bb2008-08-13 20:07:41 +000095 def setUp(self):
96 self.god = mock.mock_god()
showard50c0e712008-09-22 16:20:37 +000097 self._open_test_db()
showard56193bb2008-08-13 20:07:41 +000098 self._fill_in_test_data()
99 self._set_monitor_stubs()
100 self._dispatcher = monitor_db.Dispatcher()
showard21baa452008-10-21 00:08:39 +0000101 self._setup_dummy_user()
showardce38e0c2008-05-29 19:36:16 +0000102
103
showard56193bb2008-08-13 20:07:41 +0000104 def tearDown(self):
105 self._close_test_db()
106 self.god.unstub_all()
showardce38e0c2008-05-29 19:36:16 +0000107
108
showard2bab8f42008-11-12 18:15:22 +0000109 def _create_job(self, hosts=[], metahosts=[], priority=0, active=False,
showard4c5374f2008-09-04 17:02:56 +0000110 synchronous=False):
showard2bab8f42008-11-12 18:15:22 +0000111 synch_count = synchronous and 2 or 1
showard12bc8a82008-10-09 16:49:53 +0000112 created_on = datetime.datetime(2008, 1, 1)
showard2bab8f42008-11-12 18:15:22 +0000113 status = models.HostQueueEntry.Status.QUEUED
114 if active:
115 status = models.HostQueueEntry.Status.RUNNING
showard21baa452008-10-21 00:08:39 +0000116 job = models.Job.objects.create(
117 name='test', owner='my_user', priority=priority,
showard2bab8f42008-11-12 18:15:22 +0000118 synch_count=synch_count, created_on=created_on,
showard0fc38302008-10-23 00:44:07 +0000119 reboot_before=models.RebootBefore.NEVER)
jadmanski0afbb632008-06-06 21:10:57 +0000120 for host_id in hosts:
showardb1e51872008-10-07 11:08:18 +0000121 models.HostQueueEntry.objects.create(job=job, priority=priority,
showard2bab8f42008-11-12 18:15:22 +0000122 host_id=host_id, status=status)
showardb1e51872008-10-07 11:08:18 +0000123 models.IneligibleHostQueue.objects.create(job=job, host_id=host_id)
jadmanski0afbb632008-06-06 21:10:57 +0000124 for label_id in metahosts:
showardb1e51872008-10-07 11:08:18 +0000125 models.HostQueueEntry.objects.create(job=job, priority=priority,
126 meta_host_id=label_id,
showard2bab8f42008-11-12 18:15:22 +0000127 status=status)
showardb1e51872008-10-07 11:08:18 +0000128 return job
showardce38e0c2008-05-29 19:36:16 +0000129
130
jadmanski0afbb632008-06-06 21:10:57 +0000131 def _create_job_simple(self, hosts, use_metahost=False,
showard2bab8f42008-11-12 18:15:22 +0000132 priority=0, active=False):
jadmanski0afbb632008-06-06 21:10:57 +0000133 'An alternative interface to _create_job'
134 args = {'hosts' : [], 'metahosts' : []}
135 if use_metahost:
136 args['metahosts'] = hosts
137 else:
138 args['hosts'] = hosts
showardb1e51872008-10-07 11:08:18 +0000139 return self._create_job(priority=priority, active=active, **args)
showardce38e0c2008-05-29 19:36:16 +0000140
141
showard56193bb2008-08-13 20:07:41 +0000142 def _update_hqe(self, set, where=''):
143 query = 'UPDATE host_queue_entries SET ' + set
144 if where:
145 query += ' WHERE ' + where
146 self._do_query(query)
147
148
showardb2e2c322008-10-14 17:33:55 +0000149class DispatcherSchedulingTest(BaseSchedulerTest):
showard56193bb2008-08-13 20:07:41 +0000150 _jobs_scheduled = []
151
152 def _set_monitor_stubs(self):
153 super(DispatcherSchedulingTest, self)._set_monitor_stubs()
154 def run_stub(hqe_self, assigned_host=None):
155 hqe_self.set_status('Starting')
156 if hqe_self.meta_host:
157 host = assigned_host
158 else:
159 host = hqe_self.host
160 self._record_job_scheduled(hqe_self.job.id, host.id)
161 return Dummy()
162 monitor_db.HostQueueEntry.run = run_stub
163
164
165 def _record_job_scheduled(self, job_id, host_id):
166 record = (job_id, host_id)
167 self.assert_(record not in self._jobs_scheduled,
168 'Job %d scheduled on host %d twice' %
169 (job_id, host_id))
170 self._jobs_scheduled.append(record)
171
172
173 def _assert_job_scheduled_on(self, job_id, host_id):
174 record = (job_id, host_id)
175 self.assert_(record in self._jobs_scheduled,
176 'Job %d not scheduled on host %d as expected\n'
177 'Jobs scheduled: %s' %
178 (job_id, host_id, self._jobs_scheduled))
179 self._jobs_scheduled.remove(record)
180
181
182 def _check_for_extra_schedulings(self):
183 if len(self._jobs_scheduled) != 0:
184 self.fail('Extra jobs scheduled: ' +
185 str(self._jobs_scheduled))
186
187
jadmanski0afbb632008-06-06 21:10:57 +0000188 def _convert_jobs_to_metahosts(self, *job_ids):
189 sql_tuple = '(' + ','.join(str(i) for i in job_ids) + ')'
190 self._do_query('UPDATE host_queue_entries SET '
191 'meta_host=host_id, host_id=NULL '
192 'WHERE job_id IN ' + sql_tuple)
showardce38e0c2008-05-29 19:36:16 +0000193
194
jadmanski0afbb632008-06-06 21:10:57 +0000195 def _lock_host(self, host_id):
196 self._do_query('UPDATE hosts SET locked=1 WHERE id=' +
197 str(host_id))
showardce38e0c2008-05-29 19:36:16 +0000198
199
jadmanski0afbb632008-06-06 21:10:57 +0000200 def setUp(self):
showard56193bb2008-08-13 20:07:41 +0000201 super(DispatcherSchedulingTest, self).setUp()
jadmanski0afbb632008-06-06 21:10:57 +0000202 self._jobs_scheduled = []
showardce38e0c2008-05-29 19:36:16 +0000203
204
jadmanski0afbb632008-06-06 21:10:57 +0000205 def _test_basic_scheduling_helper(self, use_metahosts):
206 'Basic nonmetahost scheduling'
207 self._create_job_simple([1], use_metahosts)
208 self._create_job_simple([2], use_metahosts)
209 self._dispatcher._schedule_new_jobs()
210 self._assert_job_scheduled_on(1, 1)
211 self._assert_job_scheduled_on(2, 2)
212 self._check_for_extra_schedulings()
showardce38e0c2008-05-29 19:36:16 +0000213
214
jadmanski0afbb632008-06-06 21:10:57 +0000215 def _test_priorities_helper(self, use_metahosts):
216 'Test prioritization ordering'
217 self._create_job_simple([1], use_metahosts)
218 self._create_job_simple([2], use_metahosts)
219 self._create_job_simple([1,2], use_metahosts)
220 self._create_job_simple([1], use_metahosts, priority=1)
221 self._dispatcher._schedule_new_jobs()
222 self._assert_job_scheduled_on(4, 1) # higher priority
223 self._assert_job_scheduled_on(2, 2) # earlier job over later
224 self._check_for_extra_schedulings()
showardce38e0c2008-05-29 19:36:16 +0000225
226
jadmanski0afbb632008-06-06 21:10:57 +0000227 def _test_hosts_ready_helper(self, use_metahosts):
228 """
229 Only hosts that are status=Ready, unlocked and not invalid get
230 scheduled.
231 """
232 self._create_job_simple([1], use_metahosts)
233 self._do_query('UPDATE hosts SET status="Running" WHERE id=1')
234 self._dispatcher._schedule_new_jobs()
235 self._check_for_extra_schedulings()
showardce38e0c2008-05-29 19:36:16 +0000236
jadmanski0afbb632008-06-06 21:10:57 +0000237 self._do_query('UPDATE hosts SET status="Ready", locked=1 '
238 'WHERE id=1')
239 self._dispatcher._schedule_new_jobs()
240 self._check_for_extra_schedulings()
showardce38e0c2008-05-29 19:36:16 +0000241
jadmanski0afbb632008-06-06 21:10:57 +0000242 self._do_query('UPDATE hosts SET locked=0, invalid=1 '
243 'WHERE id=1')
244 self._dispatcher._schedule_new_jobs()
showard5df2b192008-07-03 19:51:57 +0000245 if not use_metahosts:
246 self._assert_job_scheduled_on(1, 1)
jadmanski0afbb632008-06-06 21:10:57 +0000247 self._check_for_extra_schedulings()
showardce38e0c2008-05-29 19:36:16 +0000248
249
jadmanski0afbb632008-06-06 21:10:57 +0000250 def _test_hosts_idle_helper(self, use_metahosts):
251 'Only idle hosts get scheduled'
showard2bab8f42008-11-12 18:15:22 +0000252 self._create_job(hosts=[1], active=True)
jadmanski0afbb632008-06-06 21:10:57 +0000253 self._create_job_simple([1], use_metahosts)
254 self._dispatcher._schedule_new_jobs()
255 self._check_for_extra_schedulings()
showardce38e0c2008-05-29 19:36:16 +0000256
257
showard63a34772008-08-18 19:32:50 +0000258 def _test_obey_ACLs_helper(self, use_metahosts):
259 self._do_query('DELETE FROM acl_groups_hosts WHERE host_id=1')
260 self._create_job_simple([1], use_metahosts)
261 self._dispatcher._schedule_new_jobs()
262 self._check_for_extra_schedulings()
263
264
showard989f25d2008-10-01 11:38:11 +0000265 def _test_only_if_needed_labels_helper(self, use_metahosts):
266 # apply only_if_needed label3 to host1
showardb1e51872008-10-07 11:08:18 +0000267 label3 = models.Label.smart_get('label3')
268 models.Host.smart_get('host1').labels.add(label3)
269
270 job = self._create_job_simple([1], use_metahosts)
showard989f25d2008-10-01 11:38:11 +0000271 # if the job doesn't depend on label3, there should be no scheduling
272 self._dispatcher._schedule_new_jobs()
273 self._check_for_extra_schedulings()
274
275 # now make the job depend on label3
showardb1e51872008-10-07 11:08:18 +0000276 job.dependency_labels.add(label3)
showard989f25d2008-10-01 11:38:11 +0000277 self._dispatcher._schedule_new_jobs()
278 self._assert_job_scheduled_on(1, 1)
279 self._check_for_extra_schedulings()
280
281 if use_metahosts:
282 # should also work if the metahost is the only_if_needed label
283 self._do_query('DELETE FROM jobs_dependency_labels')
284 self._create_job(metahosts=[3])
285 self._dispatcher._schedule_new_jobs()
286 self._assert_job_scheduled_on(2, 1)
287 self._check_for_extra_schedulings()
288
289
jadmanski0afbb632008-06-06 21:10:57 +0000290 def test_basic_scheduling(self):
291 self._test_basic_scheduling_helper(False)
showardce38e0c2008-05-29 19:36:16 +0000292
293
jadmanski0afbb632008-06-06 21:10:57 +0000294 def test_priorities(self):
295 self._test_priorities_helper(False)
showardce38e0c2008-05-29 19:36:16 +0000296
297
jadmanski0afbb632008-06-06 21:10:57 +0000298 def test_hosts_ready(self):
299 self._test_hosts_ready_helper(False)
showardce38e0c2008-05-29 19:36:16 +0000300
301
jadmanski0afbb632008-06-06 21:10:57 +0000302 def test_hosts_idle(self):
303 self._test_hosts_idle_helper(False)
showardce38e0c2008-05-29 19:36:16 +0000304
305
showard63a34772008-08-18 19:32:50 +0000306 def test_obey_ACLs(self):
307 self._test_obey_ACLs_helper(False)
308
309
showard989f25d2008-10-01 11:38:11 +0000310 def test_only_if_needed_labels(self):
311 self._test_only_if_needed_labels_helper(False)
312
313
showard63a34772008-08-18 19:32:50 +0000314 def test_non_metahost_on_invalid_host(self):
315 """
316 Non-metahost entries can get scheduled on invalid hosts (this is how
317 one-time hosts work).
318 """
319 self._do_query('UPDATE hosts SET invalid=1')
320 self._test_basic_scheduling_helper(False)
321
322
jadmanski0afbb632008-06-06 21:10:57 +0000323 def test_metahost_scheduling(self):
showard63a34772008-08-18 19:32:50 +0000324 """
325 Basic metahost scheduling
326 """
jadmanski0afbb632008-06-06 21:10:57 +0000327 self._test_basic_scheduling_helper(True)
showardce38e0c2008-05-29 19:36:16 +0000328
329
jadmanski0afbb632008-06-06 21:10:57 +0000330 def test_metahost_priorities(self):
331 self._test_priorities_helper(True)
showardce38e0c2008-05-29 19:36:16 +0000332
333
jadmanski0afbb632008-06-06 21:10:57 +0000334 def test_metahost_hosts_ready(self):
335 self._test_hosts_ready_helper(True)
showardce38e0c2008-05-29 19:36:16 +0000336
337
jadmanski0afbb632008-06-06 21:10:57 +0000338 def test_metahost_hosts_idle(self):
339 self._test_hosts_idle_helper(True)
showardce38e0c2008-05-29 19:36:16 +0000340
341
showard63a34772008-08-18 19:32:50 +0000342 def test_metahost_obey_ACLs(self):
343 self._test_obey_ACLs_helper(True)
344
345
showard989f25d2008-10-01 11:38:11 +0000346 def test_metahost_only_if_needed_labels(self):
347 self._test_only_if_needed_labels_helper(True)
348
349
jadmanski0afbb632008-06-06 21:10:57 +0000350 def test_nonmetahost_over_metahost(self):
351 """
352 Non-metahost entries should take priority over metahost entries
353 for the same host
354 """
355 self._create_job(metahosts=[1])
356 self._create_job(hosts=[1])
357 self._dispatcher._schedule_new_jobs()
358 self._assert_job_scheduled_on(2, 1)
359 self._check_for_extra_schedulings()
showardce38e0c2008-05-29 19:36:16 +0000360
361
jadmanski0afbb632008-06-06 21:10:57 +0000362 def test_metahosts_obey_blocks(self):
363 """
364 Metahosts can't get scheduled on hosts already scheduled for
365 that job.
366 """
367 self._create_job(metahosts=[1], hosts=[1])
368 # make the nonmetahost entry complete, so the metahost can try
369 # to get scheduled
showard56193bb2008-08-13 20:07:41 +0000370 self._update_hqe(set='complete = 1', where='host_id=1')
jadmanski0afbb632008-06-06 21:10:57 +0000371 self._dispatcher._schedule_new_jobs()
372 self._check_for_extra_schedulings()
showardce38e0c2008-05-29 19:36:16 +0000373
374
showard56193bb2008-08-13 20:07:41 +0000375 def test_only_schedule_queued_entries(self):
376 self._create_job(metahosts=[1])
377 self._update_hqe(set='active=1, host_id=2')
378 self._dispatcher._schedule_new_jobs()
379 self._check_for_extra_schedulings()
380
381
showardfa8629c2008-11-04 16:51:23 +0000382 def test_no_ready_hosts(self):
383 self._create_job(hosts=[1])
384 self._do_query('UPDATE hosts SET status="Repair Failed"')
385 self._dispatcher._schedule_new_jobs()
386 self._check_for_extra_schedulings()
387
388
showardb2e2c322008-10-14 17:33:55 +0000389class DispatcherThrottlingTest(BaseSchedulerTest):
showard4c5374f2008-09-04 17:02:56 +0000390 """
391 Test that the dispatcher throttles:
392 * total number of running processes
393 * number of processes started per cycle
394 """
395 _MAX_RUNNING = 3
396 _MAX_STARTED = 2
397
398 def setUp(self):
399 super(DispatcherThrottlingTest, self).setUp()
400 self._dispatcher.max_running_processes = self._MAX_RUNNING
401 self._dispatcher.max_processes_started_per_cycle = self._MAX_STARTED
402
403
404 class DummyAgent(object):
405 _is_running = False
406 _is_done = False
407 num_processes = 1
408
409 def is_running(self):
410 return self._is_running
411
412
413 def tick(self):
414 self._is_running = True
415
416
417 def is_done(self):
418 return self._is_done
419
420
421 def set_done(self, done):
422 self._is_done = done
423 self._is_running = not done
424
425
426 def _setup_some_agents(self, num_agents):
427 self._agents = [self.DummyAgent() for i in xrange(num_agents)]
428 self._dispatcher._agents = list(self._agents)
429
430
431 def _run_a_few_cycles(self):
432 for i in xrange(4):
433 self._dispatcher._handle_agents()
434
435
436 def _assert_agents_started(self, indexes, is_started=True):
437 for i in indexes:
438 self.assert_(self._agents[i].is_running() == is_started,
439 'Agent %d %sstarted' %
440 (i, is_started and 'not ' or ''))
441
442
443 def _assert_agents_not_started(self, indexes):
444 self._assert_agents_started(indexes, False)
445
446
447 def test_throttle_total(self):
448 self._setup_some_agents(4)
449 self._run_a_few_cycles()
450 self._assert_agents_started([0, 1, 2])
451 self._assert_agents_not_started([3])
452
453
454 def test_throttle_per_cycle(self):
455 self._setup_some_agents(3)
456 self._dispatcher._handle_agents()
457 self._assert_agents_started([0, 1])
458 self._assert_agents_not_started([2])
459
460
461 def test_throttle_with_synchronous(self):
462 self._setup_some_agents(2)
463 self._agents[0].num_processes = 3
464 self._run_a_few_cycles()
465 self._assert_agents_started([0])
466 self._assert_agents_not_started([1])
467
468
469 def test_large_agent_starvation(self):
470 """
471 Ensure large agents don't get starved by lower-priority agents.
472 """
473 self._setup_some_agents(3)
474 self._agents[1].num_processes = 3
475 self._run_a_few_cycles()
476 self._assert_agents_started([0])
477 self._assert_agents_not_started([1, 2])
478
479 self._agents[0].set_done(True)
480 self._run_a_few_cycles()
481 self._assert_agents_started([1])
482 self._assert_agents_not_started([2])
483
484
485 def test_zero_process_agent(self):
486 self._setup_some_agents(5)
487 self._agents[4].num_processes = 0
488 self._run_a_few_cycles()
489 self._assert_agents_started([0, 1, 2, 4])
490 self._assert_agents_not_started([3])
491
492
showard1be97432008-10-17 15:30:45 +0000493class FindAbortTest(BaseSchedulerTest):
showard56193bb2008-08-13 20:07:41 +0000494 """
showard1be97432008-10-17 15:30:45 +0000495 Test the dispatcher abort functionality.
showard56193bb2008-08-13 20:07:41 +0000496 """
showard9d9ffd52008-11-09 23:14:35 +0000497 def _check_agent(self, agent, entry_and_host_id, include_host_tasks):
showard1be97432008-10-17 15:30:45 +0000498 self.assert_(isinstance(agent, monitor_db.Agent))
499 tasks = list(agent.queue.queue)
showard9d9ffd52008-11-09 23:14:35 +0000500 self.assert_(len(tasks) > 0)
showard1be97432008-10-17 15:30:45 +0000501
showard9d9ffd52008-11-09 23:14:35 +0000502 abort = tasks[0]
showard1be97432008-10-17 15:30:45 +0000503 self.assert_(isinstance(abort, monitor_db.AbortTask))
504 self.assertEquals(abort.queue_entry.id, entry_and_host_id)
505
showard9d9ffd52008-11-09 23:14:35 +0000506 if not include_host_tasks:
507 self.assertEquals(len(tasks), 1)
508 return
509
510 self.assertEquals(len(tasks), 3)
511 cleanup, verify = tasks[1:]
512
showard45ae8192008-11-05 19:32:53 +0000513 self.assert_(isinstance(cleanup, monitor_db.CleanupTask))
514 self.assertEquals(cleanup.host.id, entry_and_host_id)
showard1be97432008-10-17 15:30:45 +0000515
516 self.assert_(isinstance(verify, monitor_db.VerifyTask))
517 self.assertEquals(verify.host.id, entry_and_host_id)
showard56193bb2008-08-13 20:07:41 +0000518
519
showard9d9ffd52008-11-09 23:14:35 +0000520 def _check_agents(self, agents, include_host_tasks):
showard1be97432008-10-17 15:30:45 +0000521 self.assertEquals(len(agents), 2)
522 for index, agent in enumerate(agents):
showard9d9ffd52008-11-09 23:14:35 +0000523 self._check_agent(agent, index + 1, include_host_tasks)
showard56193bb2008-08-13 20:07:41 +0000524
525
526 def test_find_aborting_inactive(self):
527 self._create_job(hosts=[1, 2])
528 self._update_hqe(set='status="Abort"')
529
showard56193bb2008-08-13 20:07:41 +0000530 self._dispatcher._find_aborting()
531
showard9d9ffd52008-11-09 23:14:35 +0000532 self._check_agents(self._dispatcher._agents, include_host_tasks=False)
showard56193bb2008-08-13 20:07:41 +0000533 self.god.check_playback()
534
535
536 def test_find_aborting_active(self):
537 self._create_job(hosts=[1, 2])
538 self._update_hqe(set='status="Abort", active=1')
539 # have to make an Agent for the active HQEs
showard1be97432008-10-17 15:30:45 +0000540 agent = self.god.create_mock_class(monitor_db.Agent, 'old_agent')
showard56193bb2008-08-13 20:07:41 +0000541 agent.queue_entry_ids = [1, 2]
542 self._dispatcher.add_agent(agent)
543
showard56193bb2008-08-13 20:07:41 +0000544 self._dispatcher._find_aborting()
545
showard9d9ffd52008-11-09 23:14:35 +0000546 self._check_agents(self._dispatcher._agents, include_host_tasks=True)
showard56193bb2008-08-13 20:07:41 +0000547 self.god.check_playback()
548
showard1be97432008-10-17 15:30:45 +0000549 # ensure agent gets aborted
550 abort1 = self._dispatcher._agents[0].queue.queue[0]
551 self.assertEquals(abort1.agents_to_abort, [agent])
552 abort2 = self._dispatcher._agents[1].queue.queue[0]
553 self.assertEquals(abort2.agents_to_abort, [])
554
showard56193bb2008-08-13 20:07:41 +0000555
showard98863972008-10-29 21:14:56 +0000556class JobTimeoutTest(BaseSchedulerTest):
showard2bab8f42008-11-12 18:15:22 +0000557 def _test_synch_start_timeout_helper(self, expect_abort,
558 set_created_on=True, set_active=True,
559 set_acl=True):
showard98863972008-10-29 21:14:56 +0000560 self._dispatcher.synch_job_start_timeout_minutes = 60
561 job = self._create_job(hosts=[1, 2])
showard98863972008-10-29 21:14:56 +0000562 if set_active:
563 hqe = job.hostqueueentry_set.filter(host__id=1)[0]
564 hqe.status = 'Pending'
565 hqe.active = 1
566 hqe.save()
567
568 everyone_acl = models.AclGroup.smart_get('Everyone')
569 host1 = models.Host.smart_get(1)
570 if set_acl:
571 everyone_acl.hosts.add(host1)
572 else:
573 everyone_acl.hosts.remove(host1)
574
575 job.created_on = datetime.datetime.now()
576 if set_created_on:
577 job.created_on -= datetime.timedelta(minutes=100)
578 job.save()
579
580 self._dispatcher._abort_jobs_past_synch_start_timeout()
581
582 for hqe in job.hostqueueentry_set.all():
583 if expect_abort:
584 self.assert_(hqe.status in ('Abort', 'Aborted'), hqe.status)
585 else:
586 self.assert_(hqe.status not in ('Abort', 'Aborted'), hqe.status)
587
588
589 def test_synch_start_timeout_helper(self):
590 # no abort if any of the condition aren't met
showard2bab8f42008-11-12 18:15:22 +0000591 self._test_synch_start_timeout_helper(False, set_created_on=False)
592 self._test_synch_start_timeout_helper(False, set_active=False)
593 self._test_synch_start_timeout_helper(False, set_acl=False)
showard98863972008-10-29 21:14:56 +0000594 # abort if all conditions are met
showard2bab8f42008-11-12 18:15:22 +0000595 self._test_synch_start_timeout_helper(True)
showard98863972008-10-29 21:14:56 +0000596
597
jadmanski3d161b02008-06-06 15:43:36 +0000598class PidfileRunMonitorTest(unittest.TestCase):
jadmanski0afbb632008-06-06 21:10:57 +0000599 results_dir = '/test/path'
600 pidfile_path = os.path.join(results_dir, monitor_db.AUTOSERV_PID_FILE)
601 pid = 12345
showard21baa452008-10-21 00:08:39 +0000602 num_tests_failed = 1
jadmanski0afbb632008-06-06 21:10:57 +0000603 args = ('nice -n 10 autoserv -P 123-myuser/myhost -p -n '
604 '-r ' + results_dir + ' -b -u myuser -l my-job-name '
605 '-m myhost /tmp/filejx43Zi -c')
606 bad_args = args.replace(results_dir, '/random/results/dir')
jadmanski3d161b02008-06-06 15:43:36 +0000607
jadmanski0afbb632008-06-06 21:10:57 +0000608 def setUp(self):
609 self.god = mock.mock_god()
610 self.god.stub_function(monitor_db, 'open')
611 self.god.stub_function(os.path, 'exists')
612 self.god.stub_function(monitor_db.email_manager,
613 'enqueue_notify_email')
614 self.monitor = monitor_db.PidfileRunMonitor(self.results_dir)
jadmanski3d161b02008-06-06 15:43:36 +0000615
616
jadmanski0afbb632008-06-06 21:10:57 +0000617 def tearDown(self):
618 self.god.unstub_all()
jadmanski3d161b02008-06-06 15:43:36 +0000619
620
jadmanski0afbb632008-06-06 21:10:57 +0000621 def set_not_yet_run(self):
622 os.path.exists.expect_call(self.pidfile_path).and_return(False)
jadmanski3d161b02008-06-06 15:43:36 +0000623
624
jadmanski0afbb632008-06-06 21:10:57 +0000625 def setup_pidfile(self, pidfile_contents):
626 os.path.exists.expect_call(self.pidfile_path).and_return(True)
627 pidfile = StringIO.StringIO(pidfile_contents)
628 monitor_db.open.expect_call(
629 self.pidfile_path, 'r').and_return(pidfile)
jadmanski3d161b02008-06-06 15:43:36 +0000630
631
showard3dd6b882008-10-27 19:21:39 +0000632 def set_empty_pidfile(self):
633 self.setup_pidfile('')
634
635
jadmanski0afbb632008-06-06 21:10:57 +0000636 def set_running(self):
637 self.setup_pidfile(str(self.pid) + '\n')
jadmanski3d161b02008-06-06 15:43:36 +0000638
639
jadmanski0afbb632008-06-06 21:10:57 +0000640 def set_complete(self, error_code):
641 self.setup_pidfile(str(self.pid) + '\n' +
showard21baa452008-10-21 00:08:39 +0000642 str(error_code) + '\n' +
643 str(self.num_tests_failed))
jadmanski3d161b02008-06-06 15:43:36 +0000644
645
showard21baa452008-10-21 00:08:39 +0000646 def _test_read_pidfile_helper(self, expected_pid, expected_exit_status,
647 expected_num_tests_failed):
648 self.monitor._read_pidfile()
649 self.assertEquals(self.monitor._state.pid, expected_pid)
650 self.assertEquals(self.monitor._state.exit_status, expected_exit_status)
651 self.assertEquals(self.monitor._state.num_tests_failed,
652 expected_num_tests_failed)
jadmanski0afbb632008-06-06 21:10:57 +0000653 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000654
655
showard21baa452008-10-21 00:08:39 +0000656 def _get_expected_tests_failed(self, expected_exit_status):
657 if expected_exit_status is None:
658 expected_tests_failed = None
659 else:
660 expected_tests_failed = self.num_tests_failed
661 return expected_tests_failed
662
663
jadmanski0afbb632008-06-06 21:10:57 +0000664 def test_read_pidfile(self):
665 self.set_not_yet_run()
showard21baa452008-10-21 00:08:39 +0000666 self._test_read_pidfile_helper(None, None, None)
jadmanski3d161b02008-06-06 15:43:36 +0000667
showard3dd6b882008-10-27 19:21:39 +0000668 self.set_empty_pidfile()
669 self._test_read_pidfile_helper(None, None, None)
670
jadmanski0afbb632008-06-06 21:10:57 +0000671 self.set_running()
showard21baa452008-10-21 00:08:39 +0000672 self._test_read_pidfile_helper(self.pid, None, None)
jadmanski3d161b02008-06-06 15:43:36 +0000673
jadmanski0afbb632008-06-06 21:10:57 +0000674 self.set_complete(123)
showard21baa452008-10-21 00:08:39 +0000675 self._test_read_pidfile_helper(self.pid, 123, self.num_tests_failed)
jadmanski3d161b02008-06-06 15:43:36 +0000676
677
jadmanski0afbb632008-06-06 21:10:57 +0000678 def test_read_pidfile_error(self):
679 self.setup_pidfile('asdf')
680 self.assertRaises(monitor_db.PidfileException,
showard21baa452008-10-21 00:08:39 +0000681 self.monitor._read_pidfile)
jadmanski0afbb632008-06-06 21:10:57 +0000682 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000683
684
jadmanski0afbb632008-06-06 21:10:57 +0000685 def setup_proc_cmdline(self, args):
686 proc_cmdline = args.replace(' ', '\x00')
687 proc_file = StringIO.StringIO(proc_cmdline)
688 monitor_db.open.expect_call(
689 '/proc/%d/cmdline' % self.pid, 'r').and_return(proc_file)
jadmanski3d161b02008-06-06 15:43:36 +0000690
691
jadmanski0afbb632008-06-06 21:10:57 +0000692 def setup_find_autoservs(self, process_dict):
693 self.god.stub_class_method(monitor_db.Dispatcher,
694 'find_autoservs')
695 monitor_db.Dispatcher.find_autoservs.expect_call().and_return(
696 process_dict)
jadmanski3d161b02008-06-06 15:43:36 +0000697
698
showard21baa452008-10-21 00:08:39 +0000699 def _test_get_pidfile_info_helper(self, expected_pid, expected_exit_status,
700 expected_num_tests_failed):
701 self.monitor._get_pidfile_info()
702 self.assertEquals(self.monitor._state.pid, expected_pid)
703 self.assertEquals(self.monitor._state.exit_status, expected_exit_status)
704 self.assertEquals(self.monitor._state.num_tests_failed,
705 expected_num_tests_failed)
jadmanski0afbb632008-06-06 21:10:57 +0000706 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000707
708
jadmanski0afbb632008-06-06 21:10:57 +0000709 def test_get_pidfile_info(self):
showard21baa452008-10-21 00:08:39 +0000710 """
711 normal cases for get_pidfile_info
712 """
jadmanski0afbb632008-06-06 21:10:57 +0000713 # running
714 self.set_running()
715 self.setup_proc_cmdline(self.args)
showard21baa452008-10-21 00:08:39 +0000716 self._test_get_pidfile_info_helper(self.pid, None, None)
jadmanski3d161b02008-06-06 15:43:36 +0000717
jadmanski0afbb632008-06-06 21:10:57 +0000718 # exited during check
719 self.set_running()
720 monitor_db.open.expect_call(
721 '/proc/%d/cmdline' % self.pid, 'r').and_raises(IOError)
722 self.set_complete(123) # pidfile gets read again
showard21baa452008-10-21 00:08:39 +0000723 self._test_get_pidfile_info_helper(self.pid, 123, self.num_tests_failed)
jadmanski3d161b02008-06-06 15:43:36 +0000724
jadmanski0afbb632008-06-06 21:10:57 +0000725 # completed
726 self.set_complete(123)
showard21baa452008-10-21 00:08:39 +0000727 self._test_get_pidfile_info_helper(self.pid, 123, self.num_tests_failed)
jadmanski3d161b02008-06-06 15:43:36 +0000728
729
jadmanski0afbb632008-06-06 21:10:57 +0000730 def test_get_pidfile_info_running_no_proc(self):
showard21baa452008-10-21 00:08:39 +0000731 """
732 pidfile shows process running, but no proc exists
733 """
jadmanski0afbb632008-06-06 21:10:57 +0000734 # running but no proc
735 self.set_running()
736 monitor_db.open.expect_call(
737 '/proc/%d/cmdline' % self.pid, 'r').and_raises(IOError)
738 self.set_running()
739 monitor_db.email_manager.enqueue_notify_email.expect_call(
740 mock.is_string_comparator(), mock.is_string_comparator())
showard21baa452008-10-21 00:08:39 +0000741 self._test_get_pidfile_info_helper(self.pid, 1, 0)
jadmanski0afbb632008-06-06 21:10:57 +0000742 self.assertTrue(self.monitor.lost_process)
jadmanski3d161b02008-06-06 15:43:36 +0000743
744
jadmanski0afbb632008-06-06 21:10:57 +0000745 def test_get_pidfile_info_not_yet_run(self):
showard21baa452008-10-21 00:08:39 +0000746 """
747 pidfile hasn't been written yet
748 """
jadmanski0afbb632008-06-06 21:10:57 +0000749 # process not running
750 self.set_not_yet_run()
751 self.setup_find_autoservs({})
showard21baa452008-10-21 00:08:39 +0000752 self._test_get_pidfile_info_helper(None, None, None)
jadmanski3d161b02008-06-06 15:43:36 +0000753
jadmanski0afbb632008-06-06 21:10:57 +0000754 # process running
755 self.set_not_yet_run()
756 self.setup_find_autoservs({self.pid : self.args})
showard21baa452008-10-21 00:08:39 +0000757 self._test_get_pidfile_info_helper(None, None, None)
jadmanski3d161b02008-06-06 15:43:36 +0000758
jadmanski0afbb632008-06-06 21:10:57 +0000759 # another process running under same pid
760 self.set_not_yet_run()
761 self.setup_find_autoservs({self.pid : self.bad_args})
showard21baa452008-10-21 00:08:39 +0000762 self._test_get_pidfile_info_helper(None, None, None)
jadmanski3d161b02008-06-06 15:43:36 +0000763
764
765class AgentTest(unittest.TestCase):
jadmanski0afbb632008-06-06 21:10:57 +0000766 def setUp(self):
767 self.god = mock.mock_god()
jadmanski3d161b02008-06-06 15:43:36 +0000768
769
jadmanski0afbb632008-06-06 21:10:57 +0000770 def tearDown(self):
771 self.god.unstub_all()
jadmanski3d161b02008-06-06 15:43:36 +0000772
773
jadmanski0afbb632008-06-06 21:10:57 +0000774 def test_agent(self):
775 task1 = self.god.create_mock_class(monitor_db.AgentTask,
776 'task1')
777 task2 = self.god.create_mock_class(monitor_db.AgentTask,
778 'task2')
779 task3 = self.god.create_mock_class(monitor_db.AgentTask,
780 'task3')
jadmanski3d161b02008-06-06 15:43:36 +0000781
jadmanski0afbb632008-06-06 21:10:57 +0000782 task1.start.expect_call()
783 task1.is_done.expect_call().and_return(False)
784 task1.poll.expect_call()
785 task1.is_done.expect_call().and_return(True)
786 task1.is_done.expect_call().and_return(True)
787 task1.success = True
jadmanski3d161b02008-06-06 15:43:36 +0000788
jadmanski0afbb632008-06-06 21:10:57 +0000789 task2.start.expect_call()
790 task2.is_done.expect_call().and_return(True)
791 task2.is_done.expect_call().and_return(True)
792 task2.success = False
793 task2.failure_tasks = [task3]
jadmanski3d161b02008-06-06 15:43:36 +0000794
jadmanski0afbb632008-06-06 21:10:57 +0000795 task3.start.expect_call()
796 task3.is_done.expect_call().and_return(True)
797 task3.is_done.expect_call().and_return(True)
798 task3.success = True
jadmanski3d161b02008-06-06 15:43:36 +0000799
jadmanski0afbb632008-06-06 21:10:57 +0000800 agent = monitor_db.Agent([task1, task2])
801 agent.dispatcher = object()
802 agent.start()
803 while not agent.is_done():
804 agent.tick()
805 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000806
807
808class AgentTasksTest(unittest.TestCase):
jadmanski0afbb632008-06-06 21:10:57 +0000809 TEMP_DIR = '/temp/dir'
showard97aed502008-11-04 02:01:24 +0000810 RESULTS_DIR = '/results/dir'
jadmanski0afbb632008-06-06 21:10:57 +0000811 HOSTNAME = 'myhost'
jadmanskifb7cfb12008-07-09 14:13:21 +0000812 HOST_PROTECTION = host_protections.default
jadmanski3d161b02008-06-06 15:43:36 +0000813
jadmanski0afbb632008-06-06 21:10:57 +0000814 def setUp(self):
815 self.god = mock.mock_god()
816 self.god.stub_with(tempfile, 'mkdtemp',
817 mock.mock_function('mkdtemp', self.TEMP_DIR))
showard8fe93b52008-11-18 17:53:22 +0000818 self.god.stub_with(os.path, 'exists',
819 mock.mock_function('exists', True))
820 self.god.stub_with(shutil, 'rmtree', mock.mock_function('rmtree', None))
jadmanski0afbb632008-06-06 21:10:57 +0000821 self.god.stub_class_method(monitor_db.RunMonitor, 'run')
822 self.god.stub_class_method(monitor_db.RunMonitor, 'exit_code')
showard8fe93b52008-11-18 17:53:22 +0000823 self.god.stub_class_method(monitor_db.PreJobTask, '_move_results')
jadmanski0afbb632008-06-06 21:10:57 +0000824 self.host = self.god.create_mock_class(monitor_db.Host, 'host')
825 self.host.hostname = self.HOSTNAME
jadmanskifb7cfb12008-07-09 14:13:21 +0000826 self.host.protection = self.HOST_PROTECTION
jadmanski0afbb632008-06-06 21:10:57 +0000827 self.queue_entry = self.god.create_mock_class(
828 monitor_db.HostQueueEntry, 'queue_entry')
showard97aed502008-11-04 02:01:24 +0000829 self.job = self.god.create_mock_class(monitor_db.Job, 'job')
830 self.queue_entry.job = self.job
jadmanski0afbb632008-06-06 21:10:57 +0000831 self.queue_entry.host = self.host
832 self.queue_entry.meta_host = None
jadmanski3d161b02008-06-06 15:43:36 +0000833
834
jadmanski0afbb632008-06-06 21:10:57 +0000835 def tearDown(self):
836 self.god.unstub_all()
jadmanski3d161b02008-06-06 15:43:36 +0000837
838
jadmanski0afbb632008-06-06 21:10:57 +0000839 def run_task(self, task, success):
840 """
841 Do essentially what an Agent would do, but protect againt
842 infinite looping from test errors.
843 """
844 if not getattr(task, 'agent', None):
845 task.agent = object()
846 task.start()
847 count = 0
848 while not task.is_done():
849 count += 1
850 if count > 10:
851 print 'Task failed to finish'
852 # in case the playback has clues to why it
853 # failed
854 self.god.check_playback()
855 self.fail()
856 task.poll()
857 self.assertEquals(task.success, success)
jadmanski3d161b02008-06-06 15:43:36 +0000858
859
jadmanski0afbb632008-06-06 21:10:57 +0000860 def setup_run_monitor(self, exit_status):
861 monitor_db.RunMonitor.run.expect_call()
862 monitor_db.RunMonitor.exit_code.expect_call()
863 monitor_db.RunMonitor.exit_code.expect_call().and_return(
864 exit_status)
jadmanski3d161b02008-06-06 15:43:36 +0000865
866
jadmanski0afbb632008-06-06 21:10:57 +0000867 def _test_repair_task_helper(self, success):
868 self.host.set_status.expect_call('Repairing')
869 if success:
870 self.setup_run_monitor(0)
871 self.host.set_status.expect_call('Ready')
872 else:
873 self.setup_run_monitor(1)
874 self.host.set_status.expect_call('Repair Failed')
jadmanski3d161b02008-06-06 15:43:36 +0000875
jadmanski0afbb632008-06-06 21:10:57 +0000876 task = monitor_db.RepairTask(self.host)
showard56193bb2008-08-13 20:07:41 +0000877 self.assertEquals(task.failure_tasks, [])
jadmanski0afbb632008-06-06 21:10:57 +0000878 self.run_task(task, success)
jadmanskifb7cfb12008-07-09 14:13:21 +0000879
880 expected_protection = host_protections.Protection.get_string(
881 host_protections.default)
mbligh3e0f7e02008-07-28 19:42:01 +0000882 expected_protection = host_protections.Protection.get_attr_name(
883 expected_protection)
884
mblighc1603522008-07-17 21:32:21 +0000885 self.assertTrue(set(task.monitor.cmd) >=
mblighf40cf532008-06-23 23:53:23 +0000886 set(['autoserv', '-R', '-m', self.HOSTNAME, '-r',
jadmanskifb7cfb12008-07-09 14:13:21 +0000887 self.TEMP_DIR, '--host-protection',
888 expected_protection]))
jadmanski0afbb632008-06-06 21:10:57 +0000889 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000890
891
jadmanski0afbb632008-06-06 21:10:57 +0000892 def test_repair_task(self):
893 self._test_repair_task_helper(True)
894 self._test_repair_task_helper(False)
jadmanski3d161b02008-06-06 15:43:36 +0000895
896
jadmanski0afbb632008-06-06 21:10:57 +0000897 def test_repair_task_with_queue_entry(self):
jadmanski0afbb632008-06-06 21:10:57 +0000898 self.host.set_status.expect_call('Repairing')
showarde788ea62008-11-17 21:02:47 +0000899 self.queue_entry.requeue.expect_call()
jadmanski0afbb632008-06-06 21:10:57 +0000900 self.setup_run_monitor(1)
901 self.host.set_status.expect_call('Repair Failed')
showarde788ea62008-11-17 21:02:47 +0000902 self.queue_entry.handle_host_failure.expect_call()
jadmanski3d161b02008-06-06 15:43:36 +0000903
showarde788ea62008-11-17 21:02:47 +0000904 task = monitor_db.RepairTask(self.host, self.queue_entry)
jadmanski0afbb632008-06-06 21:10:57 +0000905 self.run_task(task, False)
906 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000907
908
jadmanski0afbb632008-06-06 21:10:57 +0000909 def setup_verify_expects(self, success, use_queue_entry):
910 if use_queue_entry:
showard2bab8f42008-11-12 18:15:22 +0000911 self.queue_entry.clear_results_dir.expect_call()
showard8fe93b52008-11-18 17:53:22 +0000912 self.queue_entry.set_status.expect_call('Verifying')
jadmanski0afbb632008-06-06 21:10:57 +0000913 self.host.set_status.expect_call('Verifying')
914 if success:
915 self.setup_run_monitor(0)
916 self.host.set_status.expect_call('Ready')
showard2bab8f42008-11-12 18:15:22 +0000917 if use_queue_entry:
918 self.queue_entry.on_pending.expect_call()
jadmanski0afbb632008-06-06 21:10:57 +0000919 else:
920 self.setup_run_monitor(1)
showard8fe93b52008-11-18 17:53:22 +0000921 if use_queue_entry and not self.queue_entry.meta_host:
922 self.queue_entry.set_execution_subdir.expect_call()
923 monitor_db.VerifyTask._move_results.expect_call()
jadmanski3d161b02008-06-06 15:43:36 +0000924
925
showard56193bb2008-08-13 20:07:41 +0000926 def _check_verify_failure_tasks(self, verify_task):
927 self.assertEquals(len(verify_task.failure_tasks), 1)
928 repair_task = verify_task.failure_tasks[0]
929 self.assert_(isinstance(repair_task, monitor_db.RepairTask))
930 self.assertEquals(verify_task.host, repair_task.host)
showard8fe93b52008-11-18 17:53:22 +0000931 if verify_task.queue_entry:
932 self.assertEquals(repair_task.queue_entry, verify_task.queue_entry)
showard56193bb2008-08-13 20:07:41 +0000933 else:
showarde788ea62008-11-17 21:02:47 +0000934 self.assertEquals(repair_task.queue_entry, None)
showard56193bb2008-08-13 20:07:41 +0000935
936
937 def _test_verify_task_helper(self, success, use_queue_entry=False,
938 use_meta_host=False):
jadmanski0afbb632008-06-06 21:10:57 +0000939 self.setup_verify_expects(success, use_queue_entry)
jadmanski3d161b02008-06-06 15:43:36 +0000940
jadmanski0afbb632008-06-06 21:10:57 +0000941 if use_queue_entry:
942 task = monitor_db.VerifyTask(
943 queue_entry=self.queue_entry)
944 else:
945 task = monitor_db.VerifyTask(host=self.host)
showard56193bb2008-08-13 20:07:41 +0000946 self._check_verify_failure_tasks(task)
jadmanski0afbb632008-06-06 21:10:57 +0000947 self.run_task(task, success)
mblighc1603522008-07-17 21:32:21 +0000948 self.assertTrue(set(task.monitor.cmd) >=
mblighf40cf532008-06-23 23:53:23 +0000949 set(['autoserv', '-v', '-m', self.HOSTNAME, '-r',
950 self.TEMP_DIR]))
jadmanski0afbb632008-06-06 21:10:57 +0000951 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000952
953
jadmanski0afbb632008-06-06 21:10:57 +0000954 def test_verify_task_with_host(self):
showard56193bb2008-08-13 20:07:41 +0000955 self._test_verify_task_helper(True)
956 self._test_verify_task_helper(False)
jadmanski3d161b02008-06-06 15:43:36 +0000957
958
jadmanski0afbb632008-06-06 21:10:57 +0000959 def test_verify_task_with_queue_entry(self):
showard56193bb2008-08-13 20:07:41 +0000960 self._test_verify_task_helper(True, use_queue_entry=True)
961 self._test_verify_task_helper(False, use_queue_entry=True)
962
963
964 def test_verify_task_with_metahost(self):
showard8fe93b52008-11-18 17:53:22 +0000965 self.queue_entry.meta_host = 1
966 self.test_verify_task_with_queue_entry()
jadmanski3d161b02008-06-06 15:43:36 +0000967
968
showard1be97432008-10-17 15:30:45 +0000969 def test_abort_task(self):
970 queue_entry = self.god.create_mock_class(monitor_db.HostQueueEntry,
971 'queue_entry')
972 queue_entry.host_id, queue_entry.job_id = 1, 2
973 task = self.god.create_mock_class(monitor_db.AgentTask, 'task')
974 agent = self.god.create_mock_class(monitor_db.Agent, 'agent')
975 agent.active_task = task
976
showard1be97432008-10-17 15:30:45 +0000977 task.abort.expect_call()
978 queue_entry.set_status.expect_call('Aborted')
979
980 abort_task = monitor_db.AbortTask(queue_entry, [agent])
981 self.run_task(abort_task, True)
showard97aed502008-11-04 02:01:24 +0000982 self.god.check_playback()
983
984
985 def _setup_pre_parse_expects(self, is_synch, num_machines):
showard97aed502008-11-04 02:01:24 +0000986 self.queue_entry.results_dir.expect_call().and_return(self.RESULTS_DIR)
987 self.queue_entry.set_status.expect_call('Parsing')
988
989
990 def _setup_post_parse_expects(self, autoserv_success):
991 pidfile_monitor = monitor_db.PidfileRunMonitor.expect_new(
992 self.RESULTS_DIR)
993 if autoserv_success:
994 code, status = 0, 'Completed'
995 else:
996 code, status = 1, 'Failed'
997 pidfile_monitor.exit_code.expect_call().and_return(code)
998 self.queue_entry.set_status.expect_call(status)
999
1000
1001 def _test_final_reparse_task_helper(self, is_synch=False, num_machines=1,
1002 autoserv_success=True):
1003 tko_dir = '/tko/dir'
1004 monitor_db.AUTOTEST_TKO_DIR = tko_dir
1005 parse_path = os.path.join(tko_dir, 'parse')
1006
1007 self._setup_pre_parse_expects(is_synch, num_machines)
1008 self.setup_run_monitor(0)
1009 self._setup_post_parse_expects(autoserv_success)
1010
1011 task = monitor_db.FinalReparseTask([self.queue_entry])
1012 self.run_task(task, True)
1013
1014 self.god.check_playback()
showard2bab8f42008-11-12 18:15:22 +00001015 cmd = [parse_path, '-l', '2', '-r', '-o', self.RESULTS_DIR]
showard97aed502008-11-04 02:01:24 +00001016 self.assertEquals(task.cmd, cmd)
1017
1018
1019 def test_final_reparse_task(self):
1020 self.god.stub_class(monitor_db, 'PidfileRunMonitor')
1021 self._test_final_reparse_task_helper()
1022 self._test_final_reparse_task_helper(num_machines=2)
1023 self._test_final_reparse_task_helper(is_synch=True)
1024 self._test_final_reparse_task_helper(autoserv_success=False)
1025
1026
1027 def test_final_reparse_throttling(self):
1028 self.god.stub_class(monitor_db, 'PidfileRunMonitor')
1029 self.god.stub_function(monitor_db.FinalReparseTask,
1030 '_can_run_new_parse')
1031
1032 self._setup_pre_parse_expects(False, 1)
1033 monitor_db.FinalReparseTask._can_run_new_parse.expect_call().and_return(
1034 False)
1035 monitor_db.FinalReparseTask._can_run_new_parse.expect_call().and_return(
1036 True)
1037 self.setup_run_monitor(0)
1038 self._setup_post_parse_expects(True)
1039
1040 task = monitor_db.FinalReparseTask([self.queue_entry])
1041 self.run_task(task, True)
1042 self.god.check_playback()
showard1be97432008-10-17 15:30:45 +00001043
1044
showard45ae8192008-11-05 19:32:53 +00001045 def _test_cleanup_task_helper(self, success, use_queue_entry=False):
showardfa8629c2008-11-04 16:51:23 +00001046 if use_queue_entry:
1047 self.queue_entry.get_host.expect_call().and_return(self.host)
showard8fe93b52008-11-18 17:53:22 +00001048 self.queue_entry.clear_results_dir.expect_call()
showard45ae8192008-11-05 19:32:53 +00001049 self.host.set_status.expect_call('Cleaning')
showardfa8629c2008-11-04 16:51:23 +00001050 if success:
1051 self.setup_run_monitor(0)
1052 self.host.set_status.expect_call('Ready')
1053 self.host.update_field.expect_call('dirty', 0)
1054 else:
1055 self.setup_run_monitor(1)
showard8fe93b52008-11-18 17:53:22 +00001056 if use_queue_entry and not self.queue_entry.meta_host:
1057 self.queue_entry.set_execution_subdir.expect_call()
1058 monitor_db.VerifyTask._move_results.expect_call()
showardfa8629c2008-11-04 16:51:23 +00001059
1060 if use_queue_entry:
showard45ae8192008-11-05 19:32:53 +00001061 task = monitor_db.CleanupTask(queue_entry=self.queue_entry)
showardfa8629c2008-11-04 16:51:23 +00001062 else:
showard45ae8192008-11-05 19:32:53 +00001063 task = monitor_db.CleanupTask(host=self.host)
showardfa8629c2008-11-04 16:51:23 +00001064 self.assertEquals(len(task.failure_tasks), 1)
1065 repair_task = task.failure_tasks[0]
1066 self.assert_(isinstance(repair_task, monitor_db.RepairTask))
1067 if use_queue_entry:
showarde788ea62008-11-17 21:02:47 +00001068 self.assertEquals(repair_task.queue_entry, self.queue_entry)
showardfa8629c2008-11-04 16:51:23 +00001069
1070 self.run_task(task, success)
1071
1072 self.god.check_playback()
1073 self.assert_(set(task.monitor.cmd) >=
showard45ae8192008-11-05 19:32:53 +00001074 set(['autoserv', '--cleanup', '-m', self.HOSTNAME,
1075 '-r', self.TEMP_DIR]))
showardfa8629c2008-11-04 16:51:23 +00001076
showard45ae8192008-11-05 19:32:53 +00001077 def test_cleanup_task(self):
1078 self._test_cleanup_task_helper(True)
1079 self._test_cleanup_task_helper(False)
showardfa8629c2008-11-04 16:51:23 +00001080
1081
showard45ae8192008-11-05 19:32:53 +00001082 def test_cleanup_task_with_queue_entry(self):
1083 self._test_cleanup_task_helper(False, True)
showardfa8629c2008-11-04 16:51:23 +00001084
1085
showardb2e2c322008-10-14 17:33:55 +00001086class JobTest(BaseSchedulerTest):
showard2bab8f42008-11-12 18:15:22 +00001087 def setUp(self):
1088 super(JobTest, self).setUp()
1089 self.god.stub_function(os.path, 'exists')
1090 self.god.stub_function(monitor_db, 'ensure_directory_exists')
1091
1092
1093 def _setup_directory_expects(self, execution_subdir):
1094 job_path = os.path.join('.', '1-my_user')
1095 results_dir = os.path.join(job_path, execution_subdir)
1096 monitor_db.ensure_directory_exists.expect_call(job_path)
1097 os.path.exists.expect_call(results_dir)
1098 monitor_db.ensure_directory_exists.expect_call(results_dir)
1099
1100
showarde77ac672008-11-14 22:42:33 +00001101 def _test_run_helper(self, expect_agent=True,
1102 expected_status=models.HostQueueEntry.Status.STARTING):
showardb2e2c322008-10-14 17:33:55 +00001103 job = monitor_db.Job.fetch('id = 1').next()
1104 queue_entry = monitor_db.HostQueueEntry.fetch('id = 1').next()
1105 agent = job.run(queue_entry)
1106
showard2bab8f42008-11-12 18:15:22 +00001107 self.god.check_playback()
showarde77ac672008-11-14 22:42:33 +00001108 self.assertEquals(models.HostQueueEntry.smart_get(1).status,
1109 expected_status)
showard2bab8f42008-11-12 18:15:22 +00001110
showard9976ce92008-10-15 20:28:13 +00001111 if not expect_agent:
1112 self.assertEquals(agent, None)
1113 return
1114
showardb2e2c322008-10-14 17:33:55 +00001115 self.assert_(isinstance(agent, monitor_db.Agent))
1116 tasks = list(agent.queue.queue)
1117 return tasks
1118
1119
1120 def test_run_asynchronous(self):
1121 self._create_job(hosts=[1, 2])
1122
1123 tasks = self._test_run_helper()
1124
showard2bab8f42008-11-12 18:15:22 +00001125 self.assertEquals(len(tasks), 1)
1126 verify_task = tasks[0]
showardb2e2c322008-10-14 17:33:55 +00001127
1128 self.assert_(isinstance(verify_task, monitor_db.VerifyTask))
1129 self.assertEquals(verify_task.queue_entry.id, 1)
1130
showardb2e2c322008-10-14 17:33:55 +00001131
showard9976ce92008-10-15 20:28:13 +00001132 def test_run_asynchronous_skip_verify(self):
1133 job = self._create_job(hosts=[1, 2])
1134 job.run_verify = False
1135 job.save()
showard2bab8f42008-11-12 18:15:22 +00001136 self._setup_directory_expects('host1')
showard9976ce92008-10-15 20:28:13 +00001137
1138 tasks = self._test_run_helper()
1139
1140 self.assertEquals(len(tasks), 1)
1141 queue_task = tasks[0]
1142
1143 self.assert_(isinstance(queue_task, monitor_db.QueueTask))
1144 self.assertEquals(queue_task.job.id, 1)
1145
1146
showardb2e2c322008-10-14 17:33:55 +00001147 def test_run_synchronous_verify(self):
1148 self._create_job(hosts=[1, 2], synchronous=True)
1149
1150 tasks = self._test_run_helper()
1151 self.assertEquals(len(tasks), 1)
1152 verify_task = tasks[0]
1153
showard2bab8f42008-11-12 18:15:22 +00001154 self.assert_(isinstance(verify_task, monitor_db.VerifyTask))
showardb2e2c322008-10-14 17:33:55 +00001155 self.assertEquals(verify_task.queue_entry.id, 1)
1156
1157
showard9976ce92008-10-15 20:28:13 +00001158 def test_run_synchronous_skip_verify(self):
1159 job = self._create_job(hosts=[1, 2], synchronous=True)
1160 job.run_verify = False
1161 job.save()
1162
showarde77ac672008-11-14 22:42:33 +00001163 self._test_run_helper(
1164 expect_agent=False,
1165 expected_status=models.HostQueueEntry.Status.PENDING)
showard9976ce92008-10-15 20:28:13 +00001166
1167 queue_entry = models.HostQueueEntry.smart_get(1)
1168 self.assertEquals(queue_entry.status, 'Pending')
1169
1170
showardb2e2c322008-10-14 17:33:55 +00001171 def test_run_synchronous_ready(self):
1172 self._create_job(hosts=[1, 2], synchronous=True)
showard2bab8f42008-11-12 18:15:22 +00001173 self._update_hqe("status='Pending', execution_subdir='")
1174 self._setup_directory_expects('group0')
showardb2e2c322008-10-14 17:33:55 +00001175
1176 tasks = self._test_run_helper()
1177 self.assertEquals(len(tasks), 1)
1178 queue_task = tasks[0]
1179
1180 self.assert_(isinstance(queue_task, monitor_db.QueueTask))
1181 self.assertEquals(queue_task.job.id, 1)
1182 hqe_ids = [hqe.id for hqe in queue_task.queue_entries]
1183 self.assertEquals(hqe_ids, [1, 2])
1184
1185
showard21baa452008-10-21 00:08:39 +00001186 def test_reboot_before_always(self):
1187 job = self._create_job(hosts=[1])
showard0fc38302008-10-23 00:44:07 +00001188 job.reboot_before = models.RebootBefore.ALWAYS
showard21baa452008-10-21 00:08:39 +00001189 job.save()
1190
1191 tasks = self._test_run_helper()
showard2bab8f42008-11-12 18:15:22 +00001192 self.assertEquals(len(tasks), 2)
showard45ae8192008-11-05 19:32:53 +00001193 cleanup_task = tasks[0]
1194 self.assert_(isinstance(cleanup_task, monitor_db.CleanupTask))
1195 self.assertEquals(cleanup_task.host.id, 1)
showard21baa452008-10-21 00:08:39 +00001196
1197
1198 def _test_reboot_before_if_dirty_helper(self, expect_reboot):
1199 job = self._create_job(hosts=[1])
showard0fc38302008-10-23 00:44:07 +00001200 job.reboot_before = models.RebootBefore.IF_DIRTY
showard21baa452008-10-21 00:08:39 +00001201 job.save()
1202
1203 tasks = self._test_run_helper()
showard2bab8f42008-11-12 18:15:22 +00001204 self.assertEquals(len(tasks), expect_reboot and 2 or 1)
showard21baa452008-10-21 00:08:39 +00001205 if expect_reboot:
showard45ae8192008-11-05 19:32:53 +00001206 cleanup_task = tasks[0]
1207 self.assert_(isinstance(cleanup_task, monitor_db.CleanupTask))
1208 self.assertEquals(cleanup_task.host.id, 1)
showard21baa452008-10-21 00:08:39 +00001209
1210 def test_reboot_before_if_dirty(self):
1211 models.Host.smart_get(1).update_object(dirty=True)
1212 self._test_reboot_before_if_dirty_helper(True)
1213
1214
1215 def test_reboot_before_not_dirty(self):
1216 models.Host.smart_get(1).update_object(dirty=False)
1217 self._test_reboot_before_if_dirty_helper(False)
1218
1219
1220
showardce38e0c2008-05-29 19:36:16 +00001221if __name__ == '__main__':
jadmanski0afbb632008-06-06 21:10:57 +00001222 unittest.main()