class IsmCopyProfile(): CRYPTPASS = "******" # Receiving args module = AnsibleModule(argument_spec=dict( config=dict(type="str", required=True), ism_source_profile_name=dict(type="str", required=True), ism_profile_name=dict(typer="str", required=True), ism_profile_data=dict(type="dict", required=False))) def __init__(self): self.__present() def __present(self): # Instance of common class self.common = IsmCommon(self.module) # check for blank("") and None self.common.required_param_check(self.module.params["config"], "config") self.common.required_param_check( self.module.params["ism_source_profile_name"], "ism_source_profile_name") self.common.required_param_check( self.module.params["ism_profile_name"], "ism_profile_name") try: # Pre-process self.common.preProcess(self.module.params, NodeCheck=False, noHost=True) self.module.params['config'] = self.common.covert_unicode( self.module.params['config']) self.module.params[ 'ism_source_profile_name'] = self.common.covert_unicode( self.module.params['ism_source_profile_name']) self.module.params[ 'ism_profile_name'] = self.common.covert_unicode( self.module.params['ism_profile_name']) if self.module.params['ism_profile_data']: self.common.covertUnicodeHashDict( self.module.params['ism_profile_data']) # Check profile check_profile_result = \ self.__checkProfile(self.module.params['ism_source_profile_name'], self.module.params['ism_profile_name']) # Get profile get_profile_result = self.__getProfile(check_profile_result) # Copy profile self.__copyProfile(get_profile_result) self.module.exit_json(changed=True, ism_copy_profile="Success") except Exception as e: self.module.log(str(e)) self.module.log(traceback.format_exc()) self.module.fail_json(msg=str(e)) finally: self.common.ismLogout() def __checkProfile(self, source, dest): profile_id = None # source and dest profile name are same if source == dest: msg = "ism_source_profile_name and ism_profile_name have duplicate values: {0}".\ format(source) self.module.log(msg) self.module.fail_json(msg=msg) # Get REST URL rest_url = self.common.getRestUrl(self.common.PROFILE_LIST_REST_URL) # REST API execution json_data = self.common.execRest(rest_url, self.common.GET, self.common.RESPONSE_CODE_200) for profile in json_data['IsmBody']['ProfileList']: if profile['ProfileName'] == dest: # already copied self.module.exit_json(changed=False, ism_copy_profile="Success") elif profile['ProfileName'] == source: profile_id = profile['ProfileId'] # Profile not found if not profile_id: msg = "profile not found: {0}".format(source) self.module.log(msg) self.module.fail_json(msg=msg) return profile_id def __getProfile(self, profile_id): # Get REST URL rest_url = self.common.getRestUrl( self.common.PROFILE_LIST_REST_URL, "/" + profile_id + "?passwordkey=" + self.CRYPTPASS) # REST API execution json_data = self.common.execRest(rest_url, self.common.GET, self.common.RESPONSE_CODE_200) source_info = json_data['IsmBody'] # delete create profile REST-API not supported keys not_supported_keys = [ 'ProfileId', 'PathName', 'AssignedNodeId', 'Status', 'InternalStatus', 'VerifyStatus', 'HistoryList', 'VerifyList', 'TimeStampInfo' ] for not_supported_key in not_supported_keys: if not_supported_key in source_info: del source_info[not_supported_key] # add information if self.module.params['ism_profile_data']: dict_data = source_info['ProfileData'] dict_set = dict(self.module.params['ism_profile_data']) source_info['ProfileData'] = self.common.mergeDicts( dict_data, dict_set) source_info['ProfileName'] = self.module.params['ism_profile_name'] source_info['OneTimePasswordKey'] = self.CRYPTPASS all_data = {"IsmBody": source_info} return all_data def __copyProfile(self, body): # Get REST URL rest_url = self.common.getRestUrl(self.common.PROFILE_LIST_REST_URL) # REST API execution param_str = "\'" + self.common.singleEscape(json.dumps(body)) + "\'" self.common.execRest(rest_url, self.common.POST, self.common.RESPONSE_CODE_201, param_str)
class IsmBackup(): PEXPECT_VERSION = "4.7.0" PEXPECT_VERSION_MSG = 'The pexpect >= 4.7.0 python module is required' PXSSH_DEBUG = False PXSSH_CONNECT_TIMEOUT = 60 PXSSH_MSG_HEADER = "SSH connection error: {0}" PXSSH_OPTION = { "ConnectTimeout": PXSSH_CONNECT_TIMEOUT, "StrictHostKeyChecking": "no", "UserKnownHostsFile": "/dev/null" } PORT_SSH = 22 FTP_CONNECT_TIMEOUT = 60 FTP_MSG_CONNECT_HEADER = "FTP connection error: {0}" FTP_MSG_OPERATION_HEADER = "FTP operation error: {0}" RE_CONNECT_ERROR = re.compile(r'^could not set shell prompt') RE_START_BACKUP = re.compile(r'^Start backup process\? \[y/n\]: ', re.MULTILINE) RE_ERROR = re.compile(r'^(ERROR:\d+:.+)$', re.MULTILINE) RE_OUTPUT_FILE = re.compile(r'^Output file: (ism.+\.gz)', re.MULTILINE) FTP_DIR = "/Administrator/ftp/" module = AnsibleModule(argument_spec=dict( config=dict(type="str", required=True), hostname=dict(type="str", required=True), dest_dir=dict(type="str", required=True), timeout=dict(type="int", default=0, required=False))) def __init__(self): self.__present() def __present(self): self.common = IsmCommon(self.module) # check for blank("") and None self.common.required_param_check(self.module.params["config"], "config") self.common.required_param_check(self.module.params["hostname"], "hostname") self.common.required_param_check(self.module.params["dest_dir"], "dest_dir") # check pexpect installed and its version if not HAS_PEXPECT: self.module.fail_json(msg=self.PEXPECT_VERSION_MSG) if not self.common.checkLibraryVersion(pexpect.__version__, "4.7.0"): self.module.fail_json(msg=self.PEXPECT_VERSION_MSG) try: self.common.preProcess( self.module.params, usableEssential=True, NodeCheck=False, paramListNotBlank=["timeout" ], # don't convert None to blank("") doIsmLogin=False) # convert to unicode self.module.params['config'] = self.common.covert_unicode( self.module.params['config']) self.module.params['hostname'] = self.common.covert_unicode( self.module.params['hostname']) self.module.params['dest_dir'] = self.common.covert_unicode( self.module.params['dest_dir']) self.dest_dir = self.module.params["dest_dir"] self.timeout = self.module.params["timeout"] if not (self.timeout) or self.timeout <= 0: # less than or equal 0 self.timeout = None # no timeout config_json = self.common.ism_config_json self.ism_ip = config_json["ip"] self.ism_user_name = config_json["credentials"]["userName"] self.ism_password = config_json["credentials"]["password"] self.ism_password = self.common.decryptIsmPassword( self.ism_password, self.ism_ip) filename = self.__backup() dest_file = os.path.join(self.dest_dir, filename) self.__download(dest_file, filename) self.module.exit_json(changed=True, ism_backup_file=dest_file) except Exception as e: self.module.log(traceback.format_exc()) self.module.fail_json(msg=str(e)) def __backup(self): ssh = None try: ssh = pxssh.pxssh(options=self.PXSSH_OPTION) if self.PXSSH_DEBUG: # pxssh stdout for debug ssh.logfile = sys.stdout try: ssh.login(self.ism_ip, username=self.ism_user_name, password=self.ism_password, login_timeout=self.PXSSH_CONNECT_TIMEOUT, port=self.PORT_SSH) except pexpect.ExceptionPexpect as e: msg = str(e) if self.RE_CONNECT_ERROR.match(msg): # connection error msg = self.PXSSH_MSG_HEADER.format( "Failed to connect host") else: msg = self.PXSSH_MSG_HEADER.format(msg) self.module.log(msg) self.module.log(traceback.format_exc()) self.module.fail_json(msg=msg) ssh.sendline("ismadm system backup") # waiting backup size estimation index = ssh.expect( [self.RE_START_BACKUP, self.RE_ERROR, ssh.PROMPT], timeout=self.timeout) if index == 1: # error message msg = ssh.match.group(1).rstrip() self.module.log(msg) self.module.fail_json(msg=msg) elif index == 2: # not ISM server msg = "backup failed: not ISM server" self.module.log(msg) self.module.log("output={0}".format(ssh.before)) self.module.fail_json(msg=msg) # start backup ssh.sendline("y") # waiting backup complete ssh.expect(ssh.PROMPT, timeout=self.timeout) output = ssh.before match = self.RE_ERROR.search(output) if match: # error message msg = match.group(1).rstrip() self.module.log(msg) self.module.fail_json(msg=msg) match = self.RE_OUTPUT_FILE.search(output) if not match: # Output file not found msg = "missing backup file info" self.module.log(msg) self.module.log("output={0}".format(output)) self.module.fail_json(msg=msg) filename = match.group(1) return filename except pexpect.TIMEOUT: msg = "waiting for backup timeout: {0}s".format(self.timeout) self.module.log(msg) self.module.log(traceback.format_exc()) self.module.fail_json(msg=msg) finally: # close if ssh: try: ssh.close() except Exception: # ignore error self.module.log(traceback.format_exc()) def __download(self, dest_file, ftp_file): ftp = None file_deleted = False try: try: ftp = FTP(self.ism_ip, self.ism_user_name, self.ism_password, self.FTP_CONNECT_TIMEOUT) except Exception as e: msg = self.FTP_MSG_CONNECT_HEADER.format(e) self.module.log(msg) self.module.log(traceback.format_exc()) self.module.fail_json(msg=msg) with open(dest_file, 'wb') as f: try: ftp.retrbinary('RETR ' + self.FTP_DIR + ftp_file, f.write) ftp.delete(self.FTP_DIR + ftp_file) file_deleted = True except Exception as e: msg = self.FTP_MSG_OPERATION_HEADER.format(e) self.module.log(msg) self.module.log(traceback.format_exc()) self.module.fail_json(msg=msg) except Exception as e: self.module.log(traceback.format_exc()) self.module.fail_json(msg=str(e)) finally: # FTP logout if ftp: try: if not file_deleted: # delete file ftp.delete(self.FTP_DIR + ftp_file) ftp.quit() except Exception: # ignore error self.module.log(traceback.format_exc())