1#!/usr/bin/python
2'''
3(c) 2018-2019, NetApp, Inc
4GNU General Public License v3.0+
5(see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6'''
7
8from __future__ import absolute_import, division, print_function
9__metaclass__ = type
10
11ANSIBLE_METADATA = {'metadata_version': '1.1',
12                    'status': ['preview'],
13                    'supported_by': 'certified'}
14
15DOCUMENTATION = '''
16
17module: na_ontap_ldap
18
19short_description: NetApp ONTAP LDAP
20extends_documentation_fragment:
21    - netapp.na_ontap
22version_added: '2.9'
23author: Milan Zink (@zeten30) <zeten30@gmail.com>/<mzink@redhat.com>
24
25description:
26- Create, modify or delete LDAP on NetApp ONTAP SVM/vserver
27
28options:
29
30  state:
31    description:
32    - Whether the LDAP is present or not.
33    choices: ['present', 'absent']
34    default: 'present'
35    type: str
36
37  vserver:
38    description:
39    - vserver/svm configured to use LDAP
40    required: true
41    type: str
42
43  name:
44    description:
45    - The name of LDAP client configuration
46    required: true
47    type: str
48
49  skip_config_validation:
50    description:
51    - Skip LDAP validation
52    choices: ['true', 'false']
53    type: str
54'''
55
56EXAMPLES = '''
57
58    - name: Enable LDAP on SVM
59      na_ontap_ldap:
60        state:         present
61        name:          'example_ldap'
62        vserver:       'vserver1'
63        hostname:      "{{ netapp_hostname }}"
64        username:      "{{ netapp_username }}"
65        password:      "{{ netapp_password }}"
66
67'''
68
69RETURN = '''
70'''
71
72import traceback
73import ansible.module_utils.netapp as netapp_utils
74from ansible.module_utils.basic import AnsibleModule
75from ansible.module_utils._text import to_native
76from ansible.module_utils.netapp_module import NetAppModule
77
78HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
79
80
81class NetAppOntapLDAP(object):
82    '''
83    LDAP Client definition class
84    '''
85
86    def __init__(self):
87        self.argument_spec = netapp_utils.na_ontap_host_argument_spec()
88        self.argument_spec.update(dict(
89            name=dict(required=True, type='str'),
90            skip_config_validation=dict(required=False, default=None, choices=['true', 'false']),
91            state=dict(required=False, choices=['present', 'absent'], default='present'),
92            vserver=dict(required=True, type='str')
93        ))
94
95        self.module = AnsibleModule(
96            argument_spec=self.argument_spec,
97            supports_check_mode=True
98        )
99        self.na_helper = NetAppModule()
100        self.parameters = self.na_helper.set_parameters(self.module.params)
101
102        if HAS_NETAPP_LIB is False:
103            self.module.fail_json(
104                msg="the python NetApp-Lib module is required")
105        else:
106            self.server = netapp_utils.setup_na_ontap_zapi(module=self.module, vserver=self.parameters['vserver'])
107
108    def get_ldap(self, client_config_name=None):
109        '''
110        Checks if LDAP config exists.
111
112        :return:
113            ldap config object if found
114            None if not found
115        :rtype: object/None
116        '''
117        # Make query
118        config_info = netapp_utils.zapi.NaElement('ldap-config-get-iter')
119
120        if client_config_name is None:
121            client_config_name = self.parameters['name']
122
123        query_details = netapp_utils.zapi.NaElement.create_node_with_children('ldap-config', **{'client-config': client_config_name})
124
125        query = netapp_utils.zapi.NaElement('query')
126        query.add_child_elem(query_details)
127        config_info.add_child_elem(query)
128
129        result = self.server.invoke_successfully(config_info, enable_tunneling=True)
130
131        # Get LDAP configuration details
132        config_details = None
133        if (result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1):
134            attributes_list = result.get_child_by_name('attributes-list')
135            config_info = attributes_list.get_child_by_name('ldap-config')
136
137            # Define config details structure
138            config_details = {'client_config': config_info.get_child_content('client-config'),
139                              'skip_config_validation': config_info.get_child_content('skip-config-validation'),
140                              'vserver': config_info.get_child_content('vserver')}
141
142        return config_details
143
144    def create_ldap(self):
145        '''
146        Create LDAP configuration
147        '''
148        options = {
149            'client-config': self.parameters['name'],
150            'client-enabled': 'true'
151        }
152
153        if self.parameters.get('skip_config_validation') is not None:
154            options['skip-config-validation'] = self.parameters['skip_config_validation']
155
156        # Initialize NaElement
157        ldap_create = netapp_utils.zapi.NaElement.create_node_with_children('ldap-config-create', **options)
158
159        # Try to create LDAP configuration
160        try:
161            self.server.invoke_successfully(ldap_create, enable_tunneling=True)
162        except netapp_utils.zapi.NaApiError as errcatch:
163            self.module.fail_json(msg='Error creating LDAP configuration %s: %s' % (self.parameters['name'], to_native(errcatch)),
164                                  exception=traceback.format_exc())
165
166    def delete_ldap(self):
167        '''
168        Delete LDAP configuration
169        '''
170        ldap_client_delete = netapp_utils.zapi.NaElement.create_node_with_children('ldap-config-delete', **{})
171
172        try:
173            self.server.invoke_successfully(ldap_client_delete, enable_tunneling=True)
174        except netapp_utils.zapi.NaApiError as errcatch:
175            self.module.fail_json(msg='Error deleting LDAP configuration %s: %s' % (
176                self.parameters['name'], to_native(errcatch)), exception=traceback.format_exc())
177
178    def modify_ldap(self, modify):
179        '''
180        Modify LDAP
181        :param modify: list of modify attributes
182        '''
183        ldap_modify = netapp_utils.zapi.NaElement('ldap-config-modify')
184        ldap_modify.add_new_child('client-config', self.parameters['name'])
185
186        for attribute in modify:
187            if attribute == 'skip_config_validation':
188                ldap_modify.add_new_child('skip-config-validation', self.parameters[attribute])
189
190        # Try to modify LDAP
191        try:
192            self.server.invoke_successfully(ldap_modify, enable_tunneling=True)
193        except netapp_utils.zapi.NaApiError as errcatch:
194            self.module.fail_json(msg='Error modifying LDAP %s: %s' % (self.parameters['name'], to_native(errcatch)),
195                                  exception=traceback.format_exc())
196
197    def apply(self):
198        '''Call create/modify/delete operations.'''
199        current = self.get_ldap()
200        cd_action = self.na_helper.get_cd_action(current, self.parameters)
201        modify = self.na_helper.get_modified_attributes(current, self.parameters)
202        #  create an ems log event for users with auto support turned on
203        netapp_utils.ems_log_event("na_ontap_ldap", self.server)
204
205        if self.na_helper.changed:
206            if self.module.check_mode:
207                pass
208            else:
209                if cd_action == 'create':
210                    self.create_ldap()
211                elif cd_action == 'delete':
212                    self.delete_ldap()
213                elif modify:
214                    self.modify_ldap(modify)
215        self.module.exit_json(changed=self.na_helper.changed)
216
217
218#
219# MAIN
220#
221def main():
222    '''ONTAP LDAP client configuration'''
223    ldapclient = NetAppOntapLDAP()
224    ldapclient.apply()
225
226
227if __name__ == '__main__':
228    main()
229