network/gaiia/daily_preseem_sync_workflow.json
2026-07-19 14:42:02 -05:00

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" }]
}
]
}