]>
Commit | Line | Data |
---|---|---|
4eb44502 PB |
1 | #!/usr/bin/python |
2 | # -*- coding: utf-8 -*- | |
3 | ||
4 | # (c) 2013, Chatham Financial <oss@chathamfinancial.com> | |
5 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | |
6 | ||
7 | from __future__ import absolute_import, division, print_function | |
8 | __metaclass__ = type | |
9 | ||
10 | ||
11 | ANSIBLE_METADATA = {'metadata_version': '1.1', | |
12 | 'status': ['preview'], | |
13 | 'supported_by': 'community'} | |
14 | ||
15 | ||
16 | DOCUMENTATION = ''' | |
17 | --- | |
18 | module: rabbitmq_user_3_7_9 | |
19 | short_description: Adds or removes users to RabbitMQ | |
20 | description: | |
21 | - Add or remove users to RabbitMQ and assign permissions | |
22 | version_added: "1.1" | |
23 | author: '"Chris Hoffman (@chrishoffman)"' | |
24 | options: | |
25 | user: | |
26 | description: | |
27 | - Name of user to add | |
28 | required: true | |
29 | default: null | |
30 | aliases: [username, name] | |
31 | password: | |
32 | description: | |
33 | - Password of user to add. | |
34 | - To change the password of an existing user, you must also specify | |
35 | C(force=yes). | |
36 | required: false | |
37 | default: null | |
38 | tags: | |
39 | description: | |
40 | - User tags specified as comma delimited | |
41 | required: false | |
42 | default: null | |
43 | permissions: | |
44 | description: | |
45 | - a list of dicts, each dict contains vhost, configure_priv, write_priv, and read_priv, | |
46 | and represents a permission rule for that vhost. | |
47 | - This option should be preferable when you care about all permissions of the user. | |
48 | - You should use vhost, configure_priv, write_priv, and read_priv options instead | |
49 | if you care about permissions for just some vhosts. | |
50 | required: false | |
51 | default: [] | |
52 | vhost: | |
53 | description: | |
54 | - vhost to apply access privileges. | |
55 | - This option will be ignored when permissions option is used. | |
56 | required: false | |
57 | default: / | |
58 | node: | |
59 | description: | |
60 | - erlang node name of the rabbit we wish to configure | |
61 | required: false | |
62 | default: rabbit | |
63 | version_added: "1.2" | |
64 | configure_priv: | |
65 | description: | |
66 | - Regular expression to restrict configure actions on a resource | |
67 | for the specified vhost. | |
68 | - By default all actions are restricted. | |
69 | - This option will be ignored when permissions option is used. | |
70 | required: false | |
71 | default: ^$ | |
72 | write_priv: | |
73 | description: | |
74 | - Regular expression to restrict configure actions on a resource | |
75 | for the specified vhost. | |
76 | - By default all actions are restricted. | |
77 | - This option will be ignored when permissions option is used. | |
78 | required: false | |
79 | default: ^$ | |
80 | read_priv: | |
81 | description: | |
82 | - Regular expression to restrict configure actions on a resource | |
83 | for the specified vhost. | |
84 | - By default all actions are restricted. | |
85 | - This option will be ignored when permissions option is used. | |
86 | required: false | |
87 | default: ^$ | |
88 | force: | |
89 | description: | |
90 | - Deletes and recreates the user. | |
91 | required: false | |
92 | default: "no" | |
93 | choices: [ "yes", "no" ] | |
94 | state: | |
95 | description: | |
96 | - Specify if user is to be added or removed | |
97 | required: false | |
98 | default: present | |
99 | choices: [present, absent] | |
100 | ''' | |
101 | ||
102 | EXAMPLES = ''' | |
103 | # Add user to server and assign full access control on / vhost. | |
104 | # The user might have permission rules for other vhost but you don't care. | |
105 | - rabbitmq_user_3_7_9: | |
106 | user: joe | |
107 | password: changeme | |
108 | vhost: / | |
109 | configure_priv: .* | |
110 | read_priv: .* | |
111 | write_priv: .* | |
112 | state: present | |
113 | ||
114 | # Add user to server and assign full access control on / vhost. | |
115 | # The user doesn't have permission rules for other vhosts | |
116 | - rabbitmq_user_3_7_9: | |
117 | user: joe | |
118 | password: changeme | |
119 | permissions: | |
120 | - vhost: / | |
121 | configure_priv: .* | |
122 | read_priv: .* | |
123 | write_priv: .* | |
124 | state: present | |
125 | ''' | |
126 | ||
127 | from ansible.module_utils.basic import AnsibleModule | |
128 | ||
129 | ||
130 | class RabbitMqUser(object): | |
131 | def __init__(self, module, username, password, tags, permissions, | |
132 | node, bulk_permissions=False): | |
133 | self.module = module | |
134 | self.username = username | |
135 | self.password = password | |
136 | self.node = node | |
137 | if not tags: | |
138 | self.tags = list() | |
139 | else: | |
140 | self.tags = tags.split(',') | |
141 | ||
142 | self.permissions = permissions | |
143 | self.bulk_permissions = bulk_permissions | |
144 | ||
145 | self._tags = None | |
146 | self._permissions = [] | |
147 | self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True) | |
148 | ||
149 | def _exec(self, args, run_in_check_mode=False): | |
150 | if not self.module.check_mode or run_in_check_mode: | |
151 | cmd = [self._rabbitmqctl, '-q'] | |
152 | if self.node is not None: | |
153 | cmd.extend(['-n', self.node]) | |
154 | rc, out, err = self.module.run_command(cmd + args, check_rc=True) | |
155 | return out.splitlines() if len(out.strip()) else [] | |
156 | return list() | |
157 | ||
158 | def get(self): | |
159 | users = self._exec(self._list_args(['list_users']), True) | |
160 | ||
161 | for user_tag in users: | |
162 | if '\t' not in user_tag: | |
163 | continue | |
164 | ||
165 | user, tags = user_tag.split('\t') | |
166 | ||
167 | if user == self.username: | |
168 | for c in ['[', ']', ' ']: | |
169 | tags = tags.replace(c, '') | |
170 | ||
171 | if tags != '': | |
172 | self._tags = tags.split(',') | |
173 | else: | |
174 | self._tags = list() | |
175 | ||
176 | self._permissions = self._get_permissions() | |
177 | return True | |
178 | return False | |
179 | ||
180 | def _get_permissions(self): | |
181 | perms_out = self._exec(self._list_args(['list_user_permissions', self.username]), True) | |
182 | ||
183 | perms_list = list() | |
184 | for perm in perms_out: | |
185 | vhost, configure_priv, write_priv, read_priv = perm.split('\t') | |
186 | if not self.bulk_permissions: | |
187 | if vhost == self.permissions[0]['vhost']: | |
188 | perms_list.append(dict(vhost=vhost, configure_priv=configure_priv, | |
189 | write_priv=write_priv, read_priv=read_priv)) | |
190 | break | |
191 | else: | |
192 | perms_list.append(dict(vhost=vhost, configure_priv=configure_priv, | |
193 | write_priv=write_priv, read_priv=read_priv)) | |
194 | return perms_list | |
195 | ||
196 | ''' | |
197 | Monkey Patching the 'rabbitmq_user_3_7_9' ansible module for 3.7.9 rabbit version | |
198 | where headers were added in the output | |
199 | Cf: https://github.com/rabbitmq/rabbitmq-cli/issues/264 | |
200 | ''' | |
201 | def _list_args(self, args): | |
202 | return args + ['--no-table-headers'] | |
203 | ||
204 | def add(self): | |
205 | if self.password is not None: | |
206 | self._exec(['add_user', self.username, self.password]) | |
207 | else: | |
208 | self._exec(['add_user', self.username, '']) | |
209 | self._exec(['clear_password', self.username]) | |
210 | ||
211 | def delete(self): | |
212 | self._exec(['delete_user', self.username]) | |
213 | ||
214 | def set_tags(self): | |
215 | self._exec(['set_user_tags', self.username] + self.tags) | |
216 | ||
217 | def set_permissions(self): | |
218 | for permission in self._permissions: | |
219 | if permission not in self.permissions: | |
220 | cmd = ['clear_permissions', '-p'] | |
221 | cmd.append(permission['vhost']) | |
222 | cmd.append(self.username) | |
223 | self._exec(cmd) | |
224 | for permission in self.permissions: | |
225 | if permission not in self._permissions: | |
226 | cmd = ['set_permissions', '-p'] | |
227 | cmd.append(permission['vhost']) | |
228 | cmd.append(self.username) | |
229 | cmd.append(permission['configure_priv']) | |
230 | cmd.append(permission['write_priv']) | |
231 | cmd.append(permission['read_priv']) | |
232 | self._exec(cmd) | |
233 | ||
234 | def has_tags_modifications(self): | |
235 | return set(self.tags) != set(self._tags) | |
236 | ||
237 | def has_permissions_modifications(self): | |
238 | return sorted(self._permissions) != sorted(self.permissions) | |
239 | ||
240 | ||
241 | def main(): | |
242 | arg_spec = dict( | |
243 | user=dict(required=True, aliases=['username', 'name']), | |
244 | password=dict(default=None, no_log=True), | |
245 | tags=dict(default=None), | |
246 | permissions=dict(default=list(), type='list'), | |
247 | vhost=dict(default='/'), | |
248 | configure_priv=dict(default='^$'), | |
249 | write_priv=dict(default='^$'), | |
250 | read_priv=dict(default='^$'), | |
251 | force=dict(default='no', type='bool'), | |
252 | state=dict(default='present', choices=['present', 'absent']), | |
253 | node=dict(default=None) | |
254 | ) | |
255 | module = AnsibleModule( | |
256 | argument_spec=arg_spec, | |
257 | supports_check_mode=True | |
258 | ) | |
259 | ||
260 | username = module.params['user'] | |
261 | password = module.params['password'] | |
262 | tags = module.params['tags'] | |
263 | permissions = module.params['permissions'] | |
264 | vhost = module.params['vhost'] | |
265 | configure_priv = module.params['configure_priv'] | |
266 | write_priv = module.params['write_priv'] | |
267 | read_priv = module.params['read_priv'] | |
268 | force = module.params['force'] | |
269 | state = module.params['state'] | |
270 | node = module.params['node'] | |
271 | ||
272 | bulk_permissions = True | |
273 | if not permissions: | |
274 | perm = { | |
275 | 'vhost': vhost, | |
276 | 'configure_priv': configure_priv, | |
277 | 'write_priv': write_priv, | |
278 | 'read_priv': read_priv | |
279 | } | |
280 | permissions.append(perm) | |
281 | bulk_permissions = False | |
282 | ||
283 | rabbitmq_user_3_7_9 = RabbitMqUser(module, username, password, tags, permissions, | |
284 | node, bulk_permissions=bulk_permissions) | |
285 | ||
286 | result = dict(changed=False, user=username, state=state) | |
287 | ||
288 | if rabbitmq_user_3_7_9.get(): | |
289 | if state == 'absent': | |
290 | rabbitmq_user_3_7_9.delete() | |
291 | result['changed'] = True | |
292 | else: | |
293 | if force: | |
294 | rabbitmq_user_3_7_9.delete() | |
295 | rabbitmq_user_3_7_9.add() | |
296 | rabbitmq_user_3_7_9.get() | |
297 | result['changed'] = True | |
298 | ||
299 | if rabbitmq_user_3_7_9.has_tags_modifications(): | |
300 | rabbitmq_user_3_7_9.set_tags() | |
301 | result['changed'] = True | |
302 | ||
303 | if rabbitmq_user_3_7_9.has_permissions_modifications(): | |
304 | rabbitmq_user_3_7_9.set_permissions() | |
305 | result['changed'] = True | |
306 | elif state == 'present': | |
307 | rabbitmq_user_3_7_9.add() | |
308 | rabbitmq_user_3_7_9.set_tags() | |
309 | rabbitmq_user_3_7_9.set_permissions() | |
310 | result['changed'] = True | |
311 | ||
312 | module.exit_json(**result) | |
313 | ||
314 | if __name__ == '__main__': | |
315 | main() |