1#
2# Copyright 2008 Google Inc. All Rights Reserved.
3
4"""
5The acl module contains the objects and methods used to
6manage ACLs in Autotest.
7
8The valid actions are:
9add:     adds acl(s), or users or hosts to an ACL
10remove:      deletes acl(s), or users or hosts from an ACL
11list:    lists acl(s)
12
13The common options are:
14--alist / -A: file containing a list of ACLs
15
16See topic_common.py for a High Level Design and Algorithm.
17
18"""
19
20from autotest_lib.cli import topic_common, action_common
21
22
23class acl(topic_common.atest):
24    """ACL class
25    atest acl [create|delete|list|add|remove] <options>"""
26    usage_action = '[create|delete|list|add|remove]'
27    topic = 'acl_group'
28    msg_topic = 'ACL'
29    msg_items = '<acls>'
30
31    def __init__(self):
32        """Add to the parser the options common to all the ACL actions"""
33        super(acl, self).__init__()
34        self.parser.add_option('-A', '--alist',
35                               help='File listing the ACLs',
36                               type='string',
37                               default=None,
38                               metavar='ACL_FLIST')
39
40        self.topic_parse_info = topic_common.item_parse_info(
41            attribute_name='acls',
42            filename_option='alist',
43            use_leftover=True)
44
45
46    def get_items(self):
47        """Get the items in the ACL list."""
48        return self.acls
49
50
51class acl_help(acl):
52    """Just here to get the atest logic working.
53    Usage is set by its parent"""
54    pass
55
56
57class acl_list(action_common.atest_list, acl):
58    """atest acl list [--verbose]
59    [--user <users>|--mach <machine>|--alist <file>] [<acls>]"""
60    def __init__(self):
61        super(acl_list, self).__init__()
62
63        self.parser.add_option('-u', '--user',
64                               help='List ACLs containing USER',
65                               type='string',
66                               metavar='USER')
67        self.parser.add_option('-m', '--machine',
68                               help='List ACLs containing MACHINE',
69                               type='string',
70                               metavar='MACHINE')
71
72
73    def parse(self):
74        user_info = topic_common.item_parse_info(attribute_name='users',
75                                                 inline_option='user')
76        host_info = topic_common.item_parse_info(attribute_name='hosts',
77                                                 inline_option='machine')
78
79        (options, leftover) = super(acl_list, self).parse([user_info,
80                                                           host_info])
81
82        users = getattr(self, 'users')
83        hosts = getattr(self, 'hosts')
84        acls = getattr(self, 'acls')
85        if ((users and (hosts or acls)) or
86            (hosts and acls)):
87            self.invalid_syntax('Only specify one of --user,'
88                                '--machine or ACL')
89
90        if len(users) > 1:
91            self.invalid_syntax('Only specify one <user>')
92        if len(hosts) > 1:
93            self.invalid_syntax('Only specify one <machine>')
94
95        try:
96            self.users = users[0]
97        except IndexError:
98            pass
99
100        try:
101            self.hosts = hosts[0]
102        except IndexError:
103            pass
104        return (options, leftover)
105
106
107    def execute(self):
108        filters = {}
109        check_results = {}
110        if self.acls:
111            filters['name__in'] = self.acls
112            check_results['name__in'] = 'name'
113
114        if self.users:
115            filters['users__login'] = self.users
116            check_results['users__login'] = None
117
118        if self.hosts:
119            filters['hosts__hostname'] = self.hosts
120            check_results['hosts__hostname'] = None
121
122        return super(acl_list,
123                     self).execute(op='get_acl_groups',
124                                   filters=filters,
125                                   check_results=check_results)
126
127
128    def output(self, results):
129        # If an ACL was specified, always print its details
130        if self.acls or self.verbose:
131            sublist_keys=('hosts', 'users')
132        else:
133            sublist_keys=()
134
135        super(acl_list, self).output(results,
136                                     keys=('name', 'description'),
137                                     sublist_keys=sublist_keys)
138
139
140class acl_create(action_common.atest_create, acl):
141    """atest acl create <acl> --desc <description>"""
142    def __init__(self):
143        super(acl_create, self).__init__()
144        self.parser.add_option('-d', '--desc',
145                               help='Creates the ACL with the DESCRIPTION',
146                               type='string')
147        self.parser.remove_option('--alist')
148
149
150    def parse(self):
151        (options, leftover) = super(acl_create, self).parse(req_items='acls')
152
153        if not options.desc:
154            self.invalid_syntax('Must specify a description to create an ACL.')
155
156        self.data_item_key = 'name'
157        self.data['description'] = options.desc
158
159        if len(self.acls) > 1:
160            self.invalid_syntax('Can only create one ACL at a time')
161
162        return (options, leftover)
163
164
165class acl_delete(action_common.atest_delete, acl):
166    """atest acl delete [<acls> | --alist <file>"""
167    pass
168
169
170class acl_add_or_remove(acl):
171    """Shared implementation for acl add and acl remove."""
172
173    def __init__(self):
174        super(acl_add_or_remove, self).__init__()
175        # Get the appropriate help for adding or removing.
176        words = self.usage_words
177        lower_words = tuple(word.lower() for word in words)
178
179        self.parser.add_option('-u', '--user',
180                               help='%s USER(s) %s the ACL' % words,
181                               type='string',
182                               metavar='USER')
183        self.parser.add_option('-U', '--ulist',
184                               help='File containing users to %s %s '
185                               'the ACL' % lower_words,
186                               type='string',
187                               metavar='USER_FLIST')
188        self.parser.add_option('-m', '--machine',
189                               help='%s MACHINE(s) %s the ACL' % words,
190                               type='string',
191                               metavar='MACHINE')
192        self.parser.add_option('-M', '--mlist',
193                               help='File containing machines to %s %s '
194                               'the ACL' % lower_words,
195                               type='string',
196                               metavar='MACHINE_FLIST')
197
198
199    def parse(self):
200        user_info = topic_common.item_parse_info(attribute_name='users',
201                                                 inline_option='user',
202                                                 filename_option='ulist')
203        host_info = topic_common.item_parse_info(attribute_name='hosts',
204                                                 inline_option='machine',
205                                                 filename_option='mlist')
206        (options, leftover) = super(acl_add_or_remove,
207                                    self).parse([user_info, host_info],
208                                                req_items='acls')
209
210        if (not getattr(self, 'users', None) and
211            not getattr(self, 'hosts', None)):
212            self.invalid_syntax('Specify at least one USER or MACHINE')
213
214        return (options, leftover)
215
216
217class acl_add(action_common.atest_add, acl_add_or_remove):
218    """atest acl add <acl> --user <user>|
219       --machine <machine>|--mlist <FILE>]"""
220    pass
221
222
223class acl_remove(action_common.atest_remove, acl_add_or_remove):
224    """atest acl remove [<acls> | --alist <file>
225    --user <user> | --machine <machine> | --mlist <FILE>]"""
226    pass
227