1#
2# Copyright 2008 Google Inc. All Rights Reserved.
3
4"""
5The label module contains the objects and methods used to
6manage labels in Autotest.
7
8The valid actions are:
9add:     adds label(s), or hosts to an LABEL
10remove:      deletes label(s), or hosts from an LABEL
11list:    lists label(s)
12
13The common options are:
14--blist / -B: file containing a list of LABELs
15
16See topic_common.py for a High Level Design and Algorithm.
17"""
18
19import os, sys
20from autotest_lib.cli import topic_common, action_common
21
22
23class label(topic_common.atest):
24    """Label class
25    atest label [create|delete|list|add|remove] <options>"""
26    usage_action = '[create|delete|list|add|remove]'
27    topic = msg_topic = 'label'
28    msg_items = '<labels>'
29
30    def __init__(self):
31        """Add to the parser the options common to all the
32        label actions"""
33        super(label, self).__init__()
34
35        self.parser.add_option('-B', '--blist',
36                               help='File listing the labels',
37                               type='string',
38                               default=None,
39                               metavar='LABEL_FLIST')
40
41        self.topic_parse_info = topic_common.item_parse_info(
42            attribute_name='labels',
43            filename_option='blist',
44            use_leftover=True)
45
46
47    def get_items(self):
48        return self.labels
49
50
51class label_help(label):
52    """Just here to get the atest logic working.
53    Usage is set by its parent"""
54    pass
55
56
57class label_list(action_common.atest_list, label):
58    """atest label list [--platform] [--all] [--atomicgroup]
59    [--valid-only] [--machine <machine>]
60    [--blist <file>] [<labels>]"""
61    def __init__(self):
62        super(label_list, self).__init__()
63
64        self.parser.add_option('-t', '--platform-only',
65                               help='Display only platform labels',
66                               action='store_true')
67
68        self.parser.add_option('-d', '--valid-only',
69                               help='Display only valid labels',
70                               action='store_true')
71
72        self.parser.add_option('-a', '--all',
73                               help=('Display both normal & '
74                                     'platform labels'),
75                               action='store_true')
76
77        self.parser.add_option('--atomicgroup',
78                               help=('Display only atomic group labels '
79                                     'along with the atomic group name.'),
80                               action='store_true')
81
82        self.parser.add_option('-m', '--machine',
83                               help='List LABELs of MACHINE',
84                               type='string',
85                               metavar='MACHINE')
86
87
88    def parse(self):
89        host_info = topic_common.item_parse_info(attribute_name='hosts',
90                                                 inline_option='machine')
91        (options, leftover) = super(label_list, self).parse([host_info])
92
93        exclusives = [options.all, options.platform_only, options.atomicgroup]
94        if exclusives.count(True) > 1:
95            self.invalid_syntax('Only specify one of --all,'
96                                '--platform, --atomicgroup')
97
98        if len(self.hosts) > 1:
99            self.invalid_syntax(('Only one machine name allowed. '
100                                '''Use '%s host list %s' '''
101                                 'instead.') %
102                                (sys.argv[0], ','.join(self.hosts)))
103        self.all = options.all
104        self.atomicgroup = options.atomicgroup
105        self.platform_only = options.platform_only
106        self.valid_only = options.valid_only
107        return (options, leftover)
108
109
110    def execute(self):
111        filters = {}
112        check_results = {}
113        if self.hosts:
114            filters['host__hostname__in'] = self.hosts
115            check_results['host__hostname__in'] = None
116
117        if self.labels:
118            filters['name__in'] = self.labels
119            check_results['name__in'] = 'name'
120
121        return super(label_list, self).execute(op='get_labels',
122                                               filters=filters,
123                                               check_results=check_results)
124
125
126    def output(self, results):
127        if self.valid_only:
128            results = [label for label in results
129                       if not label['invalid']]
130
131        if self.platform_only:
132            results = [label for label in results
133                       if label['platform']]
134            keys = ['name', 'invalid']
135        elif self.atomicgroup:
136            results = [label for label in results
137                       if label['atomic_group']]
138            keys = ['name', 'atomic_group.name', 'invalid']
139        elif not self.all:
140            results = [label for label in results
141                       if not label['platform']]
142            keys = ['name', 'only_if_needed', 'invalid']
143        else:
144            keys = ['name', 'platform', 'only_if_needed', 'invalid']
145
146        super(label_list, self).output(results, keys)
147
148
149class label_create(action_common.atest_create, label):
150    """atest label create <labels>|--blist <file> --platform"""
151    def __init__(self):
152        super(label_create, self).__init__()
153        self.parser.add_option('-t', '--platform',
154                               help='To create this label as a platform',
155                               default=False,
156                               action='store_true')
157        self.parser.add_option('-o', '--only_if_needed',
158                               help='To mark the label as "only use if needed',
159                               default=False,
160                               action='store_true')
161
162
163    def parse(self):
164        (options, leftover) = super(label_create,
165                                    self).parse(req_items='labels')
166        self.data_item_key = 'name'
167        self.data['platform'] = options.platform
168        self.data['only_if_needed'] = options.only_if_needed
169        return (options, leftover)
170
171
172class label_delete(action_common.atest_delete, label):
173    """atest label delete <labels>|--blist <file>"""
174    pass
175
176
177
178class label_add_or_remove(label):
179    def __init__(self):
180        super(label_add_or_remove, self).__init__()
181        lower_words = tuple(word.lower() for word in self.usage_words)
182        self.parser.add_option('-m', '--machine',
183                               help=('%s MACHINE(s) %s the LABEL' %
184                                     self.usage_words),
185                               type='string',
186                               metavar='MACHINE')
187        self.parser.add_option('-M', '--mlist',
188                               help='File containing machines to %s %s '
189                               'the LABEL' % lower_words,
190                               type='string',
191                               metavar='MACHINE_FLIST')
192
193
194    def parse(self):
195        host_info = topic_common.item_parse_info(attribute_name='hosts',
196                                                 inline_option='machine',
197                                                 filename_option='mlist')
198        (options, leftover) = super(label_add_or_remove,
199                                    self).parse([host_info],
200                                                req_items='labels')
201
202        if not getattr(self, 'hosts', None):
203            self.invalid_syntax('%s %s requires at least one host' %
204                                (self.msg_topic,
205                                 self.usage_action))
206        return (options, leftover)
207
208
209class label_add(action_common.atest_add, label_add_or_remove):
210    """atest label add <labels>|--blist <file>
211    --platform [--machine <machine>] [--mlist <file>]"""
212    pass
213
214
215class label_remove(action_common.atest_remove, label_add_or_remove):
216    """atest label remove <labels>|--blist <file>
217     [--machine <machine>] [--mlist <file>]"""
218    pass
219