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)
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)
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)