Skip to content

Commit 2067dfc

Browse files
authored
Merge pull request #22 from persys-dev/debug-runtime-conditions-rev-1
Debug runtime conditions rev 1
2 parents 394c200 + 3638ff6 commit 2067dfc

119 files changed

Lines changed: 24287 additions & 2537 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/docker-image.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ jobs:
1818

1919
steps:
2020
- name: Checkout code
21-
uses: actions/checkout@v3
21+
uses: actions/checkout@v4
2222
with:
2323
fetch-depth: 0 # Fetch all history for proper change detection
2424

2525
- name: Set up Docker Buildx
26-
uses: docker/setup-buildx-action@v2
26+
uses: docker/setup-buildx-action@v4
2727

2828
- name: Build and Deploy
2929
run: |
@@ -42,7 +42,7 @@ jobs:
4242
4343
# Check each service directory for changes
4444
if echo "$CHANGED_FILES" | grep -q "^persys-gateway/"; then
45-
build_image "api-gateway" "persys-gateway"
45+
build_image "persys-gateway" "persys-gateway"
4646
fi
4747
4848
if echo "$CHANGED_FILES" | grep -q "^persys-scheduler/"; then

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ vault-mtls-mock/
1515
.env
1616
persys-automation/DESIGN_SPEC.md
1717
persys-intelligence/DESIGN_SPEC.md
18+
third_party/

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ GOCACHE ?= $(CURDIR)/.cache/go-build
77
GOMODCACHE ?= $(CURDIR)/.cache/go-mod
88
GO_ENV = GOCACHE="$(GOCACHE)" GOMODCACHE="$(GOMODCACHE)"
99

10-
SERVICES := compute-agent persys-scheduler persysctl persys-gateway persys-federation persys-forgery persys-operator vault-mtls-mock
10+
SERVICES := compute-agent persys-scheduler persysctl persys-gateway persys-federation persys-forgery persys-operator persys-automation persys-intelligence vault-mtls-mock
1111

1212
compute-agent_DIR := compute-agent
1313
compute-agent_PKG := ./cmd/agent
@@ -37,6 +37,14 @@ persys-operator_DIR := persys-operator
3737
persys-operator_PKG := ./cmd/main.go
3838
persys-operator_BIN := persys-operator
3939

40+
persys-automation_DIR := persys-automation
41+
persys-automation_PKG := ./cmd/automation
42+
persys-automation_BIN := persys-automation
43+
44+
persys-intelligence_DIR := persys-intelligence
45+
persys-intelligence_PKG := ./cmd/intelligence
46+
persys-intelligence_BIN := persys-intelligence
47+
4048
vault-mtls-mock_DIR := vault-mtls-mock
4149
vault-mtls-mock_PKG := ./main.go
4250
vault-mtls-mock_BIN := vault-mtls-mock

compute-agent

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
# Persys Compute Platform Extension Design Spec
2+
3+
Status: Draft
4+
Owner: Compute + Scheduler teams
5+
Last Updated: 2026-02-23
6+
7+
## 1. Problem Statement
8+
9+
We need four production-critical capabilities:
10+
11+
1. A real storage layer that can provision and attach volumes from NFS/Ceph (not only host bind paths).
12+
2. Dynamic cloud-init injection from user input (current behavior still defaults to mostly static seed generation).
13+
3. Separation of storage/network concerns from compute runtime logic.
14+
4. Per-workload (container/VM) utilization telemetry so scheduling, automation, and intelligence can reason about performance.
15+
16+
## 2. Current-State Findings (from code scan)
17+
18+
- `compute-agent/internal/storage/manager.go` provides an in-memory pool/allocation manager only; it is not integrated into runtime Create/Start/Delete flows.
19+
- `compute-agent/internal/runtime/docker.go` mounts only direct host bind paths (`VolumeMount.host_path`) and has no managed volume abstraction.
20+
- `compute-agent/internal/runtime/vm.go` generates cloud-init ISO but writes static fallback `meta-data`; `network-config`/`vendor-data` are not seeded into ISO files.
21+
- `compute-agent/internal/runtime/runtime.go` has a runtime interface only; storage/network provider abstractions are missing.
22+
- `compute-agent/internal/resources/monitor.go` and `compute-agent/internal/metrics/metrics.go` expose node-level metrics but not workload-level CPU/memory/io/network usage.
23+
- Scheduler/gateway/ctl mostly pass workload specs through, but control-plane contracts do not yet model managed volume lifecycle or workload telemetry envelopes.
24+
25+
## 3. Goals
26+
27+
- Introduce pluggable volume provisioning/attachment with NFS and Ceph first-class support.
28+
- Ensure VM cloud-init payload from users is injected faithfully (user-data/meta-data/network-config/vendor-data).
29+
- Decouple runtime implementations from storage/network implementations with explicit interfaces.
30+
- Publish workload utilization in agent metrics + scheduler-visible status so users can explain slow workloads.
31+
32+
## 4. Non-Goals (for this phase)
33+
34+
- Full Kubernetes CSI/CNI compatibility.
35+
- Multi-tenant quota/billing engine.
36+
- Long-term metrics storage in this same milestone (we expose and stream first).
37+
38+
## 5. Target Architecture
39+
40+
### 5.1 Compute-Agent Platform Layer
41+
42+
Add `compute-agent/internal/platform/`:
43+
44+
- `storage.go`: `StorageProvider`, `VolumeManager`, `VolumeAttachment`.
45+
- `network.go`: `NetworkProvider`, `NetworkAttachment`.
46+
- `types.go`: shared structs (`VolumeSpec`, `VolumeHandle`, `WorkloadNetSpec`).
47+
48+
Runtimes (`docker`, `compose`, `vm`) consume these interfaces instead of raw host paths.
49+
50+
### 5.2 Managed Volume Model
51+
52+
Add workload spec support for managed volumes:
53+
54+
- `name`, `driver` (`local|nfs|ceph-rbd`), `size_gb`, `access_mode`, `fs_type`, `mount_path`, `read_only`, `retain_policy`.
55+
56+
Lifecycle:
57+
58+
1. Resolve/provision volume in provider.
59+
2. Attach/stage for workload.
60+
3. Runtime mounts staged target.
61+
4. Detach on stop/delete.
62+
5. Honor retain/delete policy.
63+
64+
### 5.3 Cloud-Init Injection Model
65+
66+
For VM workloads:
67+
68+
- Accept and persist all cloud-init fields from API.
69+
- Build NoCloud seed with files:
70+
- `user-data`
71+
- `meta-data`
72+
- `network-config` (optional)
73+
- `vendor-data` (optional)
74+
- Keep deterministic seed path and checksum in workload status metadata.
75+
76+
### 5.4 Utilization Telemetry Model
77+
78+
Add workload-level usage snapshot type:
79+
80+
- `workload_id`, `type`, `cpu_percent`, `memory_bytes`, `disk_read_bytes`, `disk_write_bytes`, `net_rx_bytes`, `net_tx_bytes`, `collected_at`, `source`.
81+
82+
Sources:
83+
84+
- Containers/compose: Docker stats API.
85+
- VMs: libvirt domain stats (CPU time, memory stats, interface/block stats where available).
86+
87+
## 6. Concrete Implementation Plan
88+
89+
## Phase 0: Contracts and Schema (safe-first)
90+
91+
1. Update API contracts.
92+
93+
- `compute-agent/api/proto/agent.proto`
94+
- Add managed volume structures and fields to container/vm specs.
95+
- Add optional workload telemetry response shape (or metadata envelope) for status/list.
96+
- `persys-scheduler/api/proto/control.proto`
97+
- Mirror managed volume spec.
98+
- Extend `WorkloadStatus`/`WorkloadView` to include structured reason + optional usage snapshot.
99+
- Extend heartbeat with repeated workload usage snapshots.
100+
- Regenerate pb code in `compute-agent/pkg/api/v1`, `compute-agent/pkg/control/v1`, `persys-scheduler/internal/controlv1`, `persys-gateway/internal/controlv1`, `persysctl/internal/controlv1`.
101+
102+
2. Extend models.
103+
104+
- `compute-agent/pkg/models/workload.go`: add managed volume and usage structs.
105+
- `persys-scheduler/internal/models/models.go`: add managed volume + workload usage fields.
106+
- `persysctl/internal/models/models.go`: expose new fields for CLI output.
107+
108+
Acceptance:
109+
110+
- Backward-compatible defaults preserve old specs.
111+
- Existing apply/list/get calls still work.
112+
113+
## Phase 1: Storage Provider Integration (NFS + Ceph)
114+
115+
1. Implement provider interfaces.
116+
117+
- New:
118+
- `compute-agent/internal/platform/storage.go`
119+
- `compute-agent/internal/storage/providers/local_provider.go`
120+
- `compute-agent/internal/storage/providers/nfs_provider.go`
121+
- `compute-agent/internal/storage/providers/ceph_rbd_provider.go`
122+
123+
2. Persist volume state.
124+
125+
- Extend state store with `volumes` and `attachments` buckets.
126+
- Files:
127+
- `compute-agent/internal/state/store.go`
128+
- `compute-agent/internal/state/bolt_*.go` (new file split recommended)
129+
130+
3. Integrate with workload manager lifecycle.
131+
132+
- `compute-agent/internal/workload/manager.go`
133+
- Pre-create/attach managed volumes before runtime `Create`.
134+
- Detach/cleanup on delete based on retain policy.
135+
- Persist explicit failure reason (`STORAGE_ATTACH_FAILED`, `STORAGE_PROVISION_FAILED`).
136+
137+
4. Runtime wiring.
138+
139+
- `compute-agent/internal/runtime/docker.go`
140+
- Convert managed volume attachments into runtime mounts.
141+
- `compute-agent/internal/runtime/vm.go`
142+
- Attach Ceph/NFS-backed disks through libvirt disk source definitions.
143+
144+
5. Scheduler capability-awareness.
145+
146+
- `compute-agent/internal/control/client.go` heartbeat/register: advertise storage driver capabilities.
147+
- `persys-scheduler/internal/scheduler/scheduler.go`: only place workloads on nodes supporting requested storage driver.
148+
149+
Acceptance:
150+
151+
- Container can request NFS/Ceph volume and start with mounted volume.
152+
- VM can boot with Ceph/NFS-backed disk where requested.
153+
- Delete honors retain/delete policy.
154+
155+
## Phase 2: Dynamic Cloud-Init End-to-End
156+
157+
1. Preserve full cloud-init fields through control path.
158+
159+
- `persysctl/cmd/scheduler.go` and scheduler conversion helpers keep `user_data`, `meta_data`, `network_config`, `vendor_data` unchanged.
160+
- Ensure no lossy conversion via reduced legacy control VM schema.
161+
162+
2. Cloud-init ISO builder update.
163+
164+
- `compute-agent/internal/runtime/vm.go`
165+
- `createCloudInitISO`: write `meta-data` from user payload when provided.
166+
- Write `network-config` and `vendor-data` files if provided.
167+
- Include payload checksum in status metadata.
168+
169+
3. Validation and safety.
170+
171+
- Reject oversized/invalid cloud-init payload with explicit user-visible errors.
172+
- Redact sensitive cloud-init fields from logs while retaining hash and size.
173+
174+
Acceptance:
175+
176+
- User-provided cloud-init is faithfully applied.
177+
- Status shows `vm.cloud_init_seed_checksum`, `vm.cloud_init_seed_path`.
178+
179+
## Phase 3: Storage/Network Abstraction from Runtime
180+
181+
1. Introduce dependency-injected runtime context.
182+
183+
- `compute-agent/internal/runtime/runtime.go`
184+
- Add optional runtime dependencies struct (`StorageProvider`, `NetworkProvider`).
185+
186+
2. Network provider implementation.
187+
188+
- New `compute-agent/internal/network/providers/` with initial:
189+
- Docker network provider wrapper.
190+
- Libvirt network resolver wrapper.
191+
192+
3. Refactor runtimes.
193+
194+
- `docker.go`, `compose.go`, `vm.go` use provider interfaces, not direct ad-hoc host/network assumptions.
195+
196+
4. Bootstrap wiring.
197+
198+
- `compute-agent/cmd/agent/main.go`: instantiate provider registry and inject into runtime constructors.
199+
- `compute-agent/internal/config/config.go`: add provider-specific configuration (NFS mount options, Ceph pool/user/keyring, default network policies).
200+
201+
Acceptance:
202+
203+
- Runtime packages compile/test against mock providers.
204+
- Storage/network behavior can be tested without live Docker/libvirt by mocking providers.
205+
206+
## Phase 4: Workload Utilization Telemetry
207+
208+
1. Agent collectors.
209+
210+
- New `compute-agent/internal/telemetry/workload_usage_collector.go`.
211+
- Poll every `N` seconds and cache latest usage per workload.
212+
213+
2. Metrics exposure.
214+
215+
- Extend `compute-agent/internal/metrics/metrics.go` with labeled gauges/counters:
216+
- `persys_agent_workload_cpu_percent{workload_id,type}`
217+
- `persys_agent_workload_memory_bytes{workload_id,type}`
218+
- `persys_agent_workload_disk_read_bytes_total{workload_id,type}`
219+
- `persys_agent_workload_disk_write_bytes_total{workload_id,type}`
220+
- `persys_agent_workload_network_rx_bytes_total{workload_id,type}`
221+
- `persys_agent_workload_network_tx_bytes_total{workload_id,type}`
222+
223+
3. Status and heartbeat propagation.
224+
225+
- Agent `GetWorkloadStatus/ListWorkloads`: include latest usage snapshot in metadata/structured field.
226+
- `compute-agent/internal/control/client.go`: include per-workload usage in heartbeat.
227+
- Scheduler stores latest usage and surfaces it in:
228+
- `persys-scheduler/internal/grpcapi/service.go` (`WorkloadView`)
229+
- Gateway pass-through (`persys-gateway/controllers/scheduler.controller.go` + generated pb).
230+
231+
4. User-facing diagnostics.
232+
233+
- `persysctl` output (`workload list/get`) includes utilization and last sample timestamp.
234+
- For failed/pending/frozen workloads, show reason codes and runtime reason text from metadata.
235+
236+
Acceptance:
237+
238+
- `workload list/get` shows recent per-workload CPU/memory and at least one IO/network signal.
239+
- Scheduler can filter/report “high CPU” or “memory pressure” candidate workloads in future automation.
240+
241+
## 7. Cross-Cutting Reliability Changes
242+
243+
- Add reason-code taxonomy (shared enum or canonical string set):
244+
- `STORAGE_PROVISION_FAILED`, `STORAGE_ATTACH_FAILED`, `NETWORK_ATTACH_FAILED`, `CLOUD_INIT_INVALID`, `VM_PAUSED_IO_ERROR`, `WORKLOAD_RESOURCE_STARVATION`.
245+
- Ensure each reconcile failure writes:
246+
- machine-readable reason code,
247+
- human-readable message,
248+
- last transition time,
249+
- next retry time if retryable.
250+
251+
## 8. Rollout Strategy
252+
253+
1. Ship contracts first behind feature gates:
254+
255+
- `PERSYS_FEATURE_MANAGED_VOLUMES`
256+
- `PERSYS_FEATURE_DYNAMIC_CLOUD_INIT`
257+
- `PERSYS_FEATURE_WORKLOAD_TELEMETRY`
258+
259+
2. Enable in canary cluster order:
260+
261+
- telemetry -> cloud-init -> storage provider path.
262+
263+
3. Keep fallback paths:
264+
265+
- old host bind volume behavior remains valid.
266+
- old cloud-init single string remains valid.
267+
268+
## 9. Test Plan
269+
270+
- Unit tests:
271+
- provider allocation/attach/detach behavior.
272+
- cloud-init ISO generation with golden fixtures.
273+
- runtime + provider integration via mocks.
274+
- Integration tests:
275+
- NFS volume attach to container.
276+
- Ceph RBD attach to VM.
277+
- cloud-init network-config applied on VM boot.
278+
- telemetry visible in scheduler `GetWorkload`.
279+
- Chaos tests:
280+
- NFS/Ceph outage during attach.
281+
- libvirt transient failures during stats collection.
282+
283+
## 10. Milestone Breakdown (Execution Order)
284+
285+
1. Milestone A (1-2 weeks): proto/model updates + compatibility + CLI/gateway regeneration.
286+
2. Milestone B (2-3 weeks): storage provider framework + NFS driver + container integration.
287+
3. Milestone C (2-3 weeks): Ceph RBD + VM disk attach path + state persistence.
288+
4. Milestone D (1-2 weeks): dynamic cloud-init full payload support.
289+
5. Milestone E (2 weeks): workload telemetry collection + exposure end-to-end.
290+
6. Milestone F (1 week): hardening, migration docs, runbooks.
291+
292+
## 11. Open Decisions
293+
294+
- Ceph auth distribution mechanism (static keyring vs Vault-injected credentials).
295+
- Retain policy defaults for managed volumes (`Delete` vs `Retain`).
296+
- Whether per-workload usage history is kept in etcd or only current snapshot in control plane.
297+
298+
## 12. Definition of Done
299+
300+
- Managed volumes (NFS/Ceph) can be provisioned/attached without host-path hardcoding.
301+
- Cloud-init user payload is injected as-is and traceable via checksum/metadata.
302+
- Runtime packages depend on provider abstractions, not direct storage/network assumptions.
303+
- Users can inspect per-workload utilization and precise failure reasons from scheduler/gateway/`persysctl`.

0 commit comments

Comments
 (0)