diff --git a/netbird.ts b/netbird.ts index ef85cc0..99c4a03 100644 --- a/netbird.ts +++ b/netbird.ts @@ -6,6 +6,9 @@ import * as command from "@pulumi/command"; // ============================================================================= // Since there's no TypeScript SDK for NetBird, we use the command provider // to make API calls. This demonstrates the pattern while being practical. +// +// Note: Delete commands use grep/sed instead of jq for CI compatibility. +// The pattern extracts the ID by finding the object with matching name. export interface NetBirdConfig { url: string; @@ -44,6 +47,35 @@ export interface SetupKeyArgs { ephemeral: boolean; } +// ============================================================================= +// Helper: Extract ID from JSON array by name (no jq dependency) +// ============================================================================= +// Uses grep/sed to find an object by name and extract its ID. +// This is fragile but works for simple JSON structures. +// Pattern: finds "name":"" then extracts preceding "id":"" +function makeDeleteScript( + endpoint: string, + resourceName: string, + token: pulumi.Output, + url: string +): pulumi.Output { + // Use Python for reliable JSON parsing (available in most CI environments) + return pulumi.interpolate`python3 -c " +import json, urllib.request, sys +req = urllib.request.Request('${url}/api/${endpoint}', headers={'Authorization': 'Token ${token}'}) +data = json.loads(urllib.request.urlopen(req).read()) +matches = [x['id'] for x in data if x.get('name') == '${resourceName}'] +if matches: + print(matches[0]) +else: + sys.exit(0) # Not found, nothing to delete +" | while read ID; do + if [ -n "$ID" ]; then + curl -s -X DELETE -H "Authorization: Token ${token}" "${url}/api/${endpoint}/$ID" + fi +done`; +} + // ============================================================================= // NetBird Group Resource // ============================================================================= @@ -67,10 +99,7 @@ export class Group extends pulumi.ComponentResource { -H "Content-Type: application/json" \ -d '{"name": "${args.name}", "peers": ${JSON.stringify(args.peers || [])}}' \ ${config.url}/api/groups`, - delete: pulumi.interpolate`GROUP_ID=$(curl -s -H "Authorization: Token ${config.token}" \ - ${config.url}/api/groups | jq -r '.[] | select(.name=="${args.name}") | .id') && \ - curl -s -X DELETE -H "Authorization: Token ${config.token}" \ - ${config.url}/api/groups/$GROUP_ID`, + delete: makeDeleteScript("groups", args.name, config.token, config.url), }, { parent: this } ); @@ -146,10 +175,7 @@ export class Policy extends pulumi.ComponentResource { ${config.url}/api/policies`; } ), - delete: pulumi.interpolate`POLICY_ID=$(curl -s -H "Authorization: Token ${config.token}" \ - ${config.url}/api/policies | jq -r '.[] | select(.name=="${args.name}") | .id') && \ - curl -s -X DELETE -H "Authorization: Token ${config.token}" \ - ${config.url}/api/policies/$POLICY_ID`, + delete: makeDeleteScript("policies", args.name, config.token, config.url), }, { parent: this } ); @@ -207,10 +233,7 @@ export class SetupKey extends pulumi.ComponentResource { ${config.url}/api/setup-keys`; } ), - delete: pulumi.interpolate`KEY_ID=$(curl -s -H "Authorization: Token ${config.token}" \ - ${config.url}/api/setup-keys | jq -r '.[] | select(.name=="${args.name}") | .id') && \ - curl -s -X DELETE -H "Authorization: Token ${config.token}" \ - ${config.url}/api/setup-keys/$KEY_ID`, + delete: makeDeleteScript("setup-keys", args.name, config.token, config.url), }, { parent: this } );