@celilo/cli 0.8.2 → 0.9.0
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/AGENTS.md +10 -18
- package/CELILO_CORE_MODULES.md +61 -0
- package/CELILO_SUBSYSTEMS.md +83 -0
- package/README.md +1539 -48
- package/drizzle/0012_module_systems_sizing.sql +3 -0
- package/drizzle/0013_dns_view_overrides.sql +1 -0
- package/drizzle/meta/_journal.json +14 -0
- package/package.json +4 -3
- package/src/capabilities/well-known.test.ts +12 -7
- package/src/capabilities/well-known.ts +11 -3
- package/src/cli/command-registry.ts +65 -1
- package/src/cli/commands/module-upgrade.test.ts +29 -0
- package/src/cli/commands/module-upgrade.ts +57 -24
- package/src/cli/commands/proxmox-instance-list.test.ts +77 -0
- package/src/cli/commands/proxmox-instance-list.ts +140 -0
- package/src/cli/commands/proxmox-instance-resize.ts +235 -0
- package/src/cli/commands/proxmox-node-list.ts +1 -34
- package/src/cli/commands/proxmox-resize-guards.test.ts +55 -0
- package/src/cli/commands/proxmox-resize-guards.ts +102 -0
- package/src/cli/commands/proxmox-service.ts +38 -0
- package/src/cli/completion.ts +11 -3
- package/src/cli/index.ts +15 -0
- package/src/db/schema.ts +21 -1
- package/src/hooks/capability-loader.ts +22 -0
- package/src/manifest/template-validator.test.ts +31 -1
- package/src/manifest/template-validator.ts +9 -0
- package/src/services/deployed-systems.test.ts +73 -1
- package/src/services/deployed-systems.ts +72 -0
- package/src/services/dns-internal-records.test.ts +76 -3
- package/src/services/dns-internal-records.ts +52 -3
- package/src/services/dns-provider-backfill.ts +15 -3
- package/src/services/fleet-checks.test.ts +18 -16
- package/src/services/machine-detector.ts +34 -12
- package/src/templates/generator.ts +49 -1
- package/src/variables/context.ts +36 -7
- package/CLI_USAGE.md +0 -433
|
@@ -27,7 +27,11 @@ import {
|
|
|
27
27
|
findBrokenCapabilityDerivations,
|
|
28
28
|
} from '../services/fleet-checks';
|
|
29
29
|
import { selectInfrastructure } from '../services/infrastructure-selector';
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
deleteModuleConfig,
|
|
32
|
+
getModuleConfigValue,
|
|
33
|
+
upsertModuleConfig,
|
|
34
|
+
} from '../services/module-config';
|
|
31
35
|
import type { InfrastructureSelection } from '../types/infrastructure';
|
|
32
36
|
import { convertSecretsToJinja } from '../variables/ansible-resolver';
|
|
33
37
|
import { buildResolutionContext } from '../variables/context';
|
|
@@ -730,6 +734,50 @@ export async function generateTemplates(options: GenerateOptions): Promise<Gener
|
|
|
730
734
|
}
|
|
731
735
|
}
|
|
732
736
|
|
|
737
|
+
// Dedicated DNS-ingress IP (ISS-0156). A dns_internal provider now deploys into
|
|
738
|
+
// a PROTECTED zone (dmz) so it can see protected-zone query sources for
|
|
739
|
+
// split-horizon views (v2/INTERNAL_DNS_ZONE_VIEWS.md). `internal` devices have
|
|
740
|
+
// no route into the 10-net, so they reach the resolver through a firewall DNAT
|
|
741
|
+
// on a dedicated `internal`-subnet address. A module opts in by declaring a
|
|
742
|
+
// `dns_ingress_ip` infrastructure variable; we allocate a free IP from the
|
|
743
|
+
// `internal` subnet via IPAM and RESERVE it (so it's never re-handed-out),
|
|
744
|
+
// idempotently (reuse the stored value on re-generate). The resolver's
|
|
745
|
+
// on_install passes it to firewall.exposeService({ ingressIp }).
|
|
746
|
+
const wantsDnsIngress = manifest.variables?.owns?.some(
|
|
747
|
+
(v) => v.name === 'dns_ingress_ip' && v.source === 'infrastructure',
|
|
748
|
+
);
|
|
749
|
+
if (wantsDnsIngress) {
|
|
750
|
+
const existing = getModuleConfigValue(moduleId, 'dns_ingress_ip', db)?.value;
|
|
751
|
+
if (typeof existing === 'string' && existing.length > 0) {
|
|
752
|
+
log.success(`Using existing DNS-ingress IP ${existing} for ${moduleId}`);
|
|
753
|
+
} else {
|
|
754
|
+
const subnetRow = db.$client
|
|
755
|
+
.prepare('SELECT value FROM system_config WHERE key = ?')
|
|
756
|
+
.get('network.internal.subnet') as { value: string } | undefined;
|
|
757
|
+
if (!subnetRow?.value) {
|
|
758
|
+
return {
|
|
759
|
+
success: false,
|
|
760
|
+
error:
|
|
761
|
+
'network.internal.subnet is not configured — required to allocate the ' +
|
|
762
|
+
'dns_internal DNS-ingress IP (ISS-0156). Ensure the internal network is set up first.',
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
const { allocateIPFromSubnet, reserveIP } = await import('../ipam/allocator');
|
|
766
|
+
const { stripCIDR } = await import('../ipam/subnet-parser');
|
|
767
|
+
try {
|
|
768
|
+
const ip = stripCIDR(await allocateIPFromSubnet(subnetRow.value, 'internal', db));
|
|
769
|
+
await reserveIP(ip, 'internal', `dns-ingress:${moduleId}`, null, db);
|
|
770
|
+
upsertModuleConfig(db, moduleId, 'dns_ingress_ip', ip);
|
|
771
|
+
log.success(`Allocated DNS-ingress IP ${ip} (internal subnet) for ${moduleId}`);
|
|
772
|
+
} catch (error) {
|
|
773
|
+
return {
|
|
774
|
+
success: false,
|
|
775
|
+
error: `DNS-ingress IP allocation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
733
781
|
// Infrastructure Properties Resolution (Proxmox provider config)
|
|
734
782
|
// For Proxmox services, extract provider config and store as temporary values
|
|
735
783
|
// This happens during generation so templates can access target_node, lxc_template, etc.
|
package/src/variables/context.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
machines,
|
|
9
9
|
moduleConfigs,
|
|
10
10
|
moduleInfrastructure,
|
|
11
|
+
moduleSystems,
|
|
11
12
|
modules,
|
|
12
13
|
secrets,
|
|
13
14
|
systemConfig,
|
|
@@ -264,20 +265,48 @@ export async function buildResolutionContext(
|
|
|
264
265
|
const systemResources = getSingularSystemSpec(manifest);
|
|
265
266
|
|
|
266
267
|
if (systemResources) {
|
|
267
|
-
//
|
|
268
|
+
// The DEPLOYED size is the SYSTEM's canonical state (ISS-0150), seeded from
|
|
269
|
+
// requires.system at first provision and thereafter owned by
|
|
270
|
+
// `celilo proxmox … resize`. So sizing flows: module_systems → these config
|
|
271
|
+
// vars → `$self:{cores,memory,disk}` in the instance Terraform.
|
|
272
|
+
//
|
|
273
|
+
// Precedence: the recorded system size WINS and overwrites the cached
|
|
274
|
+
// config (a resize must propagate on the next generate); only when this
|
|
275
|
+
// module has no recorded system size yet (the very first provision, before
|
|
276
|
+
// recordDeployedSystemForModule runs below) do we fall back to
|
|
277
|
+
// requires.system — and seed-when-unset, matching the prior behavior so the
|
|
278
|
+
// first-deploy / golden output is unchanged. `requires.system` stays the
|
|
279
|
+
// minimum floor, never the canonical size. (CLAUDE.md / ISS-0150.)
|
|
280
|
+
const sizedRow = db
|
|
281
|
+
.select({
|
|
282
|
+
cpu: moduleSystems.cpu,
|
|
283
|
+
memory: moduleSystems.memory,
|
|
284
|
+
disk: moduleSystems.disk,
|
|
285
|
+
})
|
|
286
|
+
.from(moduleSystems)
|
|
287
|
+
.where(eq(moduleSystems.moduleId, moduleId))
|
|
288
|
+
.all()
|
|
289
|
+
.find((r) => r.cpu != null || r.memory != null || r.disk != null);
|
|
290
|
+
|
|
268
291
|
const resourceMappings: Array<{
|
|
269
292
|
manifestKey: keyof typeof systemResources;
|
|
270
293
|
configKey: string;
|
|
294
|
+
systemValue: number | null | undefined;
|
|
271
295
|
}> = [
|
|
272
|
-
{ manifestKey: 'cpu', configKey: 'cores' }, //
|
|
273
|
-
{ manifestKey: 'memory', configKey: 'memory' },
|
|
274
|
-
{ manifestKey: 'disk', configKey: 'disk' },
|
|
275
|
-
{ manifestKey: 'storage', configKey: 'storage' },
|
|
296
|
+
{ manifestKey: 'cpu', configKey: 'cores', systemValue: sizedRow?.cpu }, // requires.system.cpu → cores
|
|
297
|
+
{ manifestKey: 'memory', configKey: 'memory', systemValue: sizedRow?.memory },
|
|
298
|
+
{ manifestKey: 'disk', configKey: 'disk', systemValue: sizedRow?.disk },
|
|
299
|
+
{ manifestKey: 'storage', configKey: 'storage', systemValue: undefined }, // pool name, not sizing
|
|
276
300
|
];
|
|
277
301
|
|
|
278
|
-
for (const { manifestKey, configKey } of resourceMappings) {
|
|
302
|
+
for (const { manifestKey, configKey, systemValue } of resourceMappings) {
|
|
303
|
+
if (systemValue != null) {
|
|
304
|
+
// Canonical system size — always wins so a resize propagates.
|
|
305
|
+
upsertModuleConfig(db, moduleId, configKey, systemValue);
|
|
306
|
+
selfConfig[configKey] = String(systemValue);
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
279
309
|
const value = systemResources[manifestKey];
|
|
280
|
-
|
|
281
310
|
// Manifest fields are typed (cpu: number, storage: string, etc.).
|
|
282
311
|
// Pass them through unstringified so valueJson preserves the
|
|
283
312
|
// shape — see comment in the variable-defaults block above.
|
package/CLI_USAGE.md
DELETED
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
# Celilo CLI Usage Guide
|
|
2
|
-
|
|
3
|
-
Common workflows and command patterns for the Celilo CLI.
|
|
4
|
-
|
|
5
|
-
## Quick Reference
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# Import and setup
|
|
9
|
-
celilo module import <path>
|
|
10
|
-
celilo system config set <key> <value>
|
|
11
|
-
celilo module config set <module> <key> <value>
|
|
12
|
-
celilo secret set <module> <name> <value>
|
|
13
|
-
celilo module generate <module>
|
|
14
|
-
|
|
15
|
-
# Query and inspect
|
|
16
|
-
celilo module list
|
|
17
|
-
celilo module config get <module>
|
|
18
|
-
celilo system config get [key]
|
|
19
|
-
celilo system vault-password
|
|
20
|
-
|
|
21
|
-
# Manage
|
|
22
|
-
celilo module remove <module>
|
|
23
|
-
celilo help
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Common Workflows
|
|
27
|
-
|
|
28
|
-
### 1. Setting Up a New Module
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
# Step 1: Import the module
|
|
32
|
-
./celilo module import modules/homebridge
|
|
33
|
-
# Output: Successfully imported module: homebridge
|
|
34
|
-
# Files copied to: /tmp/celilo/modules/homebridge
|
|
35
|
-
|
|
36
|
-
# Step 2: Configure system-wide settings (if not already set)
|
|
37
|
-
./celilo system config set dns.primary 192.168.0.1
|
|
38
|
-
./celilo system config set dns.fallback "8.8.8.8 1.1.1.1"
|
|
39
|
-
./celilo system config set routing.internal_gateway 192.168.0.254
|
|
40
|
-
|
|
41
|
-
# Step 3: Configure module-specific settings
|
|
42
|
-
./celilo module config set homebridge vmid 2110
|
|
43
|
-
./celilo module config set homebridge hostname iot
|
|
44
|
-
./celilo module config set homebridge container_ip "192.168.0.110/24"
|
|
45
|
-
./celilo module config set homebridge gateway 192.168.0.254
|
|
46
|
-
./celilo module config set homebridge vlan 192
|
|
47
|
-
./celilo module config set homebridge cores 2
|
|
48
|
-
./celilo module config set homebridge memory 2048
|
|
49
|
-
./celilo module config set homebridge storage datacenter
|
|
50
|
-
./celilo module config set homebridge rootfs_size 20G
|
|
51
|
-
|
|
52
|
-
# Step 4: Set secrets
|
|
53
|
-
./celilo secret set homebridge api_key "your_api_key_here"
|
|
54
|
-
./celilo secret set homebridge db_password "your_password_here"
|
|
55
|
-
|
|
56
|
-
# Step 5: Generate infrastructure code
|
|
57
|
-
./celilo module generate homebridge
|
|
58
|
-
# Output: Successfully generated 8 files:
|
|
59
|
-
# - terraform/main.tf
|
|
60
|
-
# - terraform/variables.tf
|
|
61
|
-
# - ...
|
|
62
|
-
|
|
63
|
-
# Step 6: Review generated files
|
|
64
|
-
ls -la /tmp/celilo/modules/homebridge/generated/
|
|
65
|
-
cd /tmp/celilo/modules/homebridge/generated/
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### 2. Inspecting Configuration
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
# List all modules
|
|
72
|
-
./celilo module list
|
|
73
|
-
|
|
74
|
-
# Get all config for a module
|
|
75
|
-
./celilo module config get homebridge
|
|
76
|
-
|
|
77
|
-
# Get specific config value
|
|
78
|
-
./celilo module config get homebridge hostname
|
|
79
|
-
|
|
80
|
-
# Get all system config
|
|
81
|
-
./celilo system config get
|
|
82
|
-
|
|
83
|
-
# Get specific system config
|
|
84
|
-
./celilo system config get dns.primary
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### 3. Working with Secrets
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
# Set a secret
|
|
91
|
-
./celilo secret set homebridge api_key "secret_value"
|
|
92
|
-
|
|
93
|
-
# View encrypted secrets file
|
|
94
|
-
MODULE=homebridge
|
|
95
|
-
SECRETS_FILE=/tmp/celilo/modules/$MODULE/generated/ansible/inventory/secrets.yml
|
|
96
|
-
|
|
97
|
-
# Check it's encrypted
|
|
98
|
-
head -1 $SECRETS_FILE
|
|
99
|
-
# Should show: $ANSIBLE_VAULT;1.1;AES256
|
|
100
|
-
|
|
101
|
-
# Decrypt and view
|
|
102
|
-
ansible-vault view $SECRETS_FILE \
|
|
103
|
-
--vault-password-file=<(./celilo system vault-password)
|
|
104
|
-
|
|
105
|
-
# Edit encrypted secrets directly (if needed)
|
|
106
|
-
ansible-vault edit $SECRETS_FILE \
|
|
107
|
-
--vault-password-file=<(./celilo system vault-password)
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### 4. Regenerating After Changes
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
# Change configuration
|
|
114
|
-
./celilo module config set homebridge cores 4
|
|
115
|
-
./celilo module config set homebridge memory 4096
|
|
116
|
-
|
|
117
|
-
# Regenerate
|
|
118
|
-
./celilo module generate homebridge
|
|
119
|
-
|
|
120
|
-
# Generated files will reflect new configuration
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### 5. Removing a Module
|
|
124
|
-
|
|
125
|
-
```bash
|
|
126
|
-
# Remove module (cascade deletes all config and secrets)
|
|
127
|
-
./celilo module remove homebridge
|
|
128
|
-
|
|
129
|
-
# Verify removal
|
|
130
|
-
./celilo module list
|
|
131
|
-
# Should no longer show homebridge
|
|
132
|
-
|
|
133
|
-
# Manually clean up generated files if needed
|
|
134
|
-
rm -rf /tmp/celilo/modules/homebridge/
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 6. Using Generated Infrastructure
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
# Terraform workflow
|
|
141
|
-
cd /tmp/celilo/modules/homebridge/generated/terraform
|
|
142
|
-
terraform init
|
|
143
|
-
terraform plan
|
|
144
|
-
terraform apply
|
|
145
|
-
|
|
146
|
-
# Ansible workflow
|
|
147
|
-
cd /tmp/celilo/modules/homebridge/generated/ansible
|
|
148
|
-
ansible-playbook playbook.yml \
|
|
149
|
-
-i inventory/ \
|
|
150
|
-
--vault-password-file=<(celilo system vault-password)
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Advanced Usage
|
|
154
|
-
|
|
155
|
-
### Running from Different Directories
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
# From anywhere (using wrapper script)
|
|
159
|
-
/path/to/celilo/celilo module list
|
|
160
|
-
|
|
161
|
-
# From backend directory (using bun)
|
|
162
|
-
cd /path/to/celilo/backend
|
|
163
|
-
bun run src/cli/index.ts module list
|
|
164
|
-
|
|
165
|
-
# From backend directory (using npm script)
|
|
166
|
-
cd /path/to/celilo/backend
|
|
167
|
-
bun run dev -- module list
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Custom Database Location
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
# Set environment variable
|
|
174
|
-
export CELILO_DB_PATH=/custom/path/celilo.db
|
|
175
|
-
|
|
176
|
-
# Run migrations
|
|
177
|
-
bun run db:migrate
|
|
178
|
-
|
|
179
|
-
# Use CLI (will use custom database)
|
|
180
|
-
./celilo module list
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Custom Output Directory
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
# Generate to specific location
|
|
187
|
-
./celilo module generate homebridge --output /custom/output/path
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Scripting with Celilo
|
|
191
|
-
|
|
192
|
-
```bash
|
|
193
|
-
#!/bin/bash
|
|
194
|
-
# Example: setup-homebridge.sh
|
|
195
|
-
|
|
196
|
-
set -e # Exit on error
|
|
197
|
-
|
|
198
|
-
MODULE=homebridge
|
|
199
|
-
|
|
200
|
-
# Import module
|
|
201
|
-
./celilo module import "modules/$MODULE"
|
|
202
|
-
|
|
203
|
-
# Configure system
|
|
204
|
-
./celilo system config set dns.primary 192.168.0.1
|
|
205
|
-
./celilo system config set routing.internal_gateway 192.168.0.254
|
|
206
|
-
|
|
207
|
-
# Configure module (read from config file or environment)
|
|
208
|
-
./celilo module config set $MODULE vmid "${VMID}"
|
|
209
|
-
./celilo module config set $MODULE hostname "${HOSTNAME}"
|
|
210
|
-
./celilo module config set $MODULE container_ip "${CONTAINER_IP}"
|
|
211
|
-
|
|
212
|
-
# Set secrets (from secure source)
|
|
213
|
-
./celilo secret set $MODULE api_key "${API_KEY}"
|
|
214
|
-
|
|
215
|
-
# Generate
|
|
216
|
-
./celilo module generate $MODULE
|
|
217
|
-
|
|
218
|
-
echo "Setup complete! Generated files at:"
|
|
219
|
-
echo " /tmp/celilo/modules/$MODULE/generated/"
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Debugging
|
|
223
|
-
|
|
224
|
-
```bash
|
|
225
|
-
# Check if module was imported correctly
|
|
226
|
-
./celilo module list
|
|
227
|
-
|
|
228
|
-
# Verify configuration
|
|
229
|
-
./celilo module config get homebridge
|
|
230
|
-
|
|
231
|
-
# Check database directly
|
|
232
|
-
sqlite3 celilo.db "SELECT * FROM modules;"
|
|
233
|
-
sqlite3 celilo.db "SELECT * FROM module_configs WHERE module_id='homebridge';"
|
|
234
|
-
|
|
235
|
-
# View encrypted secrets (verify they're not plaintext)
|
|
236
|
-
sqlite3 celilo.db "SELECT name, substr(encrypted_value, 1, 20) || '...' AS encrypted FROM secrets WHERE module_id='homebridge';"
|
|
237
|
-
|
|
238
|
-
# Check generated files exist
|
|
239
|
-
ls -la /tmp/celilo/modules/homebridge/generated/
|
|
240
|
-
|
|
241
|
-
# Validate generated Terraform
|
|
242
|
-
cd /tmp/celilo/modules/homebridge/generated/terraform
|
|
243
|
-
terraform fmt -check
|
|
244
|
-
terraform validate
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
## Common Patterns
|
|
248
|
-
|
|
249
|
-
### Bulk Configuration
|
|
250
|
-
|
|
251
|
-
```bash
|
|
252
|
-
# Set multiple values in sequence
|
|
253
|
-
for key in vmid hostname container_ip gateway vlan cores memory storage; do
|
|
254
|
-
./celilo module config set homebridge $key "${!key}"
|
|
255
|
-
done
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Configuration from File
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
# Read config from YAML/JSON and apply
|
|
262
|
-
# Example config.yml:
|
|
263
|
-
# homebridge:
|
|
264
|
-
# vmid: 2110
|
|
265
|
-
# hostname: iot
|
|
266
|
-
# ...
|
|
267
|
-
|
|
268
|
-
# Using yq or jq
|
|
269
|
-
while IFS='=' read -r key value; do
|
|
270
|
-
./celilo module config set homebridge "$key" "$value"
|
|
271
|
-
done < <(yq eval '.homebridge | to_entries | .[] | .key + "=" + (.value | tostring)' config.yml)
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Export Configuration
|
|
275
|
-
|
|
276
|
-
```bash
|
|
277
|
-
# Export all config for a module
|
|
278
|
-
./celilo module config get homebridge > homebridge-config.txt
|
|
279
|
-
|
|
280
|
-
# Export system config
|
|
281
|
-
./celilo system config get > system-config.txt
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### Validate Before Generate
|
|
285
|
-
|
|
286
|
-
```bash
|
|
287
|
-
# Check all required config is set
|
|
288
|
-
REQUIRED_KEYS="vmid hostname container_ip gateway vlan"
|
|
289
|
-
|
|
290
|
-
for key in $REQUIRED_KEYS; do
|
|
291
|
-
if ! ./celilo module config get homebridge $key &>/dev/null; then
|
|
292
|
-
echo "ERROR: Missing required config: $key"
|
|
293
|
-
exit 1
|
|
294
|
-
fi
|
|
295
|
-
done
|
|
296
|
-
|
|
297
|
-
# All required config present, generate
|
|
298
|
-
./celilo module generate homebridge
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
## Tips & Tricks
|
|
302
|
-
|
|
303
|
-
### 1. Use Absolute Paths for Module Import
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
# Relative path (preferred - works from celilo root)
|
|
307
|
-
./celilo module import ../modules/homebridge
|
|
308
|
-
|
|
309
|
-
# Absolute path (use your actual path)
|
|
310
|
-
./celilo module import /path/to/celilo/modules/homebridge
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
The wrapper script handles relative path conversion automatically for `module import`.
|
|
314
|
-
|
|
315
|
-
### 2. Quote Values with Spaces or Special Characters
|
|
316
|
-
|
|
317
|
-
```bash
|
|
318
|
-
# Correct
|
|
319
|
-
./celilo module config set homebridge bridge_name "Home Bridge"
|
|
320
|
-
./celilo system config set dns.fallback "8.8.8.8 1.1.1.1"
|
|
321
|
-
|
|
322
|
-
# Wrong (will only set first word)
|
|
323
|
-
./celilo module config set homebridge bridge_name Home Bridge
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
### 3. Store Vault Password Securely
|
|
327
|
-
|
|
328
|
-
```bash
|
|
329
|
-
# DO NOT store vault password in plain files
|
|
330
|
-
# BAD: echo "password" > vault-pass.txt
|
|
331
|
-
|
|
332
|
-
# GOOD: Use celilo CLI with process substitution
|
|
333
|
-
ansible-vault view secrets.yml \
|
|
334
|
-
--vault-password-file=<(./celilo system vault-password)
|
|
335
|
-
|
|
336
|
-
# GOOD: Export to environment (for scripts)
|
|
337
|
-
export ANSIBLE_VAULT_PASSWORD=$(./celilo system vault-password)
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### 4. Check Help for Any Command
|
|
341
|
-
|
|
342
|
-
```bash
|
|
343
|
-
./celilo help # General help
|
|
344
|
-
./celilo module --help # Module command help
|
|
345
|
-
./celilo module config --help # Config subcommand help (shows same general help)
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
### 5. Validate Manifests Before Import
|
|
349
|
-
|
|
350
|
-
```bash
|
|
351
|
-
# Module imports will validate automatically, but you can check manually
|
|
352
|
-
cd backend
|
|
353
|
-
bun run src/cli/index.ts module import ../modules/homebridge
|
|
354
|
-
# Look for validation error messages
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
## Troubleshooting
|
|
358
|
-
|
|
359
|
-
### "Module not found" After Import
|
|
360
|
-
|
|
361
|
-
**Check import succeeded**:
|
|
362
|
-
```bash
|
|
363
|
-
./celilo module list
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
**Verify files copied**:
|
|
367
|
-
```bash
|
|
368
|
-
ls -la /tmp/celilo/modules/homebridge/
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
**Check database**:
|
|
372
|
-
```bash
|
|
373
|
-
sqlite3 celilo.db "SELECT id, name, state FROM modules;"
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
### "Variable not found" During Generate
|
|
377
|
-
|
|
378
|
-
**Check configuration is set**:
|
|
379
|
-
```bash
|
|
380
|
-
./celilo module config get homebridge
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
**Check system config**:
|
|
384
|
-
```bash
|
|
385
|
-
./celilo system config get
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
**Identify missing variables**:
|
|
389
|
-
```bash
|
|
390
|
-
# Error message will show which variables are missing:
|
|
391
|
-
# Error: Failed to resolve variables in templates:
|
|
392
|
-
# terraform/main.tf:
|
|
393
|
-
# $self:cores: Self variable 'cores' not found in module configuration
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
Set the missing config and regenerate.
|
|
397
|
-
|
|
398
|
-
### "Failed to generate Ansible secrets"
|
|
399
|
-
|
|
400
|
-
**Check Ansible is installed**:
|
|
401
|
-
```bash
|
|
402
|
-
ansible-vault --version
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
**If Ansible is missing**:
|
|
406
|
-
```bash
|
|
407
|
-
# macOS
|
|
408
|
-
brew install ansible
|
|
409
|
-
|
|
410
|
-
# Ubuntu/Debian
|
|
411
|
-
sudo apt-get install ansible
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
### Generated Files Not Where Expected
|
|
415
|
-
|
|
416
|
-
**Default location**: `/tmp/celilo/modules/<module-id>/generated/`
|
|
417
|
-
|
|
418
|
-
**Custom location**:
|
|
419
|
-
```bash
|
|
420
|
-
./celilo module generate homebridge --output /custom/path
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
**Check generation output**:
|
|
424
|
-
```bash
|
|
425
|
-
./celilo module generate homebridge
|
|
426
|
-
# Output shows: "Output: /tmp/celilo/modules/homebridge/generated"
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
## Next Steps
|
|
430
|
-
|
|
431
|
-
- Read [INTEGRATION_TESTS.md](backend/INTEGRATION_TESTS.md) for testing workflows
|
|
432
|
-
- Read [backend/README.md](backend/README.md) for architecture details
|
|
433
|
-
- Check [SETUP.md](SETUP.md) for installation and setup guides
|