1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4# (c) 2018, Simon Dodsley (simon@purestorage.com)
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7from __future__ import absolute_import, division, print_function
8__metaclass__ = type
9
10ANSIBLE_METADATA = {'metadata_version': '1.1',
11                    'status': ['preview'],
12                    'supported_by': 'community'}
13
14DOCUMENTATION = r'''
15---
16module: purefa_ds
17version_added: '2.6'
18short_description: Configure FlashArray Directory Service
19description:
20- Set or erase configuration for the directory service. There is no facility
21  to SSL certificates at this time. Use the FlashArray GUI for this
22  additional configuration work.
23- To modify an existing directory service configuration you must first delete
24  an existing configuration and then recreate with new settings.
25author:
26- Pure Storage Ansible Team (@sdodsley) <pure-ansible-team@purestorage.com>
27options:
28  state:
29    type: str
30    description:
31    - Create or delete directory service configuration
32    default: present
33    choices: [ absent, present ]
34  enable:
35    description:
36    - Whether to enable or disable directory service support.
37    default: false
38    type: bool
39  uri:
40    type: list
41    description:
42    - A list of up to 30 URIs of the directory servers. Each URI must include
43      the scheme ldap:// or ldaps:// (for LDAP over SSL), a hostname, and a
44      domain name or IP address. For example, ldap://ad.company.com configures
45      the directory service with the hostname "ad" in the domain "company.com"
46      while specifying the unencrypted LDAP protocol.
47  base_dn:
48    type: str
49    description:
50    - Sets the base of the Distinguished Name (DN) of the directory service
51      groups. The base should consist of only Domain Components (DCs). The
52      base_dn will populate with a default value when a URI is entered by
53      parsing domain components from the URI. The base DN should specify DC=
54      for each domain component and multiple DCs should be separated by commas.
55    required: true
56  bind_password:
57    type: str
58    description:
59    - Sets the password of the bind_user user name account.
60  bind_user:
61    type: str
62    description:
63    - Sets the user name that can be used to bind to and query the directory.
64    - For Active Directory, enter the username - often referred to as
65      sAMAccountName or User Logon Name - of the account that is used to
66      perform directory lookups.
67    - For OpenLDAP, enter the full DN of the user.
68  group_base:
69    type: str
70    description:
71    - Specifies where the configured groups are located in the directory
72      tree. This field consists of Organizational Units (OUs) that combine
73      with the base DN attribute and the configured group CNs to complete
74      the full Distinguished Name of the groups. The group base should
75      specify OU= for each OU and multiple OUs should be separated by commas.
76      The order of OUs is important and should get larger in scope from left
77      to right. Each OU should not exceed 64 characters in length.
78    - Not Supported from Purity 5.2.0 or higher. Use I(purefa_dsrole) module.
79  ro_group:
80    type: str
81    description:
82    - Sets the common Name (CN) of the configured directory service group
83      containing users with read-only privileges on the FlashArray. This
84      name should be just the Common Name of the group without the CN=
85      specifier. Common Names should not exceed 64 characters in length.
86    - Not Supported from Purity 5.2.0 or higher. Use I(purefa_dsrole) module.
87  sa_group:
88    type: str
89    description:
90    - Sets the common Name (CN) of the configured directory service group
91      containing administrators with storage-related privileges on the
92      FlashArray. This name should be just the Common Name of the group
93      without the CN= specifier. Common Names should not exceed 64
94      characters in length.
95    - Not Supported from Purity 5.2.0 or higher. Use I(purefa_dsrole) module.
96  aa_group:
97    type: str
98    description:
99    - Sets the common Name (CN) of the directory service group containing
100      administrators with full privileges when managing the FlashArray.
101      The name should be just the Common Name of the group without the
102      CN= specifier. Common Names should not exceed 64 characters in length.
103    - Not Supported from Purity 5.2.0 or higher. Use I(purefa_dsrole) module.
104extends_documentation_fragment:
105- purestorage.fa
106'''
107
108EXAMPLES = r'''
109- name: Delete existing directory service
110  purefa_ds:
111    state: absent
112    fa_url: 10.10.10.2
113    api_token: e31060a7-21fc-e277-6240-25983c6c4592
114
115- name: Create directory service (disabled) - Pre-5.2.0
116  purefa_ds:
117    uri: "ldap://lab.purestorage.com"
118    base_dn: "DC=lab,DC=purestorage,DC=com"
119    bind_user: Administrator
120    bind_password: password
121    group_base: "OU=Pure-Admin"
122    ro_group: PureReadOnly
123    sa_group: PureStorage
124    aa_group: PureAdmin
125    fa_url: 10.10.10.2
126    api_token: e31060a7-21fc-e277-6240-25983c6c4592
127
128- name: Create directory service (disabled) - 5.2.0 or higher
129  purefa_ds:
130    uri: "ldap://lab.purestorage.com"
131    base_dn: "DC=lab,DC=purestorage,DC=com"
132    bind_user: Administrator
133    bind_password: password
134    fa_url: 10.10.10.2
135    api_token: e31060a7-21fc-e277-6240-25983c6c4592
136
137- name: Enable existing directory service
138  purefa_ds:
139    enable: true
140    fa_url: 10.10.10.2
141    api_token: e31060a7-21fc-e277-6240-25983c6c4592
142
143- name: Disable existing directory service
144  purefa_ds:
145    enable: false
146    fa_url: 10.10.10.2
147    api_token: e31060a7-21fc-e277-6240-25983c6c4592
148
149- name: Create directory service (enabled) - Pre-5.2.0
150  purefa_ds:
151    enable: true
152    uri: "ldap://lab.purestorage.com"
153    base_dn: "DC=lab,DC=purestorage,DC=com"
154    bind_user: Administrator
155    bind_password: password
156    group_base: "OU=Pure-Admin"
157    ro_group: PureReadOnly
158    sa_group: PureStorage
159    aa_group: PureAdmin
160    fa_url: 10.10.10.2
161    api_token: e31060a7-21fc-e277-6240-25983c6c4592
162
163- name: Create directory service (enabled) - 5.2.0 or higher
164  purefa_ds:
165    enable: true
166    uri: "ldap://lab.purestorage.com"
167    base_dn: "DC=lab,DC=purestorage,DC=com"
168    bind_user: Administrator
169    bind_password: password
170    fa_url: 10.10.10.2
171    api_token: e31060a7-21fc-e277-6240-25983c6c4592
172'''
173
174RETURN = r'''
175'''
176
177from ansible.module_utils.basic import AnsibleModule
178from ansible.module_utils.pure import get_system, purefa_argument_spec
179
180
181DS_ROLE_REQUIRED_API_VERSION = '1.16'
182
183
184def update_ds(module, array):
185    """Update Directory Service"""
186    changed = False
187    module.exit_json(changed=changed)
188
189
190def enable_ds(module, array):
191    """Enable Directory Service"""
192    changed = False
193    try:
194        array.enable_directory_service()
195        changed = True
196    except Exception:
197        module.fail_json(msg='Enable Directory Service failed: Check Configuration')
198    module.exit_json(changed=changed)
199
200
201def disable_ds(module, array):
202    """Disable Directory Service"""
203    """Disable Directory Service"""
204    changed = False
205    try:
206        array.disable_directory_service()
207        changed = True
208    except Exception:
209        module.fail_json(msg='Disable Directory Service failed')
210    module.exit_json(changed=changed)
211
212
213def delete_ds(module, array):
214    """Delete Directory Service"""
215    changed = False
216    try:
217        api_version = array._list_available_rest_versions()
218        array.set_directory_service(enabled=False)
219        if DS_ROLE_REQUIRED_API_VERSION in api_version:
220            array.set_directory_service(uri=[''],
221                                        base_dn="",
222                                        bind_user="",
223                                        bind_password="",
224                                        certificate="")
225            changed = True
226        else:
227            array.set_directory_service(uri=[''],
228                                        base_dn="",
229                                        group_base="",
230                                        bind_user="",
231                                        bind_password="",
232                                        readonly_group="",
233                                        storage_admin_group="",
234                                        array_admin_group="",
235                                        certificate="")
236            changed = True
237    except Exception:
238        module.fail_json(msg='Delete Directory Service failed')
239    module.exit_json(changed=changed)
240
241
242def create_ds(module, array):
243    """Create Directory Service"""
244    changed = False
245    api_version = array._list_available_rest_versions()
246    if DS_ROLE_REQUIRED_API_VERSION in api_version:
247        if not module.params['role']:
248            module.fail_json(msg='At least one role must be configured')
249        try:
250            array.set_directory_service(uri=module.params['uri'],
251                                        base_dn=module.params['base_dn'],
252                                        bind_user=module.params['bind_user'],
253                                        bind_password=module.params['bind_password'])
254            array.set_directory_service(enabled=module.params['enable'])
255            changed = True
256        except Exception:
257            module.fail_json(msg='Create Directory Service failed: Check configuration')
258    else:
259        groups_rule = [not module.params['ro_group'],
260                       not module.params['sa_group'],
261                       not module.params['aa_group']]
262
263        if all(groups_rule):
264            module.fail_json(msg='At least one group must be configured')
265        try:
266            array.set_directory_service(uri=module.params['uri'],
267                                        base_dn=module.params['base_dn'],
268                                        group_base=module.params['group_base'],
269                                        bind_user=module.params['bind_user'],
270                                        bind_password=module.params['bind_password'],
271                                        readonly_group=module.params['ro_group'],
272                                        storage_admin_group=module.params['sa_group'],
273                                        array_admin_group=module.params['aa_group'])
274            array.set_directory_service(enabled=module.params['enable'])
275            changed = True
276        except Exception:
277            module.fail_json(msg='Create Directory Service failed: Check configuration')
278    module.exit_json(changed=changed)
279
280
281def main():
282    argument_spec = purefa_argument_spec()
283    argument_spec.update(dict(
284        uri=dict(type='list'),
285        state=dict(type='str', default='present', choices=['absent', 'present']),
286        enable=dict(type='bool', default=False),
287        bind_password=dict(type='str', no_log=True),
288        bind_user=dict(type='str'),
289        base_dn=dict(type='str'),
290        group_base=dict(type='str'),
291        ro_group=dict(type='str'),
292        sa_group=dict(type='str'),
293        aa_group=dict(type='str'),
294    ))
295
296    required_together = [['uri', 'bind_password', 'bind_user',
297                          'base_dn', 'group_base']]
298
299    module = AnsibleModule(argument_spec,
300                           required_together=required_together,
301                           supports_check_mode=False)
302
303    state = module.params['state']
304    array = get_system(module)
305    ds_exists = False
306    dirserv = array.get_directory_service()
307    ds_enabled = dirserv['enabled']
308    if dirserv['base_dn']:
309        ds_exists = True
310
311    if state == 'absent' and ds_exists:
312        delete_ds(module, array)
313    elif ds_exists and module.params['enable'] and ds_enabled:
314        update_ds(module, array)
315    elif ds_exists and not module.params['enable'] and ds_enabled:
316        disable_ds(module, array)
317    elif ds_exists and module.params['enable'] and not ds_enabled:
318        enable_ds(module, array)
319    elif not ds_exists and state == 'present':
320        create_ds(module, array)
321    else:
322        module.exit_json(changed=False)
323
324
325if __name__ == '__main__':
326    main()
327