canic_core/ops/bootstrap/
root.rs1use crate::{
2 Error,
3 cdk::api::{canister_self, trap},
4 log::Topic,
5 ops::{
6 config::ConfigOps,
7 ic::{Network, build_network, try_get_current_subnet_pid},
8 pool::{PoolOps, pool_import_canister},
9 prelude::*,
10 rpc::{CreateCanisterParent, create_canister_request},
11 storage::{env::EnvOps, topology::SubnetCanisterRegistryOps},
12 },
13};
14
15pub async fn root_set_subnet_id() {
24 let subnet_result = try_get_current_subnet_pid().await;
27 match subnet_result {
28 Ok(Some(subnet_pid)) => {
29 EnvOps::set_subnet_pid(subnet_pid);
30 return;
31 }
32 Ok(None) => {
33 if build_network() == Some(Network::Ic) {
34 let msg = "try_get_current_subnet_pid returned None on ic; refusing to fall back";
35 log!(Topic::Topology, Error, "{msg}");
36 trap(msg);
37 }
38 }
39 Err(err) => {
40 if build_network() == Some(Network::Ic) {
41 let msg = format!("try_get_current_subnet_pid failed on ic: {err}");
42 log!(Topic::Topology, Error, "{msg}");
43 trap(&msg);
44 }
45 }
46 }
47
48 let fallback = canister_self();
51 EnvOps::set_subnet_pid(fallback);
52
53 log!(
54 Topic::Topology,
55 Info,
56 "try_get_current_subnet_pid unavailable; using self as subnet: {fallback}"
57 );
58}
59
60pub async fn root_import_pool_from_config() {
64 let subnet_cfg = ConfigOps::current_subnet();
65 let import_list = match build_network() {
66 Some(Network::Local) => subnet_cfg.pool.import.local,
67 Some(Network::Ic) => subnet_cfg.pool.import.ic,
68 None => {
69 log!(
70 Topic::CanisterPool,
71 Warn,
72 "pool import skipped: build network not set"
73 );
74 return;
75 }
76 };
77
78 if import_list.is_empty() {
79 return;
80 }
81
82 let mut attempted = 0_u64;
83 let mut imported = 0_u64;
84 let mut skipped = 0_u64;
85 let mut failed = 0_u64;
86
87 for pid in import_list {
88 attempted += 1;
89 match pool_import_canister(pid).await {
90 Ok(()) => {
91 if PoolOps::contains(&pid) {
92 imported += 1;
93 } else {
94 skipped += 1;
95 }
96 }
97 Err(_) => {
98 failed += 1;
99 }
100 }
101 }
102
103 log!(
104 Topic::CanisterPool,
105 Info,
106 "pool import summary: configured={attempted}, imported={imported}, skipped={skipped}, failed={failed}"
107 );
108}
109
110pub async fn root_create_canisters() -> Result<(), Error> {
120 let subnet_cfg = ConfigOps::current_subnet();
122
123 for role in &subnet_cfg.auto_create {
125 if let Some(existing) = SubnetCanisterRegistryOps::get_type(role) {
126 log!(
127 Topic::Init,
128 Info,
129 "auto_create: {role} already registered as {}, skipping",
130 existing.pid
131 );
132 continue;
133 }
134
135 create_canister_request::<()>(role, CreateCanisterParent::Root, None).await?;
136 }
137
138 for canister in SubnetCanisterRegistryOps::export() {
140 log!(Topic::Init, Info, "🥫 {} ({})", canister.role, canister.pid);
141 }
142
143 Ok(())
144}