def _dest_exists(self, src, dest, task_vars): """Determine if destination exists on remote z/OS system""" if "/" in dest: rc, out, err = self._connection.exec_command( "ls -l {0}".format(dest)) if rc != 0: return False if len(to_text(out).split("\n")) == 2: return True if "/" in src: src = src.rstrip("/") if src.endswith("/") else src dest += "/" + os.path.basename(src) else: dest += "/" + extract_member_name(src) if is_member( src) else src rc, out, err = self._connection.exec_command( "ls -l {0}".format(dest)) if rc != 0: return False else: cmd = "LISTDS '{0}'".format(dest) tso_cmd = self._execute_module( module_name="ibm.ibm_zos_core.zos_tso_command", module_args=dict(commands=[cmd]), task_vars=task_vars, ).get("output")[0] if tso_cmd.get("rc") != 0: for line in tso_cmd.get("content"): if "NOT IN CATALOG" in line: return False return True
def _remote_cleanup(self, dest, dest_exists, task_vars): """Remove all files or data sets pointed to by 'dest' on the remote z/OS system. The idea behind this cleanup step is that if, for some reason, the module fails after copying the data, we want to return the remote system to its original state. Which means deleting any newly created files or data sets. """ if dest_exists is False: if "/" in dest: self._connection.exec_command("rm -rf {0}".format(dest)) else: module_args = dict(name=dest, state="absent") if is_member(dest): module_args["type"] = "MEMBER" self._execute_module( module_name="ibm.ibm_zos_core.zos_data_set", module_args=module_args, task_vars=task_vars, )
def mvs_file_backup(dsn, bk_dsn=None): """Create a backup data set for an MVS data set Arguments: dsn {str} -- The name of the data set to backup. It could be an MVS PS/PDS/PDSE/VSAM(KSDS), etc. bk_dsn {str} -- The name of the backup data set. Raises: BackupError: When backup data set exists. BackupError: When creation of backup data set fails. """ dsn = _validate_data_set_name(dsn).upper() if is_member(dsn): if not bk_dsn: bk_dsn = extract_dsname(dsn) + "({0})".format(temp_member_name()) bk_dsn = _validate_data_set_name(bk_dsn).upper() response = datasets._copy(dsn, bk_dsn) if response.rc != 0: raise BackupError("Unable to backup {0} to {1}".format( dsn, bk_dsn), rc=response.rc, stdout=response.stdout_response, stderr=response.stderr_response) else: if not bk_dsn: bk_dsn = datasets.tmp_name(datasets.hlq()) bk_dsn = _validate_data_set_name(bk_dsn).upper() cp_rc = _copy_ds(dsn, bk_dsn) if cp_rc == 12: # The data set is probably a PDS or PDSE # Delete allocated backup that was created when attempting to use _copy_ds() # Safe to delete because _copy_ds() would have raised an exception if it did # not successfully create the backup data set, so no risk of it predating module invocation datasets.delete(bk_dsn) _allocate_model(bk_dsn, dsn) rc, out, err = _copy_pds(dsn, bk_dsn) if rc != 0: raise BackupError( "Unable to backup data set {0} to {1}".format(dsn, bk_dsn)) return bk_dsn
def run(self, tmp=None, task_vars=None): """ handler for file transfer operations """ if task_vars is None: task_vars = dict() result = super(ActionModule, self).run(tmp, task_vars) task_args = self._task.args.copy() del tmp src = task_args.get('src', None) b_src = to_bytes(src, errors='surrogate_or_strict') dest = task_args.get('dest', None) content = task_args.get('content', None) # If self._play_context.port is None, that implies the default port 22 # was used to connect to the remote host. sftp_port = task_args.get('sftp_port', self._play_context.port or 22) force = _process_boolean(task_args.get('force'), default=True) backup = _process_boolean(task_args.get('backup'), default=False) local_follow = _process_boolean(task_args.get('local_follow'), default=False) remote_src = _process_boolean(task_args.get('remote_src'), default=False) is_binary = _process_boolean(task_args.get('is_binary'), default=False) ignore_sftp_stderr = _process_boolean( task_args.get("ignore_sftp_stderr"), default=False) backup_name = task_args.get("backup_name", None) encoding = task_args.get("encoding", None) mode = task_args.get("mode", None) owner = task_args.get("owner", None) group = task_args.get("group", None) is_pds = is_src_dir = False temp_path = is_uss = is_mvs_dest = copy_member = src_member = None if dest: if not isinstance(dest, string_types): msg = "Invalid type supplied for 'dest' option, it must be a string" return self._exit_action(result, msg, failed=True) else: is_uss = "/" in dest is_mvs_dest = is_data_set(dest) copy_member = is_member(dest) else: msg = "Destination is required" return self._exit_action(result, msg, failed=True) if src: if content: msg = "Either 'src' or 'content' can be provided; not both." return self._exit_action(result, msg, failed=True) elif not isinstance(src, string_types): msg = "Invalid type supplied for 'src' option, it must be a string" return self._exit_action(result, msg, failed=True) elif len(src) < 1 or len(dest) < 1: msg = "'src' or 'dest' must not be empty" return self._exit_action(result, msg, failed=True) else: src_member = is_member(src) if not remote_src: src = os.path.realpath(src) is_src_dir = os.path.isdir(src) is_pds = is_src_dir and is_mvs_dest if not src and not content: msg = "'src' or 'content' is required" return self._exit_action(result, msg, failed=True) if encoding and is_binary: msg = "The 'encoding' parameter is not valid for binary transfer" return self._exit_action(result, msg, failed=True) if (not backup) and backup_name is not None: msg = "Backup file provided but 'backup' parameter is False" return self._exit_action(result, msg, failed=True) if not is_uss: if mode or owner or group: msg = "Cannot specify 'mode', 'owner' or 'group' for MVS destination" return self._exit_action(result, msg, failed=True) if not isinstance(sftp_port, int) or not 0 < sftp_port <= 65535: msg = "Invalid port provided for SFTP. Expected an integer between 0 to 65535." return self._exit_action(result, msg, failed=True) if (not force) and self._dest_exists(src, dest, task_vars): return self._exit_action( result, "Destination exists. No data was copied.") if not remote_src: if local_follow and not src: msg = "No path given for local symlink" return self._exit_action(result, msg, failed=True) elif src and not os.path.exists(b_src): msg = "The local file {0} does not exist".format(src) return self._exit_action(result, msg, failed=True) elif src and not os.access(b_src, os.R_OK): msg = ("The local file {0} does not have appropriate " "read permission".format(src)) return self._exit_action(result, msg, failed=True) if content: try: local_content = _write_content_to_temp_file(content) transfer_res = self._copy_to_remote( local_content, sftp_port, ignore_stderr=ignore_sftp_stderr) finally: os.remove(local_content) else: if is_src_dir: path, dirs, files = next(os.walk(src)) if dirs: result[ "msg"] = "Subdirectory found inside source directory" result.update( dict(src=src, dest=dest, changed=False, failed=True)) return result task_args["size"] = sum( os.stat(path + "/" + f).st_size for f in files) else: if mode == "preserve": task_args["mode"] = "0{0:o}".format( stat.S_IMODE(os.stat(b_src).st_mode)) task_args["size"] = os.stat(src).st_size transfer_res = self._copy_to_remote( src, sftp_port, is_dir=is_src_dir, ignore_stderr=ignore_sftp_stderr) temp_path = transfer_res.get("temp_path") if transfer_res.get("msg"): return transfer_res task_args.update( dict(is_uss=is_uss, is_pds=is_pds, copy_member=copy_member, src_member=src_member, temp_path=temp_path, is_mvs_dest=is_mvs_dest, local_charset=encode.Defaults.get_default_system_charset())) copy_res = self._execute_module( module_name="ibm.ibm_zos_core.zos_copy", module_args=task_args, task_vars=task_vars, ) if copy_res.get("note") and not force: result["note"] = copy_res.get("note") return result if copy_res.get("msg"): result.update( dict( msg=copy_res.get("msg"), stdout=copy_res.get("stdout") or copy_res.get("module_stdout"), stderr=copy_res.get("stderr") or copy_res.get("module_stderr"), stdout_lines=copy_res.get("stdout_lines"), stderr_lines=copy_res.get("stderr_lines"), rc=copy_res.get("rc"), invocation=dict(module_args=self._task.args), )) if backup or backup_name: result["backup_name"] = copy_res.get("backup_name") self._remote_cleanup(dest, copy_res.get("dest_exists"), task_vars) return result return _update_result(is_binary, copy_res, self._task.args)
def run(self, tmp=None, task_vars=None): """ handler for file transfer operations """ if task_vars is None: task_vars = dict() result = super(ActionModule, self).run(tmp, task_vars) del tmp src = self._task.args.get('src', None) b_src = to_bytes(src, errors='surrogate_or_strict') dest = self._task.args.get('dest', None) content = self._task.args.get('content', None) force = _process_boolean(self._task.args.get('force'), default=True) backup = _process_boolean(self._task.args.get('backup'), default=False) local_follow = _process_boolean(self._task.args.get('local_follow'), default=False) remote_src = _process_boolean(self._task.args.get('remote_src'), default=False) is_binary = _process_boolean(self._task.args.get('is_binary'), default=False) backup_file = self._task.args.get("backup_file", None) encoding = self._task.args.get('encoding', None) mode = self._task.args.get('mode', None) owner = self._task.args.get('owner', None) group = self._task.args.get('group', None) new_module_args = self._task.args.copy() is_pds = is_src_dir = False temp_path = is_uss = is_mvs_dest = copy_member = src_member = None if dest: if not isinstance(dest, string_types): msg = "Invalid type supplied for 'dest' option, it must be a string" return self._exit_action(result, msg, failed=True) else: is_uss = '/' in dest is_mvs_dest = is_data_set(dest) copy_member = is_member(dest) else: msg = "Destination is required" return self._exit_action(result, msg, failed=True) if src: if content: msg = "Either 'src' or 'content' can be provided; not both." return self._exit_action(result, msg, failed=True) elif not isinstance(src, string_types): msg = "Invalid type supplied for 'src' option, it must be a string" return self._exit_action(result, msg, failed=True) elif len(src) < 1 or len(dest) < 1: msg = "'src' or 'dest' must not be empty" return self._exit_action(result, msg, failed=True) else: src_member = is_member(src) if not remote_src: src = os.path.realpath(src) is_src_dir = os.path.isdir(src) is_pds = is_src_dir and is_mvs_dest if not src and not content: msg = "'src' or 'content' is required" return self._exit_action(result, msg, failed=True) if encoding and is_binary: msg = "The 'encoding' parameter is not valid for binary transfer" return self._exit_action(result, msg, failed=True) if (not backup) and backup_file is not None: msg = "Backup file provided but 'backup' parameter is False" return self._exit_action(result, msg, failed=True) if not is_uss: if mode or owner or group: msg = "Cannot specify 'mode', 'owner' or 'group' for MVS destination" return self._exit_action(result, msg, failed=True) if (not force) and self._dest_exists(src, dest, task_vars): return self._exit_action(result, "Destination exists. No data was copied.") if not remote_src: if local_follow and not src: msg = "No path given for local symlink" return self._exit_action(result, msg, failed=True) elif src and not os.path.exists(b_src): msg = "The local file {0} does not exist".format(src) return self._exit_action(result, msg, failed=True) elif src and not os.access(b_src, os.R_OK): msg = ( "The local file {0} does not have appropriate " "read permission".format(src) ) return self._exit_action(result, msg, failed=True) if content: try: local_content = _write_content_to_temp_file(content) transfer_res = self._copy_to_remote(local_content) finally: os.remove(local_content) else: if is_src_dir: path, dirs, files = next(os.walk(src)) if dirs: result['msg'] = "Subdirectory found inside source directory" result.update(dict(src=src, dest=dest, changed=False, failed=True)) return result new_module_args['size'] = sum( os.stat(path + "/" + f).st_size for f in files ) else: if mode == 'preserve': new_module_args['mode'] = '0{0:o}'.format(stat.S_IMODE(os.stat(b_src).st_mode)) new_module_args['size'] = os.stat(src).st_size transfer_res = self._copy_to_remote(src, is_dir=is_src_dir) temp_path = transfer_res.get("temp_path") if transfer_res.get("msg"): return transfer_res new_module_args.update( dict( is_uss=is_uss, is_pds=is_pds, copy_member=copy_member, src_member=src_member, temp_path=temp_path, is_mvs_dest=is_mvs_dest ) ) copy_res = self._execute_module( module_name='zos_copy', module_args=new_module_args, task_vars=task_vars ) if copy_res.get('note') and not force: result['note'] = copy_res.get('note') return result if copy_res.get('msg'): result.update( dict( msg=copy_res.get('msg'), stdout=copy_res.get('stdout') or copy_res.get("module_stdout"), stderr=copy_res.get('stderr') or copy_res.get("module_stderr"), stdout_lines=copy_res.get("stdout_lines"), stderr_lines=copy_res.get("stderr_lines"), rc=copy_res.get('rc'), invocation=dict(module_args=self._task.args) ) ) if backup or backup_file: result['backup_file'] = copy_res.get("backup_file") self._remote_cleanup(dest, copy_res.get("dest_exists"), task_vars) return result return _update_result(is_binary, copy_res, self._task.args)