Jakob Juelich | 8b110ee | 2014-09-15 16:13:42 -0700 | [diff] [blame] | 1 | # |
| 2 | # Copyright 2008 Google Inc. All Rights Reserved. |
| 3 | |
| 4 | """ |
| 5 | The shard module contains the objects and methods used to |
| 6 | manage shards in Autotest. |
| 7 | |
| 8 | The valid actions are: |
| 9 | create: creates shard |
| 10 | remove: deletes shard(s) |
| 11 | list: lists shards with label |
| 12 | |
| 13 | See topic_common.py for a High Level Design and Algorithm. |
| 14 | """ |
| 15 | |
Dan Shi | 25e1fd4 | 2014-12-19 14:36:42 -0800 | [diff] [blame] | 16 | import sys |
Jakob Juelich | 8b110ee | 2014-09-15 16:13:42 -0700 | [diff] [blame] | 17 | from autotest_lib.cli import topic_common, action_common |
| 18 | |
| 19 | |
| 20 | class shard(topic_common.atest): |
| 21 | """shard class |
| 22 | atest shard [create|delete|list] <options>""" |
| 23 | usage_action = '[create|delete|list]' |
| 24 | topic = msg_topic = 'shard' |
| 25 | msg_items = '<shards>' |
| 26 | |
| 27 | def __init__(self): |
| 28 | """Add to the parser the options common to all the |
| 29 | shard actions""" |
| 30 | super(shard, self).__init__() |
| 31 | |
| 32 | self.topic_parse_info = topic_common.item_parse_info( |
| 33 | attribute_name='shards', |
| 34 | use_leftover=True) |
| 35 | |
| 36 | |
| 37 | def get_items(self): |
| 38 | return self.shards |
| 39 | |
| 40 | |
| 41 | class shard_help(shard): |
| 42 | """Just here to get the atest logic working. |
| 43 | Usage is set by its parent""" |
| 44 | pass |
| 45 | |
| 46 | |
| 47 | class shard_list(action_common.atest_list, shard): |
| 48 | """Class for running atest shard list [--label <labels>]""" |
| 49 | |
| 50 | def parse(self): |
| 51 | host_info = topic_common.item_parse_info(attribute_name='labels', |
| 52 | inline_option='labels') |
| 53 | return super(shard_list, self).parse([host_info]) |
| 54 | |
| 55 | |
| 56 | def execute(self): |
| 57 | return super(shard_list, self).execute(op='get_shards') |
| 58 | |
| 59 | |
| 60 | def warn_if_label_assigned_to_multiple_shards(self, results): |
| 61 | """Prints a warning if one label is assigned to multiple shards. |
| 62 | |
| 63 | This should never happen, but if it does, better be safe. |
| 64 | |
| 65 | @param results: Results as passed to output(). |
| 66 | """ |
| 67 | assigned_labels = set() |
| 68 | for line in results: |
| 69 | for label in line['labels']: |
| 70 | if label in assigned_labels: |
| 71 | sys.stderr.write('WARNING: label %s is assigned to ' |
| 72 | 'multiple shards.\n' |
| 73 | 'This will lead to unpredictable behavor ' |
| 74 | 'in which hosts and jobs will be assigned ' |
| 75 | 'to which shard.\n') |
| 76 | assigned_labels.add(label) |
| 77 | |
| 78 | |
| 79 | def output(self, results): |
| 80 | self.warn_if_label_assigned_to_multiple_shards(results) |
| 81 | super(shard_list, self).output(results, ['hostname', 'labels']) |
| 82 | |
| 83 | |
| 84 | class shard_create(action_common.atest_create, shard): |
| 85 | """Class for running atest shard create -l <label> <shard>""" |
| 86 | def __init__(self): |
| 87 | super(shard_create, self).__init__() |
| 88 | self.parser.add_option('-l', '--label', |
| 89 | help=('Assign LABEL to the SHARD. All jobs that ' |
| 90 | 'require this label, will be run on the ' |
| 91 | 'shard.'), |
| 92 | type='string', |
| 93 | metavar='LABEL') |
| 94 | |
| 95 | |
| 96 | def parse(self): |
| 97 | (options, leftover) = super(shard_create, |
| 98 | self).parse(req_items='shards') |
| 99 | if not options.label: |
| 100 | print 'Must provide a label with -l <label>' |
| 101 | self.parser.print_help() |
| 102 | sys.exit(1) |
| 103 | self.data_item_key = 'hostname' |
| 104 | self.data['label'] = options.label |
| 105 | return (options, leftover) |
| 106 | |
| 107 | |
| 108 | class shard_delete(action_common.atest_delete, shard): |
| 109 | """Class for running atest shard delete <shards>""" |
Jakob Juelich | 8b110ee | 2014-09-15 16:13:42 -0700 | [diff] [blame] | 110 | |
| 111 | def parse(self): |
| 112 | (options, leftover) = super(shard_delete, self).parse() |
Jakob Juelich | 8b110ee | 2014-09-15 16:13:42 -0700 | [diff] [blame] | 113 | self.data_item_key = 'hostname' |
| 114 | return (options, leftover) |
| 115 | |
| 116 | |
| 117 | def execute(self, *args, **kwargs): |
Jakob Juelich | 8b110ee | 2014-09-15 16:13:42 -0700 | [diff] [blame] | 118 | print 'Please ensure the shard host is powered off.' |
| 119 | print ('Otherwise DUTs might be used by multiple shards at the same ' |
| 120 | 'time, which will lead to serious correctness problems.') |
Dan Shi | 25e1fd4 | 2014-12-19 14:36:42 -0800 | [diff] [blame] | 121 | return super(shard_delete, self).execute(*args, **kwargs) |