Skip to main content

canic_core/dto/
component_provisioning.rs

1//! Module: dto::component_provisioning
2//!
3//! Responsibility: carry one canonical Fleet Component provisioning plan across boundaries.
4//! Does not own: plan derivation, validation, persistence, root effects, or receipts.
5//! Boundary: the Coordinator retains the complete plan and sends each root only its exact batch.
6
7use crate::{
8    config::{ComponentDeploymentLabel, ComponentDeploymentLimits, ComponentDeploymentPurpose},
9    dto::fleet_registry::FleetRegistryVersion,
10    ids::{
11        ComponentBinding, ComponentDeploymentConfigurationDigest, ComponentGroupDeploymentId,
12        ComponentGroupMemberPath, ComponentGroupPlacementId, ComponentGroupSpecId, ComponentSpecId,
13        FleetBinding, FleetSubnetRootBinding, FleetSubnetRootReleaseSet,
14    },
15};
16use candid::{CandidType, Principal};
17use serde::{Deserialize, Serialize};
18
19/// Complete canonical provisioning authority retained before any root effect.
20#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
21#[serde(deny_unknown_fields)]
22pub struct FleetComponentProvisioningPlan {
23    pub fleet: FleetBinding,
24    pub fleet_registry: FleetRegistryVersion,
25    pub configuration_digest: ComponentDeploymentConfigurationDigest,
26    pub operation: FleetComponentProvisioningOperation,
27    pub directory_confirmation_roots: Vec<Principal>,
28    pub batches: Vec<FleetSubnetRootProvisioningBatch>,
29}
30
31/// Controller-authenticated command that durably freezes one complete plan.
32#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
33#[serde(deny_unknown_fields)]
34pub struct FleetComponentProvisioningPrepareRequest {
35    pub operation_id: [u8; 32],
36    pub plan: FleetComponentProvisioningPlan,
37}
38
39/// Controller-authenticated command advancing one exact Coordinator provisioning step.
40#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
41#[serde(deny_unknown_fields)]
42pub struct FleetComponentProvisioningAdvanceRequest {
43    pub operation_id: [u8; 32],
44    pub plan_hash: [u8; 32],
45    pub expected_phase: FleetComponentProvisioningPhase,
46    pub expected_accepted_root_count: u32,
47    pub expected_provisioned_root_count: u32,
48    pub expected_current_root: Option<FleetComponentProvisioningRootProgress>,
49    pub expected_directory_confirmed_root_count: u32,
50    pub expected_current_publication: Option<FleetComponentPublicationRootProgress>,
51}
52
53/// Exact root-local cursor copied from passive Coordinator status before one advance.
54#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
55#[serde(deny_unknown_fields)]
56pub struct FleetComponentProvisioningRootProgress {
57    pub fleet_subnet_root: Principal,
58    pub component_count: u32,
59    pub reserved_component_count: u32,
60    pub claimed_component_count: u32,
61    pub installed_component_count: u32,
62    pub registry_committed_component_count: u32,
63}
64
65/// Exact root-local Directory cursor copied from passive Coordinator status.
66#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
67#[serde(deny_unknown_fields)]
68pub struct FleetComponentPublicationRootProgress {
69    pub fleet_subnet_root: Principal,
70    pub component_count: u32,
71    pub published_component_count: u32,
72}
73
74/// Exact passive lookup key for one Coordinator-owned provisioning operation.
75#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
76#[serde(deny_unknown_fields)]
77pub struct FleetComponentProvisioningStatusRequest {
78    pub operation_id: [u8; 32],
79    pub plan_hash: [u8; 32],
80}
81
82/// Durable Coordinator progress exposed without returning the complete plan.
83#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
84pub enum FleetComponentProvisioningPhase {
85    Planned,
86    AcceptingRoots,
87    RootsAccepted,
88    ProvisioningRoots,
89    ComponentsProvisioned,
90    ServiceTopologyPublished,
91    ConfirmingDirectories,
92    DirectoriesConfirmed,
93}
94
95/// Compact exact status for one Coordinator-owned provisioning operation.
96#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
97#[serde(deny_unknown_fields)]
98pub struct FleetComponentProvisioningStatusResponse {
99    pub operation_id: [u8; 32],
100    pub plan_hash: [u8; 32],
101    pub fleet_registry: FleetRegistryVersion,
102    pub configuration_digest: ComponentDeploymentConfigurationDigest,
103    pub operation: FleetComponentProvisioningOperation,
104    pub phase: FleetComponentProvisioningPhase,
105    pub directory_confirmation_root_count: u32,
106    pub root_batch_count: u32,
107    pub accepted_root_count: u32,
108    pub acceptance_in_flight_root: Option<Principal>,
109    pub provisioned_root_count: u32,
110    pub current_root: Option<FleetComponentProvisioningRootProgress>,
111    pub provisioning_in_flight_root: Option<Principal>,
112    pub directory_confirmed_root_count: u32,
113    pub current_publication: Option<FleetComponentPublicationRootProgress>,
114    pub publication_in_flight_root: Option<Principal>,
115    pub group_placement_count: u32,
116    pub component_count: u32,
117    pub planned_at_ns: u64,
118    pub roots_accepted_at_ns: Option<u64>,
119    pub components_provisioned_at_ns: Option<u64>,
120    pub published_fleet_registry: Option<FleetRegistryVersion>,
121    pub service_topology_published_at_ns: Option<u64>,
122    pub directories_confirmed_at_ns: Option<u64>,
123}
124
125/// Fresh-install or monotonic scale-out scope covered by one plan.
126#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
127#[serde(deny_unknown_fields)]
128pub enum FleetComponentProvisioningOperation {
129    FreshInstall,
130    ScaleOut {
131        deployment: ComponentGroupDeploymentId,
132        previous_placements: u32,
133        requested_placements: u32,
134    },
135}
136
137/// One selected root's complete canonical provisioning batch.
138#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
139#[serde(deny_unknown_fields)]
140pub struct FleetSubnetRootProvisioningBatch {
141    pub root: FleetSubnetRootBinding,
142    pub active_release_set: FleetSubnetRootReleaseSet,
143    pub placements: Vec<ComponentGroupPlacementPlan>,
144}
145
146/// One materialized copy of a completely flattened Component Group.
147#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
148#[serde(deny_unknown_fields)]
149pub struct ComponentGroupPlacementPlan {
150    pub group_placement: ComponentGroupPlacementId,
151    pub component_group: ComponentGroupSpecId,
152    pub entries: Vec<ComponentGroupPlanEntry>,
153}
154
155/// One exact top-level Component occurrence within a group placement.
156#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
157#[serde(deny_unknown_fields)]
158pub struct ComponentGroupPlanEntry {
159    pub member_path: ComponentGroupMemberPath,
160    pub component_spec: ComponentSpecId,
161    pub spec_hash: [u8; 32],
162    pub purpose: ComponentDeploymentPurpose,
163    pub labels: Vec<ComponentDeploymentLabel>,
164    pub limits: ComponentDeploymentLimits,
165}
166
167/// Coordinator-authenticated command asking one root to retain its exact plan batch.
168#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
169#[serde(deny_unknown_fields)]
170pub struct RootComponentProvisioningAcceptanceRequest {
171    pub fleet_registry: FleetRegistryVersion,
172    pub configuration_digest: ComponentDeploymentConfigurationDigest,
173    pub operation_id: [u8; 32],
174    pub plan_hash: [u8; 32],
175    pub batch: FleetSubnetRootProvisioningBatch,
176}
177
178/// Read-only lookup key for one exact root provisioning operation.
179#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
180#[serde(deny_unknown_fields)]
181pub struct RootComponentProvisioningStatusRequest {
182    pub operation_id: [u8; 32],
183    pub plan_hash: [u8; 32],
184}
185
186/// Coordinator-authenticated command advancing one exact bounded provisioning step.
187#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
188#[serde(deny_unknown_fields)]
189pub struct RootComponentProvisioningAdvanceRequest {
190    pub operation_id: [u8; 32],
191    pub plan_hash: [u8; 32],
192    pub expected_reserved_component_count: u32,
193    pub expected_claimed_component_count: u32,
194    pub expected_installed_component_count: u32,
195    pub expected_registry_committed_component_count: u32,
196}
197
198/// One exact member of a root-derived Component Group Directory.
199#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
200#[serde(deny_unknown_fields)]
201pub struct ComponentGroupDirectoryMember {
202    pub member_path: ComponentGroupMemberPath,
203    pub component_spec: ComponentSpecId,
204    pub purpose: ComponentDeploymentPurpose,
205    pub labels: Vec<ComponentDeploymentLabel>,
206    pub binding: ComponentBinding,
207}
208
209/// Protected origin of one root-derived Component Group Directory.
210#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
211#[serde(deny_unknown_fields)]
212pub struct ComponentGroupDirectoryProvenance {
213    pub authority: crate::ids::FleetRegistryAuthority,
214    pub fleet_subnet_root: Principal,
215    pub group_placement: ComponentGroupPlacementId,
216    pub component_group: ComponentGroupSpecId,
217    pub operation_id: [u8; 32],
218    pub plan_hash: [u8; 32],
219    pub placement_receipt_content_hash: [u8; 32],
220}
221
222/// Complete bounded sibling projection for one materialized Component Group placement.
223#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
224#[serde(deny_unknown_fields)]
225pub struct ComponentGroupDirectory {
226    pub provenance: ComponentGroupDirectoryProvenance,
227    pub members: Vec<ComponentGroupDirectoryMember>,
228}
229
230/// Compact proof of one exact Component Directory delivered during publication.
231#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
232#[serde(deny_unknown_fields)]
233pub struct ComponentDirectoryPublicationEvidence {
234    pub component: crate::ids::ComponentInstanceId,
235    pub content_hash: [u8; 32],
236}
237
238/// Compact proof of one exact Component Group Directory delivered during publication.
239#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
240#[serde(deny_unknown_fields)]
241pub struct ComponentGroupDirectoryPublicationEvidence {
242    pub group_placement: ComponentGroupPlacementId,
243    pub content_hash: [u8; 32],
244}
245
246/// Complete root-local evidence for one published provisioning batch.
247#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
248#[serde(deny_unknown_fields)]
249pub struct RootComponentPublicationEvidence {
250    pub fleet_registry: FleetRegistryVersion,
251    pub fleet_directory_content_hash: [u8; 32],
252    pub component_directories: Vec<ComponentDirectoryPublicationEvidence>,
253    pub component_group_directories: Vec<ComponentGroupDirectoryPublicationEvidence>,
254}
255
256/// Coordinator-authenticated command advancing one bounded root publication step.
257#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
258#[serde(deny_unknown_fields)]
259pub struct RootComponentPublicationRequest {
260    pub operation_id: [u8; 32],
261    pub plan_hash: [u8; 32],
262    pub published_fleet_registry: FleetRegistryVersion,
263    pub expected_published_component_count: u32,
264}
265
266/// One exact provisioned Component occurrence and its committed Registry identity.
267#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
268#[serde(deny_unknown_fields)]
269pub struct RootProvisionedGroupMember {
270    pub member_path: ComponentGroupMemberPath,
271    pub component_spec: ComponentSpecId,
272    pub purpose: ComponentDeploymentPurpose,
273    pub limits: ComponentDeploymentLimits,
274    pub binding: ComponentBinding,
275    pub component_registry_revision: u64,
276    pub component_registry_content_hash: [u8; 32],
277}
278
279/// Complete provisioned result for one exact group placement on this root.
280#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
281#[serde(deny_unknown_fields)]
282pub struct RootProvisionedGroupPlacement {
283    pub group_placement: ComponentGroupPlacementId,
284    pub component_group: ComponentGroupSpecId,
285    pub members: Vec<RootProvisionedGroupMember>,
286}
287
288/// Complete group-partitioned result of one root provisioning operation.
289#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
290#[serde(deny_unknown_fields)]
291pub struct RootComponentProvisioningResult {
292    pub placements: Vec<RootProvisionedGroupPlacement>,
293}
294
295/// Durable aggregate progress of one root provisioning batch.
296#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
297pub enum RootComponentProvisioningPhase {
298    Accepted,
299    Provisioned,
300    Published,
301    RuntimesActive,
302}
303
304/// Durable progress or complete terminal result for one exact root provisioning operation.
305#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
306#[serde(deny_unknown_fields)]
307pub struct RootComponentProvisioningStatusResponse {
308    pub operation_id: [u8; 32],
309    pub plan_hash: [u8; 32],
310    pub fleet_registry: FleetRegistryVersion,
311    pub configuration_digest: ComponentDeploymentConfigurationDigest,
312    pub fleet_subnet_root: Principal,
313    pub phase: RootComponentProvisioningPhase,
314    pub placement_count: u32,
315    pub component_count: u32,
316    pub reserved_component_count: u32,
317    pub claimed_component_count: u32,
318    pub installed_component_count: u32,
319    pub registry_committed_component_count: u32,
320    pub published_component_count: u32,
321    pub result: Option<RootComponentProvisioningResult>,
322    pub publication: Option<RootComponentPublicationEvidence>,
323    pub accepted_at_ns: u64,
324    pub provisioned_at_ns: Option<u64>,
325    pub published_at_ns: Option<u64>,
326    pub receipt_content_hash: [u8; 32],
327}