File: //usr/lib/python3.9/site-packages/ansible_collections/dellemc/unity/plugins/modules/nfsserver.py
# Copyright: (c) 2022, Dell Technologies
# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
"""Ansible module for managing NFS server on Unity"""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = r'''
module: nfsserver
version_added: '1.4.0'
short_description: Manage NFS server on Unity storage system
description:
- Managing the NFS server on the Unity storage system includes creating NFS server, getting NFS server details
and deleting NFS server attributes.
extends_documentation_fragment:
- dellemc.unity.unity
author:
- Meenakshi Dembi (@dembim) <[email protected]>
options:
nas_server_name:
description:
- Name of the NAS server on which NFS server will be hosted.
type: str
nas_server_id:
description:
- ID of the NAS server on which NFS server will be hosted.
type: str
nfs_server_id:
description:
- ID of the NFS server.
type: str
host_name:
description:
- Host name of the NFS server.
type: str
nfs_v4_enabled:
description:
- Indicates whether the NFSv4 is enabled on the NAS server.
type: bool
is_secure_enabled:
description:
- Indicates whether the secure NFS is enabled.
type: bool
kerberos_domain_controller_type:
description:
- Type of Kerberos Domain Controller used for secure NFS service.
choices: [CUSTOM, UNIX, WINDOWS]
type: str
kerberos_domain_controller_username:
description:
- Kerberos Domain Controller administrator username.
type: str
kerberos_domain_controller_password:
description:
- Kerberos Domain Controller administrator password.
type: str
is_extended_credentials_enabled:
description:
- Indicates whether support for more than 16 unix groups in a Unix credential.
type: bool
remove_spn_from_kerberos:
description:
- Indicates whether to remove the SPN from Kerberos Domain Controller.
default: true
type: bool
state:
description:
- Define whether the NFS server should exist or not.
choices: [absent, present]
required: true
type: str
notes:
- The I(check_mode) is supported.
- Modify operation for NFS Server is not supported.
- When I(kerberos_domain_controller_type) is C(UNIX), I(kdc_type) in I(nfs_server_details) output is displayed as C(null).
'''
EXAMPLES = r'''
- name: Create NFS server with kdctype as Windows
dellemc.unity.nfsserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
host_name: "dummy_nas23"
is_secure_enabled: True
kerberos_domain_controller_type: "WINDOWS"
kerberos_domain_controller_username: "administrator"
kerberos_domain_controller_password: "Password123!"
is_extended_credentials_enabled: True
nfs_v4_enabled: True
state: "present"
- name: Create NFS server with kdctype as Unix
dellemc.unity.nfsserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
host_name: "dummy_nas23"
is_secure_enabled: True
kerberos_domain_controller_type: "UNIX"
is_extended_credentials_enabled: True
nfs_v4_enabled: True
state: "present"
- name: Get NFS server details
dellemc.unity.nfsserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
state: "present"
- name: Delete NFS server
dellemc.unity.nfsserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
kerberos_domain_controller_username: "administrator"
kerberos_domain_controller_password: "Password123!"
unjoin_server_account: False
state: "absent"
'''
RETURN = r'''
changed:
description: Whether or not the resource has changed.
returned: always
type: bool
sample: true
nfs_server_details:
description: Details of the NFS server.
returned: When NFS server exists
type: dict
contains:
credentials_cache_ttl:
description: Credential cache refresh timeout. Resolution is in minutes. Default value is 15 minutes.
type: str
existed:
description: Indicates if NFS Server exists.
type: bool
host_name:
description: Host name of the NFS server.
type: str
id:
description: Unique identifier of the NFS Server instance.
type: str
is_extended_credentials_enabled:
description: Indicates whether the NFS server supports more than 16 Unix groups in a Unix credential.
type: bool
is_secure_enabled:
description: Indicates whether secure NFS is enabled on the NFS server.
type: bool
kdc_type:
description: Type of Kerberos Domain Controller used for secure NFS service.
type: str
nfs_v4_enabled:
description: Indicates whether NFSv4 is enabled on the NAS server.
type: bool
servicee_principal_name:
description: The Service Principal Name (SPN) for the NFS Server.
type: str
sample: {
"credentials_cache_ttl": "0:15:00",
"existed": true,
"file_interfaces": {
"UnityFileInterfaceList": [
{
"UnityFileInterface": {
"hash": 8778980109421,
"id": "if_37"
}
}
]
},
"hash": 8778980109388,
"host_name": "dummy_nas23.pie.lab.emc.com",
"id": "nfs_51",
"is_extended_credentials_enabled": true,
"is_secure_enabled": true,
"kdc_type": "KdcTypeEnum.WINDOWS",
"nas_server": {
"UnityNasServer": {
"hash": 8778980109412
}
},
"nfs_v4_enabled": true,
"servicee_principal_name": null
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
import utils
LOG = utils.get_logger('nfsserver')
application_type = "Ansible/1.6.0"
class NFSServer(object):
"""Class with NFS server operations"""
def __init__(self):
"""Define all parameters required by this module"""
self.module_params = utils.get_unity_management_host_parameters()
self.module_params.update(get_nfs_server_parameters())
mutually_exclusive = [['nas_server_name', 'nas_server_id']]
required_one_of = [['nfs_server_id', 'nas_server_name', 'nas_server_id']]
# initialize the Ansible module
self.module = AnsibleModule(
argument_spec=self.module_params,
supports_check_mode=True,
mutually_exclusive=mutually_exclusive,
required_one_of=required_one_of
)
utils.ensure_required_libs(self.module)
self.unity_conn = utils.get_unity_unisphere_connection(
self.module.params, application_type)
LOG.info('Check Mode Flag %s', self.module.check_mode)
def get_nfs_server_details(self, nfs_server_id=None, nas_server_id=None):
"""Get NFS server details.
:param: nfs_server_id: The ID of the NFS server
:param: nas_server_id: The name of the NAS server
:return: Dict containing NFS server details if exists
"""
LOG.info("Getting NFS server details")
try:
if nfs_server_id:
nfs_server_details = self.unity_conn.get_nfs_server(_id=nfs_server_id)
return nfs_server_details._get_properties()
elif nas_server_id:
nfs_server_details = self.unity_conn.get_nfs_server(nas_server=nas_server_id)
if len(nfs_server_details) > 0:
return process_dict(nfs_server_details._get_properties())
return None
except utils.HttpError as e:
if e.http_status == 401:
msg = 'Incorrect username or password provided.'
LOG.error(msg)
self.module.fail_json(msg=msg)
else:
err_msg = "Failed to get details of NFS Server" \
" with error {0}".format(str(e))
LOG.error(err_msg)
self.module.fail_json(msg=err_msg)
except utils.UnityResourceNotFoundError as e:
err_msg = "Failed to get details of NFS Server" \
" with error {0}".format(str(e))
LOG.error(err_msg)
return None
def get_nfs_server_instance(self, nfs_server_id):
"""Get NFS server instance.
:param: nfs_server_id: The ID of the NFS server
:return: Return NFS server instance if exists
"""
try:
nfs_server_obj = self.unity_conn.get_nfs_server(_id=nfs_server_id)
return nfs_server_obj
except Exception as e:
error_msg = "Failed to get the NFS server %s instance" \
" with error %s" % (nfs_server_id, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def delete_nfs_server(self, nfs_server_id, skip_unjoin=None, domain_username=None, domain_password=None):
"""Delete NFS server.
:param: nfs_server_id: The ID of the NFS server
:param: skip_unjoin: Flag indicating whether to unjoin SMB server account from AD before deletion
:param: domain_username: The domain username
:param: domain_password: The domain password
:return: Return True if NFS server is deleted
"""
LOG.info("Deleting NFS server")
try:
if not self.module.check_mode:
nfs_obj = self.get_nfs_server_instance(nfs_server_id=nfs_server_id)
nfs_obj.delete(skip_kdc_unjoin=skip_unjoin, username=domain_username, password=domain_password)
return True
except Exception as e:
msg = "Failed to delete NFS server: %s with error: %s" % (nfs_server_id, str(e))
LOG.error(msg)
self.module.fail_json(msg=msg)
def get_nas_server_id(self, nas_server_name):
"""Get NAS server ID.
:param: nas_server_name: The name of NAS server
:return: Return NAS server ID if exists
"""
LOG.info("Getting NAS server ID")
try:
obj_nas = self.unity_conn.get_nas_server(name=nas_server_name)
return obj_nas.get_id()
except Exception as e:
msg = "Failed to get details of NAS server: %s with error: %s" % (nas_server_name, str(e))
LOG.error(msg)
self.module.fail_json(msg=msg)
def is_modification_required(self, is_extended_credentials_enabled, nfs_server_details):
"""Check if modification is required in existing NFS server
:param: is_extended_credentials_enabled: Indicates whether the NFS server supports more than 16 Unix groups in a Unix credential.
:param: nfs_server_details: NFS server details
:return: True if modification is required
"""
LOG.info("Checking if any modification is required")
# Check for Extend Credential
if is_extended_credentials_enabled is not None and \
is_extended_credentials_enabled != nfs_server_details['is_extended_credentials_enabled']:
return True
def create_nfs_server(self, nas_server_id, host_name=None, nfs_v4_enabled=None, is_secure_enabled=None,
kerberos_domain_controller_type=None, kerberos_domain_controller_username=None,
kerberos_domain_controller_password=None, is_extended_credentials_enabled=None):
"""Create NFS server.
:param: nas_server_id: The ID of NAS server.
:param: host_name: Name of NFS Server.
:param: nfs_v4_enabled: Indicates whether the NFSv4 is enabled on the NAS server.
:param: is_secure_enabled: Indicates whether the secure NFS is enabled.
:param: kerberos_domain_controller_type: Type of Kerberos Domain Controller used for secure NFS service.
:param: kerberos_domain_controller_username: Kerberos Domain Controller administrator username.
:param: kerberos_domain_controller_password: Kerberos Domain Controller administrator password.
:param: is_extended_credentials_enabled: Indicates whether support for more than 16 unix groups in a Unix credential.
"""
LOG.info("Creating NFS server")
try:
if not self.module.check_mode:
kdc_enum_type = get_enum_kdctype(kerberos_domain_controller_type)
if kerberos_domain_controller_type == "UNIX":
is_extended_credentials_enabled = None
is_secure_enabled = None
utils.UnityNfsServer.create(cli=self.unity_conn._cli, nas_server=nas_server_id, host_name=host_name,
nfs_v4_enabled=nfs_v4_enabled,
is_secure_enabled=is_secure_enabled, kdc_type=kdc_enum_type,
kdc_username=kerberos_domain_controller_username,
kdc_password=kerberos_domain_controller_password,
is_extended_credentials_enabled=is_extended_credentials_enabled)
return True
except Exception as e:
msg = "Failed to create NFS server with on NAS Server %s with error: %s" % (nas_server_id, str(e))
LOG.error(msg)
self.module.fail_json(msg=msg)
def validate_input_params(self):
param_list = ["nfs_server_id", "nas_server_id", "nas_server_name", "host_name", "kerberos_domain_controller_username",
"kerberos_domain_controller_password"]
for param in param_list:
msg = "Please provide valid value for: %s" % param
if self.module.params[param] is not None and len(self.module.params[param].strip()) == 0:
errmsg = msg.format(param)
self.module.fail_json(msg=errmsg)
def perform_module_operation(self):
"""
Perform different actions on NFS server module based on parameters
passed in the playbook
"""
nfs_server_id = self.module.params['nfs_server_id']
nas_server_id = self.module.params['nas_server_id']
nas_server_name = self.module.params['nas_server_name']
host_name = self.module.params['host_name']
nfs_v4_enabled = self.module.params['nfs_v4_enabled']
is_secure_enabled = self.module.params['is_secure_enabled']
kerberos_domain_controller_type = self.module.params['kerberos_domain_controller_type']
kerberos_domain_controller_username = self.module.params['kerberos_domain_controller_username']
kerberos_domain_controller_password = self.module.params['kerberos_domain_controller_password']
is_extended_credentials_enabled = self.module.params['is_extended_credentials_enabled']
remove_spn_from_kerberos = self.module.params['remove_spn_from_kerberos']
state = self.module.params['state']
# result is a dictionary that contains changed status and NFS server details
result = dict(
changed=False,
nfs_server_details={}
)
modify_flag = False
self.validate_input_params()
if nas_server_name:
nas_server_id = self.get_nas_server_id(nas_server_name)
nfs_server_details = self.get_nfs_server_details(nfs_server_id=nfs_server_id,
nas_server_id=nas_server_id)
# Check if modification is required
if nfs_server_details and state == 'present':
modify_flag = self.is_modification_required(is_extended_credentials_enabled, nfs_server_details)
if modify_flag:
self.module.fail_json(msg="Modification of NFS Server parameters is not supported through Ansible module")
if not nfs_server_details and state == 'present':
if not nas_server_id:
self.module.fail_json(msg="Please provide nas server id/name to create NFS server.")
result['changed'] = self.create_nfs_server(nas_server_id, host_name, nfs_v4_enabled,
is_secure_enabled, kerberos_domain_controller_type,
kerberos_domain_controller_username,
kerberos_domain_controller_password,
is_extended_credentials_enabled)
if state == 'absent' and nfs_server_details:
skip_unjoin = not remove_spn_from_kerberos
result['changed'] = self.delete_nfs_server(nfs_server_details["id"], skip_unjoin,
kerberos_domain_controller_username,
kerberos_domain_controller_password)
if state == 'present':
result['nfs_server_details'] = self.get_nfs_server_details(nfs_server_id=nfs_server_id,
nas_server_id=nas_server_id)
self.module.exit_json(**result)
def get_nfs_server_parameters():
"""This method provide parameters required for the ansible
NFS server module on Unity"""
return dict(
nfs_server_id=dict(type='str'),
host_name=dict(type='str'),
nfs_v4_enabled=dict(type='bool'),
is_secure_enabled=dict(type='bool'),
kerberos_domain_controller_type=dict(type='str', choices=['UNIX', 'WINDOWS', 'CUSTOM']),
kerberos_domain_controller_username=dict(type='str'),
kerberos_domain_controller_password=dict(type='str', no_log=True),
nas_server_name=dict(type='str'),
nas_server_id=dict(type='str'),
is_extended_credentials_enabled=dict(type='bool'),
remove_spn_from_kerberos=dict(default=True, type='bool'),
state=dict(required=True, type='str', choices=['present', 'absent']),
)
def get_enum_kdctype(kerberos_domain_controller_type):
"""Getting correct enum values for kerberos_domain_controller_type
:param: kerberos_domain_controller_type: Type of Kerberos Domain Controller used for secure NFS service.
:return: enum value for kerberos_domain_controller_type.
"""
if utils.KdcTypeEnum[kerberos_domain_controller_type]:
kerberos_domain_controller_type = utils.KdcTypeEnum[kerberos_domain_controller_type]
return kerberos_domain_controller_type
def process_dict(nfs_server_details):
"""Process NFS server details.
:param: nfs_server_details: Dict containing NFS server details
:return: Processed dict containing NFS server details
"""
param_list = ['credentials_cache_ttl', 'file_interfaces', 'host_name', 'id', 'kdc_type', 'nas_server', 'is_secure_enabled',
'is_extended_credentials_enabled', 'nfs_v4_enabled', 'servicee_principal_name']
for param in param_list:
if param in nfs_server_details and param == 'credentials_cache_ttl':
nfs_server_details[param] = str(nfs_server_details[param][0])
else:
nfs_server_details[param] = nfs_server_details[param][0]
return nfs_server_details
def main():
"""Create Unity NFS server object and perform action on it
based on user input from playbook"""
obj = NFSServer()
obj.perform_module_operation()
if __name__ == '__main__':
main()