def run_module(): # define available arguments/parameters a user can pass to the module module_args = dict( uuid=dict(type='str', required=True), state=dict(type='str', required=True, choices=['absent', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC) ) # Create the return object result = { 'object': None, 'changed': False } module = AnsibleModule( argument_spec=module_args ) tet_module = TetrationApiModule(module) response = None route = f"{TETRATION_API_SENSORS}/{module.params['uuid']}" if module.params['state'] == 'query': response = tet_module.run_method('GET', route) elif module.params['state'] == 'absent': response = tet_module.run_method('DELETE', route) result['changed'] is True result['object'] = response module.exit_json(**result)
def run_module(): # define available arguments/parameters a user can pass to the module module_args = dict(app_id=dict(type='str', required=False), app_name=dict(type='str', required=False), is_primary=dict(type='bool', required=False), is_enforcing=dict(type='bool', required=False), return_details=dict(type='bool', required=False, default=False), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) result = {'changed': False, 'object': {}, 'objects': [], 'items_found': 0} module = AnsibleModule(argument_spec=module_args, mutually_exclusive=[ ['app_id', 'app_name'], ['app_id', 'is_primary'], ['app_id', 'is_enforcing'], ]) tet_module = TetrationApiModule(module) if module.params['app_id']: route = f"{TETRATION_API_APPLICATIONS}/{module.params['app_id']}" if module.params['return_details']: route = f"{route}/details" app_response = tet_module.run_method('GET', route) result['object'] = app_response if app_response: result['items_found'] = 1 else: all_apps_response = tet_module.run_method('GET', TETRATION_API_APPLICATIONS) for app in all_apps_response: if module.params['app_name'] and module.params[ 'app_name'] not in app['name']: continue if module.params['is_primary'] is not None and module.params[ 'is_primary'] != app['primary']: continue if module.params['is_enforcing'] is not None and module.params[ 'is_enforcing'] != app['enforement_enabled']: continue if module.params['return_details']: route = f"{TETRATION_API_APPLICATIONS}/{app['id']}/details" details = tet_module.run_method('GET', route) result['objects'].append(details) else: result['objects'].append(app) result['items_found'] = len(result['objects']) if result['objects']: result['object'] = result['objects'][0] module.exit_json(**result)
def run_module(): # define available arguments/parameters a user can pass to the module module_args = dict(fully_qualified_name=dict(type='str', required=False), scope_id=dict(type='str', required=False), short_name=dict(type='str', required=False), only_dirty=dict(type='bool', required=False, default=False), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) result = {'changed': False, 'object': {}, 'objects': [], 'qty_found': 0} module = AnsibleModule( argument_spec=module_args, required_one_of=[ ['fully_qualified_name', 'scope_id', 'short_name'], ], mutually_exclusive=[ ['fully_qualified_name', 'scope_id', 'short_name'], ]) tet_module = TetrationApiModule(module) all_scopes_response = tet_module.run_method('GET', TETRATION_API_SCOPES) if module.params['fully_qualified_name']: to_find = module.params['fully_qualified_name'] found_scopes = [s for s in all_scopes_response if s['name'] == to_find] if module.params['only_dirty']: found_scopes = [s for s in found_scopes if s['dirty'] is True] result['objects'] = found_scopes result['qty_found'] = len(found_scopes) if found_scopes: result['object'] = found_scopes[0] elif module.params['scope_id']: to_find = module.params['scope_id'] found_scopes = [s for s in all_scopes_response if s['id'] == to_find] if module.params['only_dirty']: found_scopes = [s for s in found_scopes if s['dirty'] is True] result['objects'] = found_scopes result['qty_found'] = len(found_scopes) if found_scopes: result['object'] = found_scopes[0] elif module.params['short_name']: to_find = module.params['short_name'] found_scopes = [ s for s in all_scopes_response if to_find in s['short_name'] ] if module.params['only_dirty']: found_scopes = [s for s in found_scopes if s['dirty'] is True] result['objects'] = found_scopes result['qty_found'] = len(found_scopes) if found_scopes: result['object'] = found_scopes[0] module.exit_json(**result)
def main(): module_args = dict( app_id=dict(type='str', required=True), version=dict(type='str', required=True), policy_action=dict(type='str', required=False, choices=['ALLOW', 'DENY']), state=dict(required=True, choices=['update', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC) ) module = AnsibleModule( argument_spec=module_args, required_if=[ ['state', 'update', ['policy_action']] ] ) tet_module = TetrationApiModule(module) # These are all elements we put in our return JSON object for clarity result = { 'changed': False, 'object': None, } route = f"{TETRATION_API_APPLICATIONS}/{module.params['app_id']}/catch_all" get_payload = { 'version': module.params['version'], } existing_policy = tet_module.run_method('GET', route, req_payload=get_payload) # Valid inputs are the version number or the version number prefixed with the letter `v` # this next step creates all possible versions for comparision possible_versions = [module.params['version'], f"v{module.params['version']}"] if existing_policy['version'] not in possible_versions: module.fail_json(msg="The application id and policy entered do not exist") if module.params['state'] == 'update': payload = { 'version': module.params['version'], 'policy_action': module.params['policy_action'] } if existing_policy['action'] != module.params['policy_action']: result['changed'] = True api_results = tet_module.run_method('PUT', route, req_payload=payload) result['object'] = api_results else: result['object'] = existing_policy # Return result module.exit_json(**result)
def main(): ''' Main entry point for module execution ''' # Module specific spec module_args = dict(root_scope_name=dict(type='str', required=True), ip_address=dict(type='str', required=False), ip_subnet=dict(type='str', required=False), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) module = AnsibleModule(argument_spec=module_args, required_one_of=[['ip_address', 'ip_subnet']]) # These are all elements we put in our return JSON object for clarity result = { "object": None, "changed": False, } # Verify a valid IP address was passed in ip_object = "" if module.params['ip_address']: try: ip_object = str(ip_address(module.params['ip_address'])) except ValueError: error_message = f"Invalid IPv4 or IPv6 Address entered. Value entered: {module.params['ip_address']}" module.fail_json(msg=error_message) # Verify a valid IP subnet was passed in if module.params['ip_subnet']: try: ip_object = str(ip_network(module.params['ip_subnet'])) except ValueError: error_message = f"Invalid IPv4 or IPv6 subnet entered. Value entered: {module.params['ip_subnet']}" module.fail_json(msg=error_message) tet_module = TetrationApiModule(module) route = f"{TETRATION_API_INVENTORY_TAG}/{module.params['root_scope_name']}/search" params = {'ip': ip_object} result['object'] = tet_module.run_method('GET', route, params=params) return module.exit_json(**result)
def main(): ''' Main entry point for module execution ''' # Module specific spec module_args = dict(root_scope_name=dict(type='str', required=True), attribute=dict(type='str', required=False), state=dict(type='str', required=True, choices=['absent', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) module = AnsibleModule(argument_spec=module_args, required_if=[['state', 'absent', ['attribute']]]) # These are all elements we put in our return JSON object for clarity tet_module = TetrationApiModule(module) result = { "object": None, "changed": False, } route = f"{TETRATION_COLUMN_NAMES}/{module.params['root_scope_name']}" current_headers = tet_module.run_method('GET', route) # --------------------------------- # STATE == 'query' # --------------------------------- if module.params['state'] == 'query': result['object'] = current_headers # --------------------------------- # STATE == 'absent' # --------------------------------- elif module.params['state'] == 'absent': if module.params['attribute'] in current_headers: delete_route = f"{route}/{module.params['attribute']}" result['object'] = tet_module.run_method('DELETE', delete_route) result['changed'] = True else: result['object'] = current_headers module.exit_json(**result)
def run_module(): # define available arguments/parameters a user can pass to the module module_args = dict(root_app_scope_id=dict(type='str', required=True), sync=dict(type='bool', required=False, default=False), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) result = dict( changed=False, object={}, ) module = AnsibleModule(argument_spec=module_args, supports_check_mode=False) tet_module = TetrationApiModule(module) all_scopes_response = tet_module.run_method('GET', TETRATION_API_SCOPES) all_scopes_lookup = {s['id']: s['short_name'] for s in all_scopes_response} if module.params['root_app_scope_id'] and module.params[ 'root_app_scope_id'] not in all_scopes_lookup.keys(): error_message = "`root_app_scope_id` passed into the module does not exist." module.fail_json(msg=error_message, searched_scope=module.params['root_app_scope_id']) req_payload = { 'root_app_scope_id': module.params['root_app_scope_id'], 'sync': module.params['sync'] } route = f"{TETRATION_API_SCOPES}/commit_dirty" response = tet_module.run_method('POST', route, req_payload=req_payload) result['object'] = response result['changed'] = True module.exit_json(**result)
def main(): # Main entry point for module execution # Module specific spec module_args = dict(profile_name=dict(type='str', required=False), profile_id=dict(type='str', required=False), filter_id=dict(type='str', required=False), filter_name=dict(type='str', required=False), state=dict(default='present', choices=['present', 'absent', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) module = AnsibleModule(argument_spec=module_args, required_one_of=[ ['profile_name', 'profile_id'], ['filter_id', 'filter_name'], ], mutually_exclusive=[ ['profile_name', 'profile_id'], ['filter_id', 'filter_name'], ]) # These are all elements we put in our return JSON object for clarity tet_module = TetrationApiModule(module) result = { 'changed': False, 'object': {}, } # ========================================================================= # Get current state of the object config_profiles = tet_module.run_method( 'GET', TETRATION_API_AGENT_CONFIG_PROFILES) config_profiles_and_ids = {c['name']: c['id'] for c in config_profiles} profile_id = None if module.params['profile_id'] in config_profiles_and_ids.values(): profile_id = module.params['profile_id'] elif module.params['profile_name'] in config_profiles_and_ids.keys(): profile_name = module.params['profile_name'] profile_id = config_profiles_and_ids[profile_name] if not profile_id: if module.params['profile_id']: module.fail_json( msg= f"Unable to find existing profile id: {module.params['profile_id']}" ) else: module.fail_json( msg= f"Unable to find existing profile named: {module.params['profile_name']}" ) # Get the existing API Scopes and Inventory Filters to verify the filter parameters passed in existing_app_scopes = tet_module.run_method('GET', TETRATION_API_SCOPES) # Build a lookup object for the app scopes app_scope_name_to_scope_id = { s['name']: s['id'] for s in existing_app_scopes } # Build the inventory filter dict but check for duplicate entries and report them if found existing_inventory_filters = tet_module.run_method( 'GET', TETRATION_API_INVENTORY_FILTER) inv_filter_name_to_filter_id = {} duplicate_values = [] for i in existing_inventory_filters: name = i['name'] inv_id = i['id'] if inv_id is None: # If the API returns an ID of None, this code won't work module.fail_json(msg='An ID returned had a value of `None`') if inv_filter_name_to_filter_id.get( name) is None: # Does the ID exist in the new dict inv_filter_name_to_filter_id[name] = inv_id else: duplicate_values.append(name) if duplicate_values: duplicate_values = set(duplicate_values) module.fail_json(msg=( 'The Tetration Server has multiple inventory filters with the same name. ' f'This is not supported with this module. Duplicate names are: {duplicate_values}' )) filter_id = None if module.params['filter_id']: # Verify the ID is a valid api scope or an inventory filter if module.params['filter_id'] in app_scope_name_to_scope_id.values(): filter_id = module.params['filter_id'] elif module.params['filter_id'] in inv_filter_name_to_filter_id.values( ): filter_id = module.params['filter_id'] elif module.params['filter_name']: # Verify the ID is a valid api scope or an inventory filter filter_name = module.params['filter_name'] if app_scope_name_to_scope_id.get(filter_name): filter_id = app_scope_name_to_scope_id[filter_name] elif inv_filter_name_to_filter_id.get(filter_name): filter_id = inv_filter_name_to_filter_id[filter_name] if filter_id is None: module.fail_json(msg='The provided filter name or id is invalid') # Get the current config intents existing_intents = tet_module.run_method( 'GET', TETRATION_API_AGENT_CONFIG_INTENTS) intent_to_find = { 'inventory_config_profile_id': profile_id, 'inventory_filter_id': filter_id } existing_intent = None for intent in existing_intents: if tet_module.is_subset(intent_to_find, intent): existing_intent = intent # --------------------------------- # STATE == 'present' # --------------------------------- if module.params['state'] == 'present': new_object = { 'inventory_config_profile_id': profile_id, 'inventory_filter_id': filter_id } if not existing_intent: result['object'] = tet_module.run_method( 'POST', TETRATION_API_AGENT_CONFIG_INTENTS, req_payload=new_object) result['changed'] = True else: result['object'] = existing_intent # --------------------------------- # STATE == 'absent' # --------------------------------- elif module.params['state'] in 'absent': if existing_intent: route = f"{TETRATION_API_AGENT_CONFIG_INTENTS}/{existing_intent['id']}" result['object'] = tet_module.run_method('DELETE', route) result['changed'] = True # --------------------------------- # STATE == 'query' # --------------------------------- else: if existing_intent: result['object'] = existing_intent module.exit_json(**result)
def main(): module_args = dict(app_name=dict(type='str', required=False), app_id=dict(type='str', required=False), app_scope_id=dict(type='str', required=False), app_scope_name=dict(type='str', required=False), description=dict(type='str', required=False), alternate_query_mode=dict(type='bool', required=False, default=False), strict_validation=dict(type='bool', required=False, default=False), primary=dict(type='bool', required=False), state=dict(required=True, choices=['present', 'absent']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) module = AnsibleModule( argument_spec=module_args, mutually_exclusive=[['app_scope_name', 'app_scope_id']], required_one_of=[ ['app_name', 'app_id'], ], ) tet_module = TetrationApiModule(module) # These are all elements we put in our return JSON object for clarity result = { 'changed': False, 'object': None, } # ========================================================================= # Verify passed in data is accurate. existing_app_scope = {} if module.params['app_scope_id']: app_scope_route = f"{TETRATION_API_SCOPES}/{module.params['app_scope_id']}" existing_app_scope = tet_module.run_method('GET', app_scope_route) if not existing_app_scope: module.fail_json( msg= f"Unable to find existing app with the id of: {module.params['app_scope_id']}" ) elif module.params['app_scope_name']: all_scopes = tet_module.run_method('GET', TETRATION_API_SCOPES) found_app_scopes = [ scope for scope in all_scopes if scope['name'] == module.params['app_scope_name'] ] if len(found_app_scopes) == 0: module.fail_json(msg=( "There were no app scopes that matched the name entered. " f"Searched for: {module.params['app_scope_name']}")) elif len(found_app_scopes) > 1: module.fail_json(msg=( "There were too many app scopes that matched the name entered. " f"Searched for: {module.params['app_scope_name']}")) existing_app_scope = found_app_scopes[0] existing_app = {} if module.params['app_id']: app_route = f"{TETRATION_API_APPLICATIONS}/{module.params['app_id']}" existing_app = tet_module.run_method('GET', app_route) if not existing_app: module.fail_json( msg= f"The App ID entered is not in the system. Searched for: {module.params['app_id']}" ) elif module.params['app_name']: # If we have an app_id, and it's valid, we don't care about searching for the app_id by name # If we don't have an app_id, then we need to find an app, but it's ok if one doesn't exist # because we'll then make it, or we could be verifying it's absent apps = tet_module.run_method('GET', TETRATION_API_APPLICATIONS) found_apps = [ found for found in apps if found['name'] == module.params['app_name'] ] if len(found_apps) > 1: module.fail_json( msg= f"There were too many apps that matched the name entered. Searched for: {module.params['app_name']}" ) elif len(found_apps) == 1: existing_app = found_apps[0] app_route = "" if existing_app: app_route = f"{TETRATION_API_APPLICATIONS}/{existing_app['id']}" # ========================================================================= # Now enforce the desired state (present, absent) # --------------------------------- # STATE == 'present' # --------------------------------- if module.params['state'] == 'present': # if the object does not exist at all, create it but verify we have all needed data first if not existing_app and not existing_app_scope: module.fail_json(msg=( "The application does not exist. " "Must provide a Scope ID or Scope Name to create a new scope." )) if not existing_app and module.params['primary'] is None: module.fail_json(msg=( "The application does not exist. " "Must provide info on if the scope is primary or not when creating a scope." )) if existing_app: updated_app = { 'name': module.params['app_name'], 'description': module.params['description'], 'primary': module.params['primary'] } if not module.params['app_name']: updated_app.pop('name') if module.params['description'] is None: updated_app.pop('description') if module.params['primary'] is None: updated_app.pop('primary') is_subset = tet_module.is_subset(updated_app, existing_app) if not is_subset: result['object'] = tet_module.run_method( 'PUT', app_route, req_payload=updated_app) result['changed'] = True else: result['object'] = existing_app else: new_app = { 'app_scope_id': existing_app_scope['id'], 'name': module.params['app_name'], 'description': module.params['description'], 'alternate_query_mode': module.params['alternate_query_mode'], 'strict_validation': module.params['strict_validation'], 'primary': module.params['primary'] } result['object'] = tet_module.run_method( "POST", TETRATION_API_APPLICATIONS, req_payload=new_app) result['changed'] = True # --------------------------------- # STATE == 'absent' # --------------------------------- elif module.params['state'] == 'absent': if existing_app: if existing_app['enforcement_enabled']: module.fail_json( msg= 'Cannot delete workspace with enforcement enabled. Disable enforcement before deleting' ) elif existing_app['primary']: module.fail_json( msg= 'Cannot delete primary application. Try making application secondary before deleting' ) result['object'] = tet_module.run_method('DELETE', app_route) result['changed'] = True # Return result module.exit_json(**result)
def run_module(): module_args = dict( name=dict(type='str', required=False), description=dict(type='str', required=False), app_scope_id=dict(type='str', required=False), id=dict(type='str', required=False), capability_app_scope_id=dict(type='str', required=False), capability_ability=dict(type='str', required=False, choices=TETRATION_API_APP_SCOPE_CAPABILITIES), state=dict(type='str', required=True, choices=['present', 'absent', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC) ) # Create the objects that will be returned result = { "object": None, "changed": False } result_obj = dict( app_scope_id=None, capabilities=[], description=None, id=None, name=None ) # Creating the Ansible Module module = AnsibleModule( argument_spec=module_args, supports_check_mode=False, required_one_of=[ ['id', 'name'] ], required_together=[ ['capability_app_scope_id', 'capability_ability'] ], required_by={ 'name': ['app_scope_id'] } ) # grant capablities (present) # role_id, capability app scope id, ability tet_module = TetrationApiModule(module) # Create an App Scope Name to ID Lookup Table all_app_scopes_response = tet_module.run_method('GET', TETRATION_API_SCOPES) all_app_scopes_lookup = {r['name']: r['id'] for r in all_app_scopes_response} # Create a Role Name - App Scope ID to Role ID Lookup Table # A role is uniquely identified by its name and app scope # Create a dict of tuples, key to look up an ID all_roles_response = tet_module.run_method('GET', TETRATION_API_ROLE) all_roles_lookup_by_name_app_id = {(r['name'], r['app_scope_id']): r['id'] for r in all_roles_response} # Role and App Scope Validation # Done here so it does not have to be done elsewhere in the module invalid_parameters = {} if module.params['app_scope_id']: scope_id = module.params['app_scope_id'] if scope_id not in all_app_scopes_lookup.values(): invalid_parameters['app_scope_id'] = scope_id if module.params['id']: role_id = module.params['id'] if role_id not in all_roles_lookup_by_name_app_id.values(): invalid_parameters['id'] = role_id if module.params['capability_app_scope_id']: capability_app_id = module.params['capability_app_scope_id'] if capability_app_id not in all_app_scopes_lookup.values(): invalid_parameters['capability_app_scope_id'] = capability_app_id if invalid_parameters: error_message = "Check the `invalid parameters` object for the invalid parameters" module.fail_json(msg=error_message, invalid_parameters=invalid_parameters) # One of these is the unique ID for the role role_id = module.params['id'] name_scope_id = module.params['name'], module.params['app_scope_id'] if module.params['state'] == 'present': if not role_id and name_scope_id not in all_roles_lookup_by_name_app_id.keys(): # Role does not exist, lets add it req_payload = { 'name': module.params['name'], 'description': module.params['description'], 'app_scope_id': module.params['app_scope_id'] } response = tet_module.run_method('POST', TETRATION_API_ROLE, req_payload=req_payload) all_roles_lookup_by_name_app_id[name_scope_id] = response['id'] result_obj = response result['changed'] = True else: # The Role exists, lets update it if role_id: route = f'{TETRATION_API_ROLE}/{role_id}' else: looked_up_role_id = all_roles_lookup_by_name_app_id[name_scope_id] route = f'{TETRATION_API_ROLE}/{looked_up_role_id}' response = tet_module.run_method('GET', route) req_payload = { 'name': module.params['name'], 'description': module.params['description'], } if module.params['name'] is None or module.params['name'] == response['name']: req_payload.pop('name', None) if module.params['name'] is None or module.params['description'] == response['description']: req_payload.pop('description') if req_payload: updated_response = tet_module.run_method('PUT', route, req_payload=req_payload) result['changed'] = True result_obj = updated_response else: result_obj = response if module.params['capability_app_scope_id']: # Check to see if any capabilities can be added if role_id: route = f'{TETRATION_API_ROLE}/{role_id}' else: looked_up_role_id = all_roles_lookup_by_name_app_id[name_scope_id] route = f'{TETRATION_API_ROLE}/{looked_up_role_id}' response = tet_module.run_method('GET', route) desired_to_add = set([(module.params['capability_app_scope_id'], module.params['capability_ability'])]) current_capabilities = [] # Create a set of tuples to determine if I need to the capability for c in response['capabilities']: curr_cap = c['app_scope_id'], c['ability'] current_capabilities.append(curr_cap) current_capabilities = set(current_capabilities) to_add = desired_to_add.difference(current_capabilities) response['cap'] = str(to_add) if to_add: req_payload = { 'app_scope_id': module.params['capability_app_scope_id'], 'ability': module.params['capability_ability'] } capability_route = f'{route}/capabilities' response = tet_module.run_method('POST', capability_route, req_payload=req_payload) result_obj['capabilities'].append(response) result['changed'] = True if module.params['state'] == 'absent': if module.params['id'] and module.params['name']: error_message = ( 'Cannot search for 2 parameters at the same time, specify either `name` or `id`' ) module.fail_json(msg=error_message) if not role_id and name_scope_id not in all_roles_lookup_by_name_app_id.keys(): module.exit_json(msg='That role does not exist in the system.', object={'success': True}) if role_id: route = f'{TETRATION_API_ROLE}/{role_id}' else: looked_up_role_id = all_roles_lookup_by_name_app_id[name_scope_id] route = f'{TETRATION_API_ROLE}/{looked_up_role_id}' role_response = tet_module.run_method('DELETE', route) result_obj = role_response result['changed'] = True if module.params['state'] == 'query': # Confirm the user didn't try and search for 2 different values if module.params['id'] and module.params['name']: error_message = ( 'Cannot search for 2 parameters at the same time, specify either `name` or `id`' ) module.fail_json(msg=error_message) # Confirm the role exists if searching by name and App Scope ID if not role_id and name_scope_id not in all_roles_lookup_by_name_app_id.keys(): error_message = ( 'There is no role that matches the value being searched for' ) module.fail_json(msg=error_message) if role_id: route = f'{TETRATION_API_ROLE}/{role_id}' else: looked_up_role_id = all_roles_lookup_by_name_app_id[name_scope_id] route = f'{TETRATION_API_ROLE}/{looked_up_role_id}' role_response = tet_module.run_method('GET', route) result_obj = role_response result['object'] = result_obj module.exit_json(**result)
def run_module(): # define available arguments/parameters a user can pass to the module module_args = dict(host_name_contains=dict(type='str'), host_name_is_exactly=dict(type='str'), interface_ip_is_exactly=dict(type='str'), interface_ip_in_network=dict(type='str'), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) # Create the return object result = {'object': [], 'changed': False, 'items_found': 0} module = AnsibleModule(argument_spec=module_args) tet_module = TetrationApiModule(module) # Verify a valid IP address was passed in if module.params['interface_ip_is_exactly']: try: ip_to_validate = ipaddress.ip_address( module.params['interface_ip_is_exactly']) except ValueError: error_message = f"Invalid IPv4 or IPv6 Address entered. Value entered: {module.params['interface_ip_is_exactly']}" module.fail_json(msg=error_message) # Verify a valid IP network was passed in if module.params['interface_ip_in_network']: try: network_to_validate = ipaddress.ip_network( module.params['interface_ip_in_network'], strict=False) result['net_to_validate'] = str(network_to_validate) except ValueError: error_message = f"Invalid IPv4 or IPv6 Network entered. Value entered: {module.params['interface_ip_in_network']}" module.fail_json(msg=error_message) response = tet_module.run_method_paginated('GET', TETRATION_API_SENSORS) for s in response: if 'deleted_at' not in s.keys(): to_append = s if module.params['host_name_contains'] and module.params[ 'host_name_contains'] not in s['host_name']: to_append = None continue if module.params['host_name_is_exactly'] and module.params[ 'host_name_is_exactly'] != s['host_name']: to_append = None continue if module.params['interface_ip_is_exactly']: ip_in_interface = False for i in s['interfaces']: try: iface_addr = ipaddress.ip_address(i['ip']) except ValueError: iface_addr = None if iface_addr == ip_to_validate: ip_in_interface = True if not ip_in_interface: to_append = None continue if module.params['interface_ip_in_network']: ip_in_network = False for i in s['interfaces']: try: iface_addr = ipaddress.ip_address(i['ip']) except ValueError: iface_addr = None if iface_addr in network_to_validate: ip_in_network = True # Once I find a match, no need to keep searching break if not ip_in_network: to_append = None continue if to_append is not None: result['object'].append(to_append) result['items_found'] = len(result['object']) module.exit_json(**result)
def main(): ''' Main entry point for module execution ''' # # Module specific spec module_args = dict(name=dict(type='str', required=False), id=dict(type='str', required=False), root_app_scope_id=dict(type='str', required=False), root_app_scope_name=dict(type='str', required=False), allow_broadcast=dict(type='bool', required=False), allow_link_local=dict(type='bool', required=False), allow_multicast=dict(type='bool', required=False), auto_upgrade_opt_out=dict(type='bool', required=False), cpu_quota_mode=dict(type='int', required=False, choices=[0, 1, 2]), cpu_quota_pct=dict(type='int', required=False), cpu_quota_us=dict(type='int', required=False), data_plane_disabled=dict(type='bool', required=False), enable_dns=dict(type='bool', required=False), enable_forensics=dict(type='bool', required=False), enable_meltdown=dict(type='bool', required=False), enable_pid_lookup=dict(type='bool', required=False), enforcement_cpu_quota_mode=dict(type='int', required=False, choices=[0, 1, 2]), enforcement_cpu_quota_pct=dict(type='int', required=False), enforcement_cpu_quota_us=dict(type='int', required=False), enforcement_disabled=dict(type='bool', required=False), enforcement_max_rss_limit=dict(type='int', required=False), enforcement_max_rss_limit_mb=dict(type='int', required=False), forensics_cpu_quota_mode=dict(type='int', required=False, choices=[0, 1, 2]), forensics_cpu_quota_pct=dict(type='int', required=False), forensics_cpu_quota_us=dict(type='int', required=False), forensics_mem_quota_bytes=dict(type='int', required=False), forensics_mem_quota_mb=dict(type='int', required=False), max_rss_limit=dict(type='int', required=False), max_rss_limit_mb=dict(type='int', required=False), preserve_existing_rules=dict(type='bool', required=False), state=dict(choices=['present', 'absent', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) # Building custom error handling to display custom error messages # Combine specs and include provider parameter module = AnsibleModule( argument_spec=module_args, required_one_of=[['root_app_scope_id', 'root_app_scope_name'], ['name', 'id']], mutually_exclusive=[ ['root_app_scope_id', 'root_app_scope_name'], ['cpu_quota_pct', 'cpu_quota_us'], ['enforcement_cpu_quota_pct', 'enforcement_cpu_quota_us'], ['forensics_cpu_quota_pct', 'forensics_cpu_quota_us'], ['enforcement_max_rss_limit', 'enforcement_max_rss_limit_mb'], ['forensics_mem_quota_bytes', 'forensics_mem_quota_mb'], ['max_rss_limit', 'max_rss_limit_mb'], ]) if module.params['name'] == 'Default': module.fail_json(msg='Cannot modify the default agent profile') # Verify the following modules have valid inputs between 1 and 100% inclusive percent_params = [ 'cpu_quota_pct', 'enforcement_cpu_quota_pct', 'forensics_cpu_quota_pct' ] invalid_percent_params = validate_ranges(percent_params, module.params, low_value=1, high_value=100) if invalid_percent_params: module.fail_json( msg= f'The following params need to be between 1 and 100 inclusive: {invalid_percent_params}' ) # Verify the following modules have valid inputs between 10,000 and 1,000,000 inclusive us_params = [ 'cpu_quota_us', 'enforcement_cpu_quota_us', 'forensics_cpu_quota_us' ] invalid_us_params = validate_ranges(us_params, module.params, low_value=10000, high_value=100000) if invalid_us_params: module.fail_json( msg= f'The following params need to be between 10,000 and 1,000,000 inclusive: {invalid_us_params}' ) # Verify the following modules have valid inputs between 128 and 2048 inclusive mb_params = ['enforcement_max_rss_limit_mb', 'forensics_mem_quota_mb'] invalid_mb_params = validate_ranges(mb_params, module.params, low_value=128, high_value=2048) if invalid_mb_params: module.fail_json( msg= f'The following params need to be between 128 and 2048 inclusive: {invalid_mb_params}' ) # Verify the following modules have valid inputs between 200 and 2048 inclusive vis_mb_params = ['max_rss_limit_mb'] invalid_vis_mb_params = validate_ranges(vis_mb_params, module.params, low_value=200, high_value=2048) if invalid_vis_mb_params: module.fail_json( msg= f'The following params need to be between 200 and 2048 inclusive: {invalid_vis_mb_params}' ) # Verify the following modules have valid inputs between 134,217,728 and 2,147,483,649 inclusive bytes_params = ['enforcement_max_rss_limit', 'forensics_mem_quota_bytes'] invalid_bytes_params = validate_ranges(bytes_params, module.params, low_value=134217728, high_value=2147483649) if invalid_bytes_params: module.fail_json( msg= f'The following params need to be between 134,217,728 and 2,147,483,649 inclusive: {invalid_bytes_params}' ) # Verify the following modules have valid inputs between 209,715,200 and 2,147,483,649 inclusive vis_bytes_params = ['max_rss_limit'] invalid_vis_bytes_params = validate_ranges(vis_bytes_params, module.params, low_value=209715200, high_value=2147483649) if invalid_vis_bytes_params: module.fail_json( msg= f'The following params need to be between 209,715,200 and 2,147,483,649 inclusive: {invalid_vis_bytes_params}' ) tet_module = TetrationApiModule(module) # These are all elements we put in our return JSON object for clarity result = { 'changed': False, 'object': {}, } # ========================================================================= # Get current state of the object app_scopes = tet_module.run_method('GET', TETRATION_API_SCOPES) app_scope_dict = {s['name']: s['id'] for s in app_scopes} existing_app_scope_id = None if module.params['root_app_scope_id'] in app_scope_dict.values(): existing_app_scope_id = module.params['root_app_scope_id'] else: scope_name = module.params['root_app_scope_name'] existing_app_scope_id = app_scope_dict.get(scope_name) if not existing_app_scope_id: if module.params['app_scope_id']: module.fail_json( msg= f"Unable to find existing app scope id: {module.params['app_scope_id']}" ) else: module.fail_json( msg= f"Unable to find existing app scope named: {module.params['app_scope_name']}" ) existing_profiles = tet_module.run_method( 'GET', TETRATION_API_AGENT_CONFIG_PROFILES) existing_profile = None for profile in existing_profiles: if module.params['id'] == profile['id']: existing_profile = profile elif module.params['name'] == profile['name']: existing_profile = profile # --------------------------------- # STATE == 'present' # --------------------------------- if module.params['state'] == 'present': new_object = { 'name': module.params['name'], 'root_app_scope_id': existing_app_scope_id, 'allow_broadcast': module.params['allow_broadcast'], 'allow_link_local': module.params['allow_link_local'], 'allow_multicast': module.params['allow_multicast'], 'auto_upgrade_opt_out': module.params['auto_upgrade_opt_out'], 'cpu_quota_mode': module.params['cpu_quota_mode'], 'cpu_quota_pct': module.params['cpu_quota_pct'], 'cpu_quota_us': module.params['cpu_quota_us'], 'data_plane_disabled': module.params['data_plane_disabled'], 'enable_dns': module.params['enable_dns'], 'enable_forensics': module.params['enable_forensics'], 'enable_meltdown': module.params['enable_meltdown'], 'enable_pid_lookup': module.params['enable_pid_lookup'], 'enforcement_cpu_quota_mode': module.params['enforcement_cpu_quota_mode'], 'enforcement_cpu_quota_pct': module.params['enforcement_cpu_quota_pct'], 'enforcement_cpu_quota_us': module.params['enforcement_cpu_quota_us'], 'enforcement_disabled': module.params['enforcement_disabled'], 'enforcement_max_rss_limit': module.params['enforcement_max_rss_limit'], 'enforcement_max_rss_limit_mb': module.params['enforcement_max_rss_limit_mb'], 'forensics_cpu_quota_mode': module.params['forensics_cpu_quota_mode'], 'forensics_cpu_quota_pct': module.params['forensics_cpu_quota_pct'], 'forensics_cpu_quota_us': module.params['forensics_cpu_quota_us'], 'forensics_mem_quota_bytes': module.params['forensics_mem_quota_bytes'], 'forensics_mem_quota_mb': module.params['forensics_mem_quota_mb'], 'max_rss_limit': module.params['max_rss_limit'], 'max_rss_limit_mb': module.params['max_rss_limit_mb'], 'preserve_existing_rules': module.params['preserve_existing_rules'], } # Remove all the undefined parameters from the new_object new_object = {k: v for k, v in new_object.items() if v is not None} if existing_profile: if tet_module.is_subset(new_object, existing_profile): # If there is no change required to the module result['object'] = existing_profile else: # A change is required route = f"{TETRATION_API_AGENT_CONFIG_PROFILES}/{existing_profile['id']}" result['object'] = tet_module.run_method( 'PUT', route, req_payload=new_object) result['changed'] = True else: result['object'] = tet_module.run_method( 'POST', TETRATION_API_AGENT_CONFIG_PROFILES, req_payload=new_object) result['changed'] = True # --------------------------------- # STATE == 'absent' # --------------------------------- elif module.params['state'] == 'absent': if existing_profile: route = f"{TETRATION_API_AGENT_CONFIG_PROFILES}/{existing_profile['id']}" result['object'] = tet_module.run_method('DELETE', route) result['changed'] = True # --------------------------------- # STATE == 'query' # --------------------------------- else: if existing_profile: result['object'] = existing_profile module.exit_json(**result)
def main(): valid_proto_names = [proto['name'] for proto in TETRATION_API_PROTOCOLS] valid_proto_ids = [proto['value'] for proto in TETRATION_API_PROTOCOLS] module_args = dict(policy_id=dict(type='str', required=True), start_port=dict(type='int', required=False), end_port=dict(type='int', required=False), proto_id=dict(type='int', required=False, choices=valid_proto_ids), proto_name=dict(type='str', required=False, choices=valid_proto_names), description=dict(type='str', required=False), approved=dict(type='bool', required=False), exclusion_filter=dict(type='bool', required=False, default=False), state=dict(required=True, choices=['present', 'absent', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) module = AnsibleModule( argument_spec=module_args, mutually_exclusive=[['proto_name', 'proto_id']], required_one_of=[ ['proto_name', 'proto_id'], ], required_together=[['start_port', 'end_port']], required_if=[ # Only the TCP and UDP protocols require the start and end ports ['proto_name', 'TCP', ['start_port', 'end_port']], ['proto_name', 'UDP', ['start_port', 'end_port']], ['proto_id', 6, ['start_port', 'end_port']], ['proto_id', 17, ['start_port', 'end_port']] ]) tet_module = TetrationApiModule(module) # These are all elements we put in our return JSON object for clarity result = { 'changed': False, 'object': {}, } # ========================================================================= # Get current state of the object route = f"{TETRATION_API_APPLICATION_POLICIES}/{module.params['policy_id']}" existing_policy = tet_module.run_method('GET', route) if not existing_policy: module.fail_json( msg= f"Unable to find existing application policy with id: {module.params['policy_id']}" ) # Convert the protocol name to a protocol id if module.params['proto_name']: proto_id_list = [ i['value'] for i in TETRATION_API_PROTOCOLS if i['name'] == module.params['proto_name'] ] proto_id = proto_id_list[0] else: proto_id = module.params['proto_id'] existing_l4_params = existing_policy['l4_params'] existing_param = find_l4_param(existing_l4_params, proto_id, module.params['start_port'], module.params['end_port']) # ========================================================================= # Now enforce the desired state (present, absent, query) # --------------------------------- # STATE == 'present' # --------------------------------- if module.params['state'] == 'present': # if the object does not exist at all, create it # deal with approved or not approved a different way new_object = { "start_port": module.params['start_port'], "end_port": module.params['end_port'], "description": module.params['description'], "proto": proto_id } # Remove unneeded entries parameters = [ 'start_port', 'end_port', 'description', ] for p in parameters: if new_object[p] is None: new_object.pop(p) # If the object does not exist, let's create it route = f"{TETRATION_API_APPLICATION_POLICIES}/{module.params['policy_id']}/l4_params" if not existing_param: l4_results = tet_module.run_method('POST', route, req_payload=new_object) new_param = find_l4_param(l4_results['l4_params'], proto_id, module.params['start_port'], module.params['end_port']) result['object'] = new_param result['changed'] = True else: result['object'] = existing_param if module.params['approved'] is not None: # If the approval status is missing, that means it's not approved current_approval_status = result['object'].get('approved', False) current_id = result['object']['id'] if current_approval_status != module.params['approved']: updated_route = f"{route}/{current_id}" payload = {"approved": module.params['approved']} approval_results = tet_module.run_method('PUT', updated_route, req_payload=payload) updated_param = find_l4_param(approval_results['l4_params'], proto_id, module.params['start_port'], module.params['end_port']) result['object'] = updated_param result['changed'] = True # --------------------------------- # STATE == 'absent' # --------------------------------- elif module.params['state'] == 'absent': if existing_param: policy_id = module.params['policy_id'] l4_param_id = existing_param['id'] route = f"{TETRATION_API_APPLICATION_POLICIES}/{policy_id}/l4_params/{l4_param_id}" payload = { "create_exclusion_filter": module.params['exclusion_filter'] } delete_results = tet_module.run_method('DELETE', route, req_payload=payload) result['changed'] = True result['object'] = delete_results # --------------------------------- # STATE == 'query' # --------------------------------- elif module.params['state'] == 'query': result['object'] = existing_param # Return result module.exit_json(**result)
def run_module(): # define available arguments/parameters a user can pass to the module single_filter = dict(field=dict(type='str', required=True), type=dict(type='str', required=True), value=dict(type='str', required=True)) query_filter_structure = dict(filters=dict(type='list', elements='dict', options=single_filter, required=True), type=dict(type='str', required=True)) nested_query_filter_structure = dict(filters=dict(type='list', elements='dict', required=True), type=dict(type='str', required=True)) module_args = dict(name=dict(type='str', required=False), id=dict(type='str', required=False), query_multiple=dict(type='dict', options=query_filter_structure, required=False), query_raw=dict(type='dict', options=nested_query_filter_structure, required=False), query_single=dict(type='dict', options=single_filter, reqired=False), app_scope_id=dict(type='str', required=False), primary=dict(type='bool', required=False, default=False), public=dict(type='bool', required=False, default=False), state=dict(choices=['present', 'absent', 'query'], required=True), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) result = {'changed': False, 'object': {}} result_obj = {} module = AnsibleModule( argument_spec=module_args, required_one_of=[ ['name', 'id'], ], mutually_exclusive=[['query_multiple', 'query_raw', 'query_single']], required_by={'name': ['app_scope_id']}) # Get current state of the object tet_module = TetrationApiModule(module) all_scopes_response = tet_module.run_method('GET', TETRATION_API_SCOPES) all_scopes_lookup = {s['id'] for s in all_scopes_response} all_inventory_filters_response = tet_module.run_method( 'GET', TETRATION_API_INVENTORY_FILTER) all_inventory_filters_lookup = {(s['name'], s['app_scope_id']): s['id'] for s in all_inventory_filters_response} unique_inventory_filter_name = module.params['name'], module.params[ 'app_scope_id'] # Since the query parameter data all goes into one field eventually, just extract it into # A value here for use later on in the module query_parameters = ['query_multiple', 'query_raw', 'query_single'] extracted_query_filter = {} for query in query_parameters: if module.params[query]: extracted_query_filter = module.params[query] # Validate items that should exist do exist if module.params['id'] and module.params[ 'id'] not in all_inventory_filters_lookup.values(): error_message = "`id` passed into the module does not exist." module.fail_json(msg=error_message, searched_filter_id=module.params['id']) if module.params['app_scope_id'] and module.params[ 'app_scope_id'] not in all_scopes_lookup: error_message = "`app_scope_id` passed into the module does not exist." module.fail_json(msg=error_message) if module.params['state'] == 'present': if module.params[ 'id'] or unique_inventory_filter_name in all_inventory_filters_lookup.keys( ): # Object exists, going to see if updates are needed if module.params['id']: inv_filter_to_update = module.params['id'] else: inv_filter_to_update = all_inventory_filters_lookup[ unique_inventory_filter_name] route = f"{TETRATION_API_INVENTORY_FILTER}/{inv_filter_to_update}" response = tet_module.run_method('GET', route) req_payload = { 'name': None, 'query': {}, 'app_scope_id': None, 'primary': None, 'public': None } # Updating the Update Object payload_keys = [k for k in req_payload.keys()] for key in payload_keys: if module.params.get(key) is not None and module.params[ key] != response[key]: req_payload[key] = module.params[key] elif key == 'query': if extracted_query_filter and extracted_query_filter != response[ 'short_query']: req_payload[key] = extracted_query_filter else: req_payload.pop(key) else: req_payload.pop(key) if req_payload: update_response = tet_module.run_method( 'PUT', route, req_payload=req_payload) result['changed'] = True result_obj = update_response else: result_obj = response elif unique_inventory_filter_name not in all_inventory_filters_lookup.keys( ): # Object does not exist, going to create it if not extracted_query_filter: error_message = ( 'In order to create a new `inventory_filter` you must also have a `query` parameter defined.' ) module.fail_json(msg=error_message) req_payload = { 'name': module.params['name'], 'query': extracted_query_filter, 'app_scope_id': module.params['app_scope_id'], 'primary': module.params['primary'], 'public': module.params['public'] } response = tet_module.run_method('POST', TETRATION_API_INVENTORY_FILTER, req_payload=req_payload) result_obj = response result['changed'] = True if module.params['state'] == 'absent': if module.params['id']: delete_id = module.params['id'] else: delete_id = all_inventory_filters_lookup.get( unique_inventory_filter_name) if delete_id: route = f"{TETRATION_API_INVENTORY_FILTER}/{delete_id}" response = tet_module.run_method('DELETE', route) result_obj = response result['changed'] = True if module.params['state'] == 'query': if module.params['id']: search_id = module.params['id'] else: if unique_inventory_filter_name in all_inventory_filters_lookup.keys( ): search_id = all_inventory_filters_lookup[ unique_inventory_filter_name] else: search_id = None if search_id: route = f"{TETRATION_API_INVENTORY_FILTER}/{search_id}" response = tet_module.run_method('GET', route) result_obj = response result['object'] = result_obj module.exit_json(**result)
def main(): module_args = dict(app_id=dict(type='str', required=True), consumer_filter_id=dict(type='str', required=False), consumer_filter_name=dict(type='str', required=False), provider_filter_id=dict(type='str', required=False), provider_filter_name=dict(type='str', required=False), version=dict(type='str', required=True), rank=dict(type='str', required=True, choices=['DEFAULT', 'ABSOLUTE']), policy_action=dict(type='str', required=True, choices=['ALLOW', 'DENY']), priority=dict(type='int', required=True), state=dict(required=True, choices=['present', 'absent', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) module = AnsibleModule( argument_spec=module_args, supports_check_mode=True, mutually_exclusive=[['consumer_filter_id', 'consumer_filter_name'], ['provider_filter_id', 'provider_filter_name']], required_one_of=[['consumer_filter_id', 'consumer_filter_name'], ['provider_filter_id', 'provider_filter_name']], required_if=[ ['state', 'present', ['policy_action', 'priority']], ]) tet_module = TetrationApiModule(module) # These are all elements we put in our return JSON object for clarity result = { 'changed': False, 'object': None, } # ========================================================================= # Verify the application ID exists route = f"{TETRATION_API_APPLICATIONS}/{module.params['app_id']}" existing_app = tet_module.run_method('GET', route) if not existing_app: module.fail_json(msg='Unable to find existing application id') # Get the existing API Scopes and Inventory Filters to verify the consumer and provider settings existing_app_scopes = tet_module.run_method('GET', TETRATION_API_SCOPES) app_scope_name_to_scope_id = {} app_scope_name_to_parent_scope_id = {} for scope in existing_app_scopes: app_scope_name_to_scope_id[scope['name']] = scope['id'] app_scope_name_to_parent_scope_id[ scope['name']] = scope['parent_app_scope_id'] existing_inventory_filters = tet_module.run_method( 'GET', TETRATION_API_INVENTORY_FILTER) # Build the inventory filter dict but check for duplicate entries and report them if found inv_filter_name_to_filter_id = {} duplicate_values = [] for i in existing_inventory_filters: name = i['name'] inv_id = i['id'] if inv_id is None: module.fail_json(msg='An ID returned had a value of `None`') if inv_filter_name_to_filter_id.get(name) is None: inv_filter_name_to_filter_id[name] = inv_id else: duplicate_values.append(name) if duplicate_values: duplicate_values = set(duplicate_values) module.fail_json(msg=( 'The Tetration Server has multiple inventory filters with the same name. ' 'This is not supported with this module. ' f'Duplicate names are: {duplicate_values}')) consumer_id = None provider_id = None if module.params['consumer_filter_id']: # Verify the ID is a valid api scope or an inventory filter if module.params[ 'consumer_filter_id'] in app_scope_name_to_scope_id.values(): consumer_id = module.params['consumer_filter_id'] elif module.params[ 'consumer_filter_id'] in inv_filter_name_to_filter_id.values(): consumer_id = module.params['consumer_filter_id'] elif module.params['consumer_filter_name']: # Verify the ID is a valid api scope or an inventory filter filter_name = module.params['consumer_filter_name'] if app_scope_name_to_scope_id.get(filter_name): consumer_id = app_scope_name_to_scope_id[filter_name] elif inv_filter_name_to_filter_id.get(filter_name): consumer_id = inv_filter_name_to_filter_id[filter_name] if module.params['provider_filter_id']: # Verify the ID is a valid api scope or an inventory filter if module.params[ 'provider_filter_id'] in app_scope_name_to_scope_id.values(): provider_id = module.params['provider_filter_id'] elif module.params[ 'provider_filter_id'] in inv_filter_name_to_filter_id.values(): provider_id = module.params['provider_filter_id'] elif module.params['provider_filter_name']: # Verify the ID is a valid api scope or an inventory filter filter_name = module.params['provider_filter_name'] if app_scope_name_to_scope_id.get(filter_name): provider_id = app_scope_name_to_scope_id[filter_name] elif inv_filter_name_to_filter_id.get(filter_name): provider_id = inv_filter_name_to_filter_id[filter_name] if consumer_id is None: module.fail_json(msg='The provided consumer name or id is invalid') if provider_id is None: module.fail_json(msg='The provided provider name or id is invalid') # Get the policies for the application if module.params['rank'] == 'ABSOLUTE': policy_route = f"{route}/absolute_policies" else: policy_route = f"{route}/default_policies" existing_policies = tet_module.run_method('GET', policy_route) # Now figure out if the policy defined in the module exists existing_policy = None existing_policy_id = None desired_unique_id = (module.params['priority'], module.params['policy_action'], consumer_id, provider_id) found_policies = [] for policy in existing_policies: policy_id = (policy['priority'], policy['action'], policy['consumer_filter_id'], policy['provider_filter_id']) if policy_id == desired_unique_id: found_policies.append(policy) if len(found_policies) == 1: existing_policy = found_policies[0] existing_policy_id = found_policies[0]['id'] elif len(found_policies) >= 2: module.fail_json( msg=("Multiple policies found with the given criteria. " "Cannot use this module if multiple policies match the " "`priority`, `action`, `consumer`, and `provider` fields. " f"Duplicate policies: {found_policies}")) # --------------------------------- # STATE == 'present' # --------------------------------- if module.params['state'] == 'present': if existing_policy: result['object'] = existing_policy else: req_payload = { "version": module.params['version'], "rank": module.params['rank'], "policy_action": module.params['policy_action'], "priority": module.params['priority'], "consumer_filter_id": consumer_id, "provider_filter_id": provider_id, } add_policy_route = f"{route}/policies" result['object'] = tet_module.run_method('POST', add_policy_route, req_payload=req_payload) result['changed'] = True # --------------------------------- # STATE == 'absent' # --------------------------------- elif module.params['state'] == 'absent': if existing_policy: delete_policy_route = f"{TETRATION_API_APPLICATION_POLICIES}/{existing_policy_id}" result['object'] = tet_module.run_method('DELETE', delete_policy_route) result['changed'] = True # --------------------------------- # STATE == 'query' # --------------------------------- elif module.params['state'] == 'query': result['object'] = existing_policy # Return result module.exit_json(**result)
def run_module(): # define available arguments/parameters a user can pass to the module module_args = dict(app_scope_id=dict(type='str', required=False, default=''), app_scope_name=dict(type='str', required=False, default=''), role_ids=dict(type='list', required=False, default=[]), role_names=dict(type='list', required=False, default=[]), email=dict(type='str', required=True), first_name=dict(type='str', required=False, default=''), last_name=dict(type='str', required=False, default=''), state=dict(type='str', required=True, choices=['present', 'absent', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) # Create the objects that will be returned result = { "object": None, "changed": False, } result_obj = dict(app_scope_id=None, created_at=None, disabled_at=None, email=None, first_name=None, id=None, last_name=None, role_ids=[]) # Creating the Ansible Module module = AnsibleModule( argument_spec=module_args, supports_check_mode=True, mutually_exclusive=[['app_scope_id', 'app_scope_name'], ['role_ids', 'role_names']]) tet_module = TetrationApiModule(module) # Create an App Scope Name to ID Lookup Table all_app_scopes_response = tet_module.run_method('GET', TETRATION_API_SCOPES) all_app_scopes_lookup = { r['name'].upper(): r['id'] for r in all_app_scopes_response } # Create a Role Name to ID Lookup Table all_roles_response = tet_module.run_method('GET', TETRATION_API_ROLE) all_roles_lookup = {r['name']: r['id'] for r in all_roles_response} # Role and App Scope Validation # Done here so it does not have to be done elsewhere in the module invalid_parameters = {} if module.params['app_scope_id']: scope_id = module.params['app_scope_id'] if scope_id not in all_app_scopes_lookup.values(): invalid_parameters['app_scope_id'] = scope_id if module.params['app_scope_name']: scope_name = module.params['app_scope_name'] # case insensitive compare - all keys will be upper case. if scope_name.upper() not in all_app_scopes_lookup.keys(): invalid_parameters['app_scope_name'] = scope_name if module.params['role_ids']: invalid_role_ids = [ id for id in module.params['role_ids'] if id not in all_roles_lookup.values() ] if invalid_role_ids: invalid_parameters['role_ids'] = invalid_role_ids if module.params['role_names']: invalid_role_names = [ name for name in module.params['role_names'] if name not in all_roles_lookup.keys() ] if invalid_role_names: invalid_parameters['role_names'] = invalid_role_names if invalid_parameters: error_message = "Check the `invalid parameters` object for the invalid parameters" module.fail_json(msg=error_message, invalid_parameters=invalid_parameters) # The first thing we have to do is get the object. returned_user_object = tet_module.get_object( target=TETRATION_API_USER, params=dict(include_disabled='true'), filter=dict(email=module.params['email']), ) if returned_user_object: user_id = returned_user_object['id'] else: user_id = None # Create the user, update the user, or verify no changes needed if module.params['state'] == 'present': if returned_user_object is None: # User does not exist, so we're going to create it req_payload = { "first_name": "", "last_name": "", "email": "", "app_scope_id": "", "role_ids": [] } # Check for required parameters when creating a user if not all( [module.params['first_name'], module.params['last_name']]): error_message = ( 'The first name and last name parameters are required when ' 'creating a new user. ' 'First Name: {} ' 'Last Name: {}').format(module.params['first_name'], module.params['last_name']) module.fail_json(msg=error_message) # Now that we know the required parameters exist, update the request object req_payload['first_name'] = module.params['first_name'] req_payload['last_name'] = module.params['last_name'] req_payload['email'] = module.params['email'] # Deal with the `app_scope` parameters if module.params['app_scope_name']: # Convert the name to a scope id app_scope_id = all_app_scopes_lookup.get( module.params['app_scope_name'].upper()) req_payload['app_scope_id'] = app_scope_id elif module.params['app_scope_id']: req_payload['app_scope_id'] = module.params['app_scope_id'] else: # No data was provided, remove the parameter req_payload.pop('app_scope_id') # Deal with the `role` parameters if module.params['role_names']: # Convert the list of names to a list of id's for role_name in module.params['role_names']: role_id = all_roles_lookup.get(role_name) req_payload['role_ids'].append(role_id) elif module.params['role_ids']: req_payload['role_ids'] = module.params['role_ids'] else: # No data was provided, remove the parameter req_payload.pop('role_ids') if module.check_mode: # We just document what we would have changed result['changed'] = True for k in result_obj.keys(): result_obj[k] = req_payload.get(k) else: method_results = tet_module.run_method('POST', TETRATION_API_USER, req_payload=req_payload) if method_results: result['changed'] = True for k in result_obj.keys(): result_obj[k] = method_results.get(k) elif returned_user_object is not None: if returned_user_object['disabled_at']: # Re-enable the user if it's disabled enable_route = f'{TETRATION_API_USER}/{user_id}/enable' if not module.check_mode: method_results = tet_module.run_method( 'POST', enable_route) result_obj['disabled_at'] = method_results['disabled_at'] else: result_obj['disabled_at'] = None result['changed'] = True req_payload = { "first_name": "", "last_name": "", "email": "", "app_scope_id": "" } # Set the request payload object to update the user if module.params['first_name'] and returned_user_object[ 'first_name'] != module.params['first_name']: req_payload['first_name'] = module.params['first_name'] result_obj['first_name'] = module.params['first_name'] result['changed'] = True else: result_obj['first_name'] = returned_user_object['first_name'] req_payload.pop('first_name') if module.params['last_name'] and returned_user_object[ 'last_name'] != module.params['last_name']: req_payload['last_name'] = module.params['last_name'] result_obj['last_name'] = module.params['last_name'] result['changed'] = True else: result_obj['last_name'] = returned_user_object['last_name'] req_payload.pop('last_name') if module.params['email'] and returned_user_object[ 'email'] != module.params['email']: req_payload['email'] = module.params['email'] result_obj['email'] = module.params['email'] result['changed'] = True else: result_obj['email'] = returned_user_object['email'] req_payload.pop('email') if module.params['app_scope_id']: if returned_user_object['app_scope_id'] != module.params[ 'app_scope_id']: req_payload['app_scope_id'] = module.params['app_scope_id'] result_obj['app_scope_id'] = module.params['app_scope_id'] result['changed'] = True else: result_obj['app_scope_id'] = returned_user_object[ 'app_scope_id'] req_payload.pop('app_scope_id') elif module.params['app_scope_name']: app_scope_id = all_app_scopes_lookup.get( module.params['app_scope_name']) if returned_user_object['app_scope_id'] != app_scope_id: req_payload['app_scope_id'] = app_scope_id result_obj['app_scope_id'] = app_scope_id result['changed'] = True else: result_obj['app_scope_id'] = returned_user_object[ 'app_scope_id'] req_payload.pop('app_scope_id') else: result_obj['app_scope_id'] = returned_user_object[ 'app_scope_id'] req_payload.pop('app_scope_id') update_route = f'{TETRATION_API_USER}/{user_id}' if not module.check_mode: method_results = tet_module.run_method('PUT', update_route, req_payload=req_payload) roles_to_add = [] roles_to_delete = [] if module.params['role_ids']: current_state = set(returned_user_object['role_ids']) desired_state = set(module.params['role_ids']) roles_to_add = list(desired_state.difference(current_state)) roles_to_delete = list(current_state.difference(desired_state)) elif module.params['role_names']: current_state = set(returned_user_object['role_ids']) desired_state = [] for name in module.params['role_names']: desired_state.append(all_roles_lookup[name]) desired_state = set(desired_state) roles_to_add = list(desired_state.difference(current_state)) roles_to_delete = list(current_state.difference(desired_state)) # Set the results equal to what it is currently result_obj['role_ids'] = returned_user_object['role_ids'] req_payload = { "role_id": None, } for role in roles_to_add: add_role_route = f"{TETRATION_API_USER}/{user_id}/add_role" req_payload['role_id'] = role result_obj['role_ids'].append(role) if not module.check_mode: method_results = tet_module.run_method( 'PUT', add_role_route, req_payload=req_payload) result['changed'] = True for role in roles_to_delete: req_payload['role_id'] = role result_obj['role_ids'] = [ r for r in result_obj['role_ids'] if r != role ] remove_role_route = f"{TETRATION_API_USER}/{user_id}/remove_role" if not module.check_mode: method_results = tet_module.run_method( 'DELETE', remove_role_route, req_payload=req_payload) result['changed'] = True if module.params['state'] == 'absent': if returned_user_object and not returned_user_object['disabled_at']: # If the user exists and it's not already disabled, a change will occur result['changed'] = True if not module.check_mode: route = f"{TETRATION_API_USER}/{user_id}" method_results = tet_module.run_method('DELETE', route) if method_results: for k in result_obj.keys(): result_obj[k] = method_results.get(k) else: # Extracting the reqired info from what was returned from Tetration result_obj['app_scope_id'] = returned_user_object[ 'app_scope_id'] result_obj['created_at'] = returned_user_object['created_at'] result_obj['disabled_at'] = returned_user_object['disabled_at'] result_obj['email'] = returned_user_object['email'] result_obj['first_name'] = returned_user_object['first_name'] result_obj['id'] = returned_user_object['id'] result_obj['last_name'] = returned_user_object['last_name'] result_obj['role_ids'] = returned_user_object['role_ids'] if module.params['state'] == 'query': result['changed'] = False if returned_user_object is not None: # Extracting the reqired info from what was returned from Tetration result_obj['app_scope_id'] = returned_user_object['app_scope_id'] result_obj['created_at'] = returned_user_object['created_at'] result_obj['disabled_at'] = returned_user_object['disabled_at'] result_obj['email'] = returned_user_object['email'] result_obj['first_name'] = returned_user_object['first_name'] result_obj['id'] = returned_user_object['id'] result_obj['last_name'] = returned_user_object['last_name'] result_obj['role_ids'] = returned_user_object['role_ids'] result['object'] = result_obj # in the event of a successful module execution, you will want to # simple AnsibleModule.exit_json(), passing the key/value results module.exit_json(**result)
def run_module(): # define available arguments/parameters a user can pass to the module single_filter = dict(field=dict(type='str', required=True), type=dict(type='str', required=True), value=dict(type='str', required=True)) query_filter_structure = dict(filters=dict(type='list', elements='dict', options=single_filter, required=True), type=dict(type='str', required=True)) nested_query_filter_structure = dict(filters=dict(type='list', elements='dict', required=True), type=dict(type='str', required=True)) module_args = dict(scope_id=dict(type='str', required=False), short_name=dict(type='str', required=False), description=dict(type='str', required=False), query_multiple=dict(type='dict', options=query_filter_structure, required=False), query_raw=dict(type='dict', options=nested_query_filter_structure, required=False), query_single=dict(type='dict', options=single_filter, reqired=False), parent_app_scope_id=dict(type='str', required=False), policy_priority=dict(type='int', required=False), state=dict(choices=['present', 'absent'], required=True), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) # Create the objects that will be returned result = {"object": None, "changed": False} result_obj = dict(child_app_scope_ids=[], description=None, dirty=None, dirty_short_query=None, id=None, name=None, parent_app_scope_id=None, policy_priority=None, query=None, root_app_scope_id=None, short_name=None, short_query=None, updated_at=None, vrf_id=None) # Creating the Ansible Module module = AnsibleModule( argument_spec=module_args, supports_check_mode=True, required_one_of=[ ['scope_id', 'short_name'], ], mutually_exclusive=[['query_multiple', 'query_raw', 'query_single']], required_by={'short_name': ['parent_app_scope_id']}, ) # Get current state of the object tet_module = TetrationApiModule(module) all_scopes_response = tet_module.run_method('GET', TETRATION_API_SCOPES) all_scopes_lookup = {(s['short_name'], s['parent_app_scope_id']): s['id'] for s in all_scopes_response} unique_scope_name = module.params['short_name'], module.params[ 'parent_app_scope_id'] # Verify the passed in data is valid if module.params['scope_id'] and module.params[ 'scope_id'] not in all_scopes_lookup.values(): error_message = "`scope_id` passed into the module does not exist." module.fail_json(msg=error_message, searched_scope=module.params['scope_id']) if module.params['parent_app_scope_id'] and module.params[ 'parent_app_scope_id'] not in all_scopes_lookup.values(): error_message = "`parent_app_scope_id` passed into the module does not exist." module.fail_json(msg=error_message) # Since the query parameter data all goes into one field eventually, just extract it into # A value here for use later on in the module query_parameters = ['query_multiple', 'query_raw', 'query_single'] extracted_query_filter = {} for query in query_parameters: if module.params[query]: extracted_query_filter = module.params[query] # Implment changes as defined in the module if module.params['state'] == 'present': if module.params[ 'scope_id'] or unique_scope_name in all_scopes_lookup.keys(): # Object exists, doing an update if module.params['scope_id']: scope_id_to_update = module.params['scope_id'] else: scope_id_to_update = all_scopes_lookup[unique_scope_name] route = f"{TETRATION_API_SCOPES}/{scope_id_to_update}" response = tet_module.run_method('GET', route) req_payload = { 'short_name': None, 'short_query': {}, 'description': None, 'parent_app_scope_id': None, 'policy_priority': None } payload_keys = [k for k in req_payload.keys()] for key in payload_keys: if module.params.get(key) is not None and module.params[ key] != response[key]: req_payload[key] = module.params[key] elif key == 'short_query': if extracted_query_filter and extracted_query_filter != response[ 'short_query']: req_payload[key] = extracted_query_filter else: req_payload.pop(key) else: req_payload.pop(key) # Updating the Update Object if req_payload: update_response = tet_module.run_method( 'PUT', route, req_payload=req_payload) result['changed'] = True result_obj = update_response else: result_obj = response elif unique_scope_name not in all_scopes_lookup.keys(): # Creating a new object if not extracted_query_filter: error_message = ( 'In order to create a new `scope` you must also add a query parameter.' ) module.fail_json(msg=error_message) req_payload = { 'short_name': module.params['short_name'], 'short_query': extracted_query_filter, 'description': module.params['description'], 'parent_app_scope_id': module.params['parent_app_scope_id'], 'policy_priority': module.params['policy_priority'] } response = tet_module.run_method('POST', TETRATION_API_SCOPES, req_payload=req_payload) result_obj = response result['changed'] = True else: error_message = "An unknown error occured" module.fail_json(msg=error_message) elif module.params['state'] == 'absent': if module.params[ 'scope_id'] or unique_scope_name in all_scopes_lookup.keys(): # User exists, doing an update if module.params['scope_id']: scope_id_to_delete = module.params['scope_id'] else: scope_id_to_delete = all_scopes_lookup[unique_scope_name] route = f"{TETRATION_API_SCOPES}/{scope_id_to_delete}" response = tet_module.run_method('DELETE', route) if response.get('details'): error_message = "There are objects using this scope. Review the `details` tag for more details." module.fail_json(msg=error_message, details=response['details']) else: result['changed'] = True result_obj = response result['object'] = result_obj module.exit_json(**result)
def main(): module_args = dict(application_id=dict(type='str', required=True), version=dict(type='str', required=False, default=None), state=dict(required=True, choices=['enabled', 'disabled']), provider=dict(type='dict', required=True, options=TETRATION_PROVIDER_SPEC)) module = AnsibleModule(argument_spec=module_args) tet_module = TetrationApiModule(module) # These are all elements we put in our return JSON object for clarity result = { 'changed': False, 'object': None, } # ========================================================================= # Get current state of the object app_route = f"{TETRATION_API_APPLICATIONS}/{module.params['application_id']}" existing_app = tet_module.run_method('GET', app_route) if not existing_app: module.fail_json( msg= f"Unable to find application with id: {module.params['application_id']}" ) # --------------------------------- # STATE == 'enabled' # --------------------------------- if module.params['state'] == 'enabled': if existing_app['enforcement_enabled'] is False: result['changed'] = True elif module.params['version'] is not None and existing_app[ 'enforced_version'] != int( module.params['version'].strip('p')): # Per the API guide, the preferred method of passing the version is `p4` for Version 4 # But the version returned from the api is just an int. # This deals with passing in an int or the p for for the version result['changed'] = True if result['changed']: req_payload = {} if module.params['version']: req_payload['version'] = module.params['version'] route = f"{TETRATION_API_APPLICATIONS}/{module.params['application_id']}/enable_enforce" result['object'] = tet_module.run_method('POST', route, req_payload=req_payload) # --------------------------------- # STATE == 'disabled' # --------------------------------- elif module.params['state'] == 'disabled': result['changed'] = existing_app['enforcement_enabled'] if result['changed']: route = f"{TETRATION_API_APPLICATIONS}/{module.params['application_id']}/disable_enforce" result['object'] = tet_module.run_method('POST', route) # Return result module.exit_json(**result)
def main(): ''' Main entry point for module execution ''' # Module specific spec module_args = dict(attributes=dict(type='dict'), ip_address=dict(type='str', required=False), ip_subnet=dict(type='str', required=False), root_scope_name=dict(type='str', required=True), state=dict(type="str", required=True, choices=['absent', 'present', 'query']), provider=dict(type='dict', options=TETRATION_PROVIDER_SPEC)) module = AnsibleModule(argument_spec=module_args, required_one_of=[['ip_address', 'ip_subnet']], mutually_exclusive=[['ip_address', 'ip_subnet']], required_if=[['state', 'present', ['attributes']]]) ip_object = '' # Verify a valid IP address was passed in if module.params['ip_address']: try: ip_object = str(ip_address(module.params['ip_address'])) except ValueError: error_message = f"Invalid IPv4 or IPv6 Address entered. Value entered: {module.params['ip_address']}" module.fail_json(msg=error_message) # Verify a valid IP subnet was passed in if module.params['ip_subnet']: try: ip_object = str(ip_network(module.params['ip_subnet'])) except ValueError: error_message = f"Invalid IPv4 or IPv6 subnet entered. Value entered: {module.params['ip_subnet']}" module.fail_json(msg=error_message) # Throw error if state is absent and annotations passed if module.params['state'] == 'absent' and module.params[ 'attributes'] is not None: module.fail_json( msg= 'attributes cannot be passed for state `absent` because all attributes are cleared' ) tet_module = TetrationApiModule(module) # These are all elements we put in our return JSON object for clarity result = {"object": None, "changed": False, "tet_warnings": None} route = f"{TETRATION_API_INVENTORY_TAG}/{module.params['root_scope_name']}" # ========================================================================= # Get current state of the object params = {'ip': ip_object} query_result = tet_module.run_method('GET', route, params=params) current_attributes = query_result if query_result else {} # --------------------------------- # STATE == 'present' # --------------------------------- if module.params['state'] == 'present': if not tet_module.is_subset(module.params['attributes'], current_attributes): req_payload = { 'ip': ip_object, 'attributes': module.params['attributes'] } result['tet_warnings'] = tet_module.run_method( 'POST', route, req_payload=req_payload) result['object'] = tet_module.run_method('GET', route, params=params) result['changed'] = True else: result['object'] = current_attributes # --------------------------------- # STATE == 'absent' # --------------------------------- elif module.params['state'] == 'absent': if current_attributes: req_payload = {'ip': ip_object} tet_module.run_method('DELETE', route, req_payload=req_payload) result['changed'] = True # --------------------------------- # STATE == 'query' # --------------------------------- elif module.params['state'] == 'query': if current_attributes: result['object'] = current_attributes module.exit_json(**result)