Initial Pulumi Typescript implementation
Some checks failed
Pulumi / pulumi (push) Failing after 1m17s
Some checks failed
Pulumi / pulumi (push) Failing after 1m17s
This commit is contained in:
244
netbird.ts
Normal file
244
netbird.ts
Normal file
@@ -0,0 +1,244 @@
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as command from "@pulumi/command";
|
||||
|
||||
// =============================================================================
|
||||
// NetBird API Client using Pulumi Command Provider
|
||||
// =============================================================================
|
||||
// Since there's no TypeScript SDK for NetBird, we use the command provider
|
||||
// to make API calls. This demonstrates the pattern while being practical.
|
||||
|
||||
export interface NetBirdConfig {
|
||||
url: string;
|
||||
token: pulumi.Output<string>;
|
||||
}
|
||||
|
||||
export interface GroupArgs {
|
||||
name: string;
|
||||
peers?: string[];
|
||||
}
|
||||
|
||||
export interface PolicyRuleArgs {
|
||||
name: string;
|
||||
description?: string;
|
||||
enabled: boolean;
|
||||
sources: pulumi.Input<string>[];
|
||||
destinations: pulumi.Input<string>[];
|
||||
bidirectional: boolean;
|
||||
protocol: string;
|
||||
action: "accept" | "drop";
|
||||
}
|
||||
|
||||
export interface PolicyArgs {
|
||||
name: string;
|
||||
description?: string;
|
||||
enabled: boolean;
|
||||
rules: PolicyRuleArgs[];
|
||||
}
|
||||
|
||||
export interface SetupKeyArgs {
|
||||
name: string;
|
||||
type: "one-off" | "reusable";
|
||||
autoGroups: pulumi.Input<string>[];
|
||||
usageLimit: number;
|
||||
expiresIn: number;
|
||||
ephemeral: boolean;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// NetBird Group Resource
|
||||
// =============================================================================
|
||||
export class Group extends pulumi.ComponentResource {
|
||||
public readonly id: pulumi.Output<string>;
|
||||
public readonly name: string;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: GroupArgs,
|
||||
config: NetBirdConfig,
|
||||
opts?: pulumi.ComponentResourceOptions
|
||||
) {
|
||||
super("netbird:custom:Group", name, {}, opts);
|
||||
|
||||
const createCmd = new command.local.Command(
|
||||
`${name}-create`,
|
||||
{
|
||||
create: pulumi.interpolate`curl -s -X POST \
|
||||
-H "Authorization: Token ${config.token}" \
|
||||
-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`,
|
||||
},
|
||||
{ parent: this }
|
||||
);
|
||||
|
||||
this.id = createCmd.stdout.apply((stdout): string => {
|
||||
try {
|
||||
const result = JSON.parse(stdout);
|
||||
return result.id || "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
this.name = args.name;
|
||||
|
||||
this.registerOutputs({
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// NetBird Policy Resource
|
||||
// =============================================================================
|
||||
export class Policy extends pulumi.ComponentResource {
|
||||
public readonly id: pulumi.Output<string>;
|
||||
public readonly name: string;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: PolicyArgs,
|
||||
config: NetBirdConfig,
|
||||
opts?: pulumi.ComponentResourceOptions
|
||||
) {
|
||||
super("netbird:custom:Policy", name, {}, opts);
|
||||
|
||||
// Build the policy payload
|
||||
const rules = args.rules.map((rule) => ({
|
||||
name: rule.name,
|
||||
description: rule.description || "",
|
||||
enabled: rule.enabled,
|
||||
sources: rule.sources,
|
||||
destinations: rule.destinations,
|
||||
bidirectional: rule.bidirectional,
|
||||
protocol: rule.protocol,
|
||||
action: rule.action,
|
||||
}));
|
||||
|
||||
const createCmd = new command.local.Command(
|
||||
`${name}-create`,
|
||||
{
|
||||
create: pulumi.all([config.token, ...args.rules.flatMap(r => [...r.sources, ...r.destinations])]).apply(
|
||||
([token, ...groupIds]) => {
|
||||
const payload = {
|
||||
name: args.name,
|
||||
description: args.description || "",
|
||||
enabled: args.enabled,
|
||||
rules: args.rules.map((rule, i) => ({
|
||||
name: rule.name,
|
||||
description: rule.description || "",
|
||||
enabled: rule.enabled,
|
||||
sources: rule.sources,
|
||||
destinations: rule.destinations,
|
||||
bidirectional: rule.bidirectional,
|
||||
protocol: rule.protocol,
|
||||
action: rule.action,
|
||||
})),
|
||||
};
|
||||
return `curl -s -X POST \
|
||||
-H "Authorization: Token ${token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '${JSON.stringify(payload)}' \
|
||||
${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`,
|
||||
},
|
||||
{ parent: this }
|
||||
);
|
||||
|
||||
this.id = createCmd.stdout.apply((stdout): string => {
|
||||
try {
|
||||
const result = JSON.parse(stdout);
|
||||
return result.id || "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
this.name = args.name;
|
||||
|
||||
this.registerOutputs({
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// NetBird Setup Key Resource
|
||||
// =============================================================================
|
||||
export class SetupKey extends pulumi.ComponentResource {
|
||||
public readonly id: pulumi.Output<string>;
|
||||
public readonly key: pulumi.Output<string>;
|
||||
public readonly name: string;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: SetupKeyArgs,
|
||||
config: NetBirdConfig,
|
||||
opts?: pulumi.ComponentResourceOptions
|
||||
) {
|
||||
super("netbird:custom:SetupKey", name, {}, opts);
|
||||
|
||||
const createCmd = new command.local.Command(
|
||||
`${name}-create`,
|
||||
{
|
||||
create: pulumi.all([config.token, ...args.autoGroups]).apply(
|
||||
([token, ...groupIds]) => {
|
||||
const payload = {
|
||||
name: args.name,
|
||||
type: args.type,
|
||||
auto_groups: groupIds,
|
||||
usage_limit: args.usageLimit,
|
||||
expires_in: args.expiresIn,
|
||||
ephemeral: args.ephemeral,
|
||||
};
|
||||
return `curl -s -X POST \
|
||||
-H "Authorization: Token ${token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '${JSON.stringify(payload)}' \
|
||||
${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`,
|
||||
},
|
||||
{ parent: this }
|
||||
);
|
||||
|
||||
this.id = createCmd.stdout.apply((stdout): string => {
|
||||
try {
|
||||
const result = JSON.parse(stdout);
|
||||
return result.id || "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
this.key = createCmd.stdout.apply((stdout): string => {
|
||||
try {
|
||||
const result = JSON.parse(stdout);
|
||||
return result.key || "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
this.name = args.name;
|
||||
|
||||
this.registerOutputs({
|
||||
id: this.id,
|
||||
key: this.key,
|
||||
name: this.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user