summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSumit Kumar <timus@vt.edu>2017-02-14 16:01:16 -0500
committerjctanner <tanner.jc@gmail.com>2017-02-14 16:01:16 -0500
commit2c81e05baa77d9fd5d029aa8bc34267a09f0c6d7 (patch)
tree066dda23cd73da56d28eec3f3dc61c3c58d8c635
parent97b238b6c697cc9defd59459257288b4384239e3 (diff)
downloadansible-2c81e05baa77d9fd5d029aa8bc34267a09f0c6d7.tar.gz
Add NetApp ONTAP user module (#20723)
* Add NetApp ONTAP user module * Make changes to adhere to community guidelines * Fix PEP8 issue
-rw-r--r--lib/ansible/modules/storage/netapp/na_cdot_user.py311
1 files changed, 311 insertions, 0 deletions
diff --git a/lib/ansible/modules/storage/netapp/na_cdot_user.py b/lib/ansible/modules/storage/netapp/na_cdot_user.py
new file mode 100644
index 0000000000..bcf89844de
--- /dev/null
+++ b/lib/ansible/modules/storage/netapp/na_cdot_user.py
@@ -0,0 +1,311 @@
+#!/usr/bin/python
+
+# (c) 2017, NetApp, Inc
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
+#
+ANSIBLE_METADATA = {'status': ['preview'],
+ 'supported_by': 'community',
+ 'version': '1.0'}
+
+DOCUMENTATION = '''
+
+module: na_cdot_users
+
+short_description: useradmin configuration and management
+extends_documentation_fragment:
+ - netapp.ontap
+version_added: '2.3'
+author: Sumit Kumar (sumit4@netapp.com)
+
+description:
+- Create or destroy users.
+
+options:
+
+ state:
+ description:
+ - Whether the specified user should exist or not.
+ required: true
+ choices: ['present', 'absent']
+
+ name:
+ description:
+ - The name of the user to manage.
+ required: true
+
+ application:
+ description:
+ - Applications to grant access to.
+ required: true
+ choices: ['console', 'http','ontapi','rsh','snmp','sp','ssh','telnet']
+
+ authentication_method:
+ description:
+ - Authentication method for the application.
+ - Not all authentication methods are valid for an application.
+ - Valid authentication methods for each application are as denoted in I(authentication_choices_description).
+ authentication_choices_description:
+ - password for console application
+ - password, domain, nsswitch, cert for http application.
+ - password, domain, nsswitch, cert for ontapi application.
+ - community for snmp application (when creating SNMPv1 and SNMPv2 users).
+ - usm and community for snmp application (when creating SNMPv3 users).
+ - password for sp application.
+ - password for rsh application.
+ - password for telnet application.
+ - password, publickey, domain, nsswitch for ssh application.
+ required: true
+ choices: ['community', 'password', 'publickey', 'domain', 'nsswitch', 'usm']
+
+ set_password:
+ description:
+ - Password for the user account.
+ - It is ignored for creating snmp users, but is required for creating non-snmp users.
+ - For an existing user, this value will be used as the new password.
+ default: None
+
+ role_name:
+ description:
+ - The name of the role.
+ note: required when C(state=present)
+
+
+ vserver:
+ description:
+ - The name of the vserver to use.
+ required: true
+
+'''
+
+EXAMPLES = """
+
+ - name: Create User
+ na_cdot_user:
+ state: present
+ name: SampleUser
+ application: ssh
+ authentication_method: password
+ set_password: apn1242183u1298u41
+ role_name: vsadmin
+ vserver: ansibleVServer
+ hostname: "{{ netapp_hostname }}"
+ username: "{{ netapp_username }}"
+ password: "{{ netapp_password }}"
+
+"""
+
+RETURN = """
+
+"""
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.pycompat24 import get_exception
+import ansible.module_utils.netapp as netapp_utils
+
+HAS_NETAPP_LIB = netapp_utils.has_netapp_lib()
+
+
+class NetAppCDOTUser(object):
+ """
+ Common operations to manage users and roles.
+ """
+
+ def __init__(self):
+ self.argument_spec = netapp_utils.ontap_sf_host_argument_spec()
+ self.argument_spec.update(dict(
+ state=dict(required=True, choices=['present', 'absent']),
+ name=dict(required=True, type='str'),
+
+ application=dict(required=True, type='str', choices=[
+ 'console', 'http', 'ontapi', 'rsh',
+ 'snmp', 'sp', 'ssh', 'telnet']),
+ authentication_method=dict(required=True, type='str',
+ choices=['community', 'password',
+ 'publickey', 'domain',
+ 'nsswitch', 'usm']),
+ set_password=dict(required=False, type='str', default=None),
+ role_name=dict(required=False, type='str'),
+
+ vserver=dict(required=True, type='str'),
+ ))
+
+ self.module = AnsibleModule(
+ argument_spec=self.argument_spec,
+ required_if=[
+ ('state', 'present', ['role_name'])
+ ],
+ supports_check_mode=True
+ )
+
+ p = self.module.params
+
+ # set up state variables
+ self.state = p['state']
+ self.name = p['name']
+
+ self.application = p['application']
+ self.authentication_method = p['authentication_method']
+ self.set_password = p['set_password']
+ self.role_name = p['role_name']
+
+ self.vserver = p['vserver']
+
+ if HAS_NETAPP_LIB is False:
+ self.module.fail_json(msg="the python NetApp-Lib module is required")
+ else:
+ self.server = netapp_utils.setup_ontap_zapi(module=self.module)
+
+ def get_user(self):
+ """
+ Checks if the user exists.
+
+ :return:
+ True if user found
+ False if user is not found
+ :rtype: bool
+ """
+
+ security_login_get_iter = netapp_utils.zapi.NaElement('security-login-get-iter')
+ query_details = netapp_utils.zapi.NaElement.create_node_with_children(
+ 'security-login-account-info', **{'vserver': self.vserver,
+ 'user-name': self.name,
+ 'application': self.application,
+ 'authentication-method':
+ self.authentication_method})
+
+ query = netapp_utils.zapi.NaElement('query')
+ query.add_child_elem(query_details)
+ security_login_get_iter.add_child_elem(query)
+
+ try:
+ result = self.server.invoke_successfully(security_login_get_iter,
+ enable_tunneling=False)
+
+ if result.get_child_by_name('num-records') and int(result.get_child_content('num-records')) >= 1:
+ return True
+ else:
+ return False
+
+ except netapp_utils.zapi.NaApiError:
+ e = get_exception()
+ # Error 16034 denotes a user not being found.
+ if str(e.code) == "16034":
+ return False
+ else:
+ self.module.fail_json(msg='Error getting user %s' % self.name, exception=str(e))
+
+ def create_user(self):
+ user_create = netapp_utils.zapi.NaElement.create_node_with_children(
+ 'security-login-create', **{'vserver': self.vserver,
+ 'user-name': self.name,
+ 'application': self.application,
+ 'authentication-method':
+ self.authentication_method,
+ 'role-name': self.role_name})
+ if self.set_password is not None:
+ user_create.add_new_child('password', self.set_password)
+
+ try:
+ self.server.invoke_successfully(user_create,
+ enable_tunneling=False)
+ except netapp_utils.zapi.NaApiError:
+ err = get_exception()
+ self.module.fail_json(msg='Error creating user %s' % self.name, exception=str(err))
+
+ def delete_user(self):
+ user_delete = netapp_utils.zapi.NaElement.create_node_with_children(
+ 'security-login-delete', **{'vserver': self.vserver,
+ 'user-name': self.name,
+ 'application': self.application,
+ 'authentication-method':
+ self.authentication_method})
+
+ try:
+ self.server.invoke_successfully(user_delete,
+ enable_tunneling=False)
+ except netapp_utils.zapi.NaApiError:
+ err = get_exception()
+ self.module.fail_json(msg='Error removing user %s' % self.name, exception=str(err))
+
+ def change_password(self):
+ """
+ Changes the password
+
+ :return:
+ True if password updated
+ False if password is not updated
+ :rtype: bool
+ """
+ self.server.set_vserver(self.vserver)
+ modify_password = netapp_utils.zapi.NaElement.create_node_with_children(
+ 'security-login-modify-password', **{
+ 'new-password': str(self.set_password),
+ 'user-name': self.name})
+ try:
+ self.server.invoke_successfully(modify_password,
+ enable_tunneling=True)
+ except netapp_utils.zapi.NaApiError:
+ e = get_exception()
+ if str(e.code) == '13114':
+ return False
+ else:
+ err = get_exception()
+ self.module.fail_json(msg='Error setting password for user %s' % self.name, exception=str(err))
+
+ self.server.set_vserver(None)
+ return True
+
+ def apply(self):
+ property_changed = False
+ password_changed = False
+ user_exists = self.get_user()
+
+ if user_exists:
+ if self.state == 'absent':
+ property_changed = True
+
+ elif self.state == 'present':
+ if self.set_password is not None:
+ password_changed = self.change_password()
+ else:
+ if self.state == 'present':
+ # Check if anything needs to be updated
+ property_changed = True
+
+ if property_changed:
+ if self.module.check_mode:
+ pass
+ else:
+ if self.state == 'present':
+ if not user_exists:
+ self.create_user()
+
+ # Add ability to update parameters.
+
+ elif self.state == 'absent':
+ self.delete_user()
+
+ changed = property_changed or password_changed
+ self.module.exit_json(changed=changed)
+
+
+def main():
+ v = NetAppCDOTUser()
+ v.apply()
+
+if __name__ == '__main__':
+ main()