blob: 9e0256ffbe902359ab6bf067b7830d8f0549aa50 [file] [log] [blame]
showardce38e0c2008-05-29 19:36:16 +00001#!/usr/bin/python
2
showard12bc8a82008-10-09 16:49:53 +00003import unittest, time, subprocess, os, StringIO, tempfile, datetime
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))
818 self.god.stub_class_method(monitor_db.RunMonitor, 'run')
819 self.god.stub_class_method(monitor_db.RunMonitor, 'exit_code')
820 self.host = self.god.create_mock_class(monitor_db.Host, 'host')
821 self.host.hostname = self.HOSTNAME
jadmanskifb7cfb12008-07-09 14:13:21 +0000822 self.host.protection = self.HOST_PROTECTION
jadmanski0afbb632008-06-06 21:10:57 +0000823 self.queue_entry = self.god.create_mock_class(
824 monitor_db.HostQueueEntry, 'queue_entry')
showard97aed502008-11-04 02:01:24 +0000825 self.job = self.god.create_mock_class(monitor_db.Job, 'job')
826 self.queue_entry.job = self.job
jadmanski0afbb632008-06-06 21:10:57 +0000827 self.queue_entry.host = self.host
828 self.queue_entry.meta_host = None
jadmanski3d161b02008-06-06 15:43:36 +0000829
830
jadmanski0afbb632008-06-06 21:10:57 +0000831 def tearDown(self):
832 self.god.unstub_all()
jadmanski3d161b02008-06-06 15:43:36 +0000833
834
jadmanski0afbb632008-06-06 21:10:57 +0000835 def run_task(self, task, success):
836 """
837 Do essentially what an Agent would do, but protect againt
838 infinite looping from test errors.
839 """
840 if not getattr(task, 'agent', None):
841 task.agent = object()
842 task.start()
843 count = 0
844 while not task.is_done():
845 count += 1
846 if count > 10:
847 print 'Task failed to finish'
848 # in case the playback has clues to why it
849 # failed
850 self.god.check_playback()
851 self.fail()
852 task.poll()
853 self.assertEquals(task.success, success)
jadmanski3d161b02008-06-06 15:43:36 +0000854
855
jadmanski0afbb632008-06-06 21:10:57 +0000856 def setup_run_monitor(self, exit_status):
857 monitor_db.RunMonitor.run.expect_call()
858 monitor_db.RunMonitor.exit_code.expect_call()
859 monitor_db.RunMonitor.exit_code.expect_call().and_return(
860 exit_status)
jadmanski3d161b02008-06-06 15:43:36 +0000861
862
jadmanski0afbb632008-06-06 21:10:57 +0000863 def _test_repair_task_helper(self, success):
864 self.host.set_status.expect_call('Repairing')
865 if success:
866 self.setup_run_monitor(0)
867 self.host.set_status.expect_call('Ready')
868 else:
869 self.setup_run_monitor(1)
870 self.host.set_status.expect_call('Repair Failed')
jadmanski3d161b02008-06-06 15:43:36 +0000871
jadmanski0afbb632008-06-06 21:10:57 +0000872 task = monitor_db.RepairTask(self.host)
showard56193bb2008-08-13 20:07:41 +0000873 self.assertEquals(task.failure_tasks, [])
jadmanski0afbb632008-06-06 21:10:57 +0000874 self.run_task(task, success)
jadmanskifb7cfb12008-07-09 14:13:21 +0000875
876 expected_protection = host_protections.Protection.get_string(
877 host_protections.default)
mbligh3e0f7e02008-07-28 19:42:01 +0000878 expected_protection = host_protections.Protection.get_attr_name(
879 expected_protection)
880
mblighc1603522008-07-17 21:32:21 +0000881 self.assertTrue(set(task.monitor.cmd) >=
mblighf40cf532008-06-23 23:53:23 +0000882 set(['autoserv', '-R', '-m', self.HOSTNAME, '-r',
jadmanskifb7cfb12008-07-09 14:13:21 +0000883 self.TEMP_DIR, '--host-protection',
884 expected_protection]))
jadmanski0afbb632008-06-06 21:10:57 +0000885 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000886
887
jadmanski0afbb632008-06-06 21:10:57 +0000888 def test_repair_task(self):
889 self._test_repair_task_helper(True)
890 self._test_repair_task_helper(False)
jadmanski3d161b02008-06-06 15:43:36 +0000891
892
jadmanski0afbb632008-06-06 21:10:57 +0000893 def test_repair_task_with_queue_entry(self):
jadmanski0afbb632008-06-06 21:10:57 +0000894 self.host.set_status.expect_call('Repairing')
showarde788ea62008-11-17 21:02:47 +0000895 self.queue_entry.requeue.expect_call()
jadmanski0afbb632008-06-06 21:10:57 +0000896 self.setup_run_monitor(1)
897 self.host.set_status.expect_call('Repair Failed')
showarde788ea62008-11-17 21:02:47 +0000898 self.queue_entry.handle_host_failure.expect_call()
jadmanski3d161b02008-06-06 15:43:36 +0000899
showarde788ea62008-11-17 21:02:47 +0000900 task = monitor_db.RepairTask(self.host, self.queue_entry)
jadmanski0afbb632008-06-06 21:10:57 +0000901 self.run_task(task, False)
902 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000903
904
jadmanski0afbb632008-06-06 21:10:57 +0000905 def setup_verify_expects(self, success, use_queue_entry):
906 if use_queue_entry:
907 self.queue_entry.set_status.expect_call('Verifying')
showard2bab8f42008-11-12 18:15:22 +0000908 self.queue_entry.clear_results_dir.expect_call()
jadmanski0afbb632008-06-06 21:10:57 +0000909 self.host.set_status.expect_call('Verifying')
910 if success:
911 self.setup_run_monitor(0)
912 self.host.set_status.expect_call('Ready')
showard2bab8f42008-11-12 18:15:22 +0000913 if use_queue_entry:
914 self.queue_entry.on_pending.expect_call()
jadmanski0afbb632008-06-06 21:10:57 +0000915 else:
916 self.setup_run_monitor(1)
jadmanski3d161b02008-06-06 15:43:36 +0000917
918
showard56193bb2008-08-13 20:07:41 +0000919 def _check_verify_failure_tasks(self, verify_task):
920 self.assertEquals(len(verify_task.failure_tasks), 1)
921 repair_task = verify_task.failure_tasks[0]
922 self.assert_(isinstance(repair_task, monitor_db.RepairTask))
923 self.assertEquals(verify_task.host, repair_task.host)
924 if verify_task.queue_entry and not verify_task.queue_entry.meta_host:
showarde788ea62008-11-17 21:02:47 +0000925 self.assertEquals(repair_task.queue_entry,
showard56193bb2008-08-13 20:07:41 +0000926 verify_task.queue_entry)
927 else:
showarde788ea62008-11-17 21:02:47 +0000928 self.assertEquals(repair_task.queue_entry, None)
showard56193bb2008-08-13 20:07:41 +0000929
930
931 def _test_verify_task_helper(self, success, use_queue_entry=False,
932 use_meta_host=False):
jadmanski0afbb632008-06-06 21:10:57 +0000933 self.setup_verify_expects(success, use_queue_entry)
jadmanski3d161b02008-06-06 15:43:36 +0000934
jadmanski0afbb632008-06-06 21:10:57 +0000935 if use_queue_entry:
936 task = monitor_db.VerifyTask(
937 queue_entry=self.queue_entry)
938 else:
939 task = monitor_db.VerifyTask(host=self.host)
showard56193bb2008-08-13 20:07:41 +0000940 self._check_verify_failure_tasks(task)
jadmanski0afbb632008-06-06 21:10:57 +0000941 self.run_task(task, success)
mblighc1603522008-07-17 21:32:21 +0000942 self.assertTrue(set(task.monitor.cmd) >=
mblighf40cf532008-06-23 23:53:23 +0000943 set(['autoserv', '-v', '-m', self.HOSTNAME, '-r',
944 self.TEMP_DIR]))
jadmanski0afbb632008-06-06 21:10:57 +0000945 self.god.check_playback()
jadmanski3d161b02008-06-06 15:43:36 +0000946
947
jadmanski0afbb632008-06-06 21:10:57 +0000948 def test_verify_task_with_host(self):
showard56193bb2008-08-13 20:07:41 +0000949 self._test_verify_task_helper(True)
950 self._test_verify_task_helper(False)
jadmanski3d161b02008-06-06 15:43:36 +0000951
952
jadmanski0afbb632008-06-06 21:10:57 +0000953 def test_verify_task_with_queue_entry(self):
showard56193bb2008-08-13 20:07:41 +0000954 self._test_verify_task_helper(True, use_queue_entry=True)
955 self._test_verify_task_helper(False, use_queue_entry=True)
956
957
958 def test_verify_task_with_metahost(self):
959 self._test_verify_task_helper(True, use_queue_entry=True,
960 use_meta_host=True)
961 self._test_verify_task_helper(False, use_queue_entry=True,
962 use_meta_host=True)
jadmanski3d161b02008-06-06 15:43:36 +0000963
964
showard1be97432008-10-17 15:30:45 +0000965 def test_abort_task(self):
966 queue_entry = self.god.create_mock_class(monitor_db.HostQueueEntry,
967 'queue_entry')
968 queue_entry.host_id, queue_entry.job_id = 1, 2
969 task = self.god.create_mock_class(monitor_db.AgentTask, 'task')
970 agent = self.god.create_mock_class(monitor_db.Agent, 'agent')
971 agent.active_task = task
972
showard1be97432008-10-17 15:30:45 +0000973 task.abort.expect_call()
974 queue_entry.set_status.expect_call('Aborted')
975
976 abort_task = monitor_db.AbortTask(queue_entry, [agent])
977 self.run_task(abort_task, True)
showard97aed502008-11-04 02:01:24 +0000978 self.god.check_playback()
979
980
981 def _setup_pre_parse_expects(self, is_synch, num_machines):
showard97aed502008-11-04 02:01:24 +0000982 self.queue_entry.results_dir.expect_call().and_return(self.RESULTS_DIR)
983 self.queue_entry.set_status.expect_call('Parsing')
984
985
986 def _setup_post_parse_expects(self, autoserv_success):
987 pidfile_monitor = monitor_db.PidfileRunMonitor.expect_new(
988 self.RESULTS_DIR)
989 if autoserv_success:
990 code, status = 0, 'Completed'
991 else:
992 code, status = 1, 'Failed'
993 pidfile_monitor.exit_code.expect_call().and_return(code)
994 self.queue_entry.set_status.expect_call(status)
995
996
997 def _test_final_reparse_task_helper(self, is_synch=False, num_machines=1,
998 autoserv_success=True):
999 tko_dir = '/tko/dir'
1000 monitor_db.AUTOTEST_TKO_DIR = tko_dir
1001 parse_path = os.path.join(tko_dir, 'parse')
1002
1003 self._setup_pre_parse_expects(is_synch, num_machines)
1004 self.setup_run_monitor(0)
1005 self._setup_post_parse_expects(autoserv_success)
1006
1007 task = monitor_db.FinalReparseTask([self.queue_entry])
1008 self.run_task(task, True)
1009
1010 self.god.check_playback()
showard2bab8f42008-11-12 18:15:22 +00001011 cmd = [parse_path, '-l', '2', '-r', '-o', self.RESULTS_DIR]
showard97aed502008-11-04 02:01:24 +00001012 self.assertEquals(task.cmd, cmd)
1013
1014
1015 def test_final_reparse_task(self):
1016 self.god.stub_class(monitor_db, 'PidfileRunMonitor')
1017 self._test_final_reparse_task_helper()
1018 self._test_final_reparse_task_helper(num_machines=2)
1019 self._test_final_reparse_task_helper(is_synch=True)
1020 self._test_final_reparse_task_helper(autoserv_success=False)
1021
1022
1023 def test_final_reparse_throttling(self):
1024 self.god.stub_class(monitor_db, 'PidfileRunMonitor')
1025 self.god.stub_function(monitor_db.FinalReparseTask,
1026 '_can_run_new_parse')
1027
1028 self._setup_pre_parse_expects(False, 1)
1029 monitor_db.FinalReparseTask._can_run_new_parse.expect_call().and_return(
1030 False)
1031 monitor_db.FinalReparseTask._can_run_new_parse.expect_call().and_return(
1032 True)
1033 self.setup_run_monitor(0)
1034 self._setup_post_parse_expects(True)
1035
1036 task = monitor_db.FinalReparseTask([self.queue_entry])
1037 self.run_task(task, True)
1038 self.god.check_playback()
showard1be97432008-10-17 15:30:45 +00001039
1040
showard45ae8192008-11-05 19:32:53 +00001041 def _test_cleanup_task_helper(self, success, use_queue_entry=False):
showardfa8629c2008-11-04 16:51:23 +00001042 if use_queue_entry:
1043 self.queue_entry.get_host.expect_call().and_return(self.host)
showard45ae8192008-11-05 19:32:53 +00001044 self.host.set_status.expect_call('Cleaning')
showardfa8629c2008-11-04 16:51:23 +00001045 if success:
1046 self.setup_run_monitor(0)
1047 self.host.set_status.expect_call('Ready')
1048 self.host.update_field.expect_call('dirty', 0)
1049 else:
1050 self.setup_run_monitor(1)
showardfa8629c2008-11-04 16:51:23 +00001051
1052 if use_queue_entry:
showard45ae8192008-11-05 19:32:53 +00001053 task = monitor_db.CleanupTask(queue_entry=self.queue_entry)
showardfa8629c2008-11-04 16:51:23 +00001054 else:
showard45ae8192008-11-05 19:32:53 +00001055 task = monitor_db.CleanupTask(host=self.host)
showardfa8629c2008-11-04 16:51:23 +00001056 self.assertEquals(len(task.failure_tasks), 1)
1057 repair_task = task.failure_tasks[0]
1058 self.assert_(isinstance(repair_task, monitor_db.RepairTask))
1059 if use_queue_entry:
showarde788ea62008-11-17 21:02:47 +00001060 self.assertEquals(repair_task.queue_entry, self.queue_entry)
showardfa8629c2008-11-04 16:51:23 +00001061
1062 self.run_task(task, success)
1063
1064 self.god.check_playback()
1065 self.assert_(set(task.monitor.cmd) >=
showard45ae8192008-11-05 19:32:53 +00001066 set(['autoserv', '--cleanup', '-m', self.HOSTNAME,
1067 '-r', self.TEMP_DIR]))
showardfa8629c2008-11-04 16:51:23 +00001068
showard45ae8192008-11-05 19:32:53 +00001069 def test_cleanup_task(self):
1070 self._test_cleanup_task_helper(True)
1071 self._test_cleanup_task_helper(False)
showardfa8629c2008-11-04 16:51:23 +00001072
1073
showard45ae8192008-11-05 19:32:53 +00001074 def test_cleanup_task_with_queue_entry(self):
1075 self._test_cleanup_task_helper(False, True)
showardfa8629c2008-11-04 16:51:23 +00001076
1077
showardb2e2c322008-10-14 17:33:55 +00001078class JobTest(BaseSchedulerTest):
showard2bab8f42008-11-12 18:15:22 +00001079 def setUp(self):
1080 super(JobTest, self).setUp()
1081 self.god.stub_function(os.path, 'exists')
1082 self.god.stub_function(monitor_db, 'ensure_directory_exists')
1083
1084
1085 def _setup_directory_expects(self, execution_subdir):
1086 job_path = os.path.join('.', '1-my_user')
1087 results_dir = os.path.join(job_path, execution_subdir)
1088 monitor_db.ensure_directory_exists.expect_call(job_path)
1089 os.path.exists.expect_call(results_dir)
1090 monitor_db.ensure_directory_exists.expect_call(results_dir)
1091
1092
showarde77ac672008-11-14 22:42:33 +00001093 def _test_run_helper(self, expect_agent=True,
1094 expected_status=models.HostQueueEntry.Status.STARTING):
showardb2e2c322008-10-14 17:33:55 +00001095 job = monitor_db.Job.fetch('id = 1').next()
1096 queue_entry = monitor_db.HostQueueEntry.fetch('id = 1').next()
1097 agent = job.run(queue_entry)
1098
showard2bab8f42008-11-12 18:15:22 +00001099 self.god.check_playback()
showarde77ac672008-11-14 22:42:33 +00001100 self.assertEquals(models.HostQueueEntry.smart_get(1).status,
1101 expected_status)
showard2bab8f42008-11-12 18:15:22 +00001102
showard9976ce92008-10-15 20:28:13 +00001103 if not expect_agent:
1104 self.assertEquals(agent, None)
1105 return
1106
showardb2e2c322008-10-14 17:33:55 +00001107 self.assert_(isinstance(agent, monitor_db.Agent))
1108 tasks = list(agent.queue.queue)
1109 return tasks
1110
1111
1112 def test_run_asynchronous(self):
1113 self._create_job(hosts=[1, 2])
1114
1115 tasks = self._test_run_helper()
1116
showard2bab8f42008-11-12 18:15:22 +00001117 self.assertEquals(len(tasks), 1)
1118 verify_task = tasks[0]
showardb2e2c322008-10-14 17:33:55 +00001119
1120 self.assert_(isinstance(verify_task, monitor_db.VerifyTask))
1121 self.assertEquals(verify_task.queue_entry.id, 1)
1122
showardb2e2c322008-10-14 17:33:55 +00001123
showard9976ce92008-10-15 20:28:13 +00001124 def test_run_asynchronous_skip_verify(self):
1125 job = self._create_job(hosts=[1, 2])
1126 job.run_verify = False
1127 job.save()
showard2bab8f42008-11-12 18:15:22 +00001128 self._setup_directory_expects('host1')
showard9976ce92008-10-15 20:28:13 +00001129
1130 tasks = self._test_run_helper()
1131
1132 self.assertEquals(len(tasks), 1)
1133 queue_task = tasks[0]
1134
1135 self.assert_(isinstance(queue_task, monitor_db.QueueTask))
1136 self.assertEquals(queue_task.job.id, 1)
1137
1138
showardb2e2c322008-10-14 17:33:55 +00001139 def test_run_synchronous_verify(self):
1140 self._create_job(hosts=[1, 2], synchronous=True)
1141
1142 tasks = self._test_run_helper()
1143 self.assertEquals(len(tasks), 1)
1144 verify_task = tasks[0]
1145
showard2bab8f42008-11-12 18:15:22 +00001146 self.assert_(isinstance(verify_task, monitor_db.VerifyTask))
showardb2e2c322008-10-14 17:33:55 +00001147 self.assertEquals(verify_task.queue_entry.id, 1)
1148
1149
showard9976ce92008-10-15 20:28:13 +00001150 def test_run_synchronous_skip_verify(self):
1151 job = self._create_job(hosts=[1, 2], synchronous=True)
1152 job.run_verify = False
1153 job.save()
1154
showarde77ac672008-11-14 22:42:33 +00001155 self._test_run_helper(
1156 expect_agent=False,
1157 expected_status=models.HostQueueEntry.Status.PENDING)
showard9976ce92008-10-15 20:28:13 +00001158
1159 queue_entry = models.HostQueueEntry.smart_get(1)
1160 self.assertEquals(queue_entry.status, 'Pending')
1161
1162
showardb2e2c322008-10-14 17:33:55 +00001163 def test_run_synchronous_ready(self):
1164 self._create_job(hosts=[1, 2], synchronous=True)
showard2bab8f42008-11-12 18:15:22 +00001165 self._update_hqe("status='Pending', execution_subdir='")
1166 self._setup_directory_expects('group0')
showardb2e2c322008-10-14 17:33:55 +00001167
1168 tasks = self._test_run_helper()
1169 self.assertEquals(len(tasks), 1)
1170 queue_task = tasks[0]
1171
1172 self.assert_(isinstance(queue_task, monitor_db.QueueTask))
1173 self.assertEquals(queue_task.job.id, 1)
1174 hqe_ids = [hqe.id for hqe in queue_task.queue_entries]
1175 self.assertEquals(hqe_ids, [1, 2])
1176
1177
showard21baa452008-10-21 00:08:39 +00001178 def test_reboot_before_always(self):
1179 job = self._create_job(hosts=[1])
showard0fc38302008-10-23 00:44:07 +00001180 job.reboot_before = models.RebootBefore.ALWAYS
showard21baa452008-10-21 00:08:39 +00001181 job.save()
1182
1183 tasks = self._test_run_helper()
showard2bab8f42008-11-12 18:15:22 +00001184 self.assertEquals(len(tasks), 2)
showard45ae8192008-11-05 19:32:53 +00001185 cleanup_task = tasks[0]
1186 self.assert_(isinstance(cleanup_task, monitor_db.CleanupTask))
1187 self.assertEquals(cleanup_task.host.id, 1)
showard21baa452008-10-21 00:08:39 +00001188
1189
1190 def _test_reboot_before_if_dirty_helper(self, expect_reboot):
1191 job = self._create_job(hosts=[1])
showard0fc38302008-10-23 00:44:07 +00001192 job.reboot_before = models.RebootBefore.IF_DIRTY
showard21baa452008-10-21 00:08:39 +00001193 job.save()
1194
1195 tasks = self._test_run_helper()
showard2bab8f42008-11-12 18:15:22 +00001196 self.assertEquals(len(tasks), expect_reboot and 2 or 1)
showard21baa452008-10-21 00:08:39 +00001197 if expect_reboot:
showard45ae8192008-11-05 19:32:53 +00001198 cleanup_task = tasks[0]
1199 self.assert_(isinstance(cleanup_task, monitor_db.CleanupTask))
1200 self.assertEquals(cleanup_task.host.id, 1)
showard21baa452008-10-21 00:08:39 +00001201
1202 def test_reboot_before_if_dirty(self):
1203 models.Host.smart_get(1).update_object(dirty=True)
1204 self._test_reboot_before_if_dirty_helper(True)
1205
1206
1207 def test_reboot_before_not_dirty(self):
1208 models.Host.smart_get(1).update_object(dirty=False)
1209 self._test_reboot_before_if_dirty_helper(False)
1210
1211
1212
showardce38e0c2008-05-29 19:36:16 +00001213if __name__ == '__main__':
jadmanski0afbb632008-06-06 21:10:57 +00001214 unittest.main()