def authenticate(module): """ Authenticate with z/OSMF server. Return the authentication token. :param AnsibleModule module: the ansible module """ # create session session = get_connect_session(module) # get authentication token response_getAuth = call_auth_api(module, session, 'getAuth') if isinstance(response_getAuth, dict): if ('Set-Cookie' in response_getAuth and ('LtpaToken2' in response_getAuth['Set-Cookie'] or 'jwtToken' in response_getAuth['Set-Cookie'])): auth = dict() if 'LtpaToken2' in response_getAuth['Set-Cookie']: auth['LtpaToken2'] = re.findall( 'LtpaToken2=(.+?);', response_getAuth['Set-Cookie'])[0] if 'jwtToken' in response_getAuth['Set-Cookie']: auth['jwtToken'] = re.findall( 'jwtToken=(.+?);', response_getAuth['Set-Cookie'])[0] auth['zmf_host'] = module.params['zmf_host'] auth['zmf_port'] = module.params['zmf_port'] module.exit_json(**auth) else: module.fail_json( msg= 'Failed to authenticate with z/OSMF server ---- Cannot obtain the authentication token.' ) else: module.fail_json( msg='Failed to authenticate with z/OSMF server ---- ' + response_getAuth)
def file_exist(module): """ Check if a USS file or directory already exists Return exist_result to indicate if a USS file or directory with same name already exists. :param AnsibleModule module: the ansible module """ exist_result = dict(type=None) # create session session = get_connect_session(module) target = module.params['file_path'].strip() if not target.startswith('/'): target = '/' + target exist_result['session'] = session exist_result['target'] = target # setup file parent path and file name f_path = target[:target.rfind('/')] f_name = target[target.rfind('/') + 1:] if f_path.startswith('/'): f_path = f_path[1:] module.params['f_path'] = f_path module.params['f_name'] = f_name # step1 - check if the target USS file or directory with same name already exists res_list = call_file_api(module, session, 'list') if res_list.status_code == 200: res_content = json.loads(res_list.content) if 'returnedRows' in res_content and res_content['returnedRows'] > 0: exist_result['file_properties'] = res_content['items'][0] if res_content['items'][0]['mode'].startswith('d'): exist_result['type'] = 'directory' else: exist_result['type'] = 'file' # list tag of the target USS file or directory request_body = dict() request_body['request'] = 'chtag' request_body['action'] = 'list' request_headers = dict() request_headers['Content-Type'] = 'application/json' res_operate = call_file_api(module, session, 'operate', request_headers, json.dumps(request_body)) if res_operate.status_code == 200: res_content = json.loads(res_operate.content) if 'stdout' in res_content: exist_result['file_properties']['tag'] = res_content[ 'stdout'][0] else: res_json = res_list.json() if (res_list.status_code == 404 and 'category' in res_json and 'rc' in res_json and 'reason' in res_json and res_json['category'] == 1 and res_json['rc'] == 4 and res_json['reason'] == 8): # parent path not found exist_result['type'] = 'error' return exist_result
def fetch_file(module): """ Fetch USS file from z/OS Return the message to indicate whether the USS file is successfully fetched. Return file_content of the retrieved contents. Return file_matched_content of the matched contents if file_search is specified. Return file_matched_range of the range of the matched contents if file_search is specified. Return file_checksum of the checksum if file_search and file_range are not specified. :param AnsibleModule module: the ansible module """ fetch_result = dict( changed=False, message='', ) # create session session = get_connect_session(module) file = module.params['file_src'].strip() path = module.params['file_dest'].strip() host = module.params['zmf_host'].strip() fetch_src = file if not fetch_src.startswith('/'): fetch_src = '/' + fetch_src # setup file parent path and file name f_path = fetch_src[:fetch_src.rfind('/')] f_name = fetch_src[fetch_src.rfind('/') + 1:] if f_path.startswith('/'): f_path = f_path[1:] module.params['f_path'] = f_path module.params['f_name'] = f_name # step1 - combine request headers request_headers = dict() if module.params['file_data_type'] == 'text' and module.params[ 'file_encoding'] is not None: request_headers[ 'X-IBM-Data-Type'] = 'text;fileEncoding=' + module.params[ 'file_encoding']['from'] request_headers[ 'Content-Type'] = 'text/plain;charset=' + module.params[ 'file_encoding']['to'] else: request_headers['X-IBM-Data-Type'] = module.params['file_data_type'] if module.params['file_range'] is not None: if 'end' in module.params['file_range']: end = module.params['file_range']['end'] else: end = 0 if 'start' in module.params['file_range']: range = str(module.params['file_range']['start']) + '-' + str(end) else: range = '-' + str(end) if module.params['file_data_type'] == 'text': request_headers['X-IBM-Record-Range'] = range else: request_headers['Range'] = 'bytes=' + range if module.params['file_checksum'] is not None and module.params[ 'file_checksum'].strip() != '': request_headers['If-None-Match'] = module.params[ 'file_checksum'].strip() # step2 - fetch USS file res_fetch = call_file_api(module, session, 'fetch', request_headers) res_cd = res_fetch.status_code if res_cd != 200 and res_cd != 206 and res_cd != 416 and res_cd != 304: # handle response error res_error = res_fetch.json() if ('category' in res_error and res_error['category'] == 6 and 'rc' in res_error and res_error['rc'] == 8 and 'reason' in res_error and res_error['reason'] == 1046): # not fail - no conntents returned in the range of records (500) fetch_result[ 'message'] = 'The USS file ' + fetch_src + ' is not fetched since no contents is returned in the specified range.' module.exit_json(**fetch_result) else: # fail - return JSON error report module.fail_json(msg='Failed to fetch the USS file ' + fetch_src + ' ---- Http request error: ' + str(res_cd) + ': ' + str(res_error)) else: # handle response res_hd = res_fetch.headers if 'Etag' in res_hd: fetch_result['file_checksum'] = res_hd['Etag'] if 'X-IBM-Record-Range' in res_hd: fetch_result['file_matched_range'] = res_hd['X-IBM-Record-Range'] fetch_result['file_matched_content'] = [] if 'Content-Length' in res_hd and int( res_hd['Content-Length']) == 0: # no matched conntents with the specified search keyword (200) fetch_result[ 'message'] = 'The USS file ' + fetch_src + ' is not fetched since no matched contents is found with the specified search keyword.' module.exit_json(**fetch_result) if res_cd == 304: # file not changed when file_checksum is specified (304) fetch_result[ 'message'] = 'The USS file ' + fetch_src + ' is not fetched since it is not changed.' elif res_cd == 416: # no conntents returned in the range of bytes (416) fetch_result[ 'message'] = 'The USS file ' + fetch_src + ' is not fetched since no contents is returned in the specified range.' else: # save the returned conntents to local (200/206) if file.startswith('/'): file = file[1:] if not path.endswith('/'): path += '/' if module.params['file_flat'] is False: path += host + '/' + file[0:file.rfind('/') + 1] file = file[file.rfind('/') + 1:] try: if not os.path.exists(path): os.makedirs(path, 0o755) else: os.chmod(path, 0o755) except OSError as ex: module.fail_json(msg='Failed to fetch the USS file ' + fetch_src + ' ---- OS error: ' + str(ex)) if res_cd == 206: # binary contents returned in the specified range of bytes (206) f_write = open(path + file + '.range', 'wb') f_write.write(res_fetch.content) f_write.close() fetch_result['message'] = 'A range of bytes in the USS file ' + fetch_src + ' is fetched successfully and saved in: ' \ + path + file + '.range' elif 'file_matched_range' in fetch_result: # matched text contents returned with the specified search keyword (200) f_write = open(path + file + '.search', 'w') f_write.write(res_fetch.text) f_write.close() fetch_result['file_matched_content'] = res_fetch.text.split( '\n') fetch_result['message'] = 'The matched contents in the USS file ' + fetch_src + ' is fetched successfully and saved in: ' \ + path + file + '.search' elif 'file_checksum' not in fetch_result: # text contents returned in the specified range of records (200) f_write = open(path + file + '.range', 'w') f_write.write(res_fetch.text) f_write.close() fetch_result['file_content'] = res_fetch.text.split('\n') fetch_result['message'] = 'A range of records in the USS file ' + fetch_src + ' is fetched successfully and saved in: ' \ + path + file + '.range' else: # all contents returned (200) if res_hd['Content-Type'].find('text/plain') > -1: # text contents returned f_write = open(path + file, 'w') f_write.write(res_fetch.text) f_write.close() fetch_result['file_content'] = res_fetch.text.split('\n') else: # binary contents returned f_write = open(path + file, 'wb') f_write.write(res_fetch.content) f_write.close() fetch_result[ 'message'] = 'The USS file ' + fetch_src + ' is fetched successfully and saved in: ' + path + file module.exit_json(**fetch_result)
def action_delete(module): """ Delete the workflow instance specified by workflow_key. If workflow_key is not supplied, delete the workflow instance specified by workflow_name. Return the message to indicate whether the workflow instance does not exist or is deleted. :param AnsibleModule module: the ansible module """ workflow_key = '' delete_by_key = False delete_result = dict(changed=False, deleted=False, message='') # create session session = get_connect_session(module) # decide if delete by name or key if module.params['workflow_key'] is not None and module.params[ 'workflow_key'].strip() != '': workflow_key = module.params['workflow_key'] delete_by_key = True # step1 - find workflow instance by name if needed if workflow_key == '': if module.params['workflow_name'] is None or module.params[ 'workflow_name'].strip() == '': module.fail_json( msg= 'A valid argument of either workflow_name or workflow_key is required.' ) response_list = call_workflow_api(module, session, 'list', workflow_key) if isinstance(response_list, dict): if 'workflows' in response_list and len( response_list['workflows']) > 0: workflow_key = response_list['workflows'][0]['workflowKey'] else: delete_result[ 'message'] = 'Workflow instance named: ' + module.params[ 'workflow_name'] + ' does not exist.' module.exit_json(**delete_result) else: module.fail_json(msg='Failed to find workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_list) # step2 - delete workflow instance response_delete = call_workflow_api(module, session, 'delete', workflow_key) if isinstance(response_delete, dict): delete_result['changed'] = True delete_result['deleted'] = True if delete_by_key is True: delete_result[ 'message'] = 'Workflow instance with key: ' + workflow_key + ' is deleted.' else: delete_result[ 'message'] = 'Workflow instance named: ' + module.params[ 'workflow_name'] + ' is deleted.' module.exit_json(**delete_result) else: if delete_by_key is True: module.fail_json( msg='Failed to delete workflow instance with key: ' + workflow_key + ' ---- ' + response_delete) else: module.fail_json(msg='Failed to delete workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_delete)
def action_check(module): """ Check status of the workflow instance specified by workflow_key. If workflow_key is not supplied, check status of the workflow instance specified by workflow_name. Return the message to indicate whether the workflow instance is completed, is not completed, or is still in progress. Return the waiting flag to indicate whether it needs to wait and check again since the workflow instance is still in progress. :param AnsibleModule module: the ansible module """ workflow_key = '' check_by_key = False next_step_name = '' check_result = dict(changed=False, waiting=True, completed=False, message='') # create session session = get_connect_session(module) # decide if check by name or key if module.params['workflow_key'] is not None and module.params[ 'workflow_key'].strip() != '': workflow_key = module.params['workflow_key'] check_by_key = True # step1 - find workflow instance by name if needed if workflow_key == '': if module.params['workflow_name'] is None or module.params[ 'workflow_name'].strip() == '': module.fail_json( msg= 'A valid argument of either workflow_name or workflow_key is required.' ) response_list = call_workflow_api(module, session, 'list', workflow_key) if isinstance(response_list, dict): if 'workflows' in response_list and len( response_list['workflows']) > 0: workflow_key = response_list['workflows'][0]['workflowKey'] else: module.fail_json(msg='No workflow instance named: ' + module.params['workflow_name'] + ' is found.') else: module.fail_json(msg='Failed to find workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_list) # step2 - get workflow properties response_retrieveP = call_workflow_api(module, session, 'retrieveProperties', workflow_key) if isinstance(response_retrieveP, dict): if 'statusName' in response_retrieveP: status = response_retrieveP['statusName'] if status == 'automation-in-progress': if check_by_key is True: check_result[ 'message'] = 'Workflow instance with key: ' + workflow_key + ' is still in progress.' else: check_result[ 'message'] = 'Workflow instance named: ' + module.params[ 'workflow_name'] + ' is still in progress.' module.exit_json(**check_result) elif status == 'complete': check_result['waiting'] = False check_result['completed'] = True if check_by_key is True: check_result[ 'message'] = 'Workflow instance with key: ' + workflow_key + ' is completed.' else: check_result[ 'message'] = 'Workflow instance named: ' + module.params[ 'workflow_name'] + ' is completed.' module.exit_json(**check_result) else: step_status = response_retrieveP['automationStatus'] check_result['waiting'] = False if step_status is None: if check_by_key is True: check_result[ 'message'] = 'Workflow instance with key: ' + workflow_key + ' is not completed: No step is started.' else: check_result[ 'message'] = 'Workflow instance named: ' + module.params[ 'workflow_name'] + ' is not completed: No step is started.' else: current_step_message = '' next_step_message = '' if step_status['currentStepNumber'] is not None: current_step_message = 'In step ' + step_status[ 'currentStepNumber'] + ' ' + step_status[ 'currentStepTitle'] + ': ' # handle specific start issues if step_status['messageID'] == 'IZUWF0145E' and step_status[ 'currentStepNumber'] is not None: next_step_name = get_next_step_name( module, step_status['currentStepNumber'], response_retrieveP) if next_step_name != '': next_step_message = ' You can manually complete this step in z/OSMF Workflows task,' \ + ' and start this workflow instance again with next step name: ' \ + next_step_name + ' specified in argument: workflow_step_name.' if step_status['messageID'] == 'IZUWF0162I': next_step_message = ' While one or more steps may be skipped.' if check_by_key is True: check_result['message'] = 'Workflow instance with key: ' + workflow_key + ' is not completed: ' \ + current_step_message + step_status['messageText'] + next_step_message else: check_result['message'] = 'Workflow instance named: ' + module.params['workflow_name'] + ' is not completed: ' \ + current_step_message + step_status['messageText'] + next_step_message module.exit_json(**check_result) else: if check_by_key is True: module.fail_json( msg= 'Failed to get properties of workflow instance with key: ' + workflow_key + '.') else: module.fail_json( msg='Failed to get properties of workflow instance named: ' + module.params['workflow_name'] + '.') else: if check_by_key is True: module.fail_json( msg='Failed to get properties of workflow instance with key: ' + workflow_key + ' ---- ' + response_retrieveP) else: module.fail_json( msg='Failed to get properties of workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_retrieveP)
def action_start(module): """ Start the workflow instance specified by workflow_key. If workflow_key is not supplied, create the workflow instance specified by workflow_name if not exist and then start it. Return the message to indicate the workflow instance is started. Return the workflow_key of the started workflow instance. :param AnsibleModule module: the ansible module """ workflow_key = '' start_by_key = False start_result = dict(changed=False, workflow_key='', message='') # create session session = get_connect_session(module) # decide if start by name or key if module.params['workflow_key'] is not None and module.params[ 'workflow_key'].strip() != '': workflow_key = module.params['workflow_key'] start_by_key = True # step1 - find workflow instance by name if workflow_key == '': if module.params['workflow_name'] is None or module.params[ 'workflow_name'].strip() == '': module.fail_json( msg= 'A valid argument of either workflow_name or workflow_key is required.' ) response_list = call_workflow_api(module, session, 'list', workflow_key) if isinstance(response_list, dict): if 'workflows' in response_list and len( response_list['workflows']) > 0: workflow_key = response_list['workflows'][0]['workflowKey'] else: module.fail_json(msg='Failed to find workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_list) # step2 - create workflow instance if needed if workflow_key == '': response_create = call_workflow_api(module, session, 'create', workflow_key) if isinstance(response_create, dict): if 'workflowKey' in response_create and response_create[ 'workflowKey'] != '': workflow_key = response_create['workflowKey'] else: module.fail_json( msg='Failed to create workflow instance named: ' + module.params['workflow_name'] + '.') else: module.fail_json(msg='Failed to create workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_create) # step3 - start workflow instance response_start = call_workflow_api(module, session, 'start', workflow_key) if isinstance(response_start, dict): start_result['changed'] = True start_result['workflow_key'] = workflow_key if start_by_key is True: start_result[ 'message'] = 'Workflow instance with key: ' + workflow_key + ' is started, you can use state=check to check its final status.' else: start_result['message'] = 'Workflow instance named: ' + module.params['workflow_name'] \ + ' is started, you can use state=check to check its final status.' module.exit_json(**start_result) else: # handle start issue caused by non-automated step next_step_message = '' if response_start.find('IZUWF5007E') > 0: next_step_message = ' You can manually complete this step in z/OSMF Workflows task,' \ + ' and start this workflow instance again with next step name specified in argument: workflow_step_name.' if start_by_key is True: module.fail_json( msg='Failed to start workflow instance with key: ' + workflow_key + ' ---- ' + response_start + next_step_message) else: module.fail_json(msg='Failed to start workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_start + next_step_message)
def action_compare(module, argument_spec_mapping): """ Indicate whether the workflow instance specified by workflow_name already exists. If the workflow instance already exists, indicate whether they have same definition files, variables and properties. Return the message to indicate whether the workflow instance does not exist, or exists with same or different definition file, variables and properties. Return the workflow_key of the existing workflow instance. Return the same_workflow_instance flag to indicate whether the existing workflow instance has same or different definition file, variables and properties. Return the completed flag to indicate whether the existing workflow instance with same definition file, variables and properties has been completed. :param AnsibleModule module: the ansible module :param dict[str, dict] argument_spec_mapping: the mapping between arguments of ansible module and params of all workflow APIs """ workflow_key = '' compare_result = dict(changed=False, workflow_key='', same_workflow_instance=False, completed=False, message='') # create session session = get_connect_session(module) # step1 - find workflow instance by name response_list = call_workflow_api(module, session, 'list', workflow_key) if isinstance(response_list, dict): if 'workflows' in response_list and len( response_list['workflows']) > 0: workflow_key = response_list['workflows'][0]['workflowKey'] else: compare_result[ 'message'] = 'No workflow instance named: ' + module.params[ 'workflow_name'] + ' is found.' module.exit_json(**compare_result) else: module.fail_json(msg='Failed to find workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_list) # step2 - compare the properties and definition files response_retrieveP = call_workflow_api(module, session, 'retrieveProperties', workflow_key) if isinstance(response_retrieveP, str): module.fail_json( msg='Failed to get properties of workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_retrieveP) response_retrieveD = dict() if module.params['workflow_file'] is not None and module.params[ 'workflow_file'].strip() != '': response_retrieveD = call_workflow_api(module, session, 'retrieveDefinition', workflow_key) if isinstance(response_retrieveD, str): module.fail_json( msg='Failed to get definition file of workflow instance named: ' + module.params['workflow_name'] + ' ---- ' + response_retrieveD) (sameD, sameV, sameP, diff_name, diff_value) = is_same_workflow_instance(module, argument_spec_mapping, response_retrieveP, response_retrieveD) if sameD is False: compare_result[ 'message'] = 'Workflow instance named: ' + module.params[ 'workflow_name'] + ' with different definition file is found.' elif sameV is False: compare_result['message'] = 'Workflow instance named: ' + module.params['workflow_name'] + ' with different variable: ' \ + diff_name + ' = ' + str(diff_value) + ' is found.' elif sameP is False: compare_result['message'] = 'Workflow instance named: ' + module.params['workflow_name'] + ' with different property: ' \ + diff_name + ' = ' + str(diff_value) + ' is found.' elif sameD is None or sameV is None: compare_result['same_workflow_instance'] = True compare_result['message'] = 'Workflow instance named: ' + module.params['workflow_name'] \ + ' is found. While it could not be compared since the argument: workflow_file is required,' \ + ' and please supply variables by the argument: workflow_vars rather than the argument: workflow_vars_file.' else: compare_result['same_workflow_instance'] = True compare_result['message'] = 'Workflow instance named: ' + module.params['workflow_name'] \ + ' with same definition file, variables and properties is found.' if compare_result[ 'same_workflow_instance'] is not False and response_retrieveP[ 'statusName'] == 'complete': compare_result['completed'] = True compare_result['workflow_key'] = workflow_key module.exit_json(**compare_result)
def copy_file(module): """ Copy data to a USS file Return the message to indicate whether the USS file is successfully copied. Return file_checksum of the checksum of the USS file. :param AnsibleModule module: the ansible module """ copy_result = dict( changed=False, message='', ) # create session session = get_connect_session(module) copy_dest = module.params['file_dest'].strip() if not copy_dest.startswith('/'): copy_dest = '/' + copy_dest copy_src = None if module.params['file_src'] is not None and module.params[ 'file_src'].strip() != '': copy_src = module.params['file_src'].strip() # setup file parent path and file name f_path = copy_dest[:copy_dest.rfind('/')] f_name = copy_dest[copy_dest.rfind('/') + 1:] if f_path.startswith('/'): f_path = f_path[1:] module.params['f_path'] = f_path module.params['f_name'] = f_name # step1 - check if the target USS file exists when file_force=false if module.params['file_force'] is False: res_list = call_file_api(module, session, 'list') if res_list.status_code == 200: res_content = json.loads(res_list.content) if 'returnedRows' in res_content and res_content[ 'returnedRows'] > 0: # not fail - no data is copied since the target USS file exists copy_result[ 'message'] = 'No data is copied since the target USS file ' + copy_dest + ' already exists and file_force is set to False.' module.exit_json(**copy_result) # step2 - read file_src or file_content f_read = None request_body = None if module.params['file_data_type'] != 'text': try: f_read = open(copy_src, 'rb') request_body = f_read.read() except OSError as ex: module.fail_json( msg='Failed to copy data to the target USS file ' + copy_dest + ' ---- OS error: ' + str(ex)) else: if module.params['file_content'] is not None and module.params[ 'file_content'].strip() != '': request_body = module.params['file_content'] else: try: f_read = open(copy_src, 'r') request_body = f_read.read() except OSError as ex: module.fail_json( msg='Failed to copy data to the target USS file ' + copy_dest + ' ---- OS error: ' + str(ex)) if f_read is not None: f_read.close() # step3 - combine request headers request_headers = dict() request_headers['X-IBM-Data-Type'] = module.params['file_data_type'] request_headers['Content-Type'] = 'text/plain' if module.params['file_data_type'] == 'text': if module.params['file_diff'] is True: request_headers['Content-Type'] = 'application/x-ibm-diff-e' if module.params['file_encoding'] is not None: request_headers[ 'X-IBM-Data-Type'] += ';fileEncoding=' + module.params[ 'file_encoding']['to'] request_headers['Content-Type'] += ';charset=' + module.params[ 'file_encoding']['from'] if module.params['file_crlf'] is True: request_headers['X-IBM-Data-Type'] += ';crlf=true' if module.params['file_checksum'] is not None and module.params[ 'file_checksum'].strip() != '': request_headers['If-Match'] = module.params['file_checksum'].strip() # step4 - copy data to the target USS file res_copy = call_file_api(module, session, 'copy', request_headers, request_body) res_cd = res_copy.status_code if res_cd != 201 and res_cd != 204: # handle response error if res_cd == 412: # fail - file has been modified when file_checksum is specified (412) module.fail_json( msg='Failed to copy data to the target USS file ' + copy_dest + ' ---- the target USS file has been modified and its checksum is: ' + res_copy.headers['Etag']) else: # fail - return JSON error report res_error = res_copy.json() module.fail_json( msg='Failed to copy data to the target USS file ' + copy_dest + ' ---- Http request error: ' + str(res_cd) + ': ' + str(res_error)) else: # handle response copy_result['changed'] = True copy_result['file_checksum'] = res_copy.headers['Etag'] if res_cd == 201: # success - a new USS file is created (201) copy_result[ 'message'] = 'The target USS file ' + copy_dest + ' is created and updated successfully.' else: # success - an existing USS file is updated (204) copy_result[ 'message'] = 'The target USS file ' + copy_dest + ' is updated successfully.' module.exit_json(**copy_result)
def issue_command(module): """ Issue a command by using a system console. Return the message to indicate the command is successful. Return the cmd_response of the issued command. Return the cmdresponse_keyword_detected flag to indicate whether the specified keyword is detected in command response. Return the broadcastmsg_keyword_detected flag to indicate whether the specified keyword is detected in broadcast messages. Return the detected_broadcastmsg of the detected message in broadcast messages if broadcastmsg_keyword_detected is True. :param AnsibleModule module: the ansible module """ cmd_response = '' response_key = '' issue_result = dict( changed=False, message='', ) # create session session = get_connect_session(module) # step1 - issue a command response_issue = call_console_api(module, session, 'issue') if isinstance(response_issue, dict): if 'cmd-response' in response_issue: cmd_response = response_issue['cmd-response'] # handle route issue if 'IEE618I' in cmd_response: module.fail_json( msg= 'Failed to issue the command ---- IEE618I ROUTE COMMAND REJECTED, INVALID SYSTEM NAME.' ) elif 'IEE345I' in cmd_response: module.fail_json( msg= 'Failed to issue the command ---- IEE345I ROUTE AUTHORITY INVALID, FAILED BY SECURITY PRODUCT.' ) else: issue_result['changed'] = True response_key = response_issue['cmd-response-key'] cmd_response = format_message_to_list(cmd_response) else: module.fail_json( msg='Failed to issue the command ---- No response is returned.' ) else: module.fail_json(msg='Failed to issue the command ---- ' + response_issue) # step2 - detect keyword if module.params[ 'console_cmdresponse_keyword'] is not None and module.params[ 'console_cmdresponse_keyword'].strip() != '': issue_result['cmdresponse_keyword_detected'] = response_issue[ 'sol-key-detected'] if module.params[ 'console_broadcastmsg_keyword'] is not None and module.params[ 'console_broadcastmsg_keyword'].strip() != '': if response_issue['status'] == 'detected': issue_result['broadcastmsg_keyword_detected'] = True issue_result['detected_broadcastmsg'] = format_message_to_list( response_issue['msg']) else: issue_result['broadcastmsg_keyword_detected'] = False # step3 - retrieve the command response and detect again check_delay = 2 check_times = module.params['console_cmdresponse_retrieve_times'] while check_times > 0: response_getResponse = call_console_api(module, session, 'getResponse', response_key) if isinstance(response_getResponse, dict): if 'cmd-response' in response_getResponse and response_getResponse[ 'cmd-response'].strip() != '': # detect again if 'cmdresponse_keyword_detected' in issue_result and issue_result[ 'cmdresponse_keyword_detected'] is False: if (module.params['console_cmdresponse_reg'] == 'Y' and re.findall( module.params['console_cmdresponse_keyword'], response_issue['cmd-response'])): issue_result['cmdresponse_keyword_detected'] = True elif module.params['console_cmdresponse_keyword'].upper( ) in response_getResponse['cmd-response'].upper(): issue_result['cmdresponse_keyword_detected'] = True # append the retrieved response cmd_response = cmd_response + format_message_to_list( response_getResponse['cmd-response']) sleep(check_delay) check_times = check_times - 1 else: module.fail_json( msg='Failed to retrieve the command response ---- ' + response_getResponse) issue_result['cmd_response'] = cmd_response # step4 - save to local if console_save_output_localpath is defined save_message = '' if module.params[ 'console_save_output_localpath'] is not None and module.params[ 'console_save_output_localpath'].strip() != '': if module.params['console_save_output_localpath'].endswith('/'): save_path = module.params[ 'console_save_output_localpath'] + module.params[ 'console_system'] + '/' else: save_path = module.params[ 'console_save_output_localpath'] + '/' + module.params[ 'console_system'] + '/' if not os.path.exists(save_path): os.makedirs(save_path, 0o755, True) else: os.chmod(save_path, 0o755) save_file = format_cmd_to_str(module.params['console_cmd']) f_write = open(save_path + save_file, 'w') f_write.writelines(format_message_to_file(cmd_response)) f_write.close() save_message = ' The command response is saved in: ' + save_path + save_file # step5 - decide if detect fails or not if 'cmdresponse_keyword_detected' not in issue_result and 'broadcastmsg_keyword_detected' not in issue_result: issue_result[ 'message'] = 'The command is issued successfully.' + save_message elif 'cmdresponse_keyword_detected' in issue_result and issue_result[ 'cmdresponse_keyword_detected'] is True: issue_result[ 'message'] = 'The command is issued successfully. The specified keyword is detected in the command response.' + save_message elif 'broadcastmsg_keyword_detected' in issue_result and issue_result[ 'broadcastmsg_keyword_detected'] is True: issue_result[ 'message'] = 'The command is issued successfully. The specified keyword is detected in broadcast messages.' + save_message else: module.fail_json( cmd_response=cmd_response, msg= 'The command is issued successfully. But no specified keywords are detected in neither the command response nor broadcast messages.' + save_message) module.exit_json(**issue_result)
def fetch_dataset(module): """ Call z/OSMF REST file and data set interface to read data set or member """ fetch_result = dict( changed=False, message='', ) # combine custom headers request_headers = dict() if module.params['dataset_data_type'] == 'text' and module.params[ 'dataset_encoding'] is not None: request_headers[ 'X-IBM-Data-Type'] = 'text;fileEncoding=' + module.params[ 'dataset_encoding']['from'] request_headers[ 'Content-Type'] = 'text/plain;charset=' + module.params[ 'dataset_encoding']['to'] else: request_headers['X-IBM-Data-Type'] = module.params['dataset_data_type'] if module.params['dataset_range'] is not None: range = module.params['dataset_range'] if 'end' in range: end = range['end'] else: end = 0 if 'start' in range: range = str(range['start']) + '-' + str(end) else: range = '-' + str(end) request_headers['X-IBM-Record-Range'] = range # create session session = get_connect_session(module) dataset = module.params['dataset_src'].strip().upper() # setup data set full name, data set name and member name ds_full_name = '' ds_v_name = '' ds_name = '' m_name = '' v_name = '' if dataset.find('(') > 0: ds_name = dataset[:dataset.find('(')] m_name = dataset[dataset.find('(') + 1:dataset.find(')')] else: ds_name = dataset if module.params['dataset_volser'] is not None and module.params[ 'dataset_volser'].strip() != '': v_name = module.params['dataset_volser'].strip().upper() ds_full_name = '-(' + v_name + ')/' + dataset ds_v_name = '-(' + v_name + ')/' + ds_name else: ds_full_name = dataset ds_v_name = ds_name module.params['ds_full_name'] = ds_full_name module.params['ds_v_name'] = ds_v_name module.params['ds_name'] = ds_name module.params['m_name'] = m_name module.params['v_name'] = v_name # fetch data set response_fetch = call_dataset_api(module, session, 'fetch', request_headers) status_code = response_fetch.status_code if status_code == 404: if module.params['dataset_volser'] is not None and module.params[ 'dataset_volser'].strip() != '': module.fail_json(msg='Failed to fetch the data set ---- ' + dataset + ' can not be found in ' + module.params['dataset_volser'].strip().upper()) else: module.fail_json(msg='Failed to fetch the data set ---- ' + dataset + ' not in catalog or catalog can not be accessed.') elif status_code != 304 and status_code != 200: # handle response error response_error = response_fetch.json() if ('category' in response_error and response_error['category'] == 6 and 'rc' in response_error and response_error['rc'] == 8 and 'reason' in response_error and response_error['reason'] == 1046): # not fail - no conntents returned in the range of records (500) fetch_result[ 'message'] = 'The data set ' + dataset + ' is not fetched since no contents is returned in the specified range.' module.exit_json(**fetch_result) else: # fail - return JSON error report module.fail_json(msg='Failed to fetch the data set ' + dataset + ' ---- Http request error: ' + str(status_code) + ': ' + str(response_error)) else: response_headers = response_fetch.headers if 'Etag' in response_headers: fetch_result['dataset_checksum'] = response_headers['Etag'] if status_code == 304: fetch_result[ 'message'] = 'The data set ' + dataset + ' is not fetched since it is not changed.' elif status_code == 200: if response_headers['Content-Type'] is not None: content_type = response_headers['Content-Type'] # initialize path path = module.params['dataset_dest'].strip() host = module.params['zmf_host'].strip() if not path.endswith('/'): path += '/' if module.params['dataset_flat'] is False: path = path + host + '/' if module.params[ 'dataset_volser'] is not None and module.params[ 'dataset_volser'].strip() != '': path = path + module.params['dataset_volser'].strip( ).upper() + '/' save_file = dataset.replace('(', '/').replace(')', '/') if save_file.find('/') != -1: tmp_path = save_file.split('/') path += tmp_path[0] + '/' save_file = tmp_path[1] try: if os.path.exists(path): os.chmod(path, 0o755) else: os.makedirs(path, 0o755) except OSError as ex: module.fail_json(msg='Failed to save the data set ' + dataset + ' ---- OS error: ' + str(ex)) if 'X-IBM-Record-Range' in response_headers: # when search fetch_result['dataset_matched_range'] = response_headers[ 'X-IBM-Record-Range'] if response_fetch.text != '': f_write = open(path + save_file + '.search', 'w') f_write.write(response_fetch.text) f_write.close() fetch_result[ 'dataset_matched_content'] = response_fetch.text.split( '\n') fetch_result['message'] = 'The matched content in the data set ' + dataset + 'is fetched successfully and saved in: ' \ + path + save_file + '.search.' else: fetch_result['dataset_matched_content'] = [] fetch_result['message'] = 'The data set ' + dataset + ' is not fetched since ' \ + 'no matched contents is found with the specified search keyword.' else: msg = 'The data set ' if 'Etag' not in response_headers: # fetch with range save_file += '.range' msg = 'A range of records in the data set ' if content_type.startswith('text/plain'): # text f_write = open(path + save_file, 'w') f_write.write(response_fetch.text) f_write.close() fetch_result[ 'dataset_content'] = response_fetch.text.split( '\n') else: # binary and record f_write = open(path + save_file, 'wb') f_write.write(response_fetch.content) f_write.close() fetch_result[ 'message'] = msg + dataset + ' is fetched successfully and saved in: ' + path + save_file else: module.fail_json( msg= 'Failed to read data set ---- Content-Type is missing in the response.' ) module.exit_json(**fetch_result)