83 lines
4.4 KiB
JSON
83 lines
4.4 KiB
JSON
{
|
|
"name": "Daily Preseem Site Inventory Sync",
|
|
"description": "SCHEDULED (daily 3am): Iterates all network sites, extracts MACs from assigned equipment fields, syncs each item to Preseem access points with its site name as tower.",
|
|
"trigger": {
|
|
"type": "SCHEDULE",
|
|
"cron": "0 3 * * *",
|
|
"nextSteps": [{ "slug": "fetch-sites" }]
|
|
},
|
|
"steps": [
|
|
{
|
|
"name": "Fetch all network sites with assigned equipment",
|
|
"slug": "fetch-sites",
|
|
"type": "GAIIA_API_GATEWAY_V1_GRAPHQL_REQUEST",
|
|
"nodeSlug": "gaiia-public-api-gateway-graphql-request",
|
|
"allowSkipExecution": false,
|
|
"outputMapper": "({ output }) => {\n const sites = output.response.networkSites.nodes;\n const items = [];\n for (const site of sites) {\n for (const assign of (site.assignedInventoryItems?.nodes || [])) {\n const inv = assign.inventoryItem || {};\n const model = inv.model?.name || '';\n // Extract MAC from any field whose name contains 'mac' (case-insensitive)\n const macs = [];\n for (const f of (inv.fields?.nodes || [])) {\n const fieldName = (f.modelField?.name || '').toLowerCase();\n const data = (f.data || '').trim();\n if (fieldName.includes('mac') && data && data !== '00:00:00:00:00:00') {\n // Normalize MAC: strip '1:' prefix, pad segments, uppercase\n const cleaned = data.startsWith('1:') ? data.slice(2) : data;\n const parts = cleaned.split(':');\n if (parts.length === 6) {\n const normalized = parts\n .map((p) => p.padStart(2, '0').toUpperCase())\n .join(':');\n macs.push(normalized);\n }\n }\n }\n if (macs.length > 0) {\n items.push({\n inventoryId: inv.id,\n model,\n siteName: site.name,\n macs: [...new Set(macs)]\n });\n }\n }\n }\n return items;\n}",
|
|
"inputs": [
|
|
{
|
|
"key": "query",
|
|
"type": "LITERAL",
|
|
"value": "string:query {\n networkSites(first: 250) {\n nodes {\n id\n name\n assignedInventoryItems {\n nodes {\n inventoryItem {\n id\n model { name }\n ipAddressV4\n fields {\n nodes { data modelField { name } }\n }\n }\n }\n }\n }\n }\n}"
|
|
},
|
|
{
|
|
"key": "variables",
|
|
"type": "FUNCTION",
|
|
"value": "({ secrets, state, utils, variables }) => ({})"
|
|
}
|
|
],
|
|
"nextSteps": [{ "slug": "if-any-items" }]
|
|
},
|
|
{
|
|
"name": "Any items to sync?",
|
|
"slug": "if-any-items",
|
|
"type": "CONDITION",
|
|
"nodeSlug": "condition",
|
|
"condition": "({ secrets, state, utils, variables }) => {\n const items = state.steps['fetch-sites'].output;\n return Array.isArray(items) && items.length > 0;\n}",
|
|
"elseSteps": [{ "slug": "end" }],
|
|
"thenSteps": [{ "slug": "sync-to-preseem" }]
|
|
},
|
|
{
|
|
"name": "Sync each item to Preseem",
|
|
"slug": "sync-to-preseem",
|
|
"type": "PARALLEL_LOOP",
|
|
"nodeSlug": "parallel-loop",
|
|
"maxConcurrentIterations": 10,
|
|
"inputs": [
|
|
{
|
|
"key": "iterable",
|
|
"type": "FUNCTION",
|
|
"value": "({ state }) => state.steps['fetch-sites'].output"
|
|
}
|
|
],
|
|
"initialSteps": [{ "slug": "preseem-put-ap" }],
|
|
"nextSteps": [{ "slug": "end" }]
|
|
},
|
|
{
|
|
"name": "PUT to Preseem access points",
|
|
"slug": "preseem-put-ap",
|
|
"type": "PRESEEM_REST_REQUEST",
|
|
"nodeSlug": "preseem-rest-request",
|
|
"parentParallelLoopSlug": "sync-to-preseem",
|
|
"allowSkipExecution": false,
|
|
"inputs": [
|
|
{
|
|
"key": "method",
|
|
"type": "LITERAL",
|
|
"value": "string:PUT"
|
|
},
|
|
{
|
|
"key": "path",
|
|
"type": "FUNCTION",
|
|
"value": "({ state }) => {\n const item = state.currentParallelLoopIterations['sync-to-preseem'];\n return `/access_points/${item.inventoryId}`;\n}"
|
|
},
|
|
{
|
|
"key": "body",
|
|
"type": "FUNCTION",
|
|
"value": "({ state }) => {\n const item = state.currentParallelLoopIterations['sync-to-preseem'];\n return {\n id: item.inventoryId,\n name: `${item.model} (${item.macs[0]})`,\n tower: item.siteName\n };\n}"
|
|
}
|
|
],
|
|
"nextSteps": [{ "slug": "sync-to-preseem-end" }]
|
|
}
|
|
]
|
|
}
|