예제 #1
0
def main():

    module_args = dict(host=dict(type='str', required=True),
                       port=dict(type='str', required=True),
                       user=dict(type='str', required=True),
                       password=dict(type='str', required=True, no_log=True),
                       src=dict(type='path', required=True),
                       mappings=dict(type='list', required=False, default=[]),
                       mode=dict(type='str', required=True),
                       replace_type=dict(type='str',
                                         required=False,
                                         default=""),
                       conditions=dict(type='list', required=False,
                                       default=[]),
                       batch=dict(type='int', required=False, default=100),
                       cert=dict(type='path', required=False),
                       unsafe_writes=dict(type='bool',
                                          required=False,
                                          default=False))

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    result = dict(changed=False,
                  queries=[],
                  updates=[],
                  asset_update_count=0,
                  relationship_update_count=0,
                  unupdated_assets=[],
                  unmapped_assets=[],
                  unmapped_relations=[])

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # Setup REST API connectivity via module_utils.igc_rest class
    igcrest = RestIGC(module,
                      result,
                      username=module.params['user'],
                      password=module.params['password'],
                      host=module.params['host'],
                      port=module.params['port'],
                      cert=module.params['cert'])

    mappings = module.params['mappings']
    src = module.params['src']
    batch = module.params['batch']

    if os.path.isdir(src):
        module.fail_json(rc=256, msg='Src %s is a directory !' % src)

    src_exists = os.path.exists(src)
    if not src_exists:
        module.fail_json(rc=257, msg='Src %s does not exist !' % src)

    f = open(to_bytes(src), 'rb')
    allAssets = json.load(f)
    f.close()

    wfl_enabled = igcrest.isWorkflowEnabled()

    for asset in allAssets:
        mappedItem = igcrest.getMappedItem(asset,
                                           mappings,
                                           wfl_enabled,
                                           batch=batch)
        if mappedItem == "":
            result['unmapped_assets'].append(asset)
            continue
        # Automatically detect the relationship properties, should be the only
        # ones that do NOT start with an underscore
        for relnprop in asset:
            if not relnprop.startswith('_'):
                aRelns = asset[relnprop]
                aMappedRelnRIDs = []
                if isinstance(aRelns, list):
                    for reln in aRelns:
                        getMappedRelation(igcrest, reln, mappings, wfl_enabled,
                                          batch, result, aMappedRelnRIDs)
                    if len(aMappedRelnRIDs) > 0:
                        update_rc, update_msg = igcrest.addRelationshipsToAsset(
                            mappedItem,
                            aMappedRelnRIDs,
                            relnprop,
                            module.params['mode'],
                            replace_type=module.params['replace_type'],
                            conditions=module.params['conditions'],
                            batch=batch)
                        if update_rc != 200:
                            result['unupdated_assets'].append(mappedItem)
                        else:
                            result['changed'] = True
                            result['asset_update_count'] += 1
                            result['relationship_update_count'] += len(
                                aMappedRelnRIDs)
                elif isinstance(aRelns, dict):
                    getMappedRelation(igcrest, aRelns, mappings, wfl_enabled,
                                      batch, result, aMappedRelnRIDs)
                    if len(aMappedRelnRIDs) == 1:
                        update_rc, update_msg = igcrest.replaceSingleRelationship(
                            mappedItem, aMappedRelnRIDs[0], relnprop)
                        if update_rc != 200:
                            result['unupdated_assets'].append(mappedItem)
                        else:
                            result['changed'] = True
                            result['asset_update_count'] += 1
                            result['relationship_update_count'] += 1

    # Close the IGC REST API session
    igcrest.closeSession()

    module.exit_json(**result)
def main():

    module_args = dict(host=dict(type='str', required=True),
                       port=dict(type='str', required=True),
                       user=dict(type='str', required=True),
                       password=dict(type='str', required=True, no_log=True),
                       bundle_name=dict(type='str', required=True),
                       dest=dict(type='path', required=True),
                       assets_to_keep=dict(type='list', required=True),
                       complete_types=dict(type='list',
                                           required=False,
                                           default=[]),
                       cert=dict(type='path', required=False),
                       unsafe_writes=dict(type='bool',
                                          required=False,
                                          default=False))

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    result = dict(changed=False, asset_count=0)

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # Setup REST API connectivity via module_utils.igc_rest class
    igcrest = RestIGC(module,
                      result,
                      username=module.params['user'],
                      password=module.params['password'],
                      host=module.params['host'],
                      port=module.params['port'],
                      cert=module.params['cert'])

    complete_types = module.params['complete_types']

    # Execute the retrieval
    xmlResults = igcrest.getOpenIGCAssets(module.params['bundle_name'])

    # Ensure search worked before proceeding
    if not xmlResults:
        module.fail_json(msg='Retrieval of OpenIGC assets failed', **result)

    # Write temporary file with the full XML output to operate against
    try:
        tmpfd_full, tmpfile_full = tempfile.mkstemp()
        f = os.fdopen(tmpfd_full, 'wb')
        f.write(xmlResults)
        f.close()
    except IOError:
        module.fail_json(
            msg='Unable to create temporary file to output OpenIGC assets',
            **result)

    assets_to_keep = module.params['assets_to_keep']
    oigc_xml = OpenIGCHandler(module, result, tmpfile_full)

    partial_assets = []
    complete_assets = []
    assets_to_drop = []

    for rid in assets_to_keep:
        e_asset = oigc_xml.getAssetById(rid)
        asset_type = oigc_xml.getType(e_asset)
        if asset_type in complete_types:
            complete_assets.append(rid)
        else:
            partial_assets.append(rid)
        a_ancestors = oigc_xml.getAncestralAssetRids(rid)
        for ancenstor in a_ancestors:
            e_ancestor = oigc_xml.getAssetById(ancenstor)
            ancestor_type = oigc_xml.getType(e_ancestor)
            if ancestor_type in complete_types and ancenstor not in complete_assets:
                complete_assets.append(ancenstor)
            elif ancenstor not in partial_assets:
                partial_assets.append(ancenstor)
        a_children = oigc_xml.getAssetChildrenRids(rid)
        for child in a_children:
            e_child = oigc_xml.getAssetById(child)
            child_type = oigc_xml.getType(e_child)
            if child_type in complete_types and child not in complete_assets:
                complete_assets.append(child)
            elif child not in partial_assets:
                partial_assets.append(child)

    for e_asset in oigc_xml.getAssets():
        rid = oigc_xml.getRid(e_asset)
        if rid not in partial_assets and rid not in complete_assets:
            if rid is not None:
                oigc_xml.dropAsset(e_asset)
        else:
            result['asset_count'] += 1

    oigc_xml.setImportActionPartials(partial_assets)
    oigc_xml.setImportActionCompletes(complete_assets)

    # Remove the interim temporary file
    os.unlink(tmpfile_full)

    # Write a new temporary file with the revised XML output,
    # and then move to specified dest location
    try:
        tmpfd, tmpfile = tempfile.mkstemp()
        f = os.fdopen(tmpfd, 'wb')
        oigc_xml.writeCustomizedXML(tmpfile)
        f.close()
    except IOError:
        module.fail_json(
            msg='Unable to create temporary file to output project details',
            **result)

    # Checksumming to identify change...
    checksum_src = module.sha1(tmpfile)
    checksum_dest = None
    dest = module.params['dest']
    b_dest = to_bytes(dest, errors='surrogate_or_strict')
    if os.access(b_dest, os.R_OK):
        checksum_dest = module.sha1(dest)

    # If the file does not already exist and/or checksums are different,
    # move the new file over the old one and mark it as changed; otherwise
    # leave the original file (delete the tmpfile) and that there was no change
    if checksum_src != checksum_dest:
        module.atomic_move(tmpfile,
                           to_native(os.path.realpath(b_dest),
                                     errors='surrogate_or_strict'),
                           unsafe_writes=module.params['unsafe_writes'])
        result['changed'] = True
    else:
        os.unlink(tmpfile)

    module.exit_json(**result)
예제 #3
0
def main():

    module_args = dict(host=dict(type='str', required=True),
                       port=dict(type='str', required=True),
                       user=dict(type='str', required=True),
                       password=dict(type='str', required=True, no_log=True),
                       asset_type=dict(type='str', required=True),
                       from_time=dict(type='int', required=True),
                       to_time=dict(type='int', required=True),
                       conditions=dict(type='list', required=False,
                                       default=[]),
                       cert=dict(type='path', required=False),
                       batch=dict(type='int', required=False, default=100))

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    result = dict(changed=False, queries=[], assets=[])

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # Setup REST API connectivity via module_utils.igc_rest class
    igcrest = RestIGC(module,
                      result,
                      username=module.params['user'],
                      password=module.params['password'],
                      host=module.params['host'],
                      port=module.params['port'],
                      cert=module.params['cert'])

    conditions = module.params['conditions']
    asset_type = module.params['asset_type']

    # Basic query
    reqJSON = {
        "properties": get_properties(asset_type),
        "types": [asset_type],
        "where": {
            "conditions": [],
            "operator": "and"
        },
        "pageSize": module.params['batch']
    }

    # Handle extended data sources in special way (to catch any changes in their underlying
    # granular assets as well) -- requires nested OR'd conditions to check for changes
    if asset_type.startswith('$'):
        a_types = igcrest.getTypesForOpenIGCBundle(asset_type)
        if not a_types:
            module.fail_json(msg='Unable to find specified OpenIGC bundle: ' +
                             asset_type,
                             **result)
        reqJSON['types'] = a_types
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "modified_on",
            "operator":
            "between"
        })
    elif asset_type == 'application':
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "object_types.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "object_types.methods.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "object_types.methods.input_parameters.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "object_types.methods.output_values.modified_on",
            "operator":
            "between"
        })
    # Handle stored procedures in special way (to catch any changes in their underlying
    # granular assets as well) -- requires nested OR'd conditions to check for changes
    elif asset_type == 'stored_procedure_definition':
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "in_parameters.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "out_parameters.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "inout_parameters.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "result_columns.modified_on",
            "operator":
            "between"
        })
    # Handle IA data rules in special way (to catch any changes in underlying execution runs)
    # -- requires nested OR'd condition to check for changes
    elif asset_type == 'data_rule' or asset_type == 'data_rule_set' or asset_type == 'metric':
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "property":
            "execution_history",
            "operator":
            "isNull"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "execution_history.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'].append({
            "min": module.params['from_time'],
            "max": module.params['to_time'],
            "property": "modified_on",
            "operator": "between"
        })
    # Handle LDM objects in special way (to catch any changes in underlying objects)
    # -- requires nested OR'd condition to check for changes
    elif asset_type == 'logical_data_model':
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'].append({
            "min": module.params['from_time'],
            "max": module.params['to_time'],
            "property": "modified_on",
            "operator": "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "contains_logical_data_models.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "subject_areas.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "logical_entities.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "logical_domains.modified_on",
            "operator":
            "between"
        })
    # Handle PDM objects in special way (to catch any changes in underlying objects)
    # -- requires nested OR'd condition to check for changes
    elif asset_type == 'physical_data_model':
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'].append({
            "min": module.params['from_time'],
            "max": module.params['to_time'],
            "property": "modified_on",
            "operator": "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "contains_physical_models.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "contains_design_tables.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "contains_design_views.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "contains_design_stored_procedures.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "physical_domains.modified_on",
            "operator":
            "between"
        })
    # Handle Database objects in special way (to catch any changes in underlying objects)
    # -- requires nested OR'd condition to check for changes
    elif asset_type == 'database':
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'].append({
            "min": module.params['from_time'],
            "max": module.params['to_time'],
            "property": "modified_on",
            "operator": "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "database_schemas.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "database_schemas.stored_procedures.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "database_schemas.views.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "database_schemas.database_tables.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "database_schemas.database_tables.database_columns.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "database_schemas.views.database_columns.modified_on",
            "operator":
            "between"
        })
    # Handle Schema objects in special way (to catch any changes in underlying objects)
    # -- requires nested OR'd condition to check for changes
    elif asset_type == 'database_schema':
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'].append({
            "min": module.params['from_time'],
            "max": module.params['to_time'],
            "property": "modified_on",
            "operator": "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "stored_procedures.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "views.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "database_tables.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "database_tables.database_columns.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "views.database_columns.modified_on",
            "operator":
            "between"
        })
    # Handle data file objects in special way (to catch any changes in underlying objects)
    # -- requires nested OR'd condition to check for changes
    elif asset_type == 'data_file':
        reqJSON['where']['conditions'].append({
            "conditions": [],
            "operator": "or"
        })
        reqJSON['where']['conditions'].append({
            "min": module.params['from_time'],
            "max": module.params['to_time'],
            "property": "modified_on",
            "operator": "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "data_file_records.modified_on",
            "operator":
            "between"
        })
        reqJSON['where']['conditions'][0]['conditions'].append({
            "min":
            module.params['from_time'],
            "max":
            module.params['to_time'],
            "property":
            "data_file_records.data_file_fields.modified_on",
            "operator":
            "between"
        })
    # Skip delta detection on the assets named in this condition, as they have no 'modified_on' to query against
    elif asset_type != 'label':
        reqJSON['where']['conditions'].append({
            "min": module.params['from_time'],
            "max": module.params['to_time'],
            "property": "modified_on",
            "operator": "between"
        })

    # Extend basic query with any optional conditions (in the outer, AND'd portion)
    if len(conditions) > 0:
        reqJSON['where']['conditions'] += conditions

    jsonResults = igcrest.search(reqJSON)

    # Ensure search worked before proceeding
    if jsonResults == '':
        module.fail_json(msg='Initial IGC REST API search failed', **result)

    result['asset_count'] = len(jsonResults)

    # Translate the retrieved item details into exportable strings
    for item in jsonResults:
        result_obj = get_asset_extract_object(module.params['asset_type'],
                                              item)
        if result_obj == "UNIMPLEMENTED":
            module.fail_json(msg='Unable to convert asset_type "' +
                             module.params['asset_type'] + '"',
                             **result)
        elif result_obj is not None:
            result['assets'].append(result_obj)

    # Close the IGC REST API session
    igcrest.closeSession()

    module.exit_json(**result)
def main():

    module_args = dict(host=dict(type='str', required=True),
                       port=dict(type='str', required=True),
                       user=dict(type='str', required=True),
                       password=dict(type='str', required=True, no_log=True),
                       src=dict(type='path', required=True),
                       complete_types=dict(type='list',
                                           required=False,
                                           default=[]),
                       cert=dict(type='path', required=False),
                       unsafe_writes=dict(type='bool',
                                          required=False,
                                          default=False))

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    result = dict(changed=False, rids={}, uploaded_xml="")

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # Setup REST API connectivity via module_utils.igc_rest class
    igcrest = RestIGC(module,
                      result,
                      username=module.params['user'],
                      password=module.params['password'],
                      host=module.params['host'],
                      port=module.params['port'],
                      cert=module.params['cert'])

    src = module.params['src']
    complete_types = module.params['complete_types']

    if os.path.isdir(src):
        module.fail_json(rc=256, msg='Src %s is a directory !' % src)

    src_exists = os.path.exists(src)
    if not src_exists:
        module.fail_json(rc=257, msg='Src %s does not exist !' % src)

    oigc_xml = OpenIGCHandler(module, result, src)

    partial_assets = []
    complete_assets = []

    for e_asset in oigc_xml.getAssets():
        rid = oigc_xml.getRid(e_asset)
        asset_type = oigc_xml.getType(e_asset)
        if asset_type in complete_types:
            complete_assets.append(rid)
        else:
            partial_assets.append(rid)

    oigc_xml.setImportActionPartials(partial_assets)
    oigc_xml.setImportActionCompletes(complete_assets)

    xmlToSend = oigc_xml.getCustomizedXMLAsString()
    if not xmlToSend:
        module.fail_json(msg='Retrieval of modified asset XML failed',
                         **result)
    else:
        result['uploaded_xml'] = xmlToSend
        asset_details = igcrest.uploadOpenIGCAssets(xmlToSend)
        if asset_details is not None:
            result['rids'] = asset_details
            result['changed'] = True
        else:
            module.fail_json(msg='Failed to upload assets', **result)

    # Close the IGC REST API session
    igcrest.closeSession()

    module.exit_json(**result)
def main():

    module_args = dict(host=dict(type='str', required=True),
                       port=dict(type='str', required=True),
                       user=dict(type='str', required=True),
                       password=dict(type='str', required=True, no_log=True),
                       asset_type=dict(type='str', required=True),
                       properties=dict(type='list',
                                       required=False,
                                       default=['name']),
                       conditions=dict(type='list', required=False,
                                       default=[]),
                       condition_join=dict(type='str',
                                           required=False,
                                           default='AND'),
                       cert=dict(type='path', required=False),
                       batch=dict(type='int', required=False, default=100),
                       extract_all=dict(type='bool',
                                        required=False,
                                        default=False))

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    result = dict(changed=False, queries=[], asset_count=0, assets=[])

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # Setup REST API connectivity via module_utils.igc_rest class
    igcrest = RestIGC(module,
                      result,
                      username=module.params['user'],
                      password=module.params['password'],
                      host=module.params['host'],
                      port=module.params['port'],
                      cert=module.params['cert'])

    conditions = module.params['conditions']
    asset_type = module.params['asset_type']
    properties = module.params['properties']
    extract_all = module.params['extract_all']

    # Basic query
    reqJSON = {
        "properties": properties,
        "types": [asset_type],
        "pageSize": module.params['batch']
    }

    if len(conditions) > 0:
        reqJSON['where'] = {
            "conditions": conditions,
            "operator": module.params['condition_join'].lower()
        }

    jsonResults = igcrest.search(reqJSON, extract_all)

    # Ensure search worked before proceeding
    if jsonResults == '':
        module.fail_json(msg='IGC query failed', **result)

    if extract_all:
        result['asset_count'] = len(jsonResults)
        result['assets'] = jsonResults
    else:
        result['asset_count'] = jsonResults['paging']['numTotal']
        result['assets'] = jsonResults['items']

    # Close the IGC REST API session
    igcrest.closeSession()

    module.exit_json(**result)
예제 #6
0
def main():

    module_args = dict(host=dict(type='str', required=True),
                       port=dict(type='str', required=True),
                       user=dict(type='str', required=True),
                       password=dict(type='str', required=True, no_log=True),
                       src=dict(type='path', required=True),
                       dest=dict(type='path', required=True),
                       mappings=dict(type='list', required=False, default=[]),
                       cert=dict(type='path', required=False),
                       unsafe_writes=dict(type='bool',
                                          required=False,
                                          default=False))

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    result = dict(changed=False,
                  asset_count=0,
                  untranslated_assets=[],
                  untranslated_relationships=[])

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # Setup REST API connectivity via module_utils.igc_rest class
    igcrest = RestIGC(module,
                      result,
                      username=module.params['user'],
                      password=module.params['password'],
                      host=module.params['host'],
                      port=module.params['port'],
                      cert=module.params['cert'])

    mappings = module.params['mappings']
    src = module.params['src']
    dest = module.params['dest']

    if os.path.isdir(src):
        module.fail_json(rc=256, msg='Src %s is a directory !' % src)

    src_exists = os.path.exists(src)
    if not src_exists:
        module.fail_json(rc=257, msg='Src %s does not exist !' % src)

    f = open(to_bytes(src), 'rb')
    allAssets = json.load(f)
    f.close()

    if len(allAssets) > 0:
        asset_type = allAssets[0]['_type']
        # Retrieve descriptive asset properties to populate headers
        asset_name, propertyMap = igcrest.getPropertyMap(asset_type)
        aRows = []
        aHeader = []
        for asset in allAssets:

            aRow = {}
            if 'Name' not in aHeader:
                aHeader.append('Name')
            aRow['Name'] = asset['_name']
            # Start by translating context of the asset itself
            for ctx in asset['_context']:
                mappedCtx = get_mapped_value(ctx['_type'], 'name',
                                             ctx['_name'], mappings)
                ctxName, ctxMap = igcrest.getPropertyMap(ctx['_type'])
                if ctxName == 'Host (Engine)':
                    ctxName = 'Host'
                if ctxName not in aHeader:
                    aHeader.append(ctxName)
                aRow[ctxName] = mappedCtx
            result['asset_count'] += 1

            for reln_property in asset:
                if not reln_property.startswith('_'):
                    aRelations = []
                    relnName = propertyMap[reln_property]
                    if relnName not in aHeader:
                        aHeader.append(relnName)
                    for reln in asset[reln_property]:
                        # Translate the context of each related asset
                        sRelation = '"'
                        for relnCtx in reln['_context']:
                            mappedRelnCtx = get_mapped_value(
                                relnCtx['_type'], 'name', relnCtx['_name'],
                                mappings)
                            sRelation += mappedRelnCtx + ">>"
                            # relnCtxName, relnCtxMap = igcrest.getPropertyMap(relnCtx['_type'])
                        sRelation += reln['_name'] + '"'
                        aRelations.append(sRelation)
                    if len(aRelations) > 0:
                        aRow[relnName] = "[" + ";".join(aRelations) + "]"
                    else:
                        aRow[relnName] = ""
            if len(aRow) > 0:
                aRows.append(aRow)
            else:
                result['untranslated_assets'].append(asset)

    # Close the IGC REST API session
    igcrest.closeSession()

    # Write temporary file with the JSON output,
    # and then move to specified dest location
    try:
        tmpfd, tmpfile = tempfile.mkstemp()
        f = os.fdopen(tmpfd, 'wb')
        f.write("+++ " + asset_name + " - begin +++\n")
        writer = csv.DictWriter(f, fieldnames=aHeader)
        writer.writeheader()
        for row in aRows:
            writer.writerow(row)
        f.write("+++ " + asset_name + " - end +++\n\n")
        f.close()
    except IOError:
        module.fail_json(
            msg=
            'Unable to create temporary file to output transformed relationships',
            **result)

    # Checksumming to identify change...
    checksum_src = module.sha1(tmpfile)
    checksum_dest = None
    b_dest = to_bytes(dest, errors='surrogate_or_strict')
    if os.access(b_dest, os.R_OK):
        checksum_dest = module.sha1(dest)

    # If the file does not already exist and/or checksums are different,
    # move the new file over the old one and mark it as changed; otherwise
    # leave the original file (delete the tmpfile) and that there was no change
    if checksum_src != checksum_dest:
        module.atomic_move(tmpfile,
                           to_native(os.path.realpath(b_dest),
                                     errors='surrogate_or_strict'),
                           unsafe_writes=module.params['unsafe_writes'])
        result['changed'] = True
    else:
        os.unlink(tmpfile)

    module.exit_json(**result)
def main():

    module_args = dict(host=dict(type='str', required=True),
                       port=dict(type='str', required=True),
                       user=dict(type='str', required=True),
                       password=dict(type='str', required=True, no_log=True),
                       asset_type=dict(type='str', required=True),
                       from_state=dict(type='str',
                                       required=False,
                                       default='ALL'),
                       action=dict(type='str', required=True),
                       comment=dict(type='str', required=False, default=''),
                       conditions=dict(type='list', required=False,
                                       default=[]),
                       condition_join=dict(type='str',
                                           required=False,
                                           default='AND'),
                       compared_to_published=dict(type='str',
                                                  required=False,
                                                  default=''),
                       cert=dict(type='path', required=False),
                       batch=dict(type='int', required=False, default=100))

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    result = dict(changed=False,
                  queries=[],
                  asset_count=0,
                  assets=[],
                  workflow_actions=[],
                  workflow_failed=[],
                  workflow_enabled=False)

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # Setup REST API connectivity via module_utils.igc_rest class
    igcrest = RestIGC(module,
                      result,
                      username=module.params['user'],
                      password=module.params['password'],
                      host=module.params['host'],
                      port=module.params['port'],
                      cert=module.params['cert'])

    conditions = module.params['conditions']
    asset_type = module.params['asset_type']
    from_state = module.params['from_state']
    action = module.params['action']
    comment = module.params['comment']
    compared_to_published = module.params['compared_to_published']
    batch = module.params['batch']

    # First check whether workflow is even enabled
    # (if not, we can return immediately as this module becomes a NOOP)
    if igcrest.isWorkflowEnabled():
        result['workflow_enabled'] = True
    else:
        igcrest.closeSession()
        module.exit_json(**result)

    incomparable_keys = [
        'history', 'development_log', 'modified_by', 'modified_on',
        'created_by', 'created_on', '_url'
    ]

    # Basic query
    reqJSON = {
        "pageSize": batch,
        "workflowMode": "draft",
        "properties": ['name', 'workflow_current_state'],
        "types": [asset_type],
        "where": {
            "conditions": [],
            "operator": "and"
        }
    }

    if from_state == 'ALL':
        reqJSON['where']['conditions'].append({
            "property": "workflow_current_state",
            "operator": "isNull",
            "negated": True
        })
    else:
        reqJSON['where']['conditions'].append({
            "property": "workflow_current_state",
            "operator": "=",
            "value": from_state.upper()
        })

    # If conditions have been provided, nest them within the outer
    # workflow state condition
    if len(conditions) > 0:
        reqJSON['where']['conditions'].append({
            "conditions":
            conditions,
            "operator":
            module.params['condition_join'].lower()
        })

    jsonResults = igcrest.search(reqJSON)

    # Ensure search worked before proceeding
    if jsonResults == '':
        module.fail_json(msg='IGC query failed', **result)

    result['asset_count'] = len(jsonResults)
    result['assets'] = jsonResults

    assets_by_state = {"DRAFT": [], "WAITING_APPROVAL": [], "APPROVED": []}

    new_assets = []
    same_assets = []
    changed_assets = []

    for asset in jsonResults:
        # For some reason 'workflow_current_state' is an array
        # (but should only ever have one entry, so always take first?)
        current_state = asset['workflow_current_state'][0]
        assets_by_state[current_state].append(asset['_id'])
        if compared_to_published != '':
            calculateAssetDelta(igcrest, module, result, incomparable_keys,
                                asset, batch, new_assets, same_assets,
                                changed_assets)

    # Easy case: we're only moving from a particular state
    if from_state != 'ALL':
        assets_to_move = assets_by_state[from_state]
        action_to_take = getNextAction(action, from_state)
        assets_to_act = getAssetsToActUpon(assets_to_move,
                                           compared_to_published, new_assets,
                                           same_assets, changed_assets)
        moveToNextState(igcrest, result, assets_to_act, from_state,
                        action_to_take, action, comment)
    # More complicated case: we want to move from all states
    else:
        # Need to iterate state-by-state...
        draft_assets = assets_by_state['DRAFT']
        if len(draft_assets) > 0:
            action_to_take = getNextAction(action, 'DRAFT')
            assets_to_act = getAssetsToActUpon(draft_assets,
                                               compared_to_published,
                                               new_assets, same_assets,
                                               changed_assets)
            moveToNextState(igcrest, result, assets_to_act, 'DRAFT',
                            action_to_take, action, comment)
        waiting_assets = assets_by_state['WAITING_APPROVAL']
        if len(waiting_assets) > 0:
            action_to_take = getNextAction(action, 'WAITING_APPROVAL')
            assets_to_act = getAssetsToActUpon(waiting_assets,
                                               compared_to_published,
                                               new_assets, same_assets,
                                               changed_assets)
            moveToNextState(igcrest, result, assets_to_act, 'WAITING_APPROVAL',
                            action_to_take, action, comment)
        approved_assets = assets_by_state['APPROVED']
        if len(approved_assets) > 0:
            action_to_take = getNextAction(action, 'APPROVED')
            assets_to_act = getAssetsToActUpon(approved_assets,
                                               compared_to_published,
                                               new_assets, same_assets,
                                               changed_assets)
            moveToNextState(igcrest, result, assets_to_act, 'APPROVED',
                            action_to_take, action, comment)

    # Close the IGC REST API session
    igcrest.closeSession()

    module.exit_json(**result)
def main():

    module_args = dict(
        host=dict(type='str', required=True),
        port=dict(type='str', required=True),
        user=dict(type='str', required=True),
        password=dict(type='str', required=True, no_log=True),
        asset_type=dict(type='str', required=True),
        relationships=dict(type='list', required=True),
        dest=dict(type='path', required=True),
        from_time=dict(type='int', required=False, default=-1),
        to_time=dict(type='int', required=False),
        conditions=dict(type='list', required=False, default=[]),
        limit=dict(type='list', required=False, default=[]),
        dev_glossary=dict(type='bool', required=False, default=False),
        batch=dict(type='int', required=False, default=100),
        cert=dict(type='path', required=False),
        unsafe_writes=dict(type='bool', required=False, default=False)
    )

    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    result = dict(
        changed=False,
        queries=[],
        asset_count=0,
        relationship_count=0
    )

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        return result

    # Setup REST API connectivity via module_utils.igc_rest class
    igcrest = RestIGC(
        module,
        result,
        username=module.params['user'],
        password=module.params['password'],
        host=module.params['host'],
        port=module.params['port'],
        cert=module.params['cert']
    )

    relnprops = module.params['relationships']
    limit = module.params['limit']
    batch = module.params['batch']
    dev_glossary = module.params['dev_glossary']
    asset_type = module.params['asset_type']
    wfl_enabled = igcrest.isWorkflowEnabled()

    # Basic query
    reqJSON = {
        "properties": relnprops,
        "types": [asset_type],
        "pageSize": batch
    }

    # Extend basic query with any optional conditions
    if len(module.params['conditions']) > 0:
        reqJSON['where'] = {
            "conditions": module.params['conditions'],
            "operator": "and"
        }
    if module.params['from_time'] != -1:
        if 'where' not in reqJSON:
            reqJSON['where'] = {
                "conditions": [],
                "operator": "and"
            }
        reqJSON['where']['conditions'].append({
            "min": module.params['from_time'],
            "max": module.params['to_time'],
            "property": "modified_on",
            "operator": "between"
        })
    if dev_glossary and wfl_enabled and igcrest.isWorkflowType(asset_type):
        reqJSON['workflowMode'] = "draft"

    # Execute the search
    jsonResults = igcrest.search(reqJSON)

    # Ensure search worked before proceeding
    if jsonResults == '':
        module.fail_json(msg='Initial IGC REST API search failed', **result)

    result['asset_count'] = len(jsonResults)

    for item in jsonResults:
        minifyItem(item)
        for itmCtx in item['_context']:
            minifyItem(itmCtx)
        for relnprop in relnprops:
            # Not all relationships are lists, some are singular; but we will wrap for ease of processing below
            bSingleRelation = False
            if 'items' in item[relnprop]:
                item[relnprop] = igcrest.getAllPages(item[relnprop]['items'],
                                                     item[relnprop]['paging'],
                                                     (dev_glossary and wfl_enabled))
            elif '_id' in item[relnprop]:
                item[relnprop] = [item[relnprop]]
                bSingleRelation = True
            else:
                item[relnprop] = []
                bSingleRelation = True
            aRemoveIndices = []
            iIdx = 0
            for relation in item[relnprop]:
                # Limit included relationships to only those types of interest
                if (len(limit) > 0) and not (relation['_type'] in limit):
                    aRemoveIndices.append(iIdx)
                else:
                    relnCtx = igcrest.getContextForItem(relation, (dev_glossary and wfl_enabled), batch=batch)
                    if relnCtx == '':
                        module.fail_json(msg='Unable to retieve context for search result', **result)
                    else:
                        minifyItem(relation)
                        for ctx in relnCtx:
                            minifyItem(ctx)
                        result['relationship_count'] += 1
                        relation['_context'] = relnCtx
                iIdx += 1
            iIdx = 0
            for removal in aRemoveIndices:
                del item[relnprop][removal - iIdx]
                iIdx += 1
            # Unbundle single relationships back out of their arrays
            if bSingleRelation:
                if len(item[relnprop]) > 0:
                    item[relnprop] = item[relnprop][0]
                else:
                    item[relnprop] = {}

    # Close the IGC REST API session
    igcrest.closeSession()

    # Write temporary file with the JSON output,
    # and then move to specified dest location
    try:
        tmpfd, tmpfile = tempfile.mkstemp()
        f = os.fdopen(tmpfd, 'wb')
        json.dump(jsonResults, f)
        f.close()
    except IOError:
        module.fail_json(msg='Unable to create temporary file to output relationship results', **result)

    # Checksumming to identify change...
    checksum_src = module.sha1(tmpfile)
    checksum_dest = None
    dest = module.params['dest']
    b_dest = to_bytes(dest, errors='surrogate_or_strict')
    if os.access(b_dest, os.R_OK):
        checksum_dest = module.sha1(dest)

    # If the file does not already exist and/or checksums are different,
    # move the new file over the old one and mark it as changed; otherwise
    # leave the original file (delete the tmpfile) and that there was no change
    if checksum_src != checksum_dest:
        module.atomic_move(tmpfile,
                           to_native(os.path.realpath(b_dest), errors='surrogate_or_strict'),
                           unsafe_writes=module.params['unsafe_writes'])
        result['changed'] = True
    else:
        os.unlink(tmpfile)

    module.exit_json(**result)