End-to-End Workflow
AIM License Required
Application Infrastructure Mapping (AIM) is a premium add-on. The features described here are available only when the uploaded product license has the AIM feature enabled – see go.ipfabric.io/aim for what it covers.
To get started with AIM, contact your Customer Success Manager or email support.ipfabric.io, then upload the reissued license file.
The two AIM endpoints described in
Overview are asynchronous: each one
schedules a background job and returns a jobId. A complete integration
therefore combines them with the Jobs table and the AIM inventory tables:
- Import the CSV files –
POST /aim/import/{snapshotId}. - Poll the import job until it finishes –
POST /tables/jobs. - Look up the application or flow ID –
POST /tables/inventory/applicationsorPOST /tables/inventory/applications/flows. - Calculate the path lookups –
POST /aim/flow-path-lookups/{snapshotId}. - Poll the path-lookup job until it finishes –
POST /tables/jobs. - Read the results –
POST /tables/inventory/applications/devices.
Design the sequence to be repeatable
Data ingested through POST /aim/import/{snapshotId} is not persisted in the
snapshot, so unloading and loading that snapshot discards it and the sequence
has to run again. Both endpoints are safe to re-run – the import merges on
the keys in your CSV files, and calculated flows are skipped – so the whole
script can simply be executed a second time. See
Imported Data Does Not Survive a Snapshot Reload
for the alternative that persists.
Supporting API Endpoints
Beyond the two AIM endpoints, the workflow uses the Jobs table to track progress and the AIM inventory tables to read the results:
/api/tables/jobs– aPOSTmethod to poll the status of scheduled jobs. Documented on this page./api/tables/inventory/applications,.../workloads,.../flows, and.../devices–POSTmethods to read the ingested data. For their columns, request fields, and response examples, see AIM Inventory Tables.
Headers must contain Content-Type: application/json and X-API-Token:. See
Authentication for alternatives.
Monitoring the Job
Poll the jobId returned by either AIM endpoint through the Jobs table until
isDone is true.
POST /api/tables/jobs
Content-Type: application/json
Warning
The Jobs table is not snapshot-scoped – do not include a snapshot key
in the request body, or the request is rejected.
Polling a Job
curl -X POST 'https://{ipf_server}/api/tables/jobs' \
--header 'Content-Type: application/json' \
--header 'X-API-Token: {api_token}' \
-d '{
"columns": ["id","name","status","isDone","startedAt","finishedAt","reason","snapshot","username"],
"filters": { "id": ["eq", "184"] },
"pagination": { "limit": 1, "start": 0 }
}'
{
"data": [
{
"id": "184",
"name": "aimFlowPathLookup",
"status": "done",
"isDone": true,
"startedAt": 1787065241653,
"finishedAt": 1787065241909,
"reason": null,
"snapshot": "8366fec8-da3e-4635-9cb3-97008ca6435b",
"username": "admin"
}
],
"_meta": { "limit": 1, "start": 0, "count": 1, "size": 1 }
}
The name column identifies the job type: aimCsvImport for the import and
aimFlowPathLookup for the path-lookup calculation. Timestamps are Unix
milliseconds.
Finding a job without its ID
If you lose the jobId, filter on the action name instead and sort by
schedule time – for example
"filters": { "name": ["eq", "aimCsvImport"] } with
"sort": { "column": "scheduledAt", "order": "desc" }.
Job Status Values
Poll until isDone is true, then branch on status:
status |
Meaning |
|---|---|
scheduled |
Queued, not started yet. |
running |
In progress. |
done |
Completed successfully. |
error |
Failed. reason contains the cause. |
cancelled |
Cancelled before completion. |
stopping |
Stop requested. |
stopped |
Stopped by a user. |
Reading Validation Errors
When a CSV fails validation, the job ends with status: "error" and reason
holds a JSON-encoded object pinpointing the offending row:
{
"file": "workloads.csv",
"row": 3,
"message": "enforcementMode: Invalid enum value. Expected 'visibility_only' | 'selective' | 'full' | 'idle' | 'unknown', received 'strict'"
}
row counts the header as row 1, so row: 3 is the second data row. It is
null for errors that are not tied to a specific row, such as an unresolved
cross-file reference.
Follow-up jobs after a successful import
A successful import also schedules the standard post-processing jobs for the
snapshot, such as topology calculation and intent verification. These appear
as separate entries in the Jobs table. They do not block the path-lookup
calculation, so you can proceed as soon as the aimCsvImport job reports
done.
Reading the Results
The four AIM inventory tables – their columns, request fields, and response examples – are documented in AIM Inventory Tables. This section covers only what the workflow needs from each of them.
| Purpose | Table | What to read |
|---|---|---|
| Verify the import | Applications | flows and workloads should match your CSV row counts. dataSourceName confirms the data came from the manual source. |
Obtain an applicationId |
Applications | The id column. flowsCalculated shows how many of the application’s flows already have a result. |
Obtain a flowId |
Flows | The id column. Filter on "pathLookupsCalculationStatus": ["eq", false] to list only the flows still needing a calculation. |
| Inspect workload interfaces | Workloads | workloadInterface holds one interface address per row. |
| Confirm the outcome | Devices | hostname and sn of each traversed device. Filter on flowId for one flow’s devices, or de-duplicate on sn for a unique device list. |
After a successful calculation, re-reading the Applications table is the quickest
confirmation: flowsCalculated and devices should both have increased.
Complete Example Script
The following script imports the CSV files, waits for the import to finish, calculates the path lookups for one application, waits again, and lists the resulting devices.
Complete Workflow
#!/usr/bin/env bash
set -euo pipefail
IPF_SERVER="ipfabric.example.com"
IPF_TOKEN="{api_token}"
SNAPSHOT="{snapshotId}"
CSV_DIR="./aim-data"
api() {
curl -sk -X POST "https://${IPF_SERVER}/api/$1" \
-H "X-API-Token: ${IPF_TOKEN}" \
-H 'Content-Type: application/json' \
-d "$2"
}
# Wait until a job reaches a terminal state; fail on a non-"done" outcome.
wait_for_job() {
local job_id="$1" result status
while :; do
result=$(api "tables/jobs" "{
\"columns\":[\"id\",\"name\",\"status\",\"isDone\",\"reason\"],
\"filters\":{\"id\":[\"eq\",\"${job_id}\"]},
\"pagination\":{\"limit\":1,\"start\":0}}")
[ "$(echo "$result" | jq -r '.data[0].isDone')" = "true" ] && break
sleep 3
done
status=$(echo "$result" | jq -r '.data[0].status')
if [ "$status" != "done" ]; then
echo "Job ${job_id} finished with status '${status}':" >&2
echo "$result" | jq -r '.data[0].reason' >&2
return 1
fi
echo "Job ${job_id} completed."
}
# 1. Import the CSV files.
import_job=$(curl -sk -X POST \
"https://${IPF_SERVER}/api/aim/import/${SNAPSHOT}" \
-H "X-API-Token: ${IPF_TOKEN}" \
-F "applications=@${CSV_DIR}/applications.csv;type=text/csv" \
-F "workloads=@${CSV_DIR}/workloads.csv;type=text/csv" \
-F "interfaces=@${CSV_DIR}/interfaces.csv;type=text/csv" \
-F "flows=@${CSV_DIR}/flows.csv;type=text/csv" | jq -r .jobId)
echo "Import job: ${import_job}"
wait_for_job "$import_job"
# 2. Resolve the application ID from its externalId.
app_id=$(api "tables/inventory/applications" "{
\"columns\":[\"id\",\"name\",\"externalId\"],
\"filters\":{\"externalId\":[\"eq\",\"app-001\"]},
\"snapshot\":\"${SNAPSHOT}\",
\"pagination\":{\"limit\":1,\"start\":0}}" | jq -r '.data[0].id')
echo "Application ID: ${app_id}"
# 3. Calculate the path lookups for that application.
lookup_job=$(curl -sk -X POST \
"https://${IPF_SERVER}/api/aim/flow-path-lookups/${SNAPSHOT}" \
-H "X-API-Token: ${IPF_TOKEN}" -H 'Content-Type: application/json' \
-d "{\"applicationId\":\"${app_id}\"}" | jq -r .jobId)
echo "Path-lookup job: ${lookup_job}"
wait_for_job "$lookup_job"
# 4. List the resulting devices.
api "tables/inventory/applications/devices" "{
\"columns\":[\"hostname\",\"sn\",\"srcApplicationName\",\"dstApplicationName\",\"applicationFlow\"],
\"snapshot\":\"${SNAPSHOT}\",
\"pagination\":{\"limit\":100,\"start\":0}}" | jq
Troubleshooting
| Symptom | Cause and resolution |
|---|---|
400 -- At least one file must be provided |
No file part was received. Send at least one CSV as multipart/form-data, and do not set Content-Type manually. |
403 on either AIM endpoint |
Missing AIM license, or the API token’s policy does not cover the endpoint. |
404 on the path-lookup endpoint, but the snapshot exists |
The snapshot is not loaded. Path lookups need the snapshot’s routing data. |
413 |
A file exceeds 50 MB. Split it and import in several requests. |
Import job status: "error" |
Read reason for the file, row, and message. Fix that row and re-import – the merge behavior makes retries safe. |
Import succeeded but the Applications devices count is 0 |
Expected. Run the path-lookup calculation. |
Flows devices is empty rather than a number |
That flow has no path-lookup result yet. On the Flows table such a flow returns null, not 0; check pathLookupsCalculationStatus for the state. |
Path lookup done but devices is still 0 |
The flow’s addresses do not trace a path in this snapshot. flowsCalculated and pathLookupsCalculationStatus still advance, because a result is recorded even when no device is traversed. Verify that srcIp and dstIp exist in the snapshot’s routing tables. |
| Workload interfaces disappeared after an import | workloads.csv was uploaded without interfaces.csv. Re-send both files together. |
| All imported AIM data gone after unloading and loading the snapshot | Expected. Data ingested through /aim/import is written to the inventory tables only and is not persisted in the snapshot, so a reload discards it. Run the sequence again, or use the settings-based CSV import for data that has to survive a reload – see Imported Data Does Not Survive a Snapshot Reload. |
Request to /api/v8.1/aim/... returns 404 |
API paths are not version-prefixed. Use /api/aim/... and select the version with the X-API-Version header. |