1# setup (you can ignore this) 2# ########################### 3 4# a bit of setup to allow overriding rpc_interace with an RPC proxy 5# (to use RPC, we would say 6# import rpc_client_lib 7# rpc_interface = rpc_client_lib.get_proxy( 8# 'http://hostname:8000/afe/server/noauth/rpc/') 9# ) 10>>> if 'rpc_interface' not in globals(): 11... from autotest_lib.frontend.afe import rpc_interface, models 12... from autotest_lib.frontend import thread_local 13... # set up a user for us to "login" as 14... user = models.User(login='debug_user') 15... user.access_level = 100 16... user.save() 17... thread_local.set_user(user) 18... 19>>> from autotest_lib.frontend.afe import model_logic 20 21# get directory of this test file; we'll need it later 22>>> import common 23>>> from autotest_lib.frontend.afe import test 24>>> import os, datetime 25>>> test_path = os.path.join(os.path.dirname(test.__file__), 26... 'doctests') 27>>> test_path = os.path.abspath(test_path) 28 29# disable logging 30>>> from autotest_lib.client.common_lib import logging_manager 31>>> logging_manager.logger.setLevel(100) 32 33>>> drone_set = models.DroneSet.default_drone_set_name() 34>>> if drone_set: 35... _ = models.DroneSet.objects.create(name=drone_set) 36 37# mock up tko rpc_interface 38>>> from autotest_lib.client.common_lib.test_utils import mock 39>>> mock.mock_god().stub_function_to_return(rpc_interface.tko_rpc_interface, 40... 'get_status_counts', 41... None) 42 43# basic interface test 44###################### 45 46# echo a comment 47>>> rpc_interface.echo('test string to echo') 48'test string to echo' 49 50# basic object management 51# ####################### 52 53# create a label 54>>> rpc_interface.add_label(name='test_label') 551 56 57# we can modify the label by referencing its ID... 58>>> rpc_interface.modify_label(1, kernel_config='/my/kernel/config') 59 60# ...or by referencing it's name 61>>> rpc_interface.modify_label('test_label', platform=True) 62 63# we use get_labels to retrieve object data 64>>> data = rpc_interface.get_labels(name='test_label') 65>>> data == [{'id': 1, 66... 'name': 'test_label', 67... 'platform': 1, 68... 'kernel_config': '/my/kernel/config', 69... 'only_if_needed' : False, 70... 'invalid': 0, 71... 'atomic_group': None}] 72True 73 74# get_labels return multiple matches as lists of dictionaries 75>>> rpc_interface.add_label(name='label1', platform=False) 762 77>>> rpc_interface.add_label(name='label2', platform=True) 783 79>>> rpc_interface.add_label(name='label3', platform=False) 804 81>>> data = rpc_interface.get_labels(platform=False) 82>>> data == [{'id': 2, 'name': 'label1', 'platform': 0, 'kernel_config': '', 83... 'only_if_needed': False, 'invalid': 0, 'atomic_group': None}, 84... {'id': 4, 'name': 'label3', 'platform': 0, 'kernel_config': '', 85... 'only_if_needed': False, 'invalid': 0, 'atomic_group': None}] 86True 87 88# delete_label takes an ID or a name as well 89>>> rpc_interface.delete_label(3) 90>>> rpc_interface.get_labels(name='label2') 91[] 92>>> rpc_interface.delete_label('test_label') 93>>> rpc_interface.delete_label('label1') 94>>> rpc_interface.delete_label('label3') 95>>> rpc_interface.get_labels() 96[] 97 98# all the add*, modify*, delete*, and get* methods work the same way 99# hosts... 100>>> rpc_interface.add_host(hostname='ipaj1', locked=True, lock_reason='Locked device on creation') 1011 102>>> data = rpc_interface.get_hosts() 103 104# delete the lock_time field, since that can't be reliably checked 105>>> del data[0]['lock_time'] 106>>> data == [{'id': 1, 107... 'hostname': 'ipaj1', 108... 'locked': 1, 109... 'synch_id': None, 110... 'status': 'Ready', 111... 'labels': [], 112... 'atomic_group': None, 113... 'acls': ['Everyone'], 114... 'platform': None, 115... 'attributes': {}, 116... 'invalid': 0, 117... 'protection': 'No protection', 118... 'locked_by': 'debug_user', 119... 'dirty': True, 120... 'leased': 1, 121... 'shard': None, 122... 'lock_reason': 'Locked device on creation'}] 123True 124>>> rpc_interface.modify_host(id='ipaj1', status='Hello') 125Traceback (most recent call last): 126ValidationError: {'status': 'Host status can not be modified by the frontend.'} 127>>> rpc_interface.modify_host(id='ipaj1', hostname='ipaj1000') 128>>> rpc_interface.modify_hosts( 129... host_filter_data={'hostname': 'ipaj1000'}, 130... update_data={'locked': False}) 131>>> data = rpc_interface.get_hosts() 132>>> bool(data[0]['locked']) 133False 134 135# test already locked/unlocked failures 136>>> rpc_interface.modify_host(id='ipaj1000', locked=False) 137Traceback (most recent call last): 138ValidationError: {'locked': u'Host ipaj1000 already unlocked.'} 139>>> rpc_interface.modify_host(id='ipaj1000', locked=True, lock_reason='Locking a locked device') 140>>> try: 141... rpc_interface.modify_host(id='ipaj1000', locked=True) 142... except model_logic.ValidationError, err: 143... pass 144>>> assert ('locked' in err.message_dict 145... and err.message_dict['locked'].startswith('Host ipaj1000 already locked')) 146>>> rpc_interface.delete_host(id='ipaj1000') 147>>> rpc_interface.get_hosts() == [] 148True 149 150# tests... 151>>> rpc_interface.add_test(name='sleeptest', test_type='Client', author='Test', 152... description='Sleep Test', test_time=1, 153... test_category='Functional', 154... test_class='Kernel', path='sleeptest') 1551 156>>> rpc_interface.modify_test('sleeptest', path='/my/path') 157>>> data = rpc_interface.get_tests() 158>>> data == [{'id': 1, 159... 'name': 'sleeptest', 160... 'author': 'Test', 161... 'description': 'Sleep Test', 162... 'dependencies': '', 163... 'experimental': 1, 164... 'sync_count': 1, 165... 'test_type': 'Client', 166... 'test_class': 'Kernel', 167... 'test_time': 'SHORT', 168... 'run_verify': 0, 169... 'run_reset': 1, 170... 'test_category': 'Functional', 171... 'path': '/my/path', 172... 'test_retry': 0}] 173True 174>>> rpc_interface.delete_test('sleeptest') 175>>> rpc_interface.get_tests() == [] 176True 177 178# profilers... 179>>> rpc_interface.add_profiler(name='oprofile') 1801 181>>> rpc_interface.modify_profiler('oprofile', description='Oh profile!') 182>>> data = rpc_interface.get_profilers() 183>>> data == [{'id': 1, 184... 'name': 'oprofile', 185... 'description': 'Oh profile!'}] 186True 187>>> rpc_interface.delete_profiler('oprofile') 188>>> rpc_interface.get_profilers() == [] 189True 190 191 192# users... 193>>> rpc_interface.add_user(login='showard') 1942 195>>> rpc_interface.modify_user('showard', access_level=1) 196>>> data = rpc_interface.get_users(login='showard') 197>>> data == [{'id': 2, 198... 'login': 'showard', 199... 'access_level': 1, 200... 'reboot_before': 'If dirty', 201... 'reboot_after': 'Never', 202... 'drone_set': None, 203... 'show_experimental': False}] 204True 205>>> rpc_interface.delete_user('showard') 206>>> rpc_interface.get_users(login='showard') == [] 207True 208 209# acl groups... 210# 1 ACL group already exists, named "Everyone" (ID 1) 211>>> rpc_interface.add_acl_group(name='my_group') 2122 213>>> rpc_interface.modify_acl_group('my_group', description='my new acl group') 214>>> data = rpc_interface.get_acl_groups(name='my_group') 215>>> data == [{'id': 2, 216... 'name': 'my_group', 217... 'description': 'my new acl group', 218... 'users': ['debug_user'], 219... 'hosts': []}] 220True 221>>> rpc_interface.delete_acl_group('my_group') 222>>> data = rpc_interface.get_acl_groups() 223>>> data == [{'id': 1, 224... 'name': 'Everyone', 225... 'description': '', 226... 'users': ['debug_user'], 227... 'hosts': []}] 228True 229 230 231# managing many-to-many relationships 232# ################################### 233 234# first, create some hosts and labels to play around with 235>>> rpc_interface.add_host(hostname='host1') 2362 237>>> rpc_interface.add_host(hostname='host2') 2383 239>>> rpc_interface.add_label(name='label1') 2402 241>>> rpc_interface.add_label(name='label2', platform=True) 2423 243 244# add hosts to labels 245>>> rpc_interface.host_add_labels(id='host1', labels=['label1']) 246>>> rpc_interface.host_add_labels(id='host2', labels=['label1', 'label2']) 247 248# check labels for hosts 249>>> data = rpc_interface.get_hosts(hostname='host1') 250>>> data[0]['labels'] 251[u'label1'] 252>>> data = rpc_interface.get_hosts(hostname='host2') 253>>> data[0]['labels'] 254[u'label1', u'label2'] 255>>> data[0]['platform'] 256u'label2' 257 258# check host lists for labels -- use double underscore to specify fields of 259# related objects 260>>> data = rpc_interface.get_hosts(labels__name='label1') 261>>> [host['hostname'] for host in data] 262[u'host1', u'host2'] 263>>> data = rpc_interface.get_hosts(labels__name='label2') 264>>> [host['hostname'] for host in data] 265[u'host2'] 266 267# remove a host from a label 268>>> rpc_interface.host_remove_labels(id='host2', labels=['label2']) 269>>> data = rpc_interface.get_hosts(hostname='host1') 270>>> data[0]['labels'] 271[u'label1'] 272>>> rpc_interface.get_hosts(labels__name='label2') 273[] 274 275# Cleanup 276>>> rpc_interface.host_remove_labels(id='host2', labels=['label1']) 277>>> rpc_interface.host_remove_labels(id='host1', labels=['label1']) 278 279 280# Other interface for new CLI 281# add hosts to labels 282>>> rpc_interface.label_add_hosts(id='label1', hosts=['host1']) 283>>> rpc_interface.label_add_hosts(id='label2', hosts=['host1', 'host2']) 284 285# check labels for hosts 286>>> data = rpc_interface.get_hosts(hostname='host1') 287>>> data[0]['labels'] 288[u'label1', u'label2'] 289>>> data = rpc_interface.get_hosts(hostname='host2') 290>>> data[0]['labels'] 291[u'label2'] 292>>> data[0]['platform'] 293u'label2' 294 295# check host lists for labels -- use double underscore to specify fields of 296# related objects 297>>> data = rpc_interface.get_hosts(labels__name='label1') 298>>> [host['hostname'] for host in data] 299[u'host1'] 300>>> data = rpc_interface.get_hosts(labels__name='label2') 301>>> [host['hostname'] for host in data] 302[u'host1', u'host2'] 303 304# remove a host from a label 305>>> rpc_interface.label_remove_hosts(id='label2', hosts=['host2']) 306>>> data = rpc_interface.get_hosts(hostname='host1') 307>>> data[0]['labels'] 308[u'label1', u'label2'] 309>>> data = rpc_interface.get_hosts(labels__name='label2') 310>>> [host['hostname'] for host in data] 311[u'host1'] 312 313# Remove multiple hosts from a label 314>>> rpc_interface.label_add_hosts(id='label2', hosts=['host2']) 315>>> data = rpc_interface.get_hosts(labels__name='label2') 316>>> [host['hostname'] for host in data] 317[u'host1', u'host2'] 318>>> rpc_interface.label_remove_hosts(id='label2', hosts=['host2', 'host1']) 319>>> rpc_interface.get_hosts(labels__name='label2') 320[] 321 322 323# ACL group relationships work similarly 324# note that all users are a member of 'Everyone' by default, and that hosts are 325# automatically made a member of 'Everyone' only when they are a member of no 326# other group 327>>> data = rpc_interface.get_acl_groups(hosts__hostname='host1') 328>>> [acl_group['name'] for acl_group in data] 329[u'Everyone'] 330 331>>> rpc_interface.add_user(login='showard', access_level=0) 3322 333>>> rpc_interface.add_acl_group(name='my_group') 3342 335 336>>> rpc_interface.acl_group_add_users('my_group', ['showard']) 337>>> rpc_interface.acl_group_add_hosts('my_group', ['host1']) 338>>> data = rpc_interface.get_acl_groups(name='my_group') 339>>> data[0]['users'] 340[u'debug_user', u'showard'] 341>>> data[0]['hosts'] 342[u'host1'] 343>>> data = rpc_interface.get_acl_groups(users__login='showard') 344>>> [acl_group['name'] for acl_group in data] 345[u'Everyone', u'my_group'] 346 347# note host has been automatically removed from 'Everyone' 348>>> data = rpc_interface.get_acl_groups(hosts__hostname='host1') 349>>> [acl_group['name'] for acl_group in data] 350[u'my_group'] 351 352>>> rpc_interface.acl_group_remove_users('my_group', ['showard']) 353>>> rpc_interface.acl_group_remove_hosts('my_group', ['host1']) 354>>> data = rpc_interface.get_acl_groups(name='my_group') 355>>> data[0]['users'], data[0]['hosts'] 356([u'debug_user'], []) 357>>> data = rpc_interface.get_acl_groups(users__login='showard') 358>>> [acl_group['name'] for acl_group in data] 359[u'Everyone'] 360 361# note host has been automatically added back to 'Everyone' 362>>> data = rpc_interface.get_acl_groups(hosts__hostname='host1') 363>>> [acl_group['name'] for acl_group in data] 364[u'Everyone'] 365 366 367# host attributes 368 369>>> rpc_interface.set_host_attribute('color', 'red', hostname='host1') 370>>> data = rpc_interface.get_hosts(hostname='host1') 371>>> data[0]['attributes'] 372{u'color': u'red'} 373 374>>> rpc_interface.set_host_attribute('color', None, hostname='host1') 375>>> data = rpc_interface.get_hosts(hostname='host1') 376>>> data[0]['attributes'] 377{} 378 379 380# host bulk modify 381################## 382 383>>> rpc_interface.modify_hosts( 384... host_filter_data={'hostname__in': ['host1', 'host2']}, 385... update_data={'locked': True, 'lock_reason': 'Locked for testing'}) 386>>> data = rpc_interface.get_hosts(hostname__in=['host1', 'host2']) 387 388>>> data[0]['locked'] 389True 390>>> data[1]['locked'] 391True 392 393>>> rpc_interface.modify_hosts( 394... host_filter_data={'id': 2}, 395... update_data={'locked': False}) 396>>> data = rpc_interface.get_hosts(hostname__in=['host1', 'host2']) 397 398>>> data[0]['locked'] 399False 400>>> data[1]['locked'] 401True 402 403 404# job management 405# ############ 406 407# note that job functions require job IDs to identify jobs, since job names are 408# not unique 409 410# add some entries to play with 411>>> rpc_interface.add_label(name='my_label', kernel_config='my_kernel_config') 4125 413>>> test_control_path = os.path.join(test_path, 'test.control') 414>>> rpc_interface.add_test(name='sleeptest', test_type='Client', author='Test', 415... test_category='Test', 416... test_class='Kernel', path=test_control_path) 4171 418>>> test_control_path = os.path.join(test_path, 'test.control.2') 419>>> rpc_interface.add_test(name='my_test', test_type='Client', author='Test', 420... test_category='Test', 421... test_class='Kernel', path=test_control_path) 4222 423>>> rpc_interface.add_host(hostname='my_label_host1') 4244 425>>> rpc_interface.add_host(hostname='my_label_host2') 4265 427>>> rpc_interface.label_add_hosts(id='my_label', hosts=['my_label_host1', 'my_label_host2']) 428 429# generate a control file 430>>> cf_info = rpc_interface.generate_control_file( 431... tests=['sleeptest', 'my_test'], 432... kernel=[{'version': '2.6.18'}, {'version': '2.6.18-blah.rpm'}, 433... {'version': '2.6.26', 'cmdline': 'foo bar'}], 434... label='my_label') 435>>> print cf_info['control_file'] #doctest: +NORMALIZE_WHITESPACE 436kernel_list = [{'version': '2.6.18', 'config_file': u'my_kernel_config'}, {'version': '2.6.18-blah.rpm', 'config_file': None}, {'cmdline': 'foo bar', 'version': '2.6.26', 'config_file': u'my_kernel_config'}] 437def step_init(): 438 for kernel_info in kernel_list: 439 job.next_step(boot_kernel, kernel_info) 440 job.next_step(step_test, kernel_info['version']) 441 if len(kernel_list) > 1: 442 job.use_sequence_number = True # include run numbers in directory names 443def boot_kernel(kernel_info): 444 # remove kernels (and associated data) not referenced by the bootloader 445 for host in job.hosts: 446 host.cleanup_kernels() 447 testkernel = job.kernel(kernel_info['version']) 448 if kernel_info['config_file']: 449 testkernel.config(kernel_info['config_file']) 450 testkernel.build() 451 testkernel.install() 452 cmdline = ' '.join((kernel_info.get('cmdline', ''), '')) 453 testkernel.boot(args=cmdline) 454def step_test(kernel_version): 455 global kernel 456 kernel = kernel_version # Set the global in case anyone is using it. 457 if len(kernel_list) > 1: 458 # this is local to a machine, safe to assume there's only one host 459 host, = job.hosts 460 job.automatic_test_tag = host.get_kernel_ver() 461 job.next_step('step0') 462 job.next_step('step1') 463def step0(): 464 job.run_test('testname') 465def step1(): 466 job.run_test('testname') 467>>> cf_info['is_server'], cf_info['synch_count'], cf_info['dependencies'] 468(False, 1, []) 469 470# generate a control file from existing body text. 471>>> cf_info_pi = rpc_interface.generate_control_file( 472... kernel=[{'version': '3.1.41'}], label='my_label', 473... client_control_file='print "Hi"\n') 474>>> print cf_info_pi['control_file'] #doctest: +NORMALIZE_WHITESPACE 475kernel_list = [{'version': '3.1.41', 'config_file': u'my_kernel_config'}] 476def step_init(): 477 for kernel_info in kernel_list: 478 job.next_step(boot_kernel, kernel_info) 479 job.next_step(step_test, kernel_info['version']) 480 if len(kernel_list) > 1: 481 job.use_sequence_number = True # include run numbers in directory names 482def boot_kernel(kernel_info): 483 # remove kernels (and associated data) not referenced by the bootloader 484 for host in job.hosts: 485 host.cleanup_kernels() 486 testkernel = job.kernel(kernel_info['version']) 487 if kernel_info['config_file']: 488 testkernel.config(kernel_info['config_file']) 489 testkernel.build() 490 testkernel.install() 491 cmdline = ' '.join((kernel_info.get('cmdline', ''), '')) 492 testkernel.boot(args=cmdline) 493def step_test(kernel_version): 494 global kernel 495 kernel = kernel_version # Set the global in case anyone is using it. 496 if len(kernel_list) > 1: 497 # this is local to a machine, safe to assume there's only one host 498 host, = job.hosts 499 job.automatic_test_tag = host.get_kernel_ver() 500 job.next_step('step0') 501def step0(): 502 print "Hi" 503 return locals() 504 505# create a job to run on host1, host2, and any two machines in my_label 506>>> rpc_interface.create_job(name='my_job', 507... priority=10, 508... control_file=cf_info['control_file'], 509... control_type='Client', 510... hosts=['host1', 'host2'], 511... meta_hosts=['my_label', 'my_label']) 5121 513 514# get job info - this does not include status info for particular hosts 515>>> data = rpc_interface.get_jobs() 516>>> data = data[0] 517>>> data['id'], data['owner'], data['name'], data['priority'] 518(1, u'debug_user', u'my_job', 10) 519>>> data['control_file'] == cf_info['control_file'] 520True 521>>> data['control_type'] 522'Client' 523 524>>> today = datetime.date.today() 525>>> data['created_on'].startswith( 526... '%d-%02d-%02d' % (today.year, today.month, today.day)) 527True 528 529# get_num_jobs - useful when dealing with large numbers of jobs 530>>> rpc_interface.get_num_jobs(name='my_job') 5311 532 533# check host queue entries for a job 534>>> data = rpc_interface.get_host_queue_entries(job=1) 535>>> len(data) 5364 537 538# get rid of created_on, it's nondeterministic 539>>> data[0]['job']['created_on'] = data[2]['job']['created_on'] = None 540 541# get_host_queue_entries returns full info about the job within each queue entry 542>>> job = data[0]['job'] 543>>> job == {'control_file': cf_info['control_file'], # the control file we used 544... 'control_type': 'Client', 545... 'created_on': None, 546... 'id': 1, 547... 'name': 'my_job', 548... 'owner': 'debug_user', 549... 'priority': 10, 550... 'synch_count': 0, 551... 'timeout': 24, 552... 'timeout_mins': 1440, 553... 'max_runtime_mins': 1440, 554... 'max_runtime_hrs' : 72, 555... 'run_verify': False, 556... 'run_reset': True, 557... 'email_list': '', 558... 'reboot_before': 'If dirty', 559... 'reboot_after': 'Never', 560... 'parse_failed_repair': True, 561... 'drone_set': drone_set, 562... 'parameterized_job': None, 563... 'test_retry': 0, 564... 'parent_job': None, 565... 'shard': None, 566... 'require_ssp': None} 567True 568 569# get_host_queue_entries returns a lot of data, so let's only check a couple 570>>> data[0] == ( 571... {'active': 0, 572... 'complete': 0, 573... 'host': {'hostname': 'host1', # full host info here 574... 'id': 2, 575... 'invalid': 0, 576... 'locked': 0, 577... 'status': 'Ready', 578... 'synch_id': None, 579... 'protection': 'No protection', 580... 'locked_by': None, 581... 'lock_time': None, 582... 'lock_reason': 'Locked for testing', 583... 'dirty': True, 584... 'leased': 1, 585... 'shard': None}, 586... 'id': 1, 587... 'job': job, # full job info here 588... 'meta_host': None, 589... 'status': 'Queued', 590... 'deleted': 0, 591... 'execution_subdir': '', 592... 'atomic_group': None, 593... 'aborted': False, 594... 'started_on': None, 595... 'finished_on': None, 596... 'full_status': 'Queued'}) 597True 598>>> data[2] == ( 599... {'active': 0, 600... 'complete': 0, 601... 'host': None, 602... 'id': 3, 603... 'job': job, 604... 'meta_host': 'my_label', 605... 'status': 'Queued', 606... 'deleted': 0, 607... 'execution_subdir': '', 608... 'atomic_group': None, 609... 'aborted': False, 610... 'started_on': None, 611... 'finished_on': None, 612... 'full_status': 'Queued'}) 613True 614>>> rpc_interface.get_num_host_queue_entries(job=1) 6154 616>>> rpc_interface.get_hqe_percentage_complete(job=1) 6170.0 618 619# get_jobs_summary adds status counts to the rest of the get_jobs info 620>>> data = rpc_interface.get_jobs_summary() 621>>> counts = data[0]['status_counts'] 622>>> counts 623{u'Queued': 4} 624 625# abort the job 626>>> data = rpc_interface.abort_host_queue_entries(job__id=1) 627>>> data = rpc_interface.get_jobs_summary(id=1) 628>>> data[0]['status_counts'] 629{u'Aborted (Queued)': 4} 630 631# Remove the two hosts in my_label 632>>> rpc_interface.delete_host(id='my_label_host1') 633>>> rpc_interface.delete_host(id='my_label_host2') 634 635 636# extra querying parameters 637# ######################### 638 639# get_* methods can take query_start and query_limit arguments to implement 640# paging and a sort_by argument to specify the sort column 641>>> data = rpc_interface.get_hosts(query_limit=1) 642>>> [host['hostname'] for host in data] 643[u'host1'] 644>>> data = rpc_interface.get_hosts(query_start=1, query_limit=1) 645>>> [host['hostname'] for host in data] 646[u'host2'] 647 648# sort_by = ['-hostname'] indicates sorting in descending order by hostname 649>>> data = rpc_interface.get_hosts(sort_by=['-hostname']) 650>>> [host['hostname'] for host in data] 651[u'host2', u'host1'] 652 653 654# cloning a job 655# ############# 656 657>>> job_id = rpc_interface.create_job(name='my_job_to_clone', 658... priority=50, 659... control_file=cf_info['control_file'], 660... control_type='Client', 661... hosts=['host2'], 662... synch_count=1) 663>>> info = rpc_interface.get_info_for_clone(job_id, False) 664>>> info['atomic_group_name'] 665>>> info['meta_host_counts'] 666{} 667>>> info['job']['dependencies'] 668[] 669>>> info['job']['priority'] 67050 671 672 673# advanced usage 674# ############## 675 676# synch_count 677>>> job_id = rpc_interface.create_job(name='my_job', 678... priority=10, 679... control_file=cf_info['control_file'], 680... control_type='Server', 681... synch_count=2, 682... hosts=['host1', 'host2']) 683 684>>> data = rpc_interface.get_jobs(id=job_id) 685>>> data[0]['synch_count'] 6862 687 688# get hosts ACL'd to a user 689>>> hosts = rpc_interface.get_hosts(aclgroup__users__login='debug_user') 690>>> sorted([host['hostname'] for host in hosts]) 691[u'host1', u'host2'] 692 693>>> rpc_interface.add_acl_group(name='mygroup') 6943 695>>> rpc_interface.acl_group_add_users('mygroup', ['debug_user']) 696>>> rpc_interface.acl_group_add_hosts('mygroup', ['host1']) 697>>> data = rpc_interface.get_acl_groups(name='Everyone')[0] 698>>> data['users'], data['hosts'] 699([u'debug_user', u'showard'], [u'host2']) 700>>> data = rpc_interface.get_acl_groups(name='mygroup')[0] 701>>> data['users'], data['hosts'] 702([u'debug_user'], [u'host1']) 703 704>>> hosts = rpc_interface.get_hosts(aclgroup__users__login='debug_user') 705>>> sorted([host['hostname'] for host in hosts]) 706[u'host1', u'host2'] 707>>> hosts = rpc_interface.get_hosts(aclgroup__users__login='showard') 708>>> [host['hostname'] for host in hosts] 709[u'host2'] 710 711>>> rpc_interface.delete_acl_group('mygroup') 712>>> data = rpc_interface.get_acl_groups(name='Everyone')[0] 713>>> sorted(data['hosts']) 714[u'host1', u'host2'] 715 716# atomic groups 717# ############# 718 719# Add an atomic group and associate some labels and new hosts with it. 720>>> mini_rack_group_id = rpc_interface.add_atomic_group( 721... name='mini rack', 722... max_number_of_machines=10, 723... description='a partial rack-o-machines') 724 725>>> label_id = rpc_interface.add_label(name='one-label') 726>>> rpc_interface.modify_label(label_id, atomic_group='mini rack') 727>>> labels = rpc_interface.get_labels(id=label_id) 728>>> assert labels[0]['atomic_group']['id'] == mini_rack_group_id, labels 729>>> rpc_interface.modify_label(label_id, atomic_group=None) 730>>> labels = rpc_interface.get_labels(id=label_id) 731>>> assert not labels[0]['atomic_group'], labels 732>>> rpc_interface.modify_label(label_id, atomic_group='mini rack') 733>>> labels = rpc_interface.get_labels(id=label_id) 734>>> assert labels[0]['atomic_group']['id'] == mini_rack_group_id, labels 735>>> data = rpc_interface.get_labels(atomic_group__name='mini rack') 736>>> assert len(data) == 1 737>>> assert data[0]['name'] == 'one-label', data 738>>> assert data[0]['atomic_group']['id'] == mini_rack_group_id, data 739 740>>> data = rpc_interface.get_atomic_groups() 741>>> assert len(data) == 1 742>>> assert data[0]['id'] == mini_rack_group_id, data 743>>> assert data[0]['max_number_of_machines'] == 10, data 744>>> assert data[0]['description'] == 'a partial rack-o-machines', data 745 746>>> rpc_interface.modify_atomic_group(1, max_number_of_machines=8) 747>>> data = rpc_interface.get_atomic_groups() 748>>> assert data[0]['max_number_of_machines'] == 8, data 749 750>>> unused = rpc_interface.add_host(hostname='ahost1') 751>>> unused = rpc_interface.add_host(hostname='ahost2') 752>>> unused = rpc_interface.add_host(hostname='ah3-blue') 753>>> unused = rpc_interface.add_host(hostname='ah4-blue') 754>>> two_id = rpc_interface.add_label(name='two-label') 755>>> rpc_interface.label_add_hosts( 756... id=two_id, hosts=['ahost1', 'ahost2', 'ah3-blue', 'ah4-blue']) 757>>> unused = rpc_interface.add_label(name='red-label') 758>>> blue_id = rpc_interface.add_label(name='blue-label') 759>>> rpc_interface.label_add_hosts(id=blue_id, hosts=['ah3-blue', 'ah4-blue']) 760 761>>> rpc_interface.atomic_group_add_labels(mini_rack_group_id, 762... ['one-label', 'two-label', 763... 'red-label']) 764>>> ag_labels = rpc_interface.get_labels(atomic_group__name='mini rack') 765>>> len(ag_labels) 7663 767>>> hosts_in_two = rpc_interface.get_hosts(multiple_labels=['two-label']) 768>>> list(sorted(h['hostname'] for h in hosts_in_two)) 769[u'ah3-blue', u'ah4-blue', u'ahost1', u'ahost2'] 770>>> rpc_interface.atomic_group_remove_labels(mini_rack_group_id, ['red-label']) 771>>> ag_labels = rpc_interface.get_labels(atomic_group__name='mini rack') 772>>> sorted(label['name'] for label in ag_labels) 773[u'one-label', u'two-label'] 774 775>>> host_list = rpc_interface.get_hosts() 776>>> hosts_by_name = {} 777>>> for host in host_list: 778... hosts_by_name[host['hostname']] = host 779... 780>>> hosts_by_name['host1']['atomic_group'] 781>>> hosts_by_name['ahost1']['atomic_group'] 782u'mini rack' 783>>> hosts_by_name['ah3-blue']['atomic_group'] 784u'mini rack' 785>>> host_list = rpc_interface.get_hosts(labels__atomic_group__name='mini rack') 786>>> list(sorted(h['hostname'] for h in host_list)) 787[u'ah3-blue', u'ah4-blue', u'ahost1', u'ahost2'] 788 789 790 791## Test creation of a job in an atomic group without specifying any 792## hosts or meta_hosts. 793 794>>> sleep_cf_info = rpc_interface.generate_control_file( 795... tests=['sleeptest'], kernel=[{'version': '2.6.18'}], 796... label='two-label') 797>>> job_id = rpc_interface.create_job( 798... name='atomic_sleeptest', priority=30, 799... control_file=sleep_cf_info['control_file'], 800... control_type='Server', synch_count=1, 801... atomic_group_name='mini rack') 802 803## Test creation of a job in an atomic group by specifying the atomic group 804## name as a meta_host rather than explicitly using the atomic_group_name 805## parameter. 806 807>>> job_id = rpc_interface.create_job( 808... name='atomic_sleeptest', priority=30, 809... control_file=sleep_cf_info['control_file'], 810... control_type='Server', synch_count=1, 811... meta_hosts=['mini rack']) 812>>> job_id = rpc_interface.create_job( 813... name='atomic_sleeptest', priority=30, 814... control_file=sleep_cf_info['control_file'], 815... control_type='Server', synch_count=1, 816... meta_hosts=['mini rack'], 817... atomic_group_name='Different') 818Traceback (most recent call last): 819ValidationError: {'meta_hosts': 'Label "mini rack" not found. If assumed to be an atomic group it would conflict with the supplied atomic group "Different".'} 820 821## Test job creation with an atomic group. 822 823# fail to create a job in an atomic group. one_time_hosts not allowed. 824>>> rpc_interface.create_job(name='my_atomic_job', 825... priority=50, 826... control_file=cf_info['control_file'], 827... control_type='Server', 828... one_time_hosts=['hostX', 'hostY'], 829... synch_count=2, 830... atomic_group_name='mini rack') 831Traceback (most recent call last): 832ValidationError: {'one_time_hosts': 'One time hosts cannot be used with an Atomic Group.'} 833 834# fail to create a job in an atomic group. Synch count larger than max 835>>> rpc_interface.create_job(name='my_atomic_job', 836... priority=50, 837... control_file=cf_info['control_file'], 838... control_type='Server', 839... synch_count=25, 840... atomic_group_name='mini rack') 841Traceback (most recent call last): 842ValidationError: {'atomic_group_name': 'You have requested a synch_count (25) greater than the maximum machines in the requested Atomic Group (8).'} 843 844# fail to create a job in an atomic group. not enough hosts due to host list. 845>>> rpc_interface.create_job(name='my_atomic_job', 846... priority=50, 847... control_file=cf_info['control_file'], 848... control_type='Server', 849... hosts=['ahost1', 'ahost2'], 850... synch_count=3, 851... atomic_group_name='mini rack') 852Traceback (most recent call last): 853ValidationError: {'hosts': 'only 2 hosts provided for job with synch_count = 3'} 854 855# fail to create a job in an atomic group. hosts not in atomic group. 856>>> rpc_interface.create_job(name='my_atomic_job', 857... priority=50, 858... control_file=cf_info['control_file'], 859... control_type='Server', 860... hosts=['host1', 'host2'], 861... synch_count=2, 862... atomic_group_name='mini rack') 863Traceback (most recent call last): 864ValidationError: {'hosts': u'Hosts "host1, host2" are not in Atomic Group "mini rack"'} 865 866# fail to create a job in an atomic group. not enough hosts due to meta_hosts. 867>>> rpc_interface.create_job(name='my_atomic_job', 868... priority=50, 869... control_file=cf_info['control_file'], 870... control_type='Server', 871... meta_hosts=['blue-label'], 872... synch_count=4, 873... atomic_group_name='mini rack') 874Traceback (most recent call last): 875ValidationError: {'atomic_group_name': u'Insufficient hosts in Atomic Group "mini rack" with the supplied dependencies and meta_hosts.'} 876 877# fail to create a job in an atomic group. not enough hosts. 878>>> rpc_interface.create_job(name='my_atomic_job', 879... priority=50, 880... control_file=cf_info['control_file'], 881... control_type='Server', 882... synch_count=5, 883... atomic_group_name='mini rack') 884Traceback (most recent call last): 885ValidationError: {'atomic_group_name': u'Insufficient hosts in Atomic Group "mini rack" with the supplied dependencies and meta_hosts.'} 886 887# create a job in an atomic group. 888>>> job_id = rpc_interface.create_job(name='my_atomic_job', 889... priority=50, 890... control_file=cf_info['control_file'], 891... control_type='Server', 892... hosts=['ahost1', 'ahost2'], 893... meta_hosts=['blue-label'], 894... synch_count=4, 895... atomic_group_name='mini rack') 896 897>>> data = rpc_interface.get_host_queue_entries(job__id=job_id) 898>>> data[0]['atomic_group']['id'] 8991 900 901# create a job using hosts in an atomic group but forget to specify the group. 902>>> rpc_interface.create_job(name='poke_foo', 903... priority=10, 904... control_file=cf_info['control_file'], 905... control_type='Client', 906... hosts=['ahost1', 'ahost2']) 907Traceback (most recent call last): 908ValidationError: {'hosts': u'Host(s) "ahost1, ahost2" are atomic group hosts but no atomic group was specified for this job.'} 909 910# Create a job using a label in an atomic group as the meta-host but forget 911# to specify the group. The frontend should figure this out for us. 912>>> job_id = rpc_interface.create_job(name='created_without_explicit_ag', 913... priority=50, 914... control_file=cf_info['control_file'], 915... control_type='Client', 916... meta_hosts=['two-label']) 917 918>>> job_id = rpc_interface.create_job( 919... name='atomic_sleeptest', priority=30, 920... control_file=sleep_cf_info['control_file'], 921... control_type='Server', synch_count=1, 922... meta_hosts=['two-label'], 923... dependencies=['blue-label']) 924>>> peon_user = models.User(login='peon_user') 925>>> peon_user.access_level = 0 926>>> from autotest_lib.client.common_lib.test_utils import mock 927>>> god = mock.mock_god() 928>>> god.stub_function(models.User, "current_user") 929>>> models.User.current_user.expect_call().and_return(peon_user) 930>>> rpc_interface.abort_host_queue_entries(job__id=job_id) 931Traceback (most recent call last): 932AclAccessViolation: You cannot abort the following job entries: 8-debug_user/two-label 933>>> god.check_playback() 934>>> god.unstub_all() 935 936>>> rpc_interface.create_job(name='never_run2', 937... priority=50, 938... control_file=cf_info['control_file'], 939... control_type='Client', 940... meta_hosts=['blue-label'], 941... dependencies=['two-label']) 942Traceback (most recent call last): 943ValidationError: {'atomic_group_name': "Dependency u'two-label' requires an atomic group but no atomic_group_name or meta_host in an atomic group was specified for this job."} 944 945>>> invisible_group_id = rpc_interface.add_atomic_group( 946... name='invisible rack', 947... max_number_of_machines=3, 948... description='a hidden rack-o-machines') 949>>> rpc_interface.atomic_group_add_labels(invisible_group_id, 950... ['blue-label']) 951>>> rpc_interface.create_job(name='never_run3', 952... priority=50, 953... control_file=cf_info['control_file'], 954... control_type='Client', 955... meta_hosts=['two-label'], 956... atomic_group_name='invisible rack') 957Traceback (most recent call last): 958ValidationError: {'atomic_group_name': "meta_hosts or dependency u'two-label' requires atomic group u'mini rack' instead of the supplied atomic_group_name=u'invisible rack'."} 959 960# we're done testing atomic groups, clean up 961>>> rpc_interface.delete_atomic_group(invisible_group_id) 962>>> rpc_interface.delete_atomic_group(mini_rack_group_id) 963>>> assert len(rpc_interface.get_atomic_groups()) == 0 964