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_accepted_root_count: u32,
46    pub expected_provisioned_root_count: u32,
47    pub expected_current_root: Option<FleetComponentProvisioningRootProgress>,
48}
49
50/// Exact root-local cursor copied from passive Coordinator status before one advance.
51#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
52#[serde(deny_unknown_fields)]
53pub struct FleetComponentProvisioningRootProgress {
54    pub fleet_subnet_root: Principal,
55    pub component_count: u32,
56    pub reserved_component_count: u32,
57    pub claimed_component_count: u32,
58    pub installed_component_count: u32,
59    pub registry_committed_component_count: u32,
60}
61
62/// Exact passive lookup key for one Coordinator-owned provisioning operation.
63#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
64#[serde(deny_unknown_fields)]
65pub struct FleetComponentProvisioningStatusRequest {
66    pub operation_id: [u8; 32],
67    pub plan_hash: [u8; 32],
68}
69
70/// Durable Coordinator progress exposed without returning the complete plan.
71#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
72pub enum FleetComponentProvisioningPhase {
73    Planned,
74    AcceptingRoots,
75    RootsAccepted,
76    ProvisioningRoots,
77    ComponentsProvisioned,
78    ServiceTopologyPublished,
79}
80
81/// Compact exact status for one Coordinator-owned provisioning operation.
82#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
83#[serde(deny_unknown_fields)]
84pub struct FleetComponentProvisioningStatusResponse {
85    pub operation_id: [u8; 32],
86    pub plan_hash: [u8; 32],
87    pub fleet_registry: FleetRegistryVersion,
88    pub configuration_digest: ComponentDeploymentConfigurationDigest,
89    pub operation: FleetComponentProvisioningOperation,
90    pub phase: FleetComponentProvisioningPhase,
91    pub directory_confirmation_root_count: u32,
92    pub root_batch_count: u32,
93    pub accepted_root_count: u32,
94    pub acceptance_in_flight_root: Option<Principal>,
95    pub provisioned_root_count: u32,
96    pub current_root: Option<FleetComponentProvisioningRootProgress>,
97    pub provisioning_in_flight_root: Option<Principal>,
98    pub group_placement_count: u32,
99    pub component_count: u32,
100    pub planned_at_ns: u64,
101    pub roots_accepted_at_ns: Option<u64>,
102    pub components_provisioned_at_ns: Option<u64>,
103    pub published_fleet_registry: Option<FleetRegistryVersion>,
104    pub service_topology_published_at_ns: Option<u64>,
105}
106
107/// Fresh-install or monotonic scale-out scope covered by one plan.
108#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
109#[serde(deny_unknown_fields)]
110pub enum FleetComponentProvisioningOperation {
111    FreshInstall,
112    ScaleOut {
113        deployment: ComponentGroupDeploymentId,
114        previous_placements: u32,
115        requested_placements: u32,
116    },
117}
118
119/// One selected root's complete canonical provisioning batch.
120#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
121#[serde(deny_unknown_fields)]
122pub struct FleetSubnetRootProvisioningBatch {
123    pub root: FleetSubnetRootBinding,
124    pub active_release_set: FleetSubnetRootReleaseSet,
125    pub placements: Vec<ComponentGroupPlacementPlan>,
126}
127
128/// One materialized copy of a completely flattened Component Group.
129#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
130#[serde(deny_unknown_fields)]
131pub struct ComponentGroupPlacementPlan {
132    pub group_placement: ComponentGroupPlacementId,
133    pub component_group: ComponentGroupSpecId,
134    pub entries: Vec<ComponentGroupPlanEntry>,
135}
136
137/// One exact top-level Component occurrence within a group placement.
138#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
139#[serde(deny_unknown_fields)]
140pub struct ComponentGroupPlanEntry {
141    pub member_path: ComponentGroupMemberPath,
142    pub component_spec: ComponentSpecId,
143    pub spec_hash: [u8; 32],
144    pub purpose: ComponentDeploymentPurpose,
145    pub labels: Vec<ComponentDeploymentLabel>,
146    pub limits: ComponentDeploymentLimits,
147}
148
149/// Coordinator-authenticated command asking one root to retain its exact plan batch.
150#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
151#[serde(deny_unknown_fields)]
152pub struct RootComponentProvisioningAcceptanceRequest {
153    pub fleet_registry: FleetRegistryVersion,
154    pub configuration_digest: ComponentDeploymentConfigurationDigest,
155    pub operation_id: [u8; 32],
156    pub plan_hash: [u8; 32],
157    pub batch: FleetSubnetRootProvisioningBatch,
158}
159
160/// Read-only lookup key for one exact root provisioning operation.
161#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
162#[serde(deny_unknown_fields)]
163pub struct RootComponentProvisioningStatusRequest {
164    pub operation_id: [u8; 32],
165    pub plan_hash: [u8; 32],
166}
167
168/// Coordinator-authenticated command advancing one exact bounded provisioning step.
169#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
170#[serde(deny_unknown_fields)]
171pub struct RootComponentProvisioningAdvanceRequest {
172    pub operation_id: [u8; 32],
173    pub plan_hash: [u8; 32],
174    pub expected_reserved_component_count: u32,
175    pub expected_claimed_component_count: u32,
176    pub expected_installed_component_count: u32,
177    pub expected_registry_committed_component_count: u32,
178}
179
180/// One exact provisioned Component occurrence and its committed Registry identity.
181#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
182#[serde(deny_unknown_fields)]
183pub struct RootProvisionedGroupMember {
184    pub member_path: ComponentGroupMemberPath,
185    pub component_spec: ComponentSpecId,
186    pub purpose: ComponentDeploymentPurpose,
187    pub limits: ComponentDeploymentLimits,
188    pub binding: ComponentBinding,
189    pub component_registry_revision: u64,
190    pub component_registry_content_hash: [u8; 32],
191}
192
193/// Complete provisioned result for one exact group placement on this root.
194#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
195#[serde(deny_unknown_fields)]
196pub struct RootProvisionedGroupPlacement {
197    pub group_placement: ComponentGroupPlacementId,
198    pub component_group: ComponentGroupSpecId,
199    pub members: Vec<RootProvisionedGroupMember>,
200}
201
202/// Complete group-partitioned result of one root provisioning operation.
203#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
204#[serde(deny_unknown_fields)]
205pub struct RootComponentProvisioningResult {
206    pub placements: Vec<RootProvisionedGroupPlacement>,
207}
208
209/// Durable aggregate progress of one root provisioning batch.
210#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
211pub enum RootComponentProvisioningPhase {
212    Accepted,
213    Provisioned,
214    Published,
215    RuntimesActive,
216}
217
218/// Durable progress or complete terminal result for one exact root provisioning operation.
219#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
220#[serde(deny_unknown_fields)]
221pub struct RootComponentProvisioningStatusResponse {
222    pub operation_id: [u8; 32],
223    pub plan_hash: [u8; 32],
224    pub fleet_registry: FleetRegistryVersion,
225    pub configuration_digest: ComponentDeploymentConfigurationDigest,
226    pub fleet_subnet_root: Principal,
227    pub phase: RootComponentProvisioningPhase,
228    pub placement_count: u32,
229    pub component_count: u32,
230    pub reserved_component_count: u32,
231    pub claimed_component_count: u32,
232    pub installed_component_count: u32,
233    pub registry_committed_component_count: u32,
234    pub result: Option<RootComponentProvisioningResult>,
235    pub accepted_at_ns: u64,
236    pub provisioned_at_ns: Option<u64>,
237    pub receipt_content_hash: [u8; 32],
238}