def get_tet_json(request_str, host=env.TET.get("host"), api_key=env.TET_API_KEY, api_sec=env.TET_SEC): # Build URL url = f"https://{host}" restclient = RestClient(url, api_key=api_key, api_secret=api_sec, verify=False) # Get Request response = restclient.get(request_str) # If successful response code return list sensors if response.status_code == 200: #print ("DEBUG GET:", json.dumps(response.json(), indent=2)) return response.json() # If response code is anything but 200, print error message with response code else: #print(f"Error processing GET request on {request_str}. Error code: {response.status_code}.") return None
def dump_applications(endpoint): restclient = RestClient(endpoint + '/', credentials_file='api_cred.json', verify=False) apps = [] resp = restclient.get('/applications') if resp.status_code == 200: respbody = json.loads(resp.text) with open('public/data/all.json', 'w+') as appf: appf.write(resp.text) respbody = json.loads(resp.text) for app in respbody: appnames = {} appnames['id'] = str(app['id']) appnames['name'] = str(app['name']) #version changed after 2.3+ try: appnames['version'] = str(app['version']) except KeyError as ke: appnames['version'] = str(app['latest_adm_version']) apps.append(appnames) for app in apps: resp = restclient.get('/applications/%s/details' % (app['id'])) if resp.status_code == 200: try: os.mkdir('public/data/%s' % (app['id'])) except: pass with open('public/data/%s.json' % (app['id']), "w+") as outf: outf.write(resp.text) with open('public/data/%s/%s.json' % (app['id'], app['version']), "w+") as outf2: outf2.write(resp.text)
def __init__(self,tetCluster,tetCreds): self._primaryApps = {} self._adjacentApps = {} self._scopes = {} self._restclient = RestClient(tetCluster, credentials_file=tetCreds, verify=False)
def get_applications( host=env.TET.get("host"), api_key=env.TET_API_KEY, api_sec=env.TET_SEC): # Build URL url = f"https://{host}" restclient = RestClient(url, api_key=api_key, api_secret=api_sec, verify=True) # HTTP Get Request response = restclient.get("/applications") # If response code is 200, then return the json response if response.status_code == 200: # JSON Response applications = response.json() return applications # If response code is anything but 200, print error message with response code else: print( f"Unable to find any Applications. Error code {response.status_code}." )
def selectTetrationApps(endpoint, credentials): restclient = RestClient(endpoint, credentials_file=credentials, verify=False) requests.packages.urllib3.disable_warnings() resp = restclient.get('/openapi/v1/applications') if not resp: sys.exit("No data returned for Tetration Apps! HTTP {}".format( resp.status_code)) app_table = [] app_table.append(['Number', 'Name', 'Author', 'Primary']) print('\nApplications: ') for i, app in enumerate(resp.json()): app_table.append([i + 1, app['name'], app['author'], app['primary']]) print('%i: %s' % (i + 1, app['name'])) # print(AsciiTable(app_table).table) choice = raw_input('\nSelect Tetration App: ') choice = choice.split(',') appIDs = [] for app in choice: if '-' in app: for app in range(int(app.split('-')[0]), int(app.split('-')[1]) + 1): appIDs.append(resp.json()[int(app) - 1]['id']) else: appIDs.append(resp.json()[int(app) - 1]['id']) return appIDs
def scope_download(hostname, api_key, api_secret, dest, validate_certs): result = {"ansible_facts": {}} api_endpoint = 'https://{0}'.format(hostname) restclient = RestClient(api_endpoint, api_key=api_key, api_secret=api_secret, verify=validate_certs) resp = restclient.get('/openapi/v1/app_scopes') if not resp.status_code == 200: return ( 1, "Error {0}: {1} during connection attempt to {2}/openapi/v1/app_scopes. \n" .format(resp.status_code, resp.reason, api_endpoint)) scopes = json.loads(resp.content) shortened_scope_list = [] for i in range(len(scopes) - 1, 0, -1): shortened_scope_list.append( dict(short_name=scopes[i]['short_name'], short_query=scopes[i]['short_query'], parent_app_scope_name=scope_name_lookup( scopes, scopes[i]['parent_app_scope_id']))) with open(dest, 'w') as f: for scope in shortened_scope_list: f.write('---\n') oyaml.dump(scope, f, allow_unicode=True, encoding='utf-8') f.write('\n') result["ansible_facts"] = {'Output': os.path.join(os.getcwd(), dest)} result['changed'] = False return (0, result)
def test_tetration(): ''' Function attempts to connect to Tetration. Arguments are retrieved from environment variables. The bulk of the work in this function is error handling. It returns a tuple that has a status code and an error message (which will be an empty string if there are no errors) ''' requests.packages.urllib3.disable_warnings() status = 200 return_msg = "Tetration connectivity verified." restclient = RestClient(os.environ['TETRATION_ENDPOINT'], api_key=os.environ['TETRATION_API_KEY'], api_secret=os.environ['TETRATION_API_SECRET'], verify=False) try: resp = restclient.get('/filters/inventories') # most likely a DNS issue except requests.exceptions.ConnectionError: status = 404 return_msg = "Error connecting to Tetration endpoint" except: status = 400 return_msg = "Unknown error connecting to Tetration" else: status = resp.status_code # this doesn't work if the Tetration endpoint is specified as a valid # website (but not a TA endpoint) because it returns all of the HTML # for the whole website if resp.status_code >= 400: return_msg = "Tetration " + str(resp.text).rstrip() return (status, return_msg)
def get_tetration_tagged_workspaces(): restclient = RestClient(tetration_url, api_key=tetration_api_key, api_secret=tetration_api_secret, verify=False) req_payload = { "filter": { "type": "and", "filters": [{ "type": "eq", "field": "user_Location", "value": aws_region }, { "type": "eq", "field": "user_Cloud Service", "value": "WorkSpaces" }] }, "scopeName": tetration_tenant, "dimensions": ['ip', 'host_uuid', "user_Cloud Service", "user_Location"], "limit": 2000 } resp = restclient.post('/inventory/search', json_body=json.dumps(req_payload)) if resp.status_code == 200: parsed_resp = json.loads(resp.content) return parsed_resp['results']
def app_download(hostname,api_key,api_secret,dest,validate_certs): result = {"ansible_facts": {}} api_endpoint = 'https://{0}'.format(hostname) restclient = RestClient(api_endpoint, api_key=api_key, api_secret=api_secret, verify=validate_certs) resp = restclient.get('/openapi/v1/applications') if not resp.status_code == 200: return (1, "Error {0}: {1} during connection attempt to {2}/openapi/v1/applications. \n".format(resp.status_code, resp.reason,api_endpoint)) apps = json.loads(resp.content) resp = restclient.get('/openapi/v1/app_scopes') if not resp.status_code == 200: return (1, "Error {0}: {1} during connection attempt to {2}/openapi/v1/app_scopes. \n".format(resp.status_code, resp.reason,api_endpoint)) scopes = json.loads(resp.content) with open(dest, 'w') as f: for app in apps: print('Retrieving details for app {0}'.format(app['name'])) resp = restclient.get('/openapi/v1/applications/{0}/details'.format(app['id'])) if not resp.status_code == 200: return (1, "Error {0}: {1} during connection attempt to {2}/openapi/v1/applications/{3}/details.\n".format( resp.status_code, resp.reason, api_endpoint, app['id'])) app_details = json.loads(resp.content) app_details['app_scope_name'] = [x['name'] for x in scopes if x['id'] == app['app_scope_id']][0] f.write('---\n') oyaml.dump(app_details, f, allow_unicode=True, encoding='utf-8') f.write('\n') result["ansible_facts"] = {'Output':os.path.join(os.getcwd(),dest)} result['changed'] = False return (0, result)
def get_app_scope( scope_id, host=env.TET.get("host"), api_key=env.TET_API_KEY, api_sec=env.TET_SEC ): # Build URL url = f"https://{host}" restclient = RestClient(url, api_key=api_key, api_secret=api_sec, verify=True) # HTTP Get Request response = restclient.get(f"/app_scopes/{scope_id}") # If response code is 200, then return the json response if response.status_code == 200: # JSON Response application_scope = response.json() return application_scope # If response code is anything but 200, print error message with response code else: print(f"Application Scope ID {scope_id} can not be found. Error code {response.status_code}.")
def search_inventory(value, host=env.TET.get("host"), api_key=env.TET_API_KEY, api_sec=env.TET_SEC): # Build URL url = f"https://{host}" restclient = RestClient(url, api_key=api_key, api_secret=api_sec, verify=True) payload = {"filter": {"type": "eq", "field": "ip", "value": value}} # HTTP Get Request response = restclient.post("/inventory/search", json_body=json.dumps(payload)) # If response code is 200, then return the json response if response.status_code == 200: # JSON Response inventory = response.json() if inventory["results"]: return inventory else: print(f"\nERROR: IP Address {value} can not be found.") exit() # If response code is anything but 200, print error message with response code else: print(f"\nSomething went wrong. Error code {response.status_code}.") exit()
def get_reg_token(): OUTPUT_TOKEN_FILE = 'registration.token' print("") app_scope = input( " Enter application scope name for this agent to register with: ") host = env.TET.get("host") api_key = env.TET_API_KEY api_sec = env.TET_SEC # Build URL url = f"https://{host}" restclient = RestClient(url, api_key=api_key, api_secret=api_sec, verify=True) resp = restclient.get('/secureconnector/name/{}/token'.format(app_scope)) if resp.status_code != 200: print("Error ({}): {}".format(resp.status_code, resp.content.decode())) sys.exit(1) else: with open(OUTPUT_TOKEN_FILE, 'w') as f: token_str = str(resp.content.decode()) f.write(token_str) print(" Agent registration token retrieved. Filename: " + OUTPUT_TOKEN_FILE)
def upload_tags(workspaces, action): restclient = RestClient( tetration_url, api_key=tetration_api_key, api_secret=tetration_api_secret, verify=False) with NamedTemporaryFile() as tf: with open(tf.name, 'w') as temp_csv: writer = csv.DictWriter(temp_csv, fieldnames=fields) writer.writeheader() for data in workspaces: writer.writerow(data) temp_csv.seek(0) req_payload = [ MultiPartOption( key='X-Tetration-Oper', val=action) ] resp = restclient.upload( temp_csv.name, '/openapi/v1/assets/cmdb/upload/{}'.format( tetration_tenant), req_payload) if resp.ok: print("Uploaded {} Annotations \n Action: {}".format( len(workspaces), action)) else: print("Failed to Upload Annotations") print(resp.text)
def delete_tags(workspaces, action): print('Deleting tags...') to_delete = [] for item in workspaces: to_delete.append({ 'ip': item['ip'], 'Cloud Service': item['user_Cloud Service'] }) restclient = RestClient(tetration_url, api_key=tetration_api_key, api_secret=tetration_api_secret, verify=False) with NamedTemporaryFile() as tf: with open(tf.name, 'w') as temp_csv: writer = csv.DictWriter(temp_csv, fieldnames=['ip', 'Cloud Service']) writer.writeheader() for data in to_delete: writer.writerow(data) temp_csv.seek(0) req_payload = [MultiPartOption(key='X-Tetration-Oper', val=action)] resp = restclient.upload( temp_csv.name, '/openapi/v1/assets/cmdb/upload/{}'.format(tetration_tenant), req_payload) if resp.ok: print("INFO: Deleted {} Annotations".format(len(workspaces))) else: print("ERROR: Failed to Upload Annotations") print(resp.text)
def get_sensors( host=env.TET.get("host"), api_key=env.TET_API_KEY, api_sec=env.TET_SEC): # Build URL url = f"https://{host}" restclient = RestClient(url, api_key=api_key, api_secret=api_sec, verify=True) # HTTP Get Request response = restclient.get("/sensors") # If successful response code return list sensors if response.status_code == 200: # print(json.dumps(response.json(), indent=2)) return response.json() # If response code is anything but 200, print error message with response code else: print( f"Error code: {response.status_code} getting sensors: {response.content}" )
def run(self, ids, **kwargs): """ Execute the 'tetration_scope' plugin NOTE: Ansible sends the non-keyword value as a list. The keyword arguments identify the Tetration host, credentials and SSL options Either specify the `api_secret` and `api_key` or use the `api_cfile` to specify a credential file By default, if not specified, SSL certification verification is disabled """ api_host = 'https://{}'.format(kwargs.get('api_host', '192.0.2.1')) api_verify = kwargs.get('api_verify', False) not_found = LookupModule.DEFAULT if kwargs.get('not_found'): not_found['short_name'] = not_found['name'] = kwargs.get( 'not_found') # Either specify api_secret = kwargs.get('api_secret', '') api_key = kwargs.get('api_key', '') # Or a JSON formatted credentials_file api_cfile = kwargs.get('api_cfile', '') display.vvv(u'Calling Tetration {} verify: {} scope_id: {}'.format( api_host, api_verify, ids)) if not api_verify: import requests requests.packages.urllib3.disable_warnings() # Verify we have non-keyword input try: ids[0] except IndexError: raise AnsibleError('the scope id or "all" must be specified') # Are credentials in a file or passed as a keyword argument? if api_cfile: restclient = RestClient(api_host, credentials_file=api_cfile, verify=api_verify) else: restclient = RestClient(api_host, api_key=api_key, api_secret=api_secret, verify=api_verify) # Do we want all scopes or specific ones? if ids[0].upper() == LookupModule.ALL: return self.all_scopes(restclient) else: return self.specific_scopes(restclient, ids, not_found)
def __init__(self, host="192.0.2.1", credentials="./credentials.json", transport=TRANSPORT): self.transport = transport self.api_endpoint = self.transport + host self.credential_file = credentials self.response = None self.inventory = {"_meta": {"hostvars": {}}} # Empty inventory self.restclient = RestClient(self.api_endpoint, verify=False, credentials_file=self.credential_file)
def dump_application_revisions( endpoint, username, password): restclient = RestClient( endpoint +'/', credentials_file='api_cred.json', verify=False) apps = [] resp = restclient.get('/applications') if resp.status_code == 200 : respbody = json.loads(resp.text) with open('public/data/all.json', 'w+') as appf: appf.write( resp.text) respbody = json.loads( resp.text) for app in respbody: appnames = {} appnames['id'] = str(app['id']) appnames['name'] = str(app['name']) #version changed after 2.3+ try: appnames['version'] = str(app['version']) except KeyError as ke: appnames['version'] = str(app['latest_adm_version']) apps.append( appnames) # go to the tetration login page driver.get(endpoint) ids = ['h4_user_email', 'h4_user_password'] vals = [ username, password] for idx, eid in enumerate(ids): element = driver.find_element_by_id( eid) element.send_keys( vals[idx]) submit_btn = driver.find_element_by_name('commit') submit_btn.click() # just give a time to get data time.sleep(10) el = driver.find_element_by_name('csrf-token') newheader = {'X-CSRF-Token': el.get_attribute('content'), 'Referer': endpoint +'/'} scookie = driver.get_cookies() newcookies = {} for x in scookie: newcookies[ x['name']] = x['value'] payload= {'clusters_only': 'false'} # extract all revision data fro each application for app in apps: for x in range(1, int(app['version'])): resp = requests.post('{0}/api/data_sets/{1}/download.json?version={2}'.format(endpoint, app['id'], x), headers = newheader, cookies=newcookies, json=payload, verify=False) newcookies = resp.cookies json_body = resp.json() with open('public/data/{0}/{1}.json'.format(app['id'], x), "w+") as outf: outf.write( json.dumps(json_body))
def run(self, app_names, **kwargs): """ Execute the 'tetration_cluster' plugin NOTE: Ansible sends the non-keyword value as a list. The keyword arguments identify the Tetration host, credentials and SSL options Either specify the `api_secret` and `api_key` or use the `api_cfile` to specify a credential file By default, if not specified, SSL certification verification is disabled """ api_host = 'https://{}'.format(kwargs.get('api_host', '192.0.2.1')) api_verify = kwargs.get('api_verify', False) # Either specify api_secret = kwargs.get('api_secret', '') api_key = kwargs.get('api_key', '') # Or a JSON formatted credentials_file api_cfile = kwargs.get('api_cfile', '') display.vvv( u'Calling Tetration {} verify: {} application name: {}'.format( api_host, api_verify, app_names)) if not api_verify: import requests requests.packages.urllib3.disable_warnings() # Verify we have non-keyword input try: app_names[0] except IndexError: raise AnsibleError( 'one or more application names must be specified') # Are credentials in a file or passed as a keyword argument? if api_cfile: restclient = RestClient(api_host, credentials_file=api_cfile, verify=api_verify) else: restclient = RestClient(api_host, api_key=api_key, api_secret=api_secret, verify=api_verify) return self.clusters(restclient, app_names)
def get_rest_client(*args, **kwargs): ''' Returns an instance of infoblox_client.connector.Connector :params args: positional arguments are silently ignored :params kwargs: dict that is passed to Connector init :returns: Connector ''' if not HAS_TETRATION_CLIENT: raise Exception('tetpyclient is required but does not appear ' 'to be installed. It can be installed using the ' 'command `pip install tetpyclient`') if not set(kwargs.keys()).issubset(TETRATION_PROVIDER_SPEC.keys()): raise ValueError( 'invalid or unsupported keyword argument for connector') for key, value in iteritems(TETRATION_PROVIDER_SPEC): if key not in kwargs: # apply default values from NIOS_PROVIDER_SPEC since we cannot just # assume the provider values are coming from AnsibleModule if 'default' in value: kwargs[key] = value['default'] # override any values with env variables unless they were # explicitly set env = ('TETRATION_%s' % key).upper() if env in os.environ: kwargs[key] = os.environ.get(env) # if key is required but still not defined raise Exception if key not in kwargs and 'required' in value and value['required']: raise ValueError('option: %s is required' % key) return RestClient(**kwargs)
class Environment(object): def __init__(self,tetCluster,tetCreds): self._primaryApps = {} self._adjacentApps = {} self._scopes = {} self._restclient = RestClient(tetCluster, credentials_file=tetCreds, verify=False) @property def primaryApps(self): return self._primaryApps @property def adjacentApps(self): return self._adjacentApps @property def tetClient(self): return self._restclient @property def scopes(self): return self._scopes def addScope(self, scope_id): self._scopes['scope']=scope_id def loadPolicy(self, appIDs): #Load Policy JSON for appID in appIDs: appDetails = self._restclient.get('/openapi/v1/applications/%s/details'%appID).json() print('\nProcessing "%s"...'%appDetails['name']) self._primaryApps[appID] = App(environment=self,app_def=appDetails)
def CreateRestClient(): """create REST API connection to Tetration cluster Returns: REST Client """ rc = RestClient(args.url, credentials_file=args.credential, verify=False) return rc
def app_upload(hostname, api_key, api_secret, source, validate_certs): result = {"ansible_facts": {'result': []}} api_endpoint = 'https://{0}'.format(hostname) restclient = RestClient(api_endpoint, api_key=api_key, api_secret=api_secret, verify=validate_certs) app_list = [] with open(source, 'r') as f: for data in oyaml.load_all(f): app_list.append(data) for i, app in enumerate(app_list): exists = False if scope['parent_app_scope_name']: resp = restclient.get('/openapi/v1/app_scopes') if not resp.status_code == 200: return ( 1, "Error {0}: {1} during connection attempt to {2}/openapi/v1/app_scopes. \n" .format(resp.status_code, resp.reason, api_endpoint)) current_scopes = json.loads(resp.content) for current_scope in current_scopes: if current_scope['short_name'] == scope['short_name']: exists = True if not exists: scope['parent_app_scope_id'] = ParentIDLookup( current_scopes, scope['parent_app_scope_name']) scope.pop('parent_app_scope_name') print('Posting scope {0} to the cluster'.format( scope['short_name'])) resp = restclient.post('/openapi/v1/app_scopes', json_body=json.dumps(scope)) if not resp.status_code == 200: return (1, "Error {0}: {1} creating scope {2}. \n{3}".format( resp.status_code, resp.reason, scope['short_name'], resp.json())) result['ansible_facts']['result'].append(resp.json()) if result['ansible_facts']['result']: result['changed'] = True else: result['changed'] = False return (0, result)
def delete_terminated_agents(agents_to_delete): restclient = RestClient(tetration_url, api_key=tetration_api_key, api_secret=tetration_api_secret, verify=False) for agent in agents_to_delete: print('INFO: Deleting sensor with uuid: {}'.format(agent['host_uuid'])) resp = restclient.delete('/openapi/v1/sensors/{}'.format( agent['host_uuid'])) if resp.ok: print('INFO: Deleted sensor with uuid: {}'.format( agent['host_uuid'])) else: print("ERROR: Failed to Deleted sensor with uuid: {}".format( agent['host_uuid'])) print(resp.text)
def main(): """ Main routine to be executed """ # Get the CLI arguements args = get_parser().parse_args() if args.debug: print("\n\n") print("Credentials file: " + args.credentials) print("Tetration Platform: " + args.platform) print("\n\n") API_ENDPOINT = args.platform API_CREDENTIALS = args.credentials RC_SESSION = RestClient(API_ENDPOINT, credentials_file=API_CREDENTIALS, verify=False) requests.packages.urllib3.disable_warnings() try: sensors = get_sensors(RC_SESSION) # Print out all the data collected print("\n") print("Software Sensors") print( tabulate(sensors, headers=[ "UUID", "CPU Quota", "Platform", "Hostname", "Current SW Ver", "PID Lookup", "Agent Type" ], tablefmt="orgtbl")) my_hardware = get_hw_sensors(RC_SESSION) # Print out all the data collected print("\n") print("Hardware Sensors") print( tabulate(my_hardware, headers=[ "Name", "IP", "Last Check-in", "NX-OS Version", "Role", "Agent Version" ], tablefmt="orgtbl")) sw_summary = "Total Software Sensors: " + str(len(sensors)) print "=" * len(sw_summary) print sw_summary print "=" * len(sw_summary) hw_summary = "Total Hardware Sensors: " + str(len(my_hardware)) print "=" * len(hw_summary) print hw_summary print "=" * len(hw_summary) except Exception, err: print "Operation failed" print traceback.format_exc(err)
def connect(): # Check credentials file exists if os.path.exists(CRED_FILE) == False: sys.exit("Error! Credentials file is not present") requests.packages.urllib3.disable_warnings() # Class Constructor rc = RestClient(API_ENDPOINT, credentials_file=CRED_FILE, verify=False) return rc
def get_key_capability(url, api_key, api_secret): """ Returns the capabilities of a given API key as a list Keyword arguments: url -- https url of the Tetration GUI api_key -- Tetration API key to be tested api_secret -- Tetration API secret for given API key """ # Each API 'capability' is a key in the following dict and the value for # each key is *one* API endpoint that requires *only* that capability to # return a successful status code. api_map = { "user_role_scope_management": "/openapi/v1/roles", "flow_inventory_query": "/openapi/v1/flowsearch/dimensions", "hw_sensor_management": "/openapi/v1/switches", "app_policy_management": "/openapi/v1/applications", "sensor_management": "/openapi/v1/sensors", "user_data_upload": "/openapi/v1/assets/cmdb/download" } restclient = RestClient(url, api_key=api_key, api_secret=api_secret, verify=False) requests.packages.urllib3.disable_warnings() # step through each capability and test the API endpoint associated with # it; if we get a status_code of 200, then add it to the list of # capabilities of the API key we are testing return_list = [] for capability, endpoint in api_map.iteritems(): try: resp = restclient.get(endpoint) if resp.status_code == 200: return_list.append(capability) except: pass return [str(x) for x in return_list]
def __init__(self, endpoint, api_key, api_secret, pigeon, options, tenant_app_scope="Default"): self.rc = RestClient(endpoint, api_key=api_key, api_secret=api_secret, verify=False) self.scopes = [] self.pigeon = pigeon self.inventory = self.Inventory() self.filters = {} self.options = options self.subnets = [] self.boolean = Boolean_Helper() self.tenant_app_scope = tenant_app_scope
def upload_server_port_config(endpoint, file_path, scope_name): restclient = RestClient(endpoint, credentials_file='api_key.json', verify=False) scope_id = get_scope_id(restclient, scope_name) if scope_id is not None and os.path.exists(file_path): req_payload = [MultiPartOption(key='X-Tetration-Oper', val='add')] resp = restclient.upload( file_path, '/openapi/v1/adm/{0}/server_ports'.format(scope_id), req_payload, timeout=200) # seconds print(resp, resp.text) else: print( 'Wrong scope name {0} or server ports config file {1} does not exist' .format(scope_name, file_path))
def upload(hostname,api_key,api_secret,source,validate_certs,owner_scope_id): result = {"ansible_facts": {}} api_endpoint = 'https://{0}'.format(hostname) restclient = RestClient(api_endpoint, api_key=api_key, api_secret=api_secret, verify=validate_certs) filter_list = [] with open(source, 'r') as f: for data in oyaml.load_all(f): filter_list.append(data) for filter in filter_list: filter['app_scope_id'] = owner_scope_id filter.pop('id') filter.pop('_id') resp = restclient.post('/openapi/v1/filters/inventories', json_body=json.dumps(filter)) if not resp.status_code == 200: return (1, "Error {0}: {1} during connection attempt to {2}/openapi/v1/filters/inventories. \n{3}".format(resp.status_code, resp.reason,api_endpoint,resp.json())) result['changed'] = True return (0, result)