diff options
-rwxr-xr-x | library/rabbitmq_user_3_7_9.py | 315 | ||||
-rw-r--r-- | tasks/rabbitmq_users.yml | 19 |
2 files changed, 323 insertions, 11 deletions
diff --git a/library/rabbitmq_user_3_7_9.py b/library/rabbitmq_user_3_7_9.py new file mode 100755 index 0000000..5be78b7 --- /dev/null +++ b/library/rabbitmq_user_3_7_9.py | |||
@@ -0,0 +1,315 @@ | |||
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() | ||
diff --git a/tasks/rabbitmq_users.yml b/tasks/rabbitmq_users.yml index 7bba65e..d09d624 100644 --- a/tasks/rabbitmq_users.yml +++ b/tasks/rabbitmq_users.yml | |||
@@ -10,15 +10,14 @@ | |||
10 | tags: "{{ item['tags']|default(omit) }}" | 10 | tags: "{{ item['tags']|default(omit) }}" |
11 | permissions: "{{ item['permissions']|default(omit) }}" | 11 | permissions: "{{ item['permissions']|default(omit) }}" |
12 | state: present | 12 | state: present |
13 | run_once: rabbitmq_enable_clustering is defined and rabbitmq_enable_clustering | ||
14 | delegate_to: "{{ rabbitmq_master|default(omit) }}" | ||
13 | become: true | 15 | become: true |
14 | with_items: "{{ rabbitmq_users }}" | 16 | with_items: "{{ rabbitmq_users }}" |
15 | when: > | 17 | when: rabbitmq_debian_version is version('3.7.9', '<') |
16 | (rabbitmq_enable_clustering is defined and | ||
17 | not rabbitmq_enable_clustering) or | ||
18 | rabbitmq_enable_clustering is not defined | ||
19 | 18 | ||
20 | - name: rabbitmq_users | creating rabbitmq users | 19 | - name: rabbitmq_users | creating rabbitmq users (rabbit >= 3.7.9) |
21 | rabbitmq_user: | 20 | rabbitmq_user_3_7_9: |
22 | name: "{{ item['name'] }}" | 21 | name: "{{ item['name'] }}" |
23 | password: "{{ item['password'] }}" | 22 | password: "{{ item['password'] }}" |
24 | vhost: "{{ item['vhost']|default(omit) }}" | 23 | vhost: "{{ item['vhost']|default(omit) }}" |
@@ -28,10 +27,8 @@ | |||
28 | tags: "{{ item['tags']|default(omit) }}" | 27 | tags: "{{ item['tags']|default(omit) }}" |
29 | permissions: "{{ item['permissions']|default(omit) }}" | 28 | permissions: "{{ item['permissions']|default(omit) }}" |
30 | state: present | 29 | state: present |
31 | run_once: yes | 30 | run_once: rabbitmq_enable_clustering is defined and rabbitmq_enable_clustering |
32 | delegate_to: "{{ rabbitmq_master }}" | 31 | delegate_to: "{{ rabbitmq_master|default(omit) }}" |
33 | become: true | 32 | become: true |
34 | with_items: "{{ rabbitmq_users }}" | 33 | with_items: "{{ rabbitmq_users }}" |
35 | when: > | 34 | when: rabbitmq_debian_version is version('3.7.9', '>=') |
36 | rabbitmq_enable_clustering is defined and | ||
37 | rabbitmq_enable_clustering | ||