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)
示例#2
0
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
示例#3
0
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)
示例#4
0
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)
示例#5
0
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)
示例#6
0
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)
示例#7
0
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)
示例#8
0
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)
示例#9
0
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)