Skip to content

Commit c525af4

Browse files
feat(nns-root): Added take_canister_snapshot to Root canister. (#8159)
Only callable by Governance. Part of [NNS1-4295]. [NNS1-4295]: https://dfinity.atlassian.net/browse/NNS1-4295 [👈 Previous PR][prev] [prev]: #8158
1 parent 88430b9 commit c525af4

File tree

8 files changed

+143
-4
lines changed

8 files changed

+143
-4
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rs/nns/handlers/root/impl/canister/canister.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ use ic_nns_handler_root::{
3030
};
3131
use ic_nns_handler_root_interface::{
3232
ChangeCanisterControllersRequest, ChangeCanisterControllersResponse,
33-
UpdateCanisterSettingsRequest, UpdateCanisterSettingsResponse,
33+
TakeCanisterSnapshotRequest, TakeCanisterSnapshotResponse, UpdateCanisterSettingsRequest,
34+
UpdateCanisterSettingsResponse,
3435
};
3536
use std::cell::RefCell;
3637

@@ -227,6 +228,20 @@ async fn update_canister_settings(
227228
.await
228229
}
229230

231+
/// Takes a snapshot of a canister controlled by NNS Root. Only callable by NNS
232+
/// Governance.
233+
#[update]
234+
async fn take_canister_snapshot(
235+
take_canister_snapshot_request: TakeCanisterSnapshotRequest,
236+
) -> TakeCanisterSnapshotResponse {
237+
check_caller_is_governance();
238+
canister_management::take_canister_snapshot(
239+
take_canister_snapshot_request,
240+
&mut new_management_canister_client(),
241+
)
242+
.await
243+
}
244+
230245
/// Resources to serve for a given http_request
231246
/// Serve an HttpRequest made to this canister
232247
#[query(

rs/nns/handlers/root/impl/canister/root.did

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,27 @@ type CallCanisterRequest = record {
151151
payload : blob;
152152
};
153153

154+
type TakeCanisterSnapshotArgs = record {
155+
canister_id : principal;
156+
replace_snapshot : opt blob;
157+
};
158+
159+
type TakeCanisterSnapshotResponse = variant {
160+
Ok : TakeCanisterSnapshotOk;
161+
Err : TakeCanisterSnapshotError;
162+
};
163+
164+
type TakeCanisterSnapshotOk = record {
165+
id : blob;
166+
taken_at_timestamp : nat64;
167+
total_size : nat64;
168+
};
169+
170+
type TakeCanisterSnapshotError = record {
171+
code : opt int32;
172+
description : text;
173+
};
174+
154175
service : () -> {
155176
canister_status : (CanisterIdRecord) -> (CanisterStatusResult);
156177
get_build_metadata : () -> (text) query;
@@ -166,4 +187,7 @@ service : () -> {
166187
UpdateCanisterSettingsResponse,
167188
);
168189
call_canister : (CallCanisterRequest) -> ();
190+
take_canister_snapshot : (TakeCanisterSnapshotArgs) -> (
191+
TakeCanisterSnapshotResponse,
192+
);
169193
}

rs/nns/handlers/root/impl/src/canister_management.rs

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
#![allow(deprecated)]
22
use crate::PROXIED_CANISTER_CALLS_TRACKER;
3-
use ic_base_types::{CanisterId, PrincipalId};
3+
use ic_base_types::{CanisterId, PrincipalId, SnapshotId};
44
use ic_cdk::{
55
api::call::{RejectionCode, call_with_payment},
66
call, caller, print,
77
};
88
use ic_management_canister_types_private::{
9-
CanisterInstallMode::Install, CanisterSettingsArgsBuilder, CreateCanisterArgs, InstallCodeArgs,
9+
CanisterInstallMode::Install, CanisterSettingsArgsBuilder, CanisterSnapshotResponse,
10+
CreateCanisterArgs, InstallCodeArgs, TakeCanisterSnapshotArgs,
1011
};
1112
use ic_nervous_system_clients::{
1213
canister_id_record::CanisterIdRecord,
@@ -23,7 +24,8 @@ use ic_nns_common::{
2324
types::CallCanisterRequest,
2425
};
2526
use ic_nns_handler_root_interface::{
26-
ChangeCanisterControllersRequest, ChangeCanisterControllersResponse,
27+
ChangeCanisterControllersRequest, ChangeCanisterControllersResponse, TakeCanisterSnapshotError,
28+
TakeCanisterSnapshotOk, TakeCanisterSnapshotRequest, TakeCanisterSnapshotResponse,
2729
UpdateCanisterSettingsError, UpdateCanisterSettingsRequest, UpdateCanisterSettingsResponse,
2830
};
2931
use ic_protobuf::{
@@ -251,3 +253,71 @@ pub async fn update_canister_settings(
251253
}
252254
}
253255
}
256+
257+
pub async fn take_canister_snapshot(
258+
take_canister_snapshot_request: TakeCanisterSnapshotRequest,
259+
management_canister_client: &mut impl ManagementCanisterClient,
260+
) -> TakeCanisterSnapshotResponse {
261+
let TakeCanisterSnapshotRequest {
262+
canister_id,
263+
replace_snapshot,
264+
} = take_canister_snapshot_request;
265+
266+
let replace_snapshot = match replace_snapshot {
267+
None => None,
268+
Some(snapshot_id) => {
269+
let snapshot_id = match SnapshotId::try_from(&snapshot_id) {
270+
Ok(ok) => ok,
271+
Err(err) => {
272+
return TakeCanisterSnapshotResponse::Err(TakeCanisterSnapshotError {
273+
code: None,
274+
description: format!("Invalid snapshot ID ({snapshot_id:02X?}): {err}"),
275+
});
276+
}
277+
};
278+
279+
Some(snapshot_id)
280+
}
281+
};
282+
283+
let take_canister_snapshot_args = TakeCanisterSnapshotArgs {
284+
canister_id,
285+
replace_snapshot,
286+
uninstall_code: None,
287+
sender_canister_version: management_canister_client.canister_version(),
288+
};
289+
290+
match management_canister_client
291+
.take_canister_snapshot(take_canister_snapshot_args)
292+
.await
293+
{
294+
Ok(result) => {
295+
let result =
296+
convert_from_canister_snapshot_response_to_take_canister_snapshot_ok(result);
297+
TakeCanisterSnapshotResponse::Ok(result)
298+
}
299+
300+
Err((code, description)) => TakeCanisterSnapshotResponse::Err(TakeCanisterSnapshotError {
301+
code: Some(code),
302+
description,
303+
}),
304+
}
305+
}
306+
307+
fn convert_from_canister_snapshot_response_to_take_canister_snapshot_ok(
308+
response: CanisterSnapshotResponse,
309+
) -> TakeCanisterSnapshotOk {
310+
let CanisterSnapshotResponse {
311+
id,
312+
taken_at_timestamp,
313+
total_size,
314+
} = response;
315+
316+
let id = id.to_vec();
317+
318+
TakeCanisterSnapshotOk {
319+
id,
320+
taken_at_timestamp,
321+
total_size,
322+
}
323+
}

rs/nns/handlers/root/interface/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ DEPENDENCIES = [
77
"//rs/nervous_system/clients",
88
"//rs/nns/constants",
99
"//rs/types/base_types",
10+
"//rs/types/management_canister_types",
1011
"@crate_index//:candid",
1112
"@crate_index//:ic-cdk",
1213
"@crate_index//:serde",

rs/nns/handlers/root/interface/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ async-trait = { workspace = true }
88
candid = { workspace = true }
99
ic-base-types = { path = "../../../../types/base_types" }
1010
ic-cdk = { workspace = true }
11+
ic-management-canister-types-private = { path = "../../../../types/management_canister_types" }
1112
ic-nervous-system-clients = { path = "../../../../nervous_system/clients" }
1213
ic-nns-constants = { path = "../../../../nns/constants" }
1314
serde = { workspace = true }

rs/nns/handlers/root/interface/src/lib.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,28 @@ pub struct UpdateCanisterSettingsError {
8282
pub code: Option<i32>,
8383
pub description: String,
8484
}
85+
86+
#[derive(Clone, Eq, PartialEq, Hash, Debug, CandidType, Deserialize)]
87+
pub struct TakeCanisterSnapshotRequest {
88+
pub canister_id: PrincipalId,
89+
pub replace_snapshot: Option</* snapshot ID */ Vec<u8>>,
90+
}
91+
92+
#[derive(Clone, Eq, PartialEq, Hash, Debug, CandidType, Deserialize)]
93+
pub enum TakeCanisterSnapshotResponse {
94+
Ok(TakeCanisterSnapshotOk),
95+
Err(TakeCanisterSnapshotError),
96+
}
97+
98+
#[derive(Clone, Eq, PartialEq, Hash, Debug, CandidType, Deserialize)]
99+
pub struct TakeCanisterSnapshotOk {
100+
pub id: Vec<u8>,
101+
pub taken_at_timestamp: u64,
102+
pub total_size: u64,
103+
}
104+
105+
#[derive(Clone, Eq, PartialEq, Hash, Debug, CandidType, Deserialize)]
106+
pub struct TakeCanisterSnapshotError {
107+
pub code: Option<i32>,
108+
pub description: String,
109+
}

rs/nns/handlers/root/unreleased_changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ on the process that this file is part of, see
99

1010
## Added
1111

12+
* Added `take_canister_snapshot` method. It is only callable by the Governance canister though.
13+
1214
## Changed
1315

1416
## Deprecated

0 commit comments

Comments
 (0)