File: //usr/lib/python3.9/site-packages/ansible_collections/dellemc/unity/plugins/modules/nasserver.py
# Copyright: (c) 2020, Dell Technologies
# Apache License version 2.0 (see MODULE-LICENSE or http://www.apache.org/licenses/LICENSE-2.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = r'''
---
module: nasserver
version_added: '1.1.0'
short_description: Manage NAS servers on Unity storage system
extends_documentation_fragment:
- dellemc.unity.unity
author:
- P Srinivas Rao (@srinivas-rao5) <[email protected]>
description:
- Managing NAS servers on Unity storage system includes get,
modification to the NAS servers.
options:
nas_server_id:
description:
- The ID of the NAS server.
- Either I(nas_server_name) or I(nas_server_id) is required to perform the task.
- The parameters I(nas_server_name) and I(nas_server_id) are mutually exclusive.
type: str
nas_server_name:
description:
- The Name of the NAS server.
- Either I(nas_server_name) or I(nas_server_id) is required to perform the task.
- The parameters I(nas_server_name) and I(nas_server_id) are mutually exclusive.
type: str
nas_server_new_name:
description:
- The new name of the NAS server.
- It can be mentioned during modification of the NAS server.
type: str
is_replication_destination:
description:
- It specifies whether the NAS server is a replication destination.
- It can be mentioned during modification of the NAS server.
type: bool
is_backup_only:
description:
- It specifies whether the NAS server is used as backup only.
- It can be mentioned during modification of the NAS server.
type: bool
is_multiprotocol_enabled:
description:
- This parameter indicates whether multiprotocol sharing mode is enabled.
- It can be mentioned during modification of the NAS server.
type: bool
allow_unmapped_user:
description:
- This flag is used to mandatorily disable access in case of any user
mapping failure.
- If C(true), then enable access in case of any user mapping failure.
- If C(false), then disable access in case of any user mapping failure.
- It can be mentioned during modification of the NAS server.
type: bool
default_windows_user:
description:
- Default windows user name used for granting access in the case of Unix
to Windows user mapping failure.
- It can be mentioned during modification of the NAS server.
type: str
default_unix_user:
description:
- Default Unix user name used for granting access in the case of Windows
to Unix user mapping failure.
- It can be mentioned during modification of the NAS server.
type: str
enable_windows_to_unix_username_mapping:
description:
- This parameter indicates whether a Unix to/from Windows user name
mapping is enabled.
- It can be mentioned during modification of the NAS server.
type: bool
is_packet_reflect_enabled:
description:
- If the packet has to be reflected, then this parameter
has to be set to C(true).
- It can be mentioned during modification of the NAS server.
type: bool
current_unix_directory_service:
description:
- This is the directory service used for querying identity information
for UNIX (such as UIDs, GIDs, net groups).
- It can be mentioned during modification of the NAS server.
type: str
choices: ["NONE", "NIS", "LOCAL", "LDAP", "LOCAL_THEN_NIS", "LOCAL_THEN_LDAP"]
replication_params:
description:
- Settings required for enabling replication.
type: dict
suboptions:
destination_nas_server_name:
description:
- Name of the destination nas server.
- Default value will be source nas server name prefixed by 'DR_'.
type: str
replication_mode:
description:
- The replication mode.
- This is mandatory to enable replication.
type: str
choices: ['asynchronous', 'manual']
rpo:
description:
- Maximum time to wait before the system syncs the source and destination LUNs.
- The I(rpo) option should be specified if the I(replication_mode) is C(asynchronous).
- The value should be in range of C(5) to C(1440).
type: int
replication_type:
description:
- Type of replication.
choices: ['local', 'remote']
type: str
remote_system:
description:
- Details of remote system to which the replication is being configured.
- The I(remote_system) option should be specified if the
I(replication_type) is C(remote).
type: dict
suboptions:
remote_system_host:
required: true
description:
- IP or FQDN for remote Unity unisphere Host.
type: str
remote_system_username:
type: str
required: true
description:
- User name of remote Unity unisphere Host.
remote_system_password:
type: str
required: true
description:
- Password of remote Unity unisphere Host.
remote_system_verifycert:
type: bool
default: true
description:
- Boolean variable to specify whether or not to validate SSL
certificate of remote Unity unisphere Host.
- C(true) - Indicates that the SSL certificate should be verified.
- C(false) - Indicates that the SSL certificate should not be
verified.
remote_system_port:
description:
- Port at which remote Unity unisphere is hosted.
type: int
default: 443
destination_pool_name:
description:
- Name of pool to allocate destination Luns.
- Mutually exclusive with I(destination_pool_id).
type: str
destination_pool_id:
description:
- Id of pool to allocate destination Luns.
- Mutually exclusive with I(destination_pool_name).
type: str
destination_sp:
description:
- Storage process of destination nas server
choices: ['SPA', 'SPB']
type: str
is_backup:
description:
- Indicates if the destination nas server is backup.
type: bool
replication_name:
description:
- User defined name for replication session.
type: str
new_replication_name:
description:
- Replication name to rename the session to.
type: str
replication_state:
description:
- State of the replication.
choices: ['enable', 'disable']
type: str
replication_reuse_resource:
description:
- This parameter indicates if existing NAS Server is to be used for replication.
type: bool
state:
description:
- Define the state of NAS server on the array.
- The value present indicates that NAS server should exist on the system after
the task is executed.
- In this release deletion of NAS server is not supported. Hence, if state is
set to C(absent) for any existing NAS server then error will be thrown.
- For any non-existing NAS server, if state is set to C(absent) then it will return None.
type: str
required: true
choices: ['present', 'absent']
notes:
- The I(check_mode) is not supported.
'''
EXAMPLES = r'''
- name: Get Details of NAS Server
dellemc.unity.nasserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "{{nas_server_name}}"
state: "present"
- name: Modify Details of NAS Server
dellemc.unity.nasserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "{{nas_server_name}}"
nas_server_new_name: "updated_sample_nas_server"
is_replication_destination: False
is_backup_only: False
is_multiprotocol_enabled: True
allow_unmapped_user: True
default_unix_user: "default_unix_sample_user"
default_windows_user: "default_windows_sample_user"
enable_windows_to_unix_username_mapping: True
current_unix_directory_service: "LDAP"
is_packet_reflect_enabled: True
state: "present"
- name: Enable replication for NAS Server on Local System
dellemc.unity.nasserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_id: "nas_10"
replication_reuse_resource: False
replication_params:
replication_name: "test_replication"
destination_nas_server_name: "destination_nas"
replication_mode: "asynchronous"
rpo: 60
replication_type: "local"
destination_pool_name: "Pool_Ansible_Neo_DND"
destination_sp: "SPA"
is_backup: True
replication_state: "enable"
state: "present"
- name: Enable replication for NAS Server on Remote System
dellemc.unity.nasserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
replication_reuse_resource: False
replication_params:
replication_name: "test_replication"
destination_nas_server_name: "destination_nas"
replication_mode: "asynchronous"
rpo: 60
replication_type: "remote"
remote_system:
remote_system_host: '10.10.10.10'
remote_system_verifycert: False
remote_system_username: 'test1'
remote_system_password: 'test1!'
destination_pool_name: "fastVP_pool"
destination_sp: "SPA"
is_backup: True
replication_state: "enable"
state: "present"
- name: Enable replication for NAS Server on Remote System in existing NAS Server
dellemc.unity.nasserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
replication_reuse_resource: True
replication_params:
destination_nas_server_name: "destination_nas"
replication_mode: "asynchronous"
rpo: 60
replication_type: "remote"
replication_name: "test_replication"
remote_system:
remote_system_host: '10.10.10.10'
remote_system_verifycert: False
remote_system_username: 'test1'
remote_system_password: 'test1!'
destination_pool_name: "fastVP_pool"
replication_state: "enable"
state: "present"
- name: Modify replication on the nasserver
dellemc.unity.nasserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
replication_params:
replication_name: "test_repl"
new_replication_name: "test_repl_updated"
replication_mode: "asynchronous"
rpo: 50
replication_state: "enable"
state: "present"
- name: Disable replication on the nasserver
dellemc.unity.nasserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
replication_state: "disable"
state: "present"
- name: Disable replication by specifying replication_name on the nasserver
dellemc.unity.nasserver:
unispherehost: "{{unispherehost}}"
username: "{{username}}"
password: "{{password}}"
validate_certs: "{{validate_certs}}"
nas_server_name: "dummy_nas"
replication_params:
replication_name: "test_replication"
replication_state: "disable"
state: "present"
'''
RETURN = r'''
changed:
description: Whether or not the resource has changed.
returned: always
type: bool
sample: True
nas_server_details:
description: The NAS server details.
type: dict
returned: When NAS server exists.
contains:
name:
description: Name of the NAS server.
type: str
id:
description: ID of the NAS server.
type: str
allow_unmapped_user:
description: Enable/disable access status in case of any user
mapping failure.
type: bool
current_unix_directory_service:
description: Directory service used for querying identity
information for UNIX (such as UIDs, GIDs, net groups).
type: str
default_unix_user:
description: Default Unix user name used for granting access
in the case of Windows to Unix user mapping failure.
type: str
default_windows_user:
description: Default windows user name used for granting
access in the case of Unix to Windows user mapping
failure.
type: str
is_backup_only:
description: Whether the NAS server is used as backup only.
type: bool
is_multi_protocol_enabled:
description: Indicates whether multiprotocol sharing mode is
enabled.
type: bool
is_packet_reflect_enabled:
description: If the packet reflect has to be enabled.
type: bool
is_replication_destination:
description: If the NAS server is a replication destination
then True.
type: bool
is_windows_to_unix_username_mapping_enabled:
description: Indicates whether a Unix to/from Windows user name
mapping is enabled.
type: bool
sample: {
"allow_unmapped_user": null,
"cifs_server": {
"UnityCifsServerList": [
{
"UnityCifsServer": {
"hash": 8761756885270,
"id": "cifs_34"
}
}
]
},
"current_sp": {
"UnityStorageProcessor": {
"hash": 8761756885273,
"id": "spb"
}
},
"current_unix_directory_service": "NasServerUnixDirectoryServiceEnum.NIS",
"default_unix_user": null,
"default_windows_user": null,
"existed": true,
"file_dns_server": {
"UnityFileDnsServer": {
"hash": 8761756885441,
"id": "dns_12"
}
},
"file_interface": {
"UnityFileInterfaceList": [
{
"UnityFileInterface": {
"hash": 8761756889908,
"id": "if_37"
}
}
]
},
"filesystems": null,
"hash": 8761757005084,
"health": {
"UnityHealth": {
"hash": 8761756867588
}
},
"home_sp": {
"UnityStorageProcessor": {
"hash": 8761756867618,
"id": "spb"
}
},
"id": "nas_10",
"is_backup_only": false,
"is_multi_protocol_enabled": false,
"is_packet_reflect_enabled": false,
"is_replication_destination": false,
"is_replication_enabled": true,
"is_windows_to_unix_username_mapping_enabled": null,
"name": "dummy_nas",
"pool": {
"UnityPool": {
"hash": 8761756885360,
"id": "pool_7"
}
},
"preferred_interface_settings": {
"UnityPreferredInterfaceSettings": {
"hash": 8761756885438,
"id": "preferred_if_10"
}
},
"replication_type": "ReplicationTypeEnum.REMOTE",
"size_allocated": 3489660928,
"tenant": null,
"virus_checker": {
"UnityVirusChecker": {
"hash": 8761756885426,
"id": "cava_10"
}
}
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.dellemc.unity.plugins.module_utils.storage.dell \
import utils
LOG = utils.get_logger('nasserver')
application_type = "Ansible/1.6.0"
class NASServer(object):
"""Class with NAS 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_nasserver_parameters())
# initialize the ansible module
mut_ex_args = [['nas_server_name', 'nas_server_id']]
required_one_of = [['nas_server_name', 'nas_server_id']]
self.module = AnsibleModule(
argument_spec=self.module_params,
supports_check_mode=False,
mutually_exclusive=mut_ex_args,
required_one_of=required_one_of
)
utils.ensure_required_libs(self.module)
# result is a dictionary that contains changed status and
# nas server details
self.result = {"changed": False,
'nas_server_details': {}}
self.unity_conn = utils.get_unity_unisphere_connection(
self.module.params, application_type)
self.nas_server_conn_obj = utils.nas_server.UnityNasServer(
self.unity_conn)
LOG.info('Connection established with the Unity Array')
def get_current_uds_enum(self, current_uds):
"""
Get the enum of the Offline Availability parameter.
:param current_uds: Current Unix Directory Service string
:return: current_uds enum
"""
if current_uds in \
utils.NasServerUnixDirectoryServiceEnum.__members__:
return utils.NasServerUnixDirectoryServiceEnum[current_uds]
else:
error_msg = "Invalid value {0} for Current Unix Directory" \
" Service provided".format(current_uds)
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def get_nas_server(self, nas_server_name, nas_server_id):
"""
Get the NAS Server Object using NAME/ID of the NAS Server.
:param nas_server_name: Name of the NAS Server
:param nas_server_id: ID of the NAS Server
:return: NAS Server object.
"""
nas_server = nas_server_name if nas_server_name else nas_server_id
try:
obj_nas = self.unity_conn.get_nas_server(_id=nas_server_id,
name=nas_server_name)
if nas_server_id and obj_nas and not obj_nas.existed:
# if obj_nas is not None and existed is observed as False,
# then None will be returned.
LOG.error("NAS Server object does not exist"
" with ID: %s ", nas_server_id)
return None
return obj_nas
except utils.HttpError as e:
if e.http_status == 401:
cred_err = "Incorrect username or password , {0}".format(
e.message)
self.module.fail_json(msg=cred_err)
else:
err_msg = "Failed to get details of NAS Server" \
" {0} with error {1}".format(nas_server, 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 NAS Server" \
" {0} with error {1}".format(nas_server, str(e))
LOG.error(err_msg)
return None
except Exception as e:
nas_server = nas_server_name if nas_server_name \
else nas_server_id
err_msg = "Failed to get nas server details {0} with" \
" error {1}".format(nas_server, str(e))
LOG.error(err_msg)
self.module.fail_json(msg=err_msg)
def to_update(self, nas_server_obj, current_uds):
LOG.info("Checking Whether the parameters are modified or not.")
# Checking all parameters individually because the nas obj return
# names are different compared to ansible parameter names.
# Current Unix Directory Service
if current_uds is not None and \
current_uds != nas_server_obj.current_unix_directory_service:
return True
# Rename NAS Server
if self.module.params['nas_server_new_name'] is not None and \
self.module.params['nas_server_new_name'] != \
nas_server_obj.name:
return True
# Is Replication Destination
if self.module.params["is_replication_destination"] is not None and \
(nas_server_obj.is_replication_destination is None or
self.module.params["is_replication_destination"] !=
nas_server_obj.is_replication_destination):
return True
# Is Multiprotocol Enabled
if self.module.params["is_multiprotocol_enabled"] is not None and \
(nas_server_obj.is_multi_protocol_enabled is None or
self.module.params["is_multiprotocol_enabled"] !=
nas_server_obj.is_multi_protocol_enabled):
return True
# Is Back Up Enabled
if self.module.params["is_backup_only"] is not None and \
(nas_server_obj.is_backup_only is None or
self.module.params["is_backup_only"] !=
nas_server_obj.is_backup_only):
return True
# Is Packet Reflect Enabled
if self.module.params["is_packet_reflect_enabled"] is not None and \
(nas_server_obj.is_packet_reflect_enabled is None or
self.module.params["is_packet_reflect_enabled"] !=
nas_server_obj.is_packet_reflect_enabled):
return True
# Allow Unmapped User
if self.module.params["allow_unmapped_user"] is not None and \
(nas_server_obj.allow_unmapped_user is None or
self.module.params["allow_unmapped_user"] !=
nas_server_obj.allow_unmapped_user):
return True
# Enable Windows To Unix User Mapping Flag
nas_win_flag = \
nas_server_obj.is_windows_to_unix_username_mapping_enabled
input_win_flag = \
self.module.params["enable_windows_to_unix_username_mapping"]
if input_win_flag is not None and \
(nas_win_flag is None or nas_win_flag != input_win_flag):
return True
# Default Windows User
if self.module.params["default_windows_user"] is not None and \
(nas_server_obj.default_windows_user is None or
self.module.params["default_windows_user"] !=
nas_server_obj.default_windows_user):
return True
# Default Unix User
if self.module.params["default_unix_user"] is not None and \
(nas_server_obj.default_unix_user is None or
self.module.params["default_unix_user"] !=
nas_server_obj.default_unix_user):
return True
return False
def update_nas_server(self, nas_server_obj, new_name=None,
default_unix_user=None, default_windows_user=None,
is_rep_dest=None, is_multiprotocol_enabled=None,
allow_unmapped_user=None, is_backup_only=None,
is_packet_reflect_enabled=None, current_uds=None,
enable_win_to_unix_name_map=None):
"""
The Details of the NAS Server will be updated in the function.
"""
try:
nas_server_obj.modify(
name=new_name,
is_replication_destination=is_rep_dest,
is_backup_only=is_backup_only,
is_multi_protocol_enabled=is_multiprotocol_enabled,
default_unix_user=default_unix_user,
default_windows_user=default_windows_user,
allow_unmapped_user=allow_unmapped_user,
is_packet_reflect_enabled=is_packet_reflect_enabled,
enable_windows_to_unix_username=enable_win_to_unix_name_map,
current_unix_directory_service=current_uds)
except Exception as e:
error_msg = "Failed to Update parameters of NAS Server" \
" %s with error %s" % (nas_server_obj.name, str(e))
LOG.error(error_msg)
self.module.fail_json(msg=error_msg)
def modify_replication_session(self, nas_server_obj, repl_session, replication_params):
""" Modify the replication session
:param: nas_server_obj: NAS server object
:param: repl_session: Replication session to be modified
:param: replication_params: Module input params
:return: True if modification is successful
"""
try:
LOG.info("Modifying replication session of nas server %s", nas_server_obj.name)
modify_payload = {}
if replication_params['replication_mode'] and \
replication_params['replication_mode'] == 'manual':
rpo = -1
elif replication_params['rpo']:
rpo = replication_params['rpo']
name = repl_session.name
if replication_params['new_replication_name'] and \
name != replication_params['new_replication_name']:
name = replication_params['new_replication_name']
if repl_session.name != name:
modify_payload['name'] = name
if ((replication_params['replication_mode'] or replication_params['rpo']) and
repl_session.max_time_out_of_sync != rpo):
modify_payload['max_time_out_of_sync'] = rpo
if modify_payload:
repl_session.modify(**modify_payload)
return True
return False
except Exception as e:
errormsg = "Modifying replication session failed with error %s", e
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def enable_replication(self, nas_server_obj, replication, replication_reuse_resource):
""" Enable replication on NAS Server
:param: nas_server_obj: NAS Server object.
:param: replication: Dict which has all the replication parameter values.
:return: True if replication is enabled else False.
"""
try:
# Validate replication params
self.validate_nas_server_replication_params(replication)
self.update_replication_params(replication, replication_reuse_resource)
repl_session = \
self.get_replication_session_on_filter(nas_server_obj, replication, "modify")
if repl_session:
return self.modify_replication_session(nas_server_obj, repl_session, replication)
self.validate_create_replication_params(replication)
replication_args_list = get_replication_args_list(replication)
# Get remote system
if 'replication_type' in replication and replication['replication_type'] == 'remote':
self.get_remote_system(replication, replication_args_list)
# Form parameters when replication_reuse_resource is False
if not replication_reuse_resource:
update_replication_arg_list(replication, replication_args_list, nas_server_obj)
nas_server_obj.replicate_with_dst_resource_provisioning(**replication_args_list)
else:
replication_args_list['dst_nas_server_id'] = replication['destination_nas_server_id']
nas_server_obj.replicate(**replication_args_list)
return True
if 'replication_type' in replication and replication['replication_type'] == 'local':
update_replication_arg_list(replication, replication_args_list, nas_server_obj)
nas_server_obj.replicate_with_dst_resource_provisioning(**replication_args_list)
return True
except Exception as e:
errormsg = "Enabling replication to the nas server %s failed " \
"with error %s" % (nas_server_obj.name, str(e))
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def disable_replication(self, obj_nas, replication_params):
""" Remove replication from the nas server
:param: replication_params: Module input params
:param: obj_nas: NAS Server object
:return: True if disabling replication is successful
"""
try:
LOG.info(("Disabling replication on the nas server %s", obj_nas.name))
if replication_params:
self.update_replication_params(replication_params, False)
repl_session = \
self.get_replication_session_on_filter(obj_nas, replication_params, "delete")
if repl_session:
repl_session.delete()
return True
return False
except Exception as e:
errormsg = "Disabling replication on the nas server %s failed " \
"with error %s" % (obj_nas.name, str(e))
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def get_replication_session_on_filter(self, obj_nas, replication_params, action):
""" Retrieves replication session on nas server
:param: obj_nas: NAS server object
:param: replication_params: Module input params
:param: action: Specifies action as modify or delete
:return: Replication session based on filter
"""
if replication_params and replication_params['remote_system']:
repl_session = \
self.get_replication_session(obj_nas, filter_key="remote_system_name",
replication_params=replication_params)
elif replication_params and replication_params['replication_name']:
repl_session = \
self.get_replication_session(obj_nas, filter_key="name",
name=replication_params['replication_name'])
else:
repl_session = self.get_replication_session(obj_nas, action=action)
if repl_session and action and replication_params and \
replication_params['replication_type'] == 'local' and \
repl_session.remote_system.name != self.unity_conn.name:
return None
return repl_session
def get_replication_session(self, obj_nas, filter_key=None, replication_params=None, name=None, action=None):
""" Retrieves the replication sessions configured for the nas server
:param: obj_nas: NAS server object
:param: filter_key: Key to filter replication sessions
:param: replication_params: Module input params
:param: name: Replication session name
:param: action: Specifies modify or delete action on replication session
:return: Replication session details
"""
try:
repl_session = self.unity_conn.get_replication_session(src_resource_id=obj_nas.id)
if not filter_key and repl_session:
if len(repl_session) > 1:
if action:
error_msg = 'There are multiple replication sessions for the nas server.'\
' Please specify replication_name in replication_params to %s.' % action
self.module.fail_json(msg=error_msg)
return repl_session
return repl_session[0]
for session in repl_session:
if filter_key == 'remote_system_name' and \
session.remote_system.name == replication_params['remote_system_name']:
return session
if filter_key == 'name' and session.name == name:
return session
return None
except Exception as e:
errormsg = "Retrieving replication session on the nas server failed " \
"with error %s", str(e)
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def get_remote_system(self, replication, replication_args_list):
remote_system_name = replication['remote_system_name']
remote_system_list = self.unity_conn.get_remote_system()
for remote_system in remote_system_list:
if remote_system.name == remote_system_name:
replication_args_list['remote_system'] = remote_system
break
if 'remote_system' not in replication_args_list.keys():
errormsg = "Remote system %s is not found" % (remote_system_name)
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def update_replication_params(self, replication, replication_reuse_resource):
""" Update replication dict with remote system information
:param: replication: Dict which has all the replication parameter values
:return: Updated replication Dict
"""
try:
if 'replication_type' in replication and replication['replication_type'] == 'remote':
connection_params = {
'unispherehost': replication['remote_system']['remote_system_host'],
'username': replication['remote_system']['remote_system_username'],
'password': replication['remote_system']['remote_system_password'],
'validate_certs': replication['remote_system']['remote_system_verifycert'],
'port': replication['remote_system']['remote_system_port']
}
remote_system_conn = utils.get_unity_unisphere_connection(
connection_params, application_type)
replication['remote_system_name'] = remote_system_conn.name
if replication['destination_pool_name'] is not None:
pool_object = remote_system_conn.get_pool(name=replication['destination_pool_name'])
replication['destination_pool_id'] = pool_object.id
if replication['destination_nas_server_name'] is not None and replication_reuse_resource:
nas_object = remote_system_conn.get_nas_server(name=replication['destination_nas_server_name'])
replication['destination_nas_server_id'] = nas_object.id
else:
replication['remote_system_name'] = self.unity_conn.name
if replication['destination_pool_name'] is not None:
pool_object = self.unity_conn.get_pool(name=replication['destination_pool_name'])
replication['destination_pool_id'] = pool_object.id
except Exception as e:
errormsg = "Updating replication params failed with error %s" % str(e)
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def validate_rpo(self, replication):
if 'replication_mode' in replication and replication['replication_mode'] == 'asynchronous' \
and replication['rpo'] is None:
errormsg = "rpo is required together with 'asynchronous' replication_mode."
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
if (replication['rpo'] and (replication['rpo'] < 5 or replication['rpo'] > 1440)) \
and (replication['replication_mode'] and replication['replication_mode'] != 'manual' or
not replication['replication_mode'] and replication['rpo'] != -1):
errormsg = "rpo value should be in range of 5 to 1440"
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def validate_nas_server_replication_params(self, replication):
""" Validate NAS server replication params
:param: replication: Dict which has all the replication parameter values
"""
# Valdiate replication
if replication is None:
errormsg = "Please specify replication_params to enable replication."
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
else:
# validate destination pool info
if replication['destination_pool_id'] is not None and replication['destination_pool_name'] is not None:
errormsg = "'destination_pool_id' and 'destination_pool_name' is mutually exclusive."
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
# Validate replication mode
self.validate_rpo(replication)
# Validate replication type
if replication['replication_type'] == 'remote' and replication['remote_system'] is None:
errormsg = "Remote_system is required together with 'remote' replication_type"
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
# Validate destination NAS server name
if 'destination_nas_name' in replication and replication['destination_nas_name'] is not None:
dst_nas_server_name_length = len(replication['destination_nas_name'])
if dst_nas_server_name_length == 0 or dst_nas_server_name_length > 95:
errormsg = "destination_nas_name value should be in range of 1 to 95"
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def validate_create_replication_params(self, replication):
''' Validate replication params '''
if replication['destination_pool_id'] is None and replication['destination_pool_name'] is None:
errormsg = "Either 'destination_pool_id' or 'destination_pool_name' is required."
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
keys = ['replication_mode', 'replication_type']
for key in keys:
if replication[key] is None:
errormsg = "Please specify %s to enable replication." % key
LOG.error(errormsg)
self.module.fail_json(msg=errormsg)
def perform_module_operation(self):
"""
Perform different actions on NAS Server based on user parameters
chosen in playbook
"""
state = self.module.params['state']
nas_server_name = self.module.params['nas_server_name']
nas_server_id = self.module.params['nas_server_id']
nas_server_new_name = self.module.params['nas_server_new_name']
default_unix_user = self.module.params['default_unix_user']
default_windows_user = self.module.params['default_windows_user']
is_replication_destination = \
self.module.params['is_replication_destination']
is_multiprotocol_enabled = \
self.module.params['is_multiprotocol_enabled']
allow_unmapped_user = self.module.params['allow_unmapped_user']
enable_windows_to_unix_username_mapping = \
self.module.params['enable_windows_to_unix_username_mapping']
is_backup_only = self.module.params['is_backup_only']
is_packet_reflect_enabled = \
self.module.params['is_packet_reflect_enabled']
current_uds = self.module.params['current_unix_directory_service']
replication = self.module.params['replication_params']
replication_state = self.module.params['replication_state']
replication_reuse_resource = self.module.params['replication_reuse_resource']
# Get the enum for the corresponding offline_availability
if current_uds:
current_uds = \
self.get_current_uds_enum(current_uds)
changed = False
if replication and replication_state is None:
self.module.fail_json(msg="Please specify replication_state along with replication_params")
'''
Get details of NAS Server.
'''
nas_server_obj = None
if nas_server_name or nas_server_id:
nas_server_obj = self.get_nas_server(nas_server_name,
nas_server_id)
# As creation is not supported and if NAS Server does not exist
# along with state as present, then error will be thrown.
if not nas_server_obj and state == "present":
msg = "NAS Server Resource not found. Please enter a valid " \
"Name/ID to get or modify the parameters of nas server."
LOG.error(msg)
self.module.fail_json(msg=msg)
'''
Update the parameters of NAS Server
'''
if nas_server_obj and state == "present":
update_flag = self.to_update(nas_server_obj, current_uds)
if update_flag:
self.update_nas_server(
nas_server_obj, nas_server_new_name, default_unix_user,
default_windows_user, is_replication_destination,
is_multiprotocol_enabled, allow_unmapped_user,
is_backup_only, is_packet_reflect_enabled,
current_uds, enable_windows_to_unix_username_mapping)
changed = True
# As deletion is not supported and if NAS Server exists along with
# state as absent, then error will be thrown.
if nas_server_obj and state == 'absent':
self.module.fail_json(msg="Deletion of NAS Server is "
"currently not supported.")
if state == 'present' and nas_server_obj and replication_state is not None:
if replication_state == 'enable':
changed = self.enable_replication(nas_server_obj, replication, replication_reuse_resource)
else:
changed = self.disable_replication(nas_server_obj, replication)
'''
Update the changed state and NAS Server details
'''
nas_server_details = None
if nas_server_obj:
nas_server_details = self.get_nas_server(
None, nas_server_obj.id)._get_properties()
self.result["changed"] = changed
self.result["nas_server_details"] = nas_server_details
self.module.exit_json(**self.result)
def get_nasserver_parameters():
"""
This method provides parameters required for the ansible NAS Server
modules on Unity
"""
return dict(
nas_server_name=dict(), nas_server_id=dict(),
nas_server_new_name=dict(),
default_unix_user=dict(),
default_windows_user=dict(),
current_unix_directory_service=dict(
choices=["NIS", "LDAP", "LOCAL_THEN_NIS",
"LOCAL_THEN_LDAP", "NONE", "LOCAL"]),
is_replication_destination=dict(type='bool'),
is_backup_only=dict(type='bool'),
is_multiprotocol_enabled=dict(type='bool'),
allow_unmapped_user=dict(type='bool'),
enable_windows_to_unix_username_mapping=dict(type='bool'),
is_packet_reflect_enabled=dict(type='bool'),
replication_params=dict(type='dict', options=dict(
destination_nas_server_name=dict(type='str'),
replication_mode=dict(type='str', choices=['asynchronous', 'manual']),
rpo=dict(type='int'),
replication_type=dict(type='str', choices=['local', 'remote']),
remote_system=dict(type='dict',
options=dict(
remote_system_host=dict(type='str', required=True, no_log=True),
remote_system_verifycert=dict(type='bool', required=False,
default=True),
remote_system_username=dict(type='str', required=True),
remote_system_password=dict(type='str', required=True, no_log=True),
remote_system_port=dict(type='int', required=False, default=443, no_log=True)
)),
destination_pool_name=dict(type='str'),
destination_pool_id=dict(type='str'),
destination_sp=dict(type='str', choices=['SPA', 'SPB']),
is_backup=dict(type='bool'),
replication_name=dict(type='str'),
new_replication_name=dict(type='str')
)),
replication_reuse_resource=dict(type='bool'),
replication_state=dict(type='str', choices=['enable', 'disable']),
state=dict(required=True, choices=['present', 'absent'], type='str')
)
def get_sp_enum(destination_sp):
"""Getting correct enum values for Storage Processor
:param: destination_sp: Storage Processor to be used in Destination NAS Server.
:return: enum value for Storage Processor.
"""
if utils.NodeEnum[destination_sp]:
destination_sp_enum = utils.NodeEnum[destination_sp]
return destination_sp_enum
def get_replication_args_list(replication_params):
"""Returns the replication args for payload"""
replication_args_list = {}
if replication_params['replication_name']:
replication_args_list['replication_name'] = replication_params['replication_name']
if 'replication_mode' in replication_params and \
replication_params['replication_mode'] == 'asynchronous':
replication_args_list['max_time_out_of_sync'] = replication_params['rpo']
else:
replication_args_list['max_time_out_of_sync'] = -1
return replication_args_list
def update_replication_arg_list(replication, replication_args_list, nas_server_obj):
""" Update replication arg list
:param: replication: Dict which has all the replication parameter values
:param: replication_args_list: the existing list which should be updated
:param: nas_server_obj: NAS Server object on which replication is to be enabled
:return: Updated replication_args_list
"""
if 'destination_sp' in replication and replication['destination_sp']:
dst_sp_enum = get_sp_enum(replication['destination_sp'])
replication_args_list['dst_sp'] = dst_sp_enum
replication_args_list['dst_pool_id'] = replication['destination_pool_id']
if 'is_backup' in replication and replication['is_backup']:
replication_args_list['is_backup_only'] = replication['is_backup']
if replication['replication_type'] == 'local':
replication_args_list['dst_nas_server_name'] = "DR_" + nas_server_obj.name
if 'destination_nas_server_name' in replication and replication['destination_nas_server_name'] is not None:
replication_args_list['dst_nas_server_name'] = replication['destination_nas_server_name']
else:
if replication['destination_nas_server_name'] is None:
replication_args_list['dst_nas_server_name'] = nas_server_obj.name
def main():
""" Create Unity NAS Server object and perform action on it
based on user input from playbook"""
obj = NASServer()
obj.perform_module_operation()
if __name__ == '__main__':
main()