@celilo/cli 0.5.0-alpha.5 → 0.5.0-alpha.7
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/package.json +2 -2
- package/src/ansible/inventory.test.ts +10 -10
- package/src/ansible/validation.test.ts +25 -15
- package/src/api-clients/proxmox.test.ts +123 -1
- package/src/api-clients/proxmox.ts +292 -7
- package/src/cli/commands/events.test.ts +4 -4
- package/src/cli/commands/events.ts +2 -2
- package/src/cli/commands/proxmox-vm-template-build.ts +164 -0
- package/src/cli/commands/service-add-proxmox.ts +62 -3
- package/src/cli/commands/service-reconfigure.test.ts +115 -0
- package/src/cli/commands/service-reconfigure.ts +110 -5
- package/src/cli/index.ts +2 -2
- package/src/config/paths.test.ts +61 -48
- package/src/hooks/capability-loader-firewall.test.ts +3 -3
- package/src/infrastructure/property-extractor.test.ts +15 -0
- package/src/infrastructure/property-extractor.ts +12 -0
- package/src/manifest/schema.ts +7 -0
- package/src/manifest/validate.test.ts +53 -0
- package/src/services/bus-interview.test.ts +2 -2
- package/src/services/bus-secret-flow.test.ts +2 -2
- package/src/services/celilo-mgmt-hooks.test.ts +3 -2
- package/src/services/deploy-validation.test.ts +2 -2
- package/src/services/dns-provider-backfill.test.ts +2 -2
- package/src/services/dns-registrations.test.ts +10 -10
- package/src/services/module-build.test.ts +43 -38
- package/src/templates/generator.test.ts +62 -12
- package/src/templates/generator.ts +48 -50
- package/src/test-utils/fixtures.test.ts +1 -1
- package/src/test-utils/integration-guard.ts +33 -0
- package/src/types/infrastructure.ts +6 -0
- package/src/variables/computed/computed-integration.test.ts +3 -3
- package/src/variables/computed/computed.test.ts +5 -5
- package/src/variables/declarative-derivation.test.ts +6 -6
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
discoverTemplateFiles,
|
|
10
10
|
generateTemplates,
|
|
11
11
|
getOutputFilename,
|
|
12
|
-
|
|
12
|
+
injectProxmoxDns,
|
|
13
13
|
isTemplateFile,
|
|
14
14
|
readTemplateFiles,
|
|
15
15
|
targetNodeFromTfState,
|
|
@@ -636,7 +636,7 @@ resource "proxmox_lxc" "container" {
|
|
|
636
636
|
});
|
|
637
637
|
});
|
|
638
638
|
|
|
639
|
-
describe('
|
|
639
|
+
describe('injectProxmoxDns', () => {
|
|
640
640
|
const LXC = [
|
|
641
641
|
'resource "proxmox_lxc" "caddy" {',
|
|
642
642
|
' target_node = "pve"',
|
|
@@ -648,7 +648,7 @@ resource "proxmox_lxc" "container" {
|
|
|
648
648
|
].join('\n');
|
|
649
649
|
|
|
650
650
|
test('injects nameserver + lifecycle when a nameserver is computable', () => {
|
|
651
|
-
const out =
|
|
651
|
+
const out = injectProxmoxDns(LXC, true);
|
|
652
652
|
expect(out).toContain(' nameserver = "$self:lxc_nameserver"');
|
|
653
653
|
expect(out).toContain(' lifecycle {');
|
|
654
654
|
expect(out).toContain(
|
|
@@ -665,7 +665,7 @@ resource "proxmox_lxc" "container" {
|
|
|
665
665
|
});
|
|
666
666
|
|
|
667
667
|
test('injects lifecycle only (no nameserver) when none is computable', () => {
|
|
668
|
-
const out =
|
|
668
|
+
const out = injectProxmoxDns(LXC, false);
|
|
669
669
|
expect(out).not.toContain('nameserver = "$self:lxc_nameserver"');
|
|
670
670
|
expect(out).toContain(' lifecycle {');
|
|
671
671
|
expect(out).toContain(
|
|
@@ -674,8 +674,8 @@ resource "proxmox_lxc" "container" {
|
|
|
674
674
|
});
|
|
675
675
|
|
|
676
676
|
test('is idempotent — already-injected content is returned unchanged', () => {
|
|
677
|
-
const once =
|
|
678
|
-
const twice =
|
|
677
|
+
const once = injectProxmoxDns(LXC, true);
|
|
678
|
+
const twice = injectProxmoxDns(once, true);
|
|
679
679
|
expect(twice).toBe(once);
|
|
680
680
|
});
|
|
681
681
|
|
|
@@ -689,27 +689,77 @@ resource "proxmox_lxc" "container" {
|
|
|
689
689
|
' start = true',
|
|
690
690
|
'}',
|
|
691
691
|
].join('\n');
|
|
692
|
-
const out =
|
|
692
|
+
const out = injectProxmoxDns(stale, true);
|
|
693
693
|
// Exactly one nameserver attribute survives.
|
|
694
694
|
expect(out.match(/nameserver\s*=/g)?.length).toBe(1);
|
|
695
695
|
// The lifecycle guard is still added (ISS-0055 extended the ignore list).
|
|
696
696
|
expect(out).toContain('ignore_changes = [nameserver,');
|
|
697
697
|
});
|
|
698
698
|
|
|
699
|
-
test('
|
|
700
|
-
const vm = [
|
|
701
|
-
|
|
699
|
+
test('injects cloud-init DNS + the VM ForceNew ignore list into proxmox_vm_qemu', () => {
|
|
700
|
+
const vm = [
|
|
701
|
+
'resource "proxmox_vm_qemu" "builder" {',
|
|
702
|
+
' target_node = "pve"',
|
|
703
|
+
' clone = "ubuntu-2204-cloudinit"',
|
|
704
|
+
' network {',
|
|
705
|
+
' bridge = "vmbr0"',
|
|
706
|
+
' }',
|
|
707
|
+
'}',
|
|
708
|
+
].join('\n');
|
|
709
|
+
const out = injectProxmoxDns(vm, true);
|
|
710
|
+
expect(out).toContain(' nameserver = "$self:lxc_nameserver"');
|
|
711
|
+
expect(out).toContain(' lifecycle {');
|
|
712
|
+
// The VM ForceNew list (telmate 3.x), NOT the LXC one.
|
|
713
|
+
expect(out).toContain(
|
|
714
|
+
' ignore_changes = [nameserver, network[0].macaddr, sshkeys, clone]',
|
|
715
|
+
);
|
|
716
|
+
const lines = out.split('\n');
|
|
717
|
+
expect(lines[0]).toBe('resource "proxmox_vm_qemu" "builder" {');
|
|
718
|
+
expect(lines[1]).toBe(' nameserver = "$self:lxc_nameserver"');
|
|
719
|
+
expect(out).toContain(' clone = "ubuntu-2204-cloudinit"');
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
test('branches the ignore list per block in a mixed lxc + vm file', () => {
|
|
723
|
+
// The forgejo-runner builder pattern: one template with both a count-gated
|
|
724
|
+
// proxmox_lxc (light) and proxmox_vm_qemu (builder) — each gets its own list.
|
|
725
|
+
const mixed = [
|
|
726
|
+
'resource "proxmox_lxc" "light" {',
|
|
727
|
+
' target_node = "pve"',
|
|
728
|
+
'}',
|
|
729
|
+
'',
|
|
730
|
+
'resource "proxmox_vm_qemu" "builder" {',
|
|
731
|
+
' clone = "ubuntu-2204-cloudinit"',
|
|
732
|
+
'}',
|
|
733
|
+
].join('\n');
|
|
734
|
+
const out = injectProxmoxDns(mixed, true);
|
|
735
|
+
expect(out).toContain(
|
|
736
|
+
'ignore_changes = [nameserver, network[0].hwaddr, rootfs[0].volume, ssh_public_keys]',
|
|
737
|
+
);
|
|
738
|
+
expect(out).toContain('ignore_changes = [nameserver, network[0].macaddr, sshkeys, clone]');
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
test('leaves non-Proxmox-compute resources untouched', () => {
|
|
742
|
+
// Not proxmox_lxc / proxmox_vm_qemu — an external-zone droplet, and the bare
|
|
743
|
+
// `proxmox_vm` type (which is NOT the cloud-init qemu resource we target).
|
|
744
|
+
const droplet = [
|
|
745
|
+
'resource "digitalocean_droplet" "edge" {',
|
|
746
|
+
' size = "s-1vcpu-1gb"',
|
|
747
|
+
'}',
|
|
748
|
+
].join('\n');
|
|
749
|
+
const bareVm = ['resource "proxmox_vm" "x" {', ' cores = 4', '}'].join('\n');
|
|
750
|
+
expect(injectProxmoxDns(droplet, true)).toBe(droplet);
|
|
751
|
+
expect(injectProxmoxDns(bareVm, true)).toBe(bareVm);
|
|
702
752
|
});
|
|
703
753
|
|
|
704
754
|
test('injects into every proxmox_lxc block in a multi-resource file', () => {
|
|
705
755
|
const two = `${LXC}\n\n${LXC.replace('"caddy"', '"forgejo"')}`;
|
|
706
|
-
const out =
|
|
756
|
+
const out = injectProxmoxDns(two, true);
|
|
707
757
|
expect(out.match(/ignore_changes = \[nameserver,/g)?.length).toBe(2);
|
|
708
758
|
});
|
|
709
759
|
|
|
710
760
|
test('matches the indentation of the resource opening line', () => {
|
|
711
761
|
const indented = [' resource "proxmox_lxc" "x" {', ' cores = 1', ' }'].join('\n');
|
|
712
|
-
const out =
|
|
762
|
+
const out = injectProxmoxDns(indented, true);
|
|
713
763
|
expect(out).toContain(' nameserver = "$self:lxc_nameserver"');
|
|
714
764
|
expect(out).toContain(' lifecycle {');
|
|
715
765
|
expect(out).toContain(
|
|
@@ -133,82 +133,80 @@ export function getOutputFilename(templateFilename: string): string {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
|
-
* Inject framework-owned DNS-at-birth into every
|
|
136
|
+
* Inject framework-owned DNS-at-birth into every Proxmox compute resource —
|
|
137
|
+
* `proxmox_lxc` and `proxmox_vm_qemu`.
|
|
137
138
|
*
|
|
138
|
-
*
|
|
139
|
+
* A node's nameserver is infrastructure celilo owns — like vmid, target_ip, and
|
|
139
140
|
* inventory — not something a module author hand-writes. Authors declare zero
|
|
140
|
-
* DNS terraform; this stamps it onto each
|
|
141
|
-
* For every block it emits:
|
|
141
|
+
* DNS terraform; this stamps it onto each Proxmox resource block at generate
|
|
142
|
+
* time. For every block it emits:
|
|
142
143
|
*
|
|
143
144
|
* - `nameserver = "$self:lxc_nameserver"` — only when a nameserver is
|
|
144
|
-
* computable (`hasNameserver`). The
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* post-deploy.
|
|
148
|
-
* - `lifecycle { ignore_changes = [
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* aspect = ongoing DNS). See v2/LXC_INTERNAL_DNS.md.
|
|
145
|
+
* computable (`hasNameserver`). The attribute is `nameserver` for both an
|
|
146
|
+
* LXC and a cloud-init VM. The first system, deployed before any
|
|
147
|
+
* `dns_internal` provider exists, has no value: it inherits the node default
|
|
148
|
+
* and the `dns-client-config` aspect repairs resolv.conf post-deploy.
|
|
149
|
+
* - `lifecycle { ignore_changes = [...] }` — always. The list is the
|
|
150
|
+
* resource's create-time / ForceNew attributes, so an unchanged redeploy is
|
|
151
|
+
* a no-op and a real change an in-place UPDATE — never the destructive
|
|
152
|
+
* REPLACE the terraform-safety guard (create-only, see terraform-safety.ts)
|
|
153
|
+
* rejects. terraform = birth DNS, the `dns-client-config` aspect = ongoing
|
|
154
|
+
* DNS. The per-type lists are in the callback. See v2/LXC_INTERNAL_DNS.md.
|
|
155
155
|
*
|
|
156
156
|
* Anchored on the resource's opening line — it never brace-matches the nested
|
|
157
|
-
*
|
|
157
|
+
* disk/network/features blocks, so it's robust to attribute order/formatting.
|
|
158
158
|
* Idempotent at file granularity: a `.tf` that already declares
|
|
159
|
-
* `ignore_changes = [nameserver
|
|
160
|
-
*
|
|
159
|
+
* `ignore_changes = [nameserver` (re-run, or an author who opted in) is returned
|
|
160
|
+
* untouched.
|
|
161
161
|
*
|
|
162
162
|
* Policy function (Rule 10.1) - pure string transformation, no I/O.
|
|
163
163
|
*
|
|
164
164
|
* @param content - Raw terraform template content (pre variable-resolution)
|
|
165
165
|
* @param hasNameserver - Whether `$self:lxc_nameserver` resolves to a value
|
|
166
|
-
* @returns Content with DNS injected into each
|
|
166
|
+
* @returns Content with DNS injected into each Proxmox compute resource
|
|
167
167
|
*/
|
|
168
|
-
export function
|
|
168
|
+
export function injectProxmoxDns(content: string, hasNameserver: boolean): string {
|
|
169
169
|
// Already injected (idempotent) or author opted into the lifecycle — done.
|
|
170
|
-
// Match the `[nameserver` prefix (no closing bracket) so this stays true
|
|
171
|
-
//
|
|
172
|
-
// `[nameserver, network[0].hwaddr, …]` — otherwise re-generate double-injects.
|
|
170
|
+
// Match the `[nameserver` prefix (no closing bracket) so this stays true for
|
|
171
|
+
// both the LXC and the VM variant — otherwise re-generate double-injects.
|
|
173
172
|
if (content.includes('ignore_changes = [nameserver')) {
|
|
174
173
|
return content;
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
// A template that still carries a `nameserver = …` attribute — a stale copied
|
|
178
|
-
// module
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
// exists and just add the lifecycle guard (the load-bearing part). Both cases
|
|
182
|
-
// converge on exactly one nameserver + ignore_changes.
|
|
177
|
+
// module, or an author who set it by hand — already supplies the value.
|
|
178
|
+
// Injecting a second `nameserver` is a terraform "Attribute redefined" error.
|
|
179
|
+
// So skip the value line when one exists and just add the lifecycle guard.
|
|
183
180
|
const alreadyHasNameserver = /^[ \t]*nameserver[ \t]*=/m.test(content);
|
|
184
181
|
|
|
185
|
-
const openLineRe = /^([ \t]*)resource\s+"proxmox_lxc"\s+"[^"]+"\s*\{[ \t]*$/gm;
|
|
186
|
-
return content.replace(openLineRe, (openLine, indent: string) => {
|
|
182
|
+
const openLineRe = /^([ \t]*)resource\s+"(proxmox_lxc|proxmox_vm_qemu)"\s+"[^"]+"\s*\{[ \t]*$/gm;
|
|
183
|
+
return content.replace(openLineRe, (openLine, indent: string, resourceType: string) => {
|
|
187
184
|
const inner = `${indent} `;
|
|
188
185
|
const injected = [openLine];
|
|
189
186
|
if (hasNameserver && !alreadyHasNameserver) {
|
|
190
187
|
injected.push(`${inner}nameserver = "$self:lxc_nameserver"`);
|
|
191
188
|
}
|
|
192
189
|
injected.push(`${inner}lifecycle {`);
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
190
|
+
// The create-time / ForceNew attributes Proxmox assigns, per resource type.
|
|
191
|
+
// Listing them makes an unchanged redeploy a no-op and a real change an
|
|
192
|
+
// in-place UPDATE, never a destructive REPLACE. A non-existent attribute
|
|
193
|
+
// here fails `terraform validate`, so each list is exactly the schema
|
|
194
|
+
// attributes the resource actually has.
|
|
195
|
+
// LXC (ISS-0055/0089): the create-time MAC + rootfs volume, plus
|
|
196
|
+
// `ssh_public_keys` (ForceNew — a fleet-key rotation must not REPLACE the
|
|
197
|
+
// container). `rootfs.size` is NOT ignored, so a disk grow still applies.
|
|
198
|
+
// We do NOT ignore `target_node` — a node change is real (migration,
|
|
199
|
+
// ISS-0090), never silently dropped.
|
|
200
|
+
// VM (telmate 3.x proxmox_vm_qemu): `clone` (ForceNew clone source),
|
|
201
|
+
// `sshkeys` + `nameserver` (ForceNew cloud-init), and the NIC `macaddr`.
|
|
202
|
+
// Initial set from the provider schema — extend if a first real VM deploy
|
|
203
|
+
// surfaces another spurious-REPLACE attribute, exactly as ISS-0055 did for
|
|
204
|
+
// the LXC list.
|
|
205
|
+
const ignore =
|
|
206
|
+
resourceType === 'proxmox_vm_qemu'
|
|
207
|
+
? 'nameserver, network[0].macaddr, sshkeys, clone'
|
|
208
|
+
: 'nameserver, network[0].hwaddr, rootfs[0].volume, ssh_public_keys';
|
|
209
|
+
injected.push(`${inner} ignore_changes = [${ignore}]`);
|
|
212
210
|
injected.push(`${inner}}`);
|
|
213
211
|
return injected.join('\n');
|
|
214
212
|
});
|
|
@@ -1008,7 +1006,7 @@ export async function generateTemplates(options: GenerateOptions): Promise<Gener
|
|
|
1008
1006
|
// every proxmox_lxc resource before resolution (terraform files only).
|
|
1009
1007
|
const content =
|
|
1010
1008
|
!isAnsibleTemplate && template.targetPath.endsWith('.tf')
|
|
1011
|
-
?
|
|
1009
|
+
? injectProxmoxDns(template.content, Boolean(context.selfConfig.lxc_nameserver))
|
|
1012
1010
|
: template.content;
|
|
1013
1011
|
const result = isAnsibleTemplate
|
|
1014
1012
|
? await convertSecretsToJinja(content, context, db)
|
|
@@ -60,7 +60,7 @@ describe('Fixture Test Utilities', () => {
|
|
|
60
60
|
test('excludes secrets from config', async () => {
|
|
61
61
|
const config = await getModuleTestConfig('dns-external');
|
|
62
62
|
expect(config).toBeDefined();
|
|
63
|
-
expect(config.vps_ip).toBe('
|
|
63
|
+
expect(config.vps_ip).toBe('192.0.2.20');
|
|
64
64
|
expect(config.secrets).toBeUndefined();
|
|
65
65
|
});
|
|
66
66
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Guard for tests that can't run in the `unit` target / on the minimal CI
|
|
5
|
+
* runner — they shell out to external tools (ansible, wg, terraform, docker…)
|
|
6
|
+
* or assert platform-specific behavior. Such tests are integration tests by
|
|
7
|
+
* Rule 7.1 and must NOT gate the unit CI.
|
|
8
|
+
*
|
|
9
|
+
* Returns `true` (→ skip) when:
|
|
10
|
+
* - CELILO_UNIT_ONLY=1 is set (the `unit` target forces them off), OR
|
|
11
|
+
* - a required tool is absent on this host, OR
|
|
12
|
+
* - we're on the wrong platform.
|
|
13
|
+
*
|
|
14
|
+
* Usage: describe.skipIf(skipIntegration({ tools: ['ansible'] }))(...)
|
|
15
|
+
* test.skipIf(skipIntegration({ platform: 'darwin' }))(...)
|
|
16
|
+
*/
|
|
17
|
+
function hasTool(tool: string): boolean {
|
|
18
|
+
try {
|
|
19
|
+
execSync(`command -v ${tool}`, { stdio: 'ignore' });
|
|
20
|
+
return true;
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function skipIntegration(
|
|
27
|
+
req: { tools?: string[]; platform?: NodeJS.Platform } = {},
|
|
28
|
+
): boolean {
|
|
29
|
+
if (process.env.CELILO_UNIT_ONLY === '1') return true;
|
|
30
|
+
if (req.tools?.some((t) => !hasTool(t))) return true;
|
|
31
|
+
if (req.platform && process.platform !== req.platform) return true;
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
@@ -31,6 +31,12 @@ export interface ProxmoxConfig {
|
|
|
31
31
|
default_target_node: string;
|
|
32
32
|
lxc_template: string;
|
|
33
33
|
storage: string;
|
|
34
|
+
/**
|
|
35
|
+
* Cloud-init VM template to clone for `requires.system.type: vm` modules — the
|
|
36
|
+
* VM analogue of `lxc_template`. Optional: only services hosting VM modules set
|
|
37
|
+
* it (the operator builds the template once, per VM_INFRA_TYPE.md).
|
|
38
|
+
*/
|
|
39
|
+
vm_template?: string;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
/**
|
|
@@ -90,7 +90,7 @@ beforeEach(async () => {
|
|
|
90
90
|
// Encrypt with the SAME master key the resolver will decrypt with (the one
|
|
91
91
|
// beforeEach wrote into CELILO_DATA_DIR).
|
|
92
92
|
const enc = encryptSecret(
|
|
93
|
-
JSON.stringify({ '
|
|
93
|
+
JSON.stringify({ 'example.net': 'pw1', 'celilo.computer': 'pw2' }),
|
|
94
94
|
await loadTestMasterKey(),
|
|
95
95
|
);
|
|
96
96
|
db.$client
|
|
@@ -133,7 +133,7 @@ describe('computed capability fields — DB integration', () => {
|
|
|
133
133
|
expect(result.success).toBe(true);
|
|
134
134
|
if (result.success) {
|
|
135
135
|
// Non-scalar computed results serialize to JSON in the string path.
|
|
136
|
-
expect(JSON.parse(result.value)).toEqual(['
|
|
136
|
+
expect(JSON.parse(result.value)).toEqual(['example.net', 'celilo.computer']);
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
139
|
|
|
@@ -170,7 +170,7 @@ describe('computed capability fields — DB integration', () => {
|
|
|
170
170
|
const reg = ctx.capabilities.dns_registrar as Record<string, unknown>;
|
|
171
171
|
|
|
172
172
|
// The real array, not the raw marker object.
|
|
173
|
-
expect(reg.domain_list).toEqual(['
|
|
173
|
+
expect(reg.domain_list).toEqual(['example.net', 'celilo.computer']);
|
|
174
174
|
expect(reg.provider).toBe('namecheap');
|
|
175
175
|
});
|
|
176
176
|
|
|
@@ -23,7 +23,7 @@ function makeLookup(data: Record<string, unknown>): LookupFn {
|
|
|
23
23
|
|
|
24
24
|
const FIXTURE = {
|
|
25
25
|
secret: {
|
|
26
|
-
ddns_passwords: { '
|
|
26
|
+
ddns_passwords: { 'example.net': 'pw1', 'celilo.computer': 'pw2' },
|
|
27
27
|
},
|
|
28
28
|
self: {
|
|
29
29
|
zone_names: { dmz: 'DMZ', app: 'App' },
|
|
@@ -34,7 +34,7 @@ const FIXTURE = {
|
|
|
34
34
|
zones_with_dupes: ['x', 'y', 'x', 'z', 'y'],
|
|
35
35
|
},
|
|
36
36
|
system: {
|
|
37
|
-
primary_domain: '
|
|
37
|
+
primary_domain: 'example.net',
|
|
38
38
|
},
|
|
39
39
|
};
|
|
40
40
|
|
|
@@ -44,7 +44,7 @@ function evalOk(expr: string): unknown {
|
|
|
44
44
|
|
|
45
45
|
describe('computed DSL — keys', () => {
|
|
46
46
|
test('keys of the ddns_passwords secret map (the domain_list case)', () => {
|
|
47
|
-
expect(evalOk('keys(secret.ddns_passwords)')).toEqual(['
|
|
47
|
+
expect(evalOk('keys(secret.ddns_passwords)')).toEqual(['example.net', 'celilo.computer']);
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
test('keys of a non-secret object', () => {
|
|
@@ -63,7 +63,7 @@ describe('computed DSL — values', () => {
|
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
test('keys of a secret map is allowed (key names are non-sensitive)', () => {
|
|
66
|
-
expect(evalOk('keys(secret.ddns_passwords)')).toEqual(['
|
|
66
|
+
expect(evalOk('keys(secret.ddns_passwords)')).toEqual(['example.net', 'celilo.computer']);
|
|
67
67
|
});
|
|
68
68
|
});
|
|
69
69
|
|
|
@@ -107,7 +107,7 @@ describe('computed DSL — concat + unique (nesting/chaining)', () => {
|
|
|
107
107
|
describe('computed DSL — format', () => {
|
|
108
108
|
test('interpolates named parts', () => {
|
|
109
109
|
expect(evalOk("format('{host}.{zone}', host=self.hostname, zone=system.primary_domain)")).toBe(
|
|
110
|
-
'dns-int.
|
|
110
|
+
'dns-int.example.net',
|
|
111
111
|
);
|
|
112
112
|
});
|
|
113
113
|
|
|
@@ -164,14 +164,14 @@ describe('resolveDeclarativeDerivation', () => {
|
|
|
164
164
|
capabilities: {
|
|
165
165
|
dns_external: {
|
|
166
166
|
server: {
|
|
167
|
-
ip: '
|
|
167
|
+
ip: '192.0.2.20',
|
|
168
168
|
},
|
|
169
169
|
},
|
|
170
170
|
},
|
|
171
171
|
};
|
|
172
172
|
|
|
173
173
|
const result = resolveDeclarativeDerivation(variable, context);
|
|
174
|
-
expect(result).toBe('
|
|
174
|
+
expect(result).toBe('192.0.2.20');
|
|
175
175
|
});
|
|
176
176
|
|
|
177
177
|
test('resolves nested capability path', () => {
|
|
@@ -193,7 +193,7 @@ describe('resolveDeclarativeDerivation', () => {
|
|
|
193
193
|
dns_external: {
|
|
194
194
|
server: {
|
|
195
195
|
ip: {
|
|
196
|
-
primary: '
|
|
196
|
+
primary: '192.0.2.20',
|
|
197
197
|
secondary: '188.166.157.3',
|
|
198
198
|
},
|
|
199
199
|
},
|
|
@@ -202,7 +202,7 @@ describe('resolveDeclarativeDerivation', () => {
|
|
|
202
202
|
};
|
|
203
203
|
|
|
204
204
|
const result = resolveDeclarativeDerivation(variable, context);
|
|
205
|
-
expect(result).toBe('
|
|
205
|
+
expect(result).toBe('192.0.2.20');
|
|
206
206
|
});
|
|
207
207
|
|
|
208
208
|
test('throws on missing capability', () => {
|
|
@@ -350,13 +350,13 @@ describe('resolveDeclarativeDerivation', () => {
|
|
|
350
350
|
secrets: {},
|
|
351
351
|
capabilities: {
|
|
352
352
|
dns_external: {
|
|
353
|
-
server: { ip: '
|
|
353
|
+
server: { ip: '192.0.2.20' },
|
|
354
354
|
},
|
|
355
355
|
},
|
|
356
356
|
};
|
|
357
357
|
|
|
358
358
|
const result = resolveDeclarativeDerivation(variable, context);
|
|
359
|
-
expect(result).toBe('caddy.example.com@
|
|
359
|
+
expect(result).toBe('caddy.example.com@192.0.2.20');
|
|
360
360
|
});
|
|
361
361
|
});
|
|
362
362
|
|