Skip to content

Commit 83388d1

Browse files
committed
amp: fix cue modules usage
1 parent abd3308 commit 83388d1

10 files changed

Lines changed: 382 additions & 314 deletions

File tree

AGENTS.md

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ make build-dev
1515
make install
1616

1717
# Check version
18-
./bin/dibra --version
18+
dibra --version
1919

2020
# Run playbook (released binary — auto-downloads agent from GitHub Releases)
2121
dibra -config playbook.yaml
@@ -304,7 +304,7 @@ dibra/
304304
│ │ ├── docker_swarm.cue # #DockerSwarmService, #DockerNode, etc.
305305
│ │ └── docker_info.cue # #DockerContainerInfo, #DockerImageInfo, etc.
306306
│ └── composed/ # Higher-level composed types
307-
│ └── deploy_service.cue # #DeployService, #InstallFromAptRepo, etc.
307+
│ └── deploy_service.cue # #InstallCaddy, etc.
308308
├── test/
309309
│ ├── Dockerfile # Ubuntu 22.04 + systemd + SSH
310310
│ ├── docker-compose.yaml # Test container orchestration
@@ -367,7 +367,7 @@ all:
367367
## Modules
368368

369369
`WHEN ADDING OR EDITING A NEW MODULE, ALWAYS ADD OR MODIFY ITS CUE SCHEMA`
370-
370+
`WHEN ADDING A NEW COMMAND OR FLAG YOU MUST ALSO ADD IT IN THE SHELL COMPLETIONS`
371371
### ping
372372

373373
A trivial test module to verify SSH connectivity. Returns "pong" on success.
@@ -3461,7 +3461,7 @@ dibra --config ./dir_with_cue_project
34613461

34623462
### Composed Types (Higher-Level Abstractions)
34633463

3464-
This is the key differentiator from YAML. Composed types encapsulate multiple low-level tasks behind a simplified interface. They use a `_tasks` field (hidden in CUE output) that decomposes into a flat task list.
3464+
This is the key differentiator from YAML. Composed types encapsulate multiple low-level tasks behind a simplified interface. They use a `tasks` field (hidden in CUE output) that decomposes into a flat task list.
34653465

34663466
#### Defining a Composed Type
34673467

@@ -3493,8 +3493,8 @@ import (
34933493
]), "\n")
34943494
34953495
// Decomposition: flat task list
3496-
_tasks: [...]
3497-
_tasks: [
3496+
tasks: [...]
3497+
tasks: [
34983498
{name: "Copy \(service_name) binary", copy: {src: binary_src, dest: binary_dest, mode: "0755"}},
34993499
{name: "Deploy \(service_name) unit", copy: {content: _unit, dest: "/etc/systemd/system/\(service_name).service", mode: "0644"}},
35003500
{let _enabled = enabled, name: "Start \(service_name)", systemd_service: {name: service_name, state: "started", enabled: _enabled, daemon_reload: true}},
@@ -3514,7 +3514,7 @@ api: #DeployService & {
35143514
}
35153515
35163516
hosts: [{name: "web1", host: "10.0.0.1", user: "root"}]
3517-
tasks: api._tasks
3517+
tasks: api.tasks
35183518
```
35193519

35203520
This decomposes into 3 concrete tasks: copy binary, deploy unit file, start service.
@@ -3529,7 +3529,7 @@ import "list"
35293529
api: #DeployService & {service_name: "my-api", binary_src: "./build/api"}
35303530
db: #DeployService & {service_name: "my-db", binary_src: "./build/db"}
35313531
3532-
tasks: list.Concat([api._tasks, db._tasks])
3532+
tasks: list.Concat([api.tasks, db.tasks])
35333533
```
35343534

35353535
#### Mixing Composed + One-Off Tasks
@@ -3541,7 +3541,7 @@ api: #DeployService & {service_name: "my-api", binary_src: "./build/api"}
35413541
35423542
tasks: list.Concat([
35433543
[{name: "Install deps", apt: {name: ["curl", "jq"], state: "present"}}],
3544-
api._tasks,
3544+
api.tasks,
35453545
[{name: "Verify", shell: {cmd: "curl -sf http://localhost:8080/health"}}],
35463546
])
35473547
```
@@ -3578,11 +3578,10 @@ Located in `cue/composed/deploy_service.cue`:
35783578
| Type | Composes | Description |
35793579
|------|----------|-------------|
35803580
| `#DeployService` | `#Copy` + `#SystemdService` | Deploy a binary as a systemd service |
3581-
| `#InstallFromAptRepo` | `#AptKey` + `#AptRepository` + `#Apt` | Add GPG key, repo, install packages |
3582-
| `#DeployDockerStack` | `#File` + `#Copy` + `#DockerCompose` | Copy compose file, deploy stack |
3583-
| `#ConfigureNginxSite` | `#Copy` + `#File` + `#Service` | Deploy nginx config, enable site, reload |
3581+
| `#InstallCaddy` | `#AptKey` + `#AptRepository` + `#Apt` | Install Caddy |
3582+
| `#Copy` + `#File` + `#Service` | Deploy nginx config, enable site, reload |
35843583

3585-
Users can create their own composed types following the same `_tasks` pattern.
3584+
Users can create their own composed types following the same `tasks` pattern.
35863585

35873586
### CUE Schema Definitions
35883587

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ It's still under heavy development and largely untested in real world.
3737
## Documentation
3838
Unfortunately for the time being the best documentation is the code and AGENTS.md
3939

40+
## CUE Composed Types
41+
42+
Available CUE composed types live in `cue/composed/` and can be imported with:
43+
44+
```cue
45+
import "dibra.dev/composed"
46+
```
47+
48+
Included types:
49+
- `#InstallCaddy`
50+
4051
## Development
4152

4253
### Git Hooks (Lint + Unit Tests)

cmd/controller/main.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,19 +1625,19 @@ func main() {
16251625

16261626
case task.DockerPrune != nil:
16271627
args := map[string]interface{}{
1628-
"containers": task.DockerPrune.Containers,
1629-
"containers_filters": task.DockerPrune.ContainersFilters,
1630-
"images": task.DockerPrune.Images,
1631-
"images_filters": task.DockerPrune.ImagesFilters,
1632-
"networks": task.DockerPrune.Networks,
1633-
"networks_filters": task.DockerPrune.NetworksFilters,
1634-
"volumes": task.DockerPrune.Volumes,
1635-
"volumes_filters": task.DockerPrune.VolumesFilters,
1636-
"builder": task.DockerPrune.Builder,
1637-
"builder_cache_all": task.DockerPrune.BuilderCacheAll,
1628+
"containers": task.DockerPrune.Containers,
1629+
"containers_filters": task.DockerPrune.ContainersFilters,
1630+
"images": task.DockerPrune.Images,
1631+
"images_filters": task.DockerPrune.ImagesFilters,
1632+
"networks": task.DockerPrune.Networks,
1633+
"networks_filters": task.DockerPrune.NetworksFilters,
1634+
"volumes": task.DockerPrune.Volumes,
1635+
"volumes_filters": task.DockerPrune.VolumesFilters,
1636+
"builder": task.DockerPrune.Builder,
1637+
"builder_cache_all": task.DockerPrune.BuilderCacheAll,
16381638
"builder_cache_filters": task.DockerPrune.BuilderCacheFilters,
1639-
"docker_host": task.DockerPrune.DockerHost,
1640-
"tls": task.DockerPrune.TLS,
1639+
"docker_host": task.DockerPrune.DockerHost,
1640+
"tls": task.DockerPrune.TLS,
16411641
}
16421642
renderedArgs, err := renderArgs(args, flattened)
16431643

@@ -2781,6 +2781,7 @@ func runSchema(args []string) error {
27812781
return err
27822782
}
27832783
fmt.Printf("Installed dibra schema (%d file(s)) at %s (version %s)\n", result.Files, result.Path, result.Version)
2784+
fmt.Printf("Installed dibra composed types (%d file(s)) at %s (version %s)\n", result.ComposedFiles, result.ComposedPath, result.Version)
27842785
return nil
27852786
case "status":
27862787
fs := flag.NewFlagSet("schema status", flag.ContinueOnError)
@@ -2801,16 +2802,20 @@ func runSchema(args []string) error {
28012802
if status.Installed {
28022803
if status.UpToDate {
28032804
fmt.Printf("Schema installed at %s (%d file(s), version %s)\n", status.Path, status.Files, status.Version)
2805+
fmt.Printf("Composed types installed at %s (%d file(s), version %s)\n", status.ComposedPath, status.ComposedFiles, status.Version)
28042806
return nil
28052807
}
28062808
if status.Version == "" {
28072809
fmt.Printf("Schema installed at %s (%d file(s), version unknown; current %s)\n", status.Path, status.Files, status.Current)
2810+
fmt.Printf("Composed types installed at %s (%d file(s), version unknown; current %s)\n", status.ComposedPath, status.ComposedFiles, status.Current)
28082811
return nil
28092812
}
28102813
fmt.Printf("Schema installed at %s (%d file(s), version %s; current %s)\n", status.Path, status.Files, status.Version, status.Current)
2814+
fmt.Printf("Composed types installed at %s (%d file(s), version %s; current %s)\n", status.ComposedPath, status.ComposedFiles, status.Version, status.Current)
28112815
return nil
28122816
}
28132817
fmt.Printf("Schema not installed (expected at %s, current %s)\n", status.Path, status.Current)
2818+
fmt.Printf("Composed types not installed (expected at %s, current %s)\n", status.ComposedPath, status.Current)
28142819
return nil
28152820
default:
28162821
return fmt.Errorf("usage: dibra schema <install|upgrade|status> [--force] [path]")
@@ -2976,10 +2981,18 @@ playbook and inventory wired to the local integration-test container.
29762981
29772982
## Quick Start
29782983
2979-
1. Run the playbook:
2984+
1. Start the test container:
2985+
2986+
make test-integration-up
2987+
2988+
2. Run the playbook:
29802989
29812990
dibra -config ./deploy.cue
29822991
2992+
3. Tear down the container when done:
2993+
2994+
make test-integration-down
2995+
29832996
## Next Steps
29842997
29852998
- Edit deploy.cue to add tasks or update host credentials.

cue/composed/deploy_service.cue

Lines changed: 67 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -10,95 +10,75 @@ import (
1010
{[string]: _}
1111
}
1212

13-
#DeployService: {
13+
#InstallCaddy: {
1414
// User-facing fields
15-
service_name: string
16-
binary_src: string
17-
binary_dest: string | *"/usr/local/bin/\(service_name)"
18-
description: string | *"Managed by dibra"
19-
user: string | *"root"
20-
config_src?: string
21-
config_dest?: string
22-
env: {[string]: string} | *{}
23-
enabled: bool | *true
15+
install_method: "apt" | *"apt"
16+
version: string | *"2"
2417

25-
// Computed: systemd unit content
26-
let _env_lines = [ for k, v in env {"Environment=\(k)=\(v)"}]
27-
let _unit = strings.Join(list.Concat([
28-
[
29-
"[Unit]",
30-
"Description=\(description)",
31-
"After=network.target",
32-
"",
33-
"[Service]",
34-
"Type=simple",
35-
"User=\(user)",
36-
"ExecStart=\(binary_dest)",
37-
"Restart=on-failure",
38-
],
39-
_env_lines,
40-
[
41-
"",
42-
"[Install]",
43-
"WantedBy=multi-user.target",
44-
],
45-
]), "\n")
18+
_versions: {
19+
"2": {
20+
key_url: "https://dl.cloudsmith.io/public/caddy/stable/gpg.key"
21+
keyring: "/usr/share/keyrings/caddy-stable-archive-keyring.gpg"
22+
repo: "deb [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main"
23+
repo_filename: "caddy-stable"
24+
}
25+
}
4626

47-
// Decomposition: flat task list
48-
_tasks: [...#Task]
49-
_tasks: [
50-
{name: "Copy \(service_name) binary", copy: {src: binary_src, dest: binary_dest, mode: "0755"}},
51-
if config_src != _|_ if config_dest != _|_ {
52-
name: "Copy \(service_name) config"
53-
copy: {src: config_src, dest: config_dest, mode: "0644"}
54-
},
55-
{name: "Deploy \(service_name) unit", copy: {content: _unit, dest: "/etc/systemd/system/\(service_name).service", mode: "0644"}},
56-
{let _enabled = enabled, name: "Start \(service_name)", systemd_service: {name: service_name, state: "started", enabled: _enabled, daemon_reload: true}},
57-
]
58-
}
59-
60-
#InstallFromAptRepo: {
61-
// User-facing fields
62-
key_url: string
63-
keyring: string
64-
repo: string
65-
repo_filename: string
66-
packages: [...string]
67-
68-
_tasks: [...#Task]
69-
_tasks: [
70-
{name: "Add GPG key for \(repo_filename)", apt_key: {url: key_url, "keyring": keyring}},
71-
{name: "Add \(repo_filename) repository", apt_repository: {"repo": repo, filename: repo_filename, update_cache: true}},
72-
{name: "Install \(repo_filename) packages", apt: {name: packages, state: "present"}},
73-
]
74-
}
75-
76-
#DeployDockerStack: {
77-
// User-facing fields
78-
stack_name: string
79-
compose_src: string
80-
compose_dest: string | *"/opt/\(stack_name)/docker-compose.yml"
81-
compose_dir: string | *"/opt/\(stack_name)"
82-
83-
_tasks: [...#Task]
84-
_tasks: [
85-
{name: "Create \(stack_name) directory", file: {path: compose_dir, state: "directory", mode: "0755"}},
86-
{name: "Deploy \(stack_name) compose file", copy: {src: compose_src, dest: compose_dest, mode: "0644"}},
87-
{name: "Deploy \(stack_name) stack", docker_compose: {project_src: compose_dir, state: "present"}},
88-
]
89-
}
90-
91-
#ConfigureNginxSite: {
92-
// User-facing fields
93-
site_name: string
94-
config_src: string
95-
config_dest: string | *"/etc/nginx/sites-available/\(site_name)"
96-
enabled_link: string | *"/etc/nginx/sites-enabled/\(site_name)"
27+
let _config = _versions[version]
9728

98-
_tasks: [...#Task]
99-
_tasks: [
100-
{name: "Deploy \(site_name) nginx config", copy: {src: config_src, dest: config_dest, mode: "0644"}},
101-
{name: "Enable \(site_name) site", file: {path: enabled_link, src: config_dest, state: "link"}},
102-
{name: "Reload nginx for \(site_name)", service: {name: "nginx", state: "reloaded"}},
103-
]
29+
tasks: [...#Task]
30+
if install_method == "apt" {
31+
tasks: [
32+
{
33+
name: "Install Caddy prerequisites"
34+
apt: {
35+
name: [
36+
"debian-keyring",
37+
"debian-archive-keyring",
38+
"apt-transport-https",
39+
"curl",
40+
]
41+
state: "present"
42+
update_cache: true
43+
}
44+
},
45+
{
46+
name: "Add Caddy GPG key"
47+
apt_key: {
48+
keyring: _config.keyring
49+
state: "present"
50+
url: _config.key_url
51+
}
52+
},
53+
{
54+
name: "Add Caddy repository"
55+
apt_repository: {
56+
filename: _config.repo_filename
57+
repo: _config.repo
58+
update_cache: true
59+
}
60+
},
61+
{
62+
name: "Ensure Caddy repo file permissions"
63+
file: {
64+
path: "/etc/apt/sources.list.d/\(_config.repo_filename).list"
65+
mode: "0644"
66+
}
67+
},
68+
{
69+
name: "Ensure Caddy keyring permissions"
70+
file: {
71+
path: _config.keyring
72+
mode: "0644"
73+
}
74+
},
75+
{
76+
name: "Install Caddy"
77+
apt: {
78+
name: "caddy"
79+
state: "present"
80+
}
81+
},
82+
]
83+
}
10484
}

0 commit comments

Comments
 (0)