@tyevco/pulumi-homelab 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/composeDiff.d.ts +16 -0
- package/dist/composeDiff.js +171 -0
- package/dist/composeDiff.js.map +1 -0
- package/dist/dockgeClient.d.ts +67 -0
- package/dist/dockgeClient.js +152 -0
- package/dist/dockgeClient.js.map +1 -0
- package/dist/envDiff.d.ts +5 -0
- package/dist/envDiff.js +45 -0
- package/dist/envDiff.js.map +1 -0
- package/dist/helpers.d.ts +28 -0
- package/dist/helpers.js +113 -0
- package/dist/helpers.js.map +1 -0
- package/dist/homelabClient.d.ts +103 -0
- package/dist/homelabClient.js +202 -0
- package/dist/homelabClient.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js.map +1 -0
- package/dist/opnsenseClient.d.ts +142 -0
- package/dist/opnsenseClient.js +592 -0
- package/dist/opnsenseClient.js.map +1 -0
- package/dist/provider.d.ts +7 -0
- package/dist/provider.js +118 -0
- package/dist/provider.js.map +1 -0
- package/dist/resources/dockgeStack.d.ts +1 -0
- package/dist/resources/dockgeStack.js +7 -0
- package/dist/resources/dockgeStack.js.map +1 -0
- package/dist/resources/lxcContainer.d.ts +9 -0
- package/dist/resources/lxcContainer.js +286 -0
- package/dist/resources/lxcContainer.js.map +1 -0
- package/dist/resources/notificationSettings.d.ts +9 -0
- package/dist/resources/notificationSettings.js +171 -0
- package/dist/resources/notificationSettings.js.map +1 -0
- package/dist/resources/opnsenseAlias.d.ts +9 -0
- package/dist/resources/opnsenseAlias.js +188 -0
- package/dist/resources/opnsenseAlias.js.map +1 -0
- package/dist/resources/opnsenseFirewallRule.d.ts +9 -0
- package/dist/resources/opnsenseFirewallRule.js +208 -0
- package/dist/resources/opnsenseFirewallRule.js.map +1 -0
- package/dist/resources/opnsenseUnboundAcl.d.ts +9 -0
- package/dist/resources/opnsenseUnboundAcl.js +193 -0
- package/dist/resources/opnsenseUnboundAcl.js.map +1 -0
- package/dist/resources/opnsenseUnboundDnsbl.d.ts +9 -0
- package/dist/resources/opnsenseUnboundDnsbl.js +186 -0
- package/dist/resources/opnsenseUnboundDnsbl.js.map +1 -0
- package/dist/resources/opnsenseUnboundForward.d.ts +9 -0
- package/dist/resources/opnsenseUnboundForward.js +195 -0
- package/dist/resources/opnsenseUnboundForward.js.map +1 -0
- package/dist/resources/opnsenseUnboundHostOverride.d.ts +9 -0
- package/dist/resources/opnsenseUnboundHostOverride.js +193 -0
- package/dist/resources/opnsenseUnboundHostOverride.js.map +1 -0
- package/dist/resources/stack.d.ts +9 -0
- package/dist/resources/stack.js +314 -0
- package/dist/resources/stack.js.map +1 -0
- package/dist/resources/traefikRoute.d.ts +9 -0
- package/dist/resources/traefikRoute.js +217 -0
- package/dist/resources/traefikRoute.js.map +1 -0
- package/dist/resources/traefikStaticConfig.d.ts +9 -0
- package/dist/resources/traefikStaticConfig.js +180 -0
- package/dist/resources/traefikStaticConfig.js.map +1 -0
- package/dist/resources/unraidVm.d.ts +9 -0
- package/dist/resources/unraidVm.js +225 -0
- package/dist/resources/unraidVm.js.map +1 -0
- package/package.json +6 -1
- package/.github/workflows/ci.yml +0 -42
- package/.github/workflows/release-please.yml +0 -88
- package/.github/workflows/release.yml +0 -87
- package/.release-please-manifest.json +0 -3
- package/CHANGELOG.md +0 -102
- package/CLAUDE.md +0 -35
- package/jest.config.js +0 -23
- package/pulumi-resource-homelab +0 -3
- package/pulumi-resource-homelab.cmd +0 -2
- package/release-please-config.json +0 -22
- package/sdk/nodejs/index.d.ts +0 -13
- package/sdk/nodejs/lxcContainer.d.ts +0 -34
- package/sdk/nodejs/notificationSettings.d.ts +0 -46
- package/sdk/nodejs/opnsenseAlias.d.ts +0 -22
- package/sdk/nodejs/opnsenseFirewallRule.d.ts +0 -49
- package/sdk/nodejs/opnsenseUnboundAcl.d.ts +0 -22
- package/sdk/nodejs/opnsenseUnboundDnsbl.d.ts +0 -40
- package/sdk/nodejs/opnsenseUnboundForward.d.ts +0 -34
- package/sdk/nodejs/opnsenseUnboundHostOverride.d.ts +0 -40
- package/sdk/nodejs/package-lock.json +0 -2967
- package/sdk/nodejs/package.json +0 -35
- package/sdk/nodejs/provider.d.ts +0 -29
- package/sdk/nodejs/stack.d.ts +0 -67
- package/sdk/nodejs/traefikRoute.d.ts +0 -16
- package/sdk/nodejs/traefikStaticConfig.d.ts +0 -13
- package/sdk/nodejs/unraidVm.d.ts +0 -32
- package/src/composeDiff.ts +0 -197
- package/src/envDiff.ts +0 -41
- package/src/helpers.ts +0 -114
- package/src/homelabClient.ts +0 -316
- package/src/index.ts +0 -218
- package/src/opnsenseClient.ts +0 -553
- package/src/provider.ts +0 -100
- package/src/resources/lxcContainer.ts +0 -285
- package/src/resources/notificationSettings.ts +0 -157
- package/src/resources/opnsenseAlias.ts +0 -176
- package/src/resources/opnsenseFirewallRule.ts +0 -194
- package/src/resources/opnsenseUnboundAcl.ts +0 -182
- package/src/resources/opnsenseUnboundDnsbl.ts +0 -174
- package/src/resources/opnsenseUnboundForward.ts +0 -182
- package/src/resources/opnsenseUnboundHostOverride.ts +0 -180
- package/src/resources/stack.ts +0 -326
- package/src/resources/traefikRoute.ts +0 -199
- package/src/resources/traefikStaticConfig.ts +0 -157
- package/src/resources/unraidVm.ts +0 -217
- package/tests/composeDiff.test.ts +0 -256
- package/tests/envDiff.test.ts +0 -84
- package/tests/helpers.test.ts +0 -313
- package/tests/homelabClient.test.ts +0 -530
- package/tests/lxcClient.test.ts +0 -240
- package/tests/lxcContainer.test.ts +0 -504
- package/tests/notificationSettings.test.ts +0 -197
- package/tests/opnsenseAlias.test.ts +0 -383
- package/tests/opnsenseClient.test.ts +0 -1669
- package/tests/opnsenseFirewallRule.test.ts +0 -397
- package/tests/opnsenseUnboundAcl.test.ts +0 -316
- package/tests/opnsenseUnboundDnsbl.test.ts +0 -314
- package/tests/opnsenseUnboundForward.test.ts +0 -305
- package/tests/opnsenseUnboundHostOverride.test.ts +0 -320
- package/tests/provider.test.ts +0 -243
- package/tests/stack.test.ts +0 -675
- package/tests/testUtils.ts +0 -123
- package/tests/traefikRoute.test.ts +0 -565
- package/tests/unraidVm.test.ts +0 -272
- package/tsconfig.json +0 -18
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface PropertyChange {
|
|
2
|
+
kind: "ADD" | "DELETE" | "UPDATE";
|
|
3
|
+
path: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Diff two plain YAML strings, returning granular property changes.
|
|
7
|
+
* No compose-specific merging or normalization is applied.
|
|
8
|
+
*/
|
|
9
|
+
export declare function diffYaml(oldYaml: string, newYaml: string): PropertyChange[];
|
|
10
|
+
/**
|
|
11
|
+
* Diff two compose configurations (main + optional override), returning granular property changes.
|
|
12
|
+
*
|
|
13
|
+
* Merges main + override following Docker Compose semantics, normalizes
|
|
14
|
+
* environment/labels from list→map form, then deep-diffs the effective configs.
|
|
15
|
+
*/
|
|
16
|
+
export declare function diffCompose(oldYaml: string, oldOverride: string | undefined, newYaml: string, newOverride: string | undefined): PropertyChange[];
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.diffYaml = diffYaml;
|
|
4
|
+
exports.diffCompose = diffCompose;
|
|
5
|
+
const yaml_1 = require("yaml");
|
|
6
|
+
/**
|
|
7
|
+
* Parse a YAML string into an object, resolving anchors/aliases.
|
|
8
|
+
* Returns an empty object on empty/undefined input.
|
|
9
|
+
*/
|
|
10
|
+
function safeParseYaml(yamlStr) {
|
|
11
|
+
if (!yamlStr || yamlStr.trim() === "")
|
|
12
|
+
return {};
|
|
13
|
+
return (0, yaml_1.parse)(yamlStr, { merge: true }) || {};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Deep-merge two compose objects following Docker Compose override semantics:
|
|
17
|
+
* - Scalars: override replaces main
|
|
18
|
+
* - Maps: deep merge (override keys added/overwrite)
|
|
19
|
+
* - Arrays: override replaces entirely
|
|
20
|
+
*/
|
|
21
|
+
function composeMerge(main, override) {
|
|
22
|
+
const result = { ...main };
|
|
23
|
+
for (const key of Object.keys(override)) {
|
|
24
|
+
const mainVal = main[key];
|
|
25
|
+
const overVal = override[key];
|
|
26
|
+
if (isPlainObject(mainVal) &&
|
|
27
|
+
isPlainObject(overVal)) {
|
|
28
|
+
result[key] = composeMerge(mainVal, overVal);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
result[key] = overVal;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
function isPlainObject(val) {
|
|
37
|
+
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Normalize compose environment/labels from list form to map form.
|
|
41
|
+
* `["FOO=bar", "BAZ=qux"]` → `{ FOO: "bar", BAZ: "qux" }`
|
|
42
|
+
*/
|
|
43
|
+
function listToMap(arr) {
|
|
44
|
+
const result = {};
|
|
45
|
+
for (const item of arr) {
|
|
46
|
+
const eqIdx = item.indexOf("=");
|
|
47
|
+
if (eqIdx === -1) {
|
|
48
|
+
result[item] = "";
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
result[item.slice(0, eqIdx)] = item.slice(eqIdx + 1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
/** Fields whose list form should be normalized to map form */
|
|
57
|
+
const NORMALIZABLE_FIELDS = new Set(["environment", "labels"]);
|
|
58
|
+
/**
|
|
59
|
+
* Walk a compose object and normalize environment/labels from list→map form.
|
|
60
|
+
* Only normalizes inside `services.<name>.<field>`.
|
|
61
|
+
*/
|
|
62
|
+
function normalizeCompose(obj) {
|
|
63
|
+
const result = { ...obj };
|
|
64
|
+
if (isPlainObject(result.services)) {
|
|
65
|
+
const services = {};
|
|
66
|
+
for (const [svcName, svcDef] of Object.entries(result.services)) {
|
|
67
|
+
if (!isPlainObject(svcDef)) {
|
|
68
|
+
services[svcName] = svcDef;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const svc = { ...svcDef };
|
|
72
|
+
for (const field of NORMALIZABLE_FIELDS) {
|
|
73
|
+
if (Array.isArray(svc[field])) {
|
|
74
|
+
svc[field] = listToMap(svc[field]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
services[svcName] = svc;
|
|
78
|
+
}
|
|
79
|
+
result.services = services;
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Format a path segment. Uses dot notation for object keys, brackets for array indices.
|
|
85
|
+
*/
|
|
86
|
+
function joinPath(prefix, key) {
|
|
87
|
+
if (typeof key === "number") {
|
|
88
|
+
return `${prefix}[${key}]`;
|
|
89
|
+
}
|
|
90
|
+
return prefix ? `${prefix}.${key}` : key;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Deep diff two values, producing a list of property changes.
|
|
94
|
+
*/
|
|
95
|
+
function deepDiff(oldVal, newVal, prefix, changes) {
|
|
96
|
+
if (oldVal === newVal)
|
|
97
|
+
return;
|
|
98
|
+
// Both plain objects → recurse per key
|
|
99
|
+
if (isPlainObject(oldVal) && isPlainObject(newVal)) {
|
|
100
|
+
const allKeys = new Set([
|
|
101
|
+
...Object.keys(oldVal),
|
|
102
|
+
...Object.keys(newVal),
|
|
103
|
+
]);
|
|
104
|
+
for (const key of allKeys) {
|
|
105
|
+
const path = joinPath(prefix, key);
|
|
106
|
+
if (!(key in oldVal)) {
|
|
107
|
+
changes.push({ kind: "ADD", path });
|
|
108
|
+
}
|
|
109
|
+
else if (!(key in newVal)) {
|
|
110
|
+
changes.push({ kind: "DELETE", path });
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
deepDiff(oldVal[key], newVal[key], path, changes);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Both arrays → positional compare
|
|
119
|
+
if (Array.isArray(oldVal) && Array.isArray(newVal)) {
|
|
120
|
+
const maxLen = Math.max(oldVal.length, newVal.length);
|
|
121
|
+
for (let i = 0; i < maxLen; i++) {
|
|
122
|
+
const path = joinPath(prefix, i);
|
|
123
|
+
if (i >= oldVal.length) {
|
|
124
|
+
changes.push({ kind: "ADD", path });
|
|
125
|
+
}
|
|
126
|
+
else if (i >= newVal.length) {
|
|
127
|
+
changes.push({ kind: "DELETE", path });
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
deepDiff(oldVal[i], newVal[i], path, changes);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
// Type mismatch or scalar difference
|
|
136
|
+
if (oldVal !== newVal) {
|
|
137
|
+
// Coerce to string for comparison to catch number/string equivalence (e.g. port "3000" vs 3000)
|
|
138
|
+
if (String(oldVal) !== String(newVal)) {
|
|
139
|
+
changes.push({ kind: "UPDATE", path: prefix });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Diff two plain YAML strings, returning granular property changes.
|
|
145
|
+
* No compose-specific merging or normalization is applied.
|
|
146
|
+
*/
|
|
147
|
+
function diffYaml(oldYaml, newYaml) {
|
|
148
|
+
const oldObj = safeParseYaml(oldYaml);
|
|
149
|
+
const newObj = safeParseYaml(newYaml);
|
|
150
|
+
const changes = [];
|
|
151
|
+
deepDiff(oldObj, newObj, "", changes);
|
|
152
|
+
return changes;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Diff two compose configurations (main + optional override), returning granular property changes.
|
|
156
|
+
*
|
|
157
|
+
* Merges main + override following Docker Compose semantics, normalizes
|
|
158
|
+
* environment/labels from list→map form, then deep-diffs the effective configs.
|
|
159
|
+
*/
|
|
160
|
+
function diffCompose(oldYaml, oldOverride, newYaml, newOverride) {
|
|
161
|
+
const oldMain = safeParseYaml(oldYaml);
|
|
162
|
+
const oldOver = safeParseYaml(oldOverride);
|
|
163
|
+
const newMain = safeParseYaml(newYaml);
|
|
164
|
+
const newOver = safeParseYaml(newOverride);
|
|
165
|
+
const oldMerged = normalizeCompose(Object.keys(oldOver).length > 0 ? composeMerge(oldMain, oldOver) : oldMain);
|
|
166
|
+
const newMerged = normalizeCompose(Object.keys(newOver).length > 0 ? composeMerge(newMain, newOver) : newMain);
|
|
167
|
+
const changes = [];
|
|
168
|
+
deepDiff(oldMerged, newMerged, "", changes);
|
|
169
|
+
return changes;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=composeDiff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composeDiff.js","sourceRoot":"","sources":["../src/composeDiff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface HomelabClientConfig {
|
|
2
|
+
url: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
}
|
|
5
|
+
export type DockgeClientConfig = HomelabClientConfig;
|
|
6
|
+
export interface ContainerInfo {
|
|
7
|
+
name: string;
|
|
8
|
+
service: string;
|
|
9
|
+
image: string;
|
|
10
|
+
state: string;
|
|
11
|
+
status: string;
|
|
12
|
+
health: string;
|
|
13
|
+
ports: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface StackInfo {
|
|
16
|
+
name: string;
|
|
17
|
+
status: string;
|
|
18
|
+
composeYaml: string;
|
|
19
|
+
envFile: string;
|
|
20
|
+
composeOverride: string;
|
|
21
|
+
autostart: boolean;
|
|
22
|
+
displayName: string;
|
|
23
|
+
containers: ContainerInfo[];
|
|
24
|
+
}
|
|
25
|
+
export type DockgeStackInfo = StackInfo;
|
|
26
|
+
export declare function configureClient(config: HomelabClientConfig): void;
|
|
27
|
+
export declare const configureDockgeClient: typeof configureClient;
|
|
28
|
+
export declare function ensureConfigured(): HomelabClientConfig;
|
|
29
|
+
export interface TraefikStaticInfo {
|
|
30
|
+
content: string;
|
|
31
|
+
lastModified: string;
|
|
32
|
+
}
|
|
33
|
+
export interface TraefikRouteInfo {
|
|
34
|
+
name: string;
|
|
35
|
+
content: string;
|
|
36
|
+
lastModified: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function listStacks(): Promise<StackInfo[]>;
|
|
39
|
+
export declare function getStack(name: string): Promise<StackInfo>;
|
|
40
|
+
export declare function createStack(name: string, composeYaml: string, envFile?: string, start?: boolean, composeOverride?: string, autostart?: boolean, displayName?: string): Promise<StackInfo>;
|
|
41
|
+
export declare function updateStack(name: string, composeYaml: string, envFile?: string, composeOverride?: string, autostart?: boolean, displayName?: string): Promise<StackInfo>;
|
|
42
|
+
export declare function deleteStack(name: string): Promise<void>;
|
|
43
|
+
export declare function startStack(name: string): Promise<StackInfo>;
|
|
44
|
+
export declare function stopStack(name: string): Promise<StackInfo>;
|
|
45
|
+
export declare function getTraefikStatic(): Promise<TraefikStaticInfo>;
|
|
46
|
+
export declare function putTraefikStatic(content: string): Promise<TraefikStaticInfo>;
|
|
47
|
+
export declare function listTraefikRoutes(): Promise<TraefikRouteInfo[]>;
|
|
48
|
+
export declare function getTraefikRoute(name: string): Promise<TraefikRouteInfo>;
|
|
49
|
+
export declare function putTraefikRoute(name: string, content: string): Promise<TraefikRouteInfo>;
|
|
50
|
+
export declare function deleteTraefikRoute(name: string): Promise<void>;
|
|
51
|
+
export interface LxcContainerInfo {
|
|
52
|
+
name: string;
|
|
53
|
+
status: number;
|
|
54
|
+
type: string;
|
|
55
|
+
ip: string;
|
|
56
|
+
autostart: boolean;
|
|
57
|
+
pid: number;
|
|
58
|
+
memory: string;
|
|
59
|
+
config: string;
|
|
60
|
+
}
|
|
61
|
+
export declare function listLxcContainers(): Promise<LxcContainerInfo[]>;
|
|
62
|
+
export declare function getLxcContainer(name: string): Promise<LxcContainerInfo>;
|
|
63
|
+
export declare function createLxcContainer(name: string, dist: string, release: string, arch: string): Promise<LxcContainerInfo>;
|
|
64
|
+
export declare function deleteLxcContainer(name: string): Promise<void>;
|
|
65
|
+
export declare function saveLxcConfig(name: string, config: string): Promise<LxcContainerInfo>;
|
|
66
|
+
export declare function startLxcContainer(name: string): Promise<LxcContainerInfo>;
|
|
67
|
+
export declare function stopLxcContainer(name: string): Promise<LxcContainerInfo>;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.configureDockgeClient = void 0;
|
|
7
|
+
exports.configureClient = configureClient;
|
|
8
|
+
exports.ensureConfigured = ensureConfigured;
|
|
9
|
+
exports.listStacks = listStacks;
|
|
10
|
+
exports.getStack = getStack;
|
|
11
|
+
exports.createStack = createStack;
|
|
12
|
+
exports.updateStack = updateStack;
|
|
13
|
+
exports.deleteStack = deleteStack;
|
|
14
|
+
exports.startStack = startStack;
|
|
15
|
+
exports.stopStack = stopStack;
|
|
16
|
+
exports.getTraefikStatic = getTraefikStatic;
|
|
17
|
+
exports.putTraefikStatic = putTraefikStatic;
|
|
18
|
+
exports.listTraefikRoutes = listTraefikRoutes;
|
|
19
|
+
exports.getTraefikRoute = getTraefikRoute;
|
|
20
|
+
exports.putTraefikRoute = putTraefikRoute;
|
|
21
|
+
exports.deleteTraefikRoute = deleteTraefikRoute;
|
|
22
|
+
exports.listLxcContainers = listLxcContainers;
|
|
23
|
+
exports.getLxcContainer = getLxcContainer;
|
|
24
|
+
exports.createLxcContainer = createLxcContainer;
|
|
25
|
+
exports.deleteLxcContainer = deleteLxcContainer;
|
|
26
|
+
exports.saveLxcConfig = saveLxcConfig;
|
|
27
|
+
exports.startLxcContainer = startLxcContainer;
|
|
28
|
+
exports.stopLxcContainer = stopLxcContainer;
|
|
29
|
+
const cross_fetch_1 = __importDefault(require("cross-fetch"));
|
|
30
|
+
let currentConfig = null;
|
|
31
|
+
function configureClient(config) {
|
|
32
|
+
currentConfig = config;
|
|
33
|
+
}
|
|
34
|
+
exports.configureDockgeClient = configureClient;
|
|
35
|
+
function ensureConfigured() {
|
|
36
|
+
if (!currentConfig) {
|
|
37
|
+
throw new Error("Homelab provider not configured. Set homelab:url and homelab:apiKey via pulumi config.");
|
|
38
|
+
}
|
|
39
|
+
return currentConfig;
|
|
40
|
+
}
|
|
41
|
+
function baseUrl() {
|
|
42
|
+
const config = ensureConfigured();
|
|
43
|
+
return config.url.replace(/\/+$/, "");
|
|
44
|
+
}
|
|
45
|
+
function headers() {
|
|
46
|
+
const config = ensureConfigured();
|
|
47
|
+
return {
|
|
48
|
+
"Authorization": `Bearer ${config.apiKey}`,
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function request(method, path, body) {
|
|
53
|
+
const url = `${baseUrl()}${path}`;
|
|
54
|
+
const res = await (0, cross_fetch_1.default)(url, {
|
|
55
|
+
method,
|
|
56
|
+
headers: headers(),
|
|
57
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
58
|
+
});
|
|
59
|
+
if (res.status === 204) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
const text = await res.text();
|
|
64
|
+
let message;
|
|
65
|
+
try {
|
|
66
|
+
const json = JSON.parse(text);
|
|
67
|
+
message = json.error || text;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
message = text;
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Dockge API ${method} ${path} failed (${res.status}): ${message}`);
|
|
73
|
+
}
|
|
74
|
+
return res.json();
|
|
75
|
+
}
|
|
76
|
+
async function listStacks() {
|
|
77
|
+
return request("GET", "/api/stacks");
|
|
78
|
+
}
|
|
79
|
+
async function getStack(name) {
|
|
80
|
+
return request("GET", `/api/stacks/${encodeURIComponent(name)}`);
|
|
81
|
+
}
|
|
82
|
+
async function createStack(name, composeYaml, envFile, start, composeOverride, autostart, displayName) {
|
|
83
|
+
return request("POST", "/api/stacks", {
|
|
84
|
+
name,
|
|
85
|
+
composeYaml,
|
|
86
|
+
envFile: envFile || "",
|
|
87
|
+
start: start !== false,
|
|
88
|
+
composeOverride: composeOverride || "",
|
|
89
|
+
autostart: autostart || false,
|
|
90
|
+
displayName: displayName || "",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async function updateStack(name, composeYaml, envFile, composeOverride, autostart, displayName) {
|
|
94
|
+
return request("PUT", `/api/stacks/${encodeURIComponent(name)}`, {
|
|
95
|
+
composeYaml,
|
|
96
|
+
envFile: envFile || "",
|
|
97
|
+
composeOverride: composeOverride !== undefined ? composeOverride : undefined,
|
|
98
|
+
autostart: autostart !== undefined ? autostart : undefined,
|
|
99
|
+
displayName: displayName !== undefined ? displayName : undefined,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async function deleteStack(name) {
|
|
103
|
+
await request("DELETE", `/api/stacks/${encodeURIComponent(name)}`);
|
|
104
|
+
}
|
|
105
|
+
async function startStack(name) {
|
|
106
|
+
return request("POST", `/api/stacks/${encodeURIComponent(name)}/start`);
|
|
107
|
+
}
|
|
108
|
+
async function stopStack(name) {
|
|
109
|
+
return request("POST", `/api/stacks/${encodeURIComponent(name)}/stop`);
|
|
110
|
+
}
|
|
111
|
+
// Traefik API functions
|
|
112
|
+
async function getTraefikStatic() {
|
|
113
|
+
return request("GET", "/api/traefik/static");
|
|
114
|
+
}
|
|
115
|
+
async function putTraefikStatic(content) {
|
|
116
|
+
return request("PUT", "/api/traefik/static", { content });
|
|
117
|
+
}
|
|
118
|
+
async function listTraefikRoutes() {
|
|
119
|
+
return request("GET", "/api/traefik/routes");
|
|
120
|
+
}
|
|
121
|
+
async function getTraefikRoute(name) {
|
|
122
|
+
return request("GET", `/api/traefik/routes/${encodeURIComponent(name)}`);
|
|
123
|
+
}
|
|
124
|
+
async function putTraefikRoute(name, content) {
|
|
125
|
+
return request("PUT", `/api/traefik/routes/${encodeURIComponent(name)}`, { content });
|
|
126
|
+
}
|
|
127
|
+
async function deleteTraefikRoute(name) {
|
|
128
|
+
await request("DELETE", `/api/traefik/routes/${encodeURIComponent(name)}`);
|
|
129
|
+
}
|
|
130
|
+
// LXC API functions
|
|
131
|
+
async function listLxcContainers() {
|
|
132
|
+
return request("GET", "/api/lxc");
|
|
133
|
+
}
|
|
134
|
+
async function getLxcContainer(name) {
|
|
135
|
+
return request("GET", `/api/lxc/${encodeURIComponent(name)}`);
|
|
136
|
+
}
|
|
137
|
+
async function createLxcContainer(name, dist, release, arch) {
|
|
138
|
+
return request("POST", "/api/lxc", { name, dist, release, arch });
|
|
139
|
+
}
|
|
140
|
+
async function deleteLxcContainer(name) {
|
|
141
|
+
await request("DELETE", `/api/lxc/${encodeURIComponent(name)}`);
|
|
142
|
+
}
|
|
143
|
+
async function saveLxcConfig(name, config) {
|
|
144
|
+
return request("PUT", `/api/lxc/${encodeURIComponent(name)}/config`, { config });
|
|
145
|
+
}
|
|
146
|
+
async function startLxcContainer(name) {
|
|
147
|
+
return request("POST", `/api/lxc/${encodeURIComponent(name)}/start`);
|
|
148
|
+
}
|
|
149
|
+
async function stopLxcContainer(name) {
|
|
150
|
+
return request("POST", `/api/lxc/${encodeURIComponent(name)}/stop`);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=dockgeClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dockgeClient.js","sourceRoot":"","sources":["../src/dockgeClient.ts"],"names":[],"mappings":"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"}
|
package/dist/envDiff.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.diffEnvFile = diffEnvFile;
|
|
4
|
+
/**
|
|
5
|
+
* Parse a .env file string into a key-value map.
|
|
6
|
+
* Skips blank lines and comments (lines starting with #).
|
|
7
|
+
*/
|
|
8
|
+
function parseEnv(content) {
|
|
9
|
+
const result = {};
|
|
10
|
+
for (const line of content.split("\n")) {
|
|
11
|
+
const trimmed = line.trim();
|
|
12
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
13
|
+
continue;
|
|
14
|
+
const eqIdx = trimmed.indexOf("=");
|
|
15
|
+
if (eqIdx === -1) {
|
|
16
|
+
result[trimmed] = "";
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
result[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Diff two .env file contents, returning per-variable property changes.
|
|
26
|
+
*/
|
|
27
|
+
function diffEnvFile(oldEnv, newEnv) {
|
|
28
|
+
const oldMap = parseEnv(oldEnv);
|
|
29
|
+
const newMap = parseEnv(newEnv);
|
|
30
|
+
const changes = [];
|
|
31
|
+
const allKeys = new Set([...Object.keys(oldMap), ...Object.keys(newMap)]);
|
|
32
|
+
for (const key of allKeys) {
|
|
33
|
+
if (!(key in oldMap)) {
|
|
34
|
+
changes.push({ kind: "ADD", path: key });
|
|
35
|
+
}
|
|
36
|
+
else if (!(key in newMap)) {
|
|
37
|
+
changes.push({ kind: "DELETE", path: key });
|
|
38
|
+
}
|
|
39
|
+
else if (oldMap[key] !== newMap[key]) {
|
|
40
|
+
changes.push({ kind: "UPDATE", path: key });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return changes;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=envDiff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envDiff.js","sourceRoot":"","sources":["../src/envDiff.ts"],"names":[],"mappings":";;AAwBA,kCAgBC;AAtCD;;;GAGG;AACH,SAAS,QAAQ,CAAC,OAAe;IAC/B,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,MAAc,EAAE,MAAc;IACxD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1E,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAC9C,CAAC;aAAM,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as grpc from "@grpc/grpc-js";
|
|
2
|
+
export declare function structToObject(struct: any): Record<string, any>;
|
|
3
|
+
export declare function objectToStruct(obj: Record<string, any>): any;
|
|
4
|
+
/**
|
|
5
|
+
* Unwrap a Pulumi secret value. Secrets are encoded as objects with a
|
|
6
|
+
* special signature key. Returns the plain value if wrapped, or the
|
|
7
|
+
* original value otherwise.
|
|
8
|
+
*/
|
|
9
|
+
export declare function unwrapSecret(val: any): any;
|
|
10
|
+
/**
|
|
11
|
+
* Recursively unwrap all secret values in an object.
|
|
12
|
+
*/
|
|
13
|
+
export declare function unwrapSecrets(obj: Record<string, any>): Record<string, any>;
|
|
14
|
+
/**
|
|
15
|
+
* Compare two values for diff purposes. Treats undefined and "" as equivalent
|
|
16
|
+
* to prevent spurious diffs when optional fields come back as empty strings
|
|
17
|
+
* from the API but were undefined in state.
|
|
18
|
+
*/
|
|
19
|
+
export declare function valuesEqual(a: any, b: any): boolean;
|
|
20
|
+
export declare function makeCheckFailure(property: string, reason: string): any;
|
|
21
|
+
export type GrpcCallback<T> = grpc.sendUnaryData<T>;
|
|
22
|
+
export type GrpcCall<Req, Res> = grpc.ServerUnaryCall<Req, Res>;
|
|
23
|
+
/**
|
|
24
|
+
* Extract the resource type token from a gRPC request URN.
|
|
25
|
+
* URN format: urn:pulumi:stack::project::type::name
|
|
26
|
+
* Since Pulumi SDK v3.132.0, getType() is available directly.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getResourceType(call: any): string;
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.structToObject = structToObject;
|
|
4
|
+
exports.objectToStruct = objectToStruct;
|
|
5
|
+
exports.unwrapSecret = unwrapSecret;
|
|
6
|
+
exports.unwrapSecrets = unwrapSecrets;
|
|
7
|
+
exports.valuesEqual = valuesEqual;
|
|
8
|
+
exports.makeCheckFailure = makeCheckFailure;
|
|
9
|
+
exports.getResourceType = getResourceType;
|
|
10
|
+
const structProto = require("google-protobuf/google/protobuf/struct_pb");
|
|
11
|
+
function structToObject(struct) {
|
|
12
|
+
if (!struct)
|
|
13
|
+
return {};
|
|
14
|
+
return unwrapSecrets(struct.toJavaScript());
|
|
15
|
+
}
|
|
16
|
+
// Recursively strip undefined values from nested objects/arrays so that
|
|
17
|
+
// Struct.fromJavaScript never encounters an undefined (which throws
|
|
18
|
+
// "Unexpected struct type").
|
|
19
|
+
function deepClean(val) {
|
|
20
|
+
if (val === undefined)
|
|
21
|
+
return null;
|
|
22
|
+
if (Array.isArray(val))
|
|
23
|
+
return val.map(deepClean);
|
|
24
|
+
if (val !== null && typeof val === "object") {
|
|
25
|
+
const out = {};
|
|
26
|
+
for (const [k, v] of Object.entries(val)) {
|
|
27
|
+
if (v !== undefined) {
|
|
28
|
+
out[k] = deepClean(v);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
return val;
|
|
34
|
+
}
|
|
35
|
+
function objectToStruct(obj) {
|
|
36
|
+
return structProto.Struct.fromJavaScript(deepClean(obj));
|
|
37
|
+
}
|
|
38
|
+
const SECRET_SIG = "4dabf18193072939515e22adb298388d";
|
|
39
|
+
/**
|
|
40
|
+
* Unwrap a Pulumi secret value. Secrets are encoded as objects with a
|
|
41
|
+
* special signature key. Returns the plain value if wrapped, or the
|
|
42
|
+
* original value otherwise.
|
|
43
|
+
*/
|
|
44
|
+
function unwrapSecret(val) {
|
|
45
|
+
if (val && typeof val === "object" && val[SECRET_SIG] !== undefined) {
|
|
46
|
+
return val["value"];
|
|
47
|
+
}
|
|
48
|
+
return val;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Recursively unwrap a single value, handling arrays and nested objects.
|
|
52
|
+
*/
|
|
53
|
+
function unwrapDeep(val) {
|
|
54
|
+
const unwrapped = unwrapSecret(val);
|
|
55
|
+
if (Array.isArray(unwrapped)) {
|
|
56
|
+
return unwrapped.map(unwrapDeep);
|
|
57
|
+
}
|
|
58
|
+
if (unwrapped && typeof unwrapped === "object") {
|
|
59
|
+
return unwrapSecrets(unwrapped);
|
|
60
|
+
}
|
|
61
|
+
return unwrapped;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Recursively unwrap all secret values in an object.
|
|
65
|
+
*/
|
|
66
|
+
function unwrapSecrets(obj) {
|
|
67
|
+
const result = {};
|
|
68
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
69
|
+
result[key] = unwrapDeep(val);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compare two values for diff purposes. Treats undefined and "" as equivalent
|
|
75
|
+
* to prevent spurious diffs when optional fields come back as empty strings
|
|
76
|
+
* from the API but were undefined in state.
|
|
77
|
+
*/
|
|
78
|
+
function valuesEqual(a, b) {
|
|
79
|
+
const normA = a === "" ? undefined : a;
|
|
80
|
+
const normB = b === "" ? undefined : b;
|
|
81
|
+
return normA === normB;
|
|
82
|
+
}
|
|
83
|
+
function makeCheckFailure(property, reason) {
|
|
84
|
+
const providerProto = require("@pulumi/pulumi/proto/provider_pb");
|
|
85
|
+
const failure = new providerProto.CheckFailure();
|
|
86
|
+
failure.setProperty(property);
|
|
87
|
+
failure.setReason(reason);
|
|
88
|
+
return failure;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Extract the resource type token from a gRPC request URN.
|
|
92
|
+
* URN format: urn:pulumi:stack::project::type::name
|
|
93
|
+
* Since Pulumi SDK v3.132.0, getType() is available directly.
|
|
94
|
+
*/
|
|
95
|
+
function getResourceType(call) {
|
|
96
|
+
// Try getType() first (available since SDK v3.132.0)
|
|
97
|
+
if (typeof call.request.getType === "function") {
|
|
98
|
+
const type = call.request.getType();
|
|
99
|
+
if (type)
|
|
100
|
+
return type;
|
|
101
|
+
}
|
|
102
|
+
// Fallback: parse from URN
|
|
103
|
+
const urn = call.request.getUrn?.();
|
|
104
|
+
if (urn) {
|
|
105
|
+
// urn:pulumi:stack::project::provider:module:Type::name
|
|
106
|
+
const parts = urn.split("::");
|
|
107
|
+
if (parts.length >= 3) {
|
|
108
|
+
return parts[2];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return "";
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
|