Skip to main content

canic_host/deployment_truth/observe/inventory/
mod.rs

1use super::super::*;
2use super::artifacts::{
3    collect_observed_artifacts, observe_canonical_runtime_config_digest, observe_config_sha256,
4    observe_deployment_manifest_digest,
5};
6use super::config::observe_local_config_facts;
7use super::identity::{InventoryIdentityFacts, local_inventory_identity};
8use super::root::{install_state_observations, observed_root_observation};
9use crate::install_root::read_named_deployment_install_state_from_root;
10use std::path::PathBuf;
11use thiserror::Error as ThisError;
12
13///
14/// LocalInventoryRequest
15///
16#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct LocalInventoryRequest {
18    pub deployment_name: String,
19    pub network: String,
20    pub workspace_root: PathBuf,
21    pub icp_root: PathBuf,
22    pub config_path: Option<PathBuf>,
23    pub observed_at: String,
24}
25
26///
27/// DeploymentTruthError
28///
29#[derive(Debug, ThisError)]
30pub enum DeploymentTruthError {
31    #[error("failed to read local deployment state: {0}")]
32    LocalState(String),
33}
34
35/// Collect read-only local deployment facts without querying or mutating IC state.
36pub fn collect_local_deployment_inventory(
37    request: &LocalInventoryRequest,
38) -> Result<DeploymentInventoryV1, DeploymentTruthError> {
39    let config = deployment_config_path(&request.workspace_root, request.config_path.as_deref());
40    let mut unresolved_observations = Vec::new();
41    let local_config_facts = observe_local_config_facts(&config, &mut unresolved_observations);
42
43    let install_state = read_named_deployment_install_state_from_root(
44        &request.icp_root,
45        &request.network,
46        &request.deployment_name,
47    )
48    .map_err(|err| DeploymentTruthError::LocalState(err.to_string()))?;
49    let raw_config_sha256 = observe_config_sha256(&config, &mut unresolved_observations);
50    let canonical_runtime_config_digest =
51        observe_canonical_runtime_config_digest(&config, &mut unresolved_observations);
52    let deployment_manifest_digest = observe_deployment_manifest_digest(
53        &request.icp_root,
54        &request.network,
55        &mut unresolved_observations,
56    );
57    let observed_artifacts = collect_observed_artifacts(
58        &request.icp_root,
59        &request.network,
60        &local_config_facts.roles,
61        &mut unresolved_observations,
62    );
63    let (observed_canisters, observed_pool) = install_state_observations(
64        install_state.as_ref(),
65        request,
66        &local_config_facts.pool_expectations,
67        &mut unresolved_observations,
68    );
69    let observed_root = observed_root_observation(
70        install_state.as_ref(),
71        request,
72        &local_config_facts.fleet_name,
73        &observed_canisters,
74    );
75    let observed_identity = Some(local_inventory_identity(
76        request,
77        InventoryIdentityFacts {
78            root_principal: install_state
79                .as_ref()
80                .map(|state| state.root_canister_id.clone()),
81            deployment_manifest_digest,
82            canonical_runtime_config_digest: canonical_runtime_config_digest.clone(),
83            observed_canisters: &observed_canisters,
84            observed_artifacts: &observed_artifacts,
85            observed_pool: &observed_pool,
86        },
87    ));
88
89    Ok(DeploymentInventoryV1 {
90        schema_version: DEPLOYMENT_TRUTH_SCHEMA_VERSION,
91        inventory_id: format!("local:{}:{}", request.network, request.deployment_name),
92        observed_at: request.observed_at.clone(),
93        observed_identity,
94        observed_root,
95        local_config: LocalDeploymentConfigV1 {
96            config_path: Some(config.display().to_string()),
97            raw_config_sha256,
98            canonical_embedded_config_sha256: canonical_runtime_config_digest,
99        },
100        observed_canisters,
101        observed_pool,
102        observed_artifacts,
103        observed_verifier_readiness: VerifierReadinessObservationV1 {
104            status: ObservationStatusV1::NotObserved,
105            role_epochs: Vec::new(),
106        },
107        unresolved_observations,
108    })
109}