Home | History | Annotate | Download | only in doctests
      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 ...   user2 = models.User(login='showard')
     19 ...   user2.access_level = 1
     20 ...   user2.save()
     21 ...
     22 >>> from autotest_lib.frontend.afe import model_logic
     23 
     24 # get directory of this test file; we'll need it later
     25 >>> import common
     26 >>> from autotest_lib.frontend.afe import test
     27 >>> import os, datetime
     28 >>> test_path = os.path.join(os.path.dirname(test.__file__),
     29 ...                                          'doctests')
     30 >>> test_path = os.path.abspath(test_path)
     31 
     32 # disable logging
     33 >>> from autotest_lib.client.common_lib import logging_manager
     34 >>> logging_manager.logger.setLevel(100)
     35 
     36 >>> drone_set = models.DroneSet.default_drone_set_name()
     37 >>> if drone_set:
     38 ...     _ = models.DroneSet.objects.create(name=drone_set)
     39 
     40 # mock up tko rpc_interface
     41 >>> from autotest_lib.client.common_lib.test_utils import mock
     42 >>> mock.mock_god().stub_function_to_return(rpc_interface.tko_rpc_interface,
     43 ...                                         'get_status_counts',
     44 ...                                         None)
     45 
     46 # basic interface test
     47 ######################
     48 
     49 # echo a comment
     50 >>> rpc_interface.echo('test string to echo')
     51 'test string to echo'
     52 
     53 # basic object management
     54 # #######################
     55 
     56 # create a label
     57 >>> rpc_interface.add_label(name='test_label')
     58 1
     59 
     60 # we can modify the label by referencing its ID...
     61 >>> rpc_interface.modify_label(1, kernel_config='/my/kernel/config')
     62 
     63 # ...or by referencing it's name
     64 >>> rpc_interface.modify_label('test_label', platform=True)
     65 
     66 # we use get_labels to retrieve object data
     67 >>> data = rpc_interface.get_labels(name='test_label')
     68 >>> data == [{'id': 1,
     69 ...           'name': 'test_label',
     70 ...           'platform': 1,
     71 ...           'kernel_config': '/my/kernel/config',
     72 ...           'only_if_needed' : False,
     73 ...           'invalid': 0,
     74 ...           'atomic_group': None}]
     75 True
     76 
     77 # get_labels return multiple matches as lists of dictionaries
     78 >>> rpc_interface.add_label(name='label1', platform=False)
     79 2
     80 >>> rpc_interface.add_label(name='label2', platform=True)
     81 3
     82 >>> rpc_interface.add_label(name='label3', platform=False)
     83 4
     84 >>> data = rpc_interface.get_labels(platform=False)
     85 >>> data == [{'id': 2, 'name': 'label1', 'platform': 0, 'kernel_config': '',
     86 ...           'only_if_needed': False, 'invalid': 0, 'atomic_group': None},
     87 ...          {'id': 4, 'name': 'label3', 'platform': 0, 'kernel_config': '',
     88 ...           'only_if_needed': False, 'invalid': 0, 'atomic_group': None}]
     89 True
     90 
     91 # delete_label takes an ID or a name as well
     92 >>> rpc_interface.delete_label(3)
     93 >>> rpc_interface.get_labels(name='label2')
     94 []
     95 >>> rpc_interface.delete_label('test_label')
     96 >>> rpc_interface.delete_label('label1')
     97 >>> rpc_interface.delete_label('label3')
     98 >>> rpc_interface.get_labels()
     99 []
    100 
    101 # all the add*, modify*, delete*, and get* methods work the same way
    102 # hosts...
    103 >>> rpc_interface.add_host(hostname='ipaj1', locked=True, lock_reason='Locked device on creation')
    104 1
    105 >>> data = rpc_interface.get_hosts()
    106 
    107 # delete the lock_time field, since that can't be reliably checked
    108 >>> del data[0]['lock_time']
    109 >>> data == [{'id': 1,
    110 ...           'hostname': 'ipaj1',
    111 ...           'locked': 1,
    112 ...           'synch_id': None,
    113 ...           'status': 'Ready',
    114 ...           'labels': [],
    115 ...           'acls': ['Everyone'],
    116 ...           'platform': None,
    117 ...           'attributes': {},
    118 ...           'invalid': 0,
    119 ...           'protection': 'No protection',
    120 ...           'locked_by': 'debug_user',
    121 ...           'dirty': True,
    122 ...           'leased': 1,
    123 ...           'shard': None,
    124 ...           'lock_reason': 'Locked device on creation'}]
    125 True
    126 >>> rpc_interface.modify_host(id='ipaj1', status='Hello')
    127 Traceback (most recent call last):
    128 ValidationError: {'status': 'Host status can not be modified by the frontend.'}
    129 >>> rpc_interface.modify_host(id='ipaj1', hostname='ipaj1000')
    130 >>> rpc_interface.modify_hosts(
    131 ...     host_filter_data={'hostname': 'ipaj1000'},
    132 ...     update_data={'locked': False})
    133 >>> data = rpc_interface.get_hosts()
    134 >>> bool(data[0]['locked'])
    135 False
    136 
    137 # test already locked/unlocked failures
    138 >>> rpc_interface.modify_host(id='ipaj1000', locked=False)
    139 Traceback (most recent call last):
    140 ValidationError: {'locked': u'Host ipaj1000 already unlocked.'}
    141 >>> rpc_interface.modify_host(id='ipaj1000', locked=True, lock_reason='Locking a locked device')
    142 >>> try:
    143 ...     rpc_interface.modify_host(id='ipaj1000', locked=True)
    144 ... except model_logic.ValidationError, err:
    145 ...     pass
    146 >>> assert ('locked' in err.message_dict
    147 ...         and err.message_dict['locked'].startswith('Host ipaj1000 already locked'))
    148 >>> rpc_interface.delete_host(id='ipaj1000')
    149 >>> rpc_interface.get_hosts() == []
    150 True
    151 
    152 # tests...
    153 >>> rpc_interface.get_tests() == []
    154 True
    155 
    156 # profilers...
    157 >>> rpc_interface.add_profiler(name='oprofile')
    158 1
    159 >>> rpc_interface.modify_profiler('oprofile', description='Oh profile!')
    160 >>> data = rpc_interface.get_profilers()
    161 >>> data == [{'id': 1,
    162 ...           'name': 'oprofile',
    163 ...           'description': 'Oh profile!'}]
    164 True
    165 >>> rpc_interface.delete_profiler('oprofile')
    166 >>> rpc_interface.get_profilers() == []
    167 True
    168 
    169 
    170 # users...
    171 >>> data = rpc_interface.get_users(login='showard')
    172 >>> data == [{'id': 2,
    173 ...           'login': 'showard',
    174 ...           'access_level': 1,
    175 ...           'reboot_before': 'If dirty',
    176 ...           'reboot_after': 'Never',
    177 ...           'drone_set': None,
    178 ...           'show_experimental': False}]
    179 True
    180 
    181 # acl groups...
    182 # 1 ACL group already exists, named "Everyone" (ID 1)
    183 >>> rpc_interface.add_acl_group(name='my_group')
    184 2
    185 >>> rpc_interface.modify_acl_group('my_group', description='my new acl group')
    186 >>> data = rpc_interface.get_acl_groups(name='my_group')
    187 >>> data == [{'id': 2,
    188 ...           'name': 'my_group',
    189 ...           'description': 'my new acl group',
    190 ...           'users': ['debug_user'],
    191 ...           'hosts': []}]
    192 True
    193 >>> rpc_interface.delete_acl_group('my_group')
    194 >>> data = rpc_interface.get_acl_groups()
    195 >>> data == [{'id': 1,
    196 ...           'name': 'Everyone',
    197 ...           'description': '',
    198 ...           'users': ['debug_user', 'showard'],
    199 ...           'hosts': []}]
    200 True
    201 
    202 
    203 # managing many-to-many relationships
    204 # ###################################
    205 
    206 # first, create some hosts and labels to play around with
    207 >>> rpc_interface.add_host(hostname='host1')
    208 2
    209 >>> rpc_interface.add_host(hostname='host2')
    210 3
    211 >>> rpc_interface.add_label(name='label1')
    212 2
    213 >>> rpc_interface.add_label(name='label2', platform=True)
    214 3
    215 
    216 # add hosts to labels
    217 >>> rpc_interface.host_add_labels(id='host1', labels=['label1'])
    218 >>> rpc_interface.host_add_labels(id='host2', labels=['label1', 'label2'])
    219 
    220 # check labels for hosts
    221 >>> data = rpc_interface.get_hosts(hostname='host1')
    222 >>> data[0]['labels']
    223 [u'label1']
    224 >>> data = rpc_interface.get_hosts(hostname='host2')
    225 >>> data[0]['labels']
    226 [u'label1', u'label2']
    227 >>> data[0]['platform']
    228 u'label2'
    229 
    230 # check host lists for labels -- use double underscore to specify fields of
    231 # related objects
    232 >>> data = rpc_interface.get_hosts(labels__name='label1')
    233 >>> [host['hostname'] for host in data]
    234 [u'host1', u'host2']
    235 >>> data = rpc_interface.get_hosts(labels__name='label2')
    236 >>> [host['hostname'] for host in data]
    237 [u'host2']
    238 
    239 # remove a host from a label
    240 >>> rpc_interface.host_remove_labels(id='host2', labels=['label2'])
    241 >>> data = rpc_interface.get_hosts(hostname='host1')
    242 >>> data[0]['labels']
    243 [u'label1']
    244 >>> rpc_interface.get_hosts(labels__name='label2')
    245 []
    246 
    247 # Cleanup
    248 >>> rpc_interface.host_remove_labels(id='host2', labels=['label1'])
    249 >>> rpc_interface.host_remove_labels(id='host1', labels=['label1'])
    250 
    251 
    252 # Other interface for new CLI
    253 # add hosts to labels
    254 >>> rpc_interface.label_add_hosts(id='label1', hosts=['host1'])
    255 >>> rpc_interface.label_add_hosts(id='label2', hosts=['host1', 'host2'])
    256 
    257 # check labels for hosts
    258 >>> data = rpc_interface.get_hosts(hostname='host1')
    259 >>> data[0]['labels']
    260 [u'label1', u'label2']
    261 >>> data = rpc_interface.get_hosts(hostname='host2')
    262 >>> data[0]['labels']
    263 [u'label2']
    264 >>> data[0]['platform']
    265 u'label2'
    266 
    267 # check host lists for labels -- use double underscore to specify fields of
    268 # related objects
    269 >>> data = rpc_interface.get_hosts(labels__name='label1')
    270 >>> [host['hostname'] for host in data]
    271 [u'host1']
    272 >>> data = rpc_interface.get_hosts(labels__name='label2')
    273 >>> [host['hostname'] for host in data]
    274 [u'host1', u'host2']
    275 
    276 # remove a host from a label
    277 >>> rpc_interface.label_remove_hosts(id='label2', hosts=['host2'])
    278 >>> data = rpc_interface.get_hosts(hostname='host1')
    279 >>> data[0]['labels']
    280 [u'label1', u'label2']
    281 >>> data = rpc_interface.get_hosts(labels__name='label2')
    282 >>> [host['hostname'] for host in data]
    283 [u'host1']
    284 
    285 # Remove multiple hosts from a label
    286 >>> rpc_interface.label_add_hosts(id='label2', hosts=['host2'])
    287 >>> data = rpc_interface.get_hosts(labels__name='label2')
    288 >>> [host['hostname'] for host in data]
    289 [u'host1', u'host2']
    290 >>> rpc_interface.label_remove_hosts(id='label2', hosts=['host2', 'host1'])
    291 >>> rpc_interface.get_hosts(labels__name='label2')
    292 []
    293 
    294 
    295 # ACL group relationships work similarly
    296 # note that all users are a member of 'Everyone' by default, and that hosts are
    297 # automatically made a member of 'Everyone' only when they are a member of no
    298 # other group
    299 >>> data = rpc_interface.get_acl_groups(hosts__hostname='host1')
    300 >>> [acl_group['name'] for acl_group in data]
    301 [u'Everyone']
    302 
    303 >>> rpc_interface.add_acl_group(name='my_group')
    304 2
    305 
    306 >>> rpc_interface.acl_group_add_users('my_group', ['showard'])
    307 >>> rpc_interface.acl_group_add_hosts('my_group', ['host1'])
    308 >>> data = rpc_interface.get_acl_groups(name='my_group')
    309 >>> data[0]['users']
    310 [u'debug_user', u'showard']
    311 >>> data[0]['hosts']
    312 [u'host1']
    313 >>> data = rpc_interface.get_acl_groups(users__login='showard')
    314 >>> [acl_group['name'] for acl_group in data]
    315 [u'Everyone', u'my_group']
    316 
    317 # note host has been automatically removed from 'Everyone'
    318 >>> data = rpc_interface.get_acl_groups(hosts__hostname='host1')
    319 >>> [acl_group['name'] for acl_group in data]
    320 [u'my_group']
    321 
    322 >>> rpc_interface.acl_group_remove_users('my_group', ['showard'])
    323 >>> rpc_interface.acl_group_remove_hosts('my_group', ['host1'])
    324 >>> data = rpc_interface.get_acl_groups(name='my_group')
    325 >>> data[0]['users'], data[0]['hosts']
    326 ([u'debug_user'], [])
    327 >>> data = rpc_interface.get_acl_groups(users__login='showard')
    328 >>> [acl_group['name'] for acl_group in data]
    329 [u'Everyone']
    330 
    331 # note host has been automatically added back to 'Everyone'
    332 >>> data = rpc_interface.get_acl_groups(hosts__hostname='host1')
    333 >>> [acl_group['name'] for acl_group in data]
    334 [u'Everyone']
    335 
    336 
    337 # host attributes
    338 
    339 >>> rpc_interface.set_host_attribute('color', 'red', hostname='host1')
    340 >>> data = rpc_interface.get_hosts(hostname='host1')
    341 >>> data[0]['attributes']
    342 {u'color': u'red'}
    343 
    344 >>> rpc_interface.set_host_attribute('color', None, hostname='host1')
    345 >>> data = rpc_interface.get_hosts(hostname='host1')
    346 >>> data[0]['attributes']
    347 {}
    348 
    349 
    350 # host bulk modify
    351 ##################
    352 
    353 >>> rpc_interface.modify_hosts(
    354 ...     host_filter_data={'hostname__in': ['host1', 'host2']},
    355 ...     update_data={'locked': True, 'lock_reason': 'Locked for testing'})
    356 >>> data = rpc_interface.get_hosts(hostname__in=['host1', 'host2'])
    357 
    358 >>> data[0]['locked']
    359 True
    360 >>> data[1]['locked']
    361 True
    362 
    363 >>> rpc_interface.modify_hosts(
    364 ...     host_filter_data={'id': 2},
    365 ...     update_data={'locked': False})
    366 >>> data = rpc_interface.get_hosts(hostname__in=['host1', 'host2'])
    367 
    368 >>> data[0]['locked']
    369 False
    370 >>> data[1]['locked']
    371 True
    372 
    373 
    374 # job management
    375 # ############
    376 
    377 # note that job functions require job IDs to identify jobs, since job names are
    378 # not unique
    379 
    380 # add some entries to play with
    381 >>> rpc_interface.add_label(name='my_label', kernel_config='my_kernel_config')
    382 5
    383 >>> rpc_interface.add_host(hostname='my_label_host1')
    384 4
    385 >>> rpc_interface.add_host(hostname='my_label_host2')
    386 5
    387 >>> rpc_interface.label_add_hosts(id='my_label', hosts=['my_label_host1', 'my_label_host2'])
    388 
    389 # generate a control file from existing body text.
    390 >>> cf_info_pi = rpc_interface.generate_control_file(
    391 ...     client_control_file='print "Hi"\n')
    392 >>> print cf_info_pi['control_file'] #doctest: +NORMALIZE_WHITESPACE
    393 def step_init():
    394     job.next_step('step0')
    395 def step0():
    396     print "Hi"
    397     return locals()
    398 
    399 # create a job to run on host1, host2, and any two machines in my_label
    400 >>> rpc_interface.create_job(name='my_job',
    401 ...                          priority=10,
    402 ...                          control_file=cf_info_pi['control_file'],
    403 ...                          control_type='Client',
    404 ...                          hosts=['host1', 'host2'],
    405 ...                          meta_hosts=['my_label', 'my_label'])
    406 1
    407 
    408 # get job info - this does not include status info for particular hosts
    409 >>> data = rpc_interface.get_jobs()
    410 >>> data = data[0]
    411 >>> data['id'], data['owner'], data['name'], data['priority']
    412 (1, u'debug_user', u'my_job', 10)
    413 >>> data['control_file'] == cf_info_pi['control_file']
    414 True
    415 >>> data['control_type']
    416 'Client'
    417 
    418 >>> today = datetime.date.today()
    419 >>> data['created_on'].startswith(
    420 ...         '%d-%02d-%02d' % (today.year, today.month, today.day))
    421 True
    422 
    423 # get_num_jobs - useful when dealing with large numbers of jobs
    424 >>> rpc_interface.get_num_jobs(name='my_job')
    425 1
    426 
    427 # check host queue entries for a job
    428 >>> data = rpc_interface.get_host_queue_entries(job=1)
    429 >>> len(data)
    430 4
    431 
    432 # get rid of created_on, it's nondeterministic
    433 >>> data[0]['job']['created_on'] = data[2]['job']['created_on'] = None
    434 
    435 # get_host_queue_entries returns full info about the job within each queue entry
    436 >>> job = data[0]['job']
    437 >>> job == {'control_file': cf_info_pi['control_file'], # the control file we used
    438 ...         'control_type': 'Client',
    439 ...         'created_on': None,
    440 ...         'id': 1,
    441 ...         'name': 'my_job',
    442 ...         'owner': 'debug_user',
    443 ...         'priority': 10,
    444 ...         'synch_count': 0,
    445 ...         'timeout': 24,
    446 ...         'timeout_mins': 1440,
    447 ...         'max_runtime_mins': 1440,
    448 ...         'max_runtime_hrs' : 72,
    449 ...         'run_verify': False,
    450 ...         'run_reset': True,
    451 ...         'email_list': '',
    452 ...         'reboot_before': 'If dirty',
    453 ...         'reboot_after': 'Never',
    454 ...         'parse_failed_repair': True,
    455 ...         'drone_set': drone_set,
    456 ...         'parameterized_job': None,
    457 ...         'test_retry': 0,
    458 ...         'parent_job': None,
    459 ...         'shard': None,
    460 ...         'require_ssp': None}
    461 True
    462 
    463 # get_host_queue_entries returns a lot of data, so let's only check a couple
    464 >>> data[0] == (
    465 ... {'active': 0,
    466 ...  'complete': 0,
    467 ...  'host': {'hostname': 'host1', # full host info here
    468 ...           'id': 2,
    469 ...           'invalid': 0,
    470 ...           'locked': 0,
    471 ...           'status': 'Ready',
    472 ...           'synch_id': None,
    473 ...           'protection': 'No protection',
    474 ...           'locked_by': None,
    475 ...           'lock_time': None,
    476 ...           'lock_reason': 'Locked for testing',
    477 ...           'dirty': True,
    478 ...           'leased': 1,
    479 ...           'shard': None},
    480 ...  'id': 1,
    481 ...  'job': job, # full job info here
    482 ...  'meta_host': None,
    483 ...  'status': 'Queued',
    484 ...  'deleted': 0,
    485 ...  'execution_subdir': '',
    486 ...  'atomic_group': None,
    487 ...  'aborted': False,
    488 ...  'started_on': None,
    489 ...  'finished_on': None,
    490 ...  'full_status': 'Queued'})
    491 True
    492 >>> data[2] == (
    493 ... {'active': 0,
    494 ...  'complete': 0,
    495 ...  'host': None,
    496 ...  'id': 3,
    497 ...  'job': job,
    498 ...  'meta_host': 'my_label',
    499 ...  'status': 'Queued',
    500 ...  'deleted': 0,
    501 ...  'execution_subdir': '',
    502 ...  'atomic_group': None,
    503 ...  'aborted': False,
    504 ...  'started_on': None,
    505 ...  'finished_on': None,
    506 ...  'full_status': 'Queued'})
    507 True
    508 >>> rpc_interface.get_num_host_queue_entries(job=1)
    509 4
    510 >>> rpc_interface.get_hqe_percentage_complete(job=1)
    511 0.0
    512 
    513 # get_jobs_summary adds status counts to the rest of the get_jobs info
    514 >>> data = rpc_interface.get_jobs_summary()
    515 >>> counts = data[0]['status_counts']
    516 >>> counts
    517 {u'Queued': 4}
    518 
    519 # abort the job
    520 >>> data = rpc_interface.abort_host_queue_entries(job__id=1)
    521 >>> data = rpc_interface.get_jobs_summary(id=1)
    522 >>> data[0]['status_counts']
    523 {u'Aborted (Queued)': 4}
    524 
    525 # Remove the two hosts in my_label
    526 >>> rpc_interface.delete_host(id='my_label_host1')
    527 >>> rpc_interface.delete_host(id='my_label_host2')
    528 
    529 
    530 # extra querying parameters
    531 # #########################
    532 
    533 # get_* methods can take query_start and query_limit arguments to implement
    534 # paging and a sort_by argument to specify the sort column
    535 >>> data = rpc_interface.get_hosts(query_limit=1)
    536 >>> [host['hostname'] for host in data]
    537 [u'host1']
    538 >>> data = rpc_interface.get_hosts(query_start=1, query_limit=1)
    539 >>> [host['hostname'] for host in data]
    540 [u'host2']
    541 
    542 # sort_by = ['-hostname'] indicates sorting in descending order by hostname
    543 >>> data = rpc_interface.get_hosts(sort_by=['-hostname'])
    544 >>> [host['hostname'] for host in data]
    545 [u'host2', u'host1']
    546 
    547 
    548 # cloning a job
    549 # #############
    550 
    551 >>> job_id = rpc_interface.create_job(name='my_job_to_clone',
    552 ...                                   priority=50,
    553 ...                                   control_file=cf_info_pi['control_file'],
    554 ...                                   control_type='Client',
    555 ...                                   hosts=['host2'],
    556 ...                                   synch_count=1)
    557 >>> info = rpc_interface.get_info_for_clone(job_id, False)
    558 >>> info['meta_host_counts']
    559 {}
    560 >>> info['job']['dependencies']
    561 []
    562 >>> info['job']['priority']
    563 50
    564 
    565 
    566 # advanced usage
    567 # ##############
    568 
    569 # synch_count
    570 >>> job_id = rpc_interface.create_job(name='my_job',
    571 ...                          priority=10,
    572 ...                          control_file=cf_info_pi['control_file'],
    573 ...                          control_type='Server',
    574 ...                          synch_count=2,
    575 ...                          hosts=['host1', 'host2'])
    576 
    577 >>> data = rpc_interface.get_jobs(id=job_id)
    578 >>> data[0]['synch_count']
    579 2
    580 
    581 # get hosts ACL'd to a user
    582 >>> hosts = rpc_interface.get_hosts(aclgroup__users__login='debug_user')
    583 >>> sorted([host['hostname'] for host in hosts])
    584 [u'host1', u'host2']
    585 
    586 >>> rpc_interface.add_acl_group(name='mygroup')
    587 3
    588 >>> rpc_interface.acl_group_add_users('mygroup', ['debug_user'])
    589 >>> rpc_interface.acl_group_add_hosts('mygroup', ['host1'])
    590 >>> data = rpc_interface.get_acl_groups(name='Everyone')[0]
    591 >>> data['users'], data['hosts']
    592 ([u'debug_user', u'showard'], [u'host2'])
    593 >>> data = rpc_interface.get_acl_groups(name='mygroup')[0]
    594 >>> data['users'], data['hosts']
    595 ([u'debug_user'], [u'host1'])
    596 
    597 >>> hosts = rpc_interface.get_hosts(aclgroup__users__login='debug_user')
    598 >>> sorted([host['hostname'] for host in hosts])
    599 [u'host1', u'host2']
    600 >>> hosts = rpc_interface.get_hosts(aclgroup__users__login='showard')
    601 >>> [host['hostname'] for host in hosts]
    602 [u'host2']
    603 
    604 >>> rpc_interface.delete_acl_group('mygroup')
    605 >>> data = rpc_interface.get_acl_groups(name='Everyone')[0]
    606 >>> sorted(data['hosts'])
    607 [u'host1', u'host2']
    608