Skip to content

Commit e36d9f5

Browse files
feat: EXC-2057: Update canister status to include environment variables (#5843)
This PR updates the canister status to expose canister environment variables. It also refactors the code to use the EnvironmentVariables type instead of the raw type, moving the struct to the /types module and updating the relevant code and tests accordingly. Follow-up: environment variables validation, expanded tests coverage, improvements.
1 parent 333217f commit e36d9f5

File tree

14 files changed

+165
-79
lines changed

14 files changed

+165
-79
lines changed

rs/embedders/src/wasmtime_embedder/system_api/sandbox_safe_system_state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,7 @@ impl SandboxSafeSystemState {
789789
system_state.memory_allocation,
790790
system_state.wasm_memory_threshold,
791791
compute_allocation,
792-
system_state.environment_variables.clone(),
792+
system_state.environment_variables.clone().into(),
793793
system_state.balance(),
794794
system_state.reserved_balance(),
795795
system_state.reserved_balance_limit(),

rs/execution_environment/src/canister_manager.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,7 @@ impl CanisterManager {
325325
}
326326
if let Some(environment_variables) = settings.environment_variables() {
327327
if self.environment_variables_flag == FlagStatus::Enabled {
328-
canister.system_state.environment_variables =
329-
environment_variables.get_environment_variables().clone();
328+
canister.system_state.environment_variables = environment_variables.clone();
330329
}
331330
}
332331
}
@@ -865,6 +864,7 @@ impl CanisterManager {
865864
.egress_payload_size,
866865
wasm_memory_limit.map(|x| x.get()),
867866
wasm_memory_threshold.get(),
867+
canister.system_state.environment_variables.clone(),
868868
))
869869
}
870870

rs/execution_environment/src/canister_manager/tests.rs

Lines changed: 59 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::{
1313
};
1414
use assert_matches::assert_matches;
1515
use candid::{CandidType, Decode, Encode};
16-
use ic_base_types::{NumSeconds, PrincipalId};
16+
use ic_base_types::{EnvironmentVariables, NumSeconds, PrincipalId};
1717
use ic_config::{
1818
execution_environment::{
1919
Config, CANISTER_GUARANTEED_CALLBACK_QUOTA, DEFAULT_WASM_MEMORY_LIMIT,
@@ -35,11 +35,12 @@ use ic_management_canister_types_private::{
3535
CanisterChange, CanisterChangeDetails, CanisterChangeOrigin, CanisterIdRecord,
3636
CanisterInstallMode, CanisterInstallModeV2, CanisterSettingsArgsBuilder,
3737
CanisterSnapshotResponse, CanisterStatusResultV2, CanisterStatusType, CanisterUpgradeOptions,
38-
ChunkHash, ClearChunkStoreArgs, CreateCanisterArgs, EmptyBlob, InstallCodeArgsV2,
39-
LoadCanisterSnapshotArgs, Method, NodeMetricsHistoryArgs, NodeMetricsHistoryResponse,
40-
OnLowWasmMemoryHookStatus, Payload, RenameCanisterArgs, RenameToArgs, StoredChunksArgs,
41-
StoredChunksReply, SubnetInfoArgs, SubnetInfoResponse, TakeCanisterSnapshotArgs,
42-
UpdateSettingsArgs, UploadChunkArgs, UploadChunkReply, WasmMemoryPersistence, IC_00,
38+
ChunkHash, ClearChunkStoreArgs, CreateCanisterArgs, EmptyBlob, EnvironmentVariable,
39+
InstallCodeArgsV2, LoadCanisterSnapshotArgs, Method, NodeMetricsHistoryArgs,
40+
NodeMetricsHistoryResponse, OnLowWasmMemoryHookStatus, Payload, RenameCanisterArgs,
41+
RenameToArgs, StoredChunksArgs, StoredChunksReply, SubnetInfoArgs, SubnetInfoResponse,
42+
TakeCanisterSnapshotArgs, UpdateSettingsArgs, UploadChunkArgs, UploadChunkReply,
43+
WasmMemoryPersistence, IC_00,
4344
};
4445
use ic_metrics::MetricsRegistry;
4546
use ic_registry_provisional_whitelist::ProvisionalWhitelist;
@@ -1297,6 +1298,36 @@ fn get_canister_status_of_stopping_canister() {
12971298
});
12981299
}
12991300

1301+
#[test]
1302+
fn canister_status_with_environment_variables() {
1303+
let mut test = ExecutionTestBuilder::new()
1304+
.with_environment_variables_flag(FlagStatus::Enabled)
1305+
.build();
1306+
let environment_variables = btreemap![
1307+
"TEST_VAR".to_string() => "test_value".to_string(),
1308+
"TEST_VAR2".to_string() => "test_value2".to_string(),
1309+
];
1310+
1311+
let settings = CanisterSettingsArgsBuilder::new()
1312+
.with_environment_variables(environment_variables.clone())
1313+
.build();
1314+
let canister_id = test
1315+
.create_canister_with_settings(*INITIAL_CYCLES, settings)
1316+
.unwrap();
1317+
let status = test.canister_status(canister_id);
1318+
let reply = get_reply(status);
1319+
let status = Decode!(&reply, CanisterStatusResultV2).unwrap();
1320+
1321+
let expected_env_vars = environment_variables
1322+
.into_iter()
1323+
.map(|(name, value)| EnvironmentVariable { name, value })
1324+
.collect::<Vec<_>>();
1325+
assert_eq!(
1326+
status.settings().environment_variables(),
1327+
&expected_env_vars
1328+
);
1329+
}
1330+
13001331
#[test]
13011332
fn set_controller_with_incorrect_controller() {
13021333
let mut test = ExecutionTestBuilder::new().build();
@@ -6667,16 +6698,17 @@ fn test_environment_variables_are_changed_via_create_canister() {
66676698
})
66686699
.build();
66696700

6670-
let mut env_vars = BTreeMap::new();
6671-
env_vars.insert("KEY1".to_string(), "VALUE1".to_string());
6672-
env_vars.insert("KEY2".to_string(), "VALUE2".to_string());
6701+
let env_vars = EnvironmentVariables::new(BTreeMap::from([
6702+
("KEY1".to_string(), "VALUE1".to_string()),
6703+
("KEY2".to_string(), "VALUE2".to_string()),
6704+
]));
66736705

66746706
// Create canister with environment variables.
66756707
let canister_id = test
66766708
.create_canister_with_settings(
66776709
Cycles::new(1_000_000_000_000_000),
66786710
CanisterSettingsArgsBuilder::new()
6679-
.with_environment_variables(env_vars.clone())
6711+
.with_environment_variables(env_vars.clone().into())
66806712
.build(),
66816713
)
66826714
.unwrap();
@@ -6696,15 +6728,16 @@ fn test_environment_variables_are_updated_on_update_settings() {
66966728
.build();
66976729
let canister_id = test.create_canister(Cycles::new(1_000_000_000_000_000));
66986730

6699-
let mut env_vars = BTreeMap::new();
6700-
env_vars.insert("KEY1".to_string(), "VALUE1".to_string());
6701-
env_vars.insert("KEY2".to_string(), "VALUE2".to_string());
6731+
let env_vars = EnvironmentVariables::new(BTreeMap::from([
6732+
("KEY1".to_string(), "VALUE1".to_string()),
6733+
("KEY2".to_string(), "VALUE2".to_string()),
6734+
]));
67026735

67036736
// Set environment variables via `update_settings`.
67046737
let args = UpdateSettingsArgs {
67056738
canister_id: canister_id.get(),
67066739
settings: CanisterSettingsArgsBuilder::new()
6707-
.with_environment_variables(env_vars.clone())
6740+
.with_environment_variables(env_vars.clone().into())
67086741
.build(),
67096742
sender_canister_version: None,
67106743
};
@@ -6739,9 +6772,10 @@ fn test_environment_variables_are_not_set_when_disabled() {
67396772
.build();
67406773

67416774
// Create environment variables.
6742-
let mut env_vars = BTreeMap::new();
6743-
env_vars.insert("KEY1".to_string(), "VALUE1".to_string());
6744-
env_vars.insert("KEY2".to_string(), "VALUE2".to_string());
6775+
let env_vars = BTreeMap::from([
6776+
("KEY1".to_string(), "VALUE1".to_string()),
6777+
("KEY2".to_string(), "VALUE2".to_string()),
6778+
]);
67456779

67466780
// Create canister with environment variables.
67476781
let canister_id = test
@@ -6755,7 +6789,10 @@ fn test_environment_variables_are_not_set_when_disabled() {
67556789

67566790
// Verify environment variables are not set.
67576791
let canister = test.canister_state(canister_id);
6758-
assert_eq!(canister.system_state.environment_variables, BTreeMap::new());
6792+
assert_eq!(
6793+
canister.system_state.environment_variables,
6794+
EnvironmentVariables::new(BTreeMap::new())
6795+
);
67596796

67606797
// Set environment variables via `update_settings`.
67616798
let args = UpdateSettingsArgs {
@@ -6770,7 +6807,10 @@ fn test_environment_variables_are_not_set_when_disabled() {
67706807

67716808
// Verify environment variables are not set.
67726809
let canister = test.canister_state(canister_id);
6773-
assert_eq!(canister.system_state.environment_variables, BTreeMap::new());
6810+
assert_eq!(
6811+
canister.system_state.environment_variables,
6812+
EnvironmentVariables::new(BTreeMap::new())
6813+
);
67746814
}
67756815

67766816
/// Creates and deploys a pair of universal canisters with the second canister being controlled by the first one

rs/execution_environment/src/canister_settings.rs

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
use ic_base_types::{NumBytes, NumSeconds};
2-
use ic_crypto_sha2::Sha256;
1+
use ic_base_types::{EnvironmentVariables, NumBytes, NumSeconds};
32
use ic_cycles_account_manager::{CyclesAccountManager, ResourceSaturation};
43
use ic_error_types::{ErrorCode, UserError};
54
use ic_interfaces::execution_environment::SubnetAvailableMemory;
6-
use ic_management_canister_types_private::{CanisterSettingsArgs, LogVisibilityV2, HASH_LENGTH};
5+
use ic_management_canister_types_private::{CanisterSettingsArgs, LogVisibilityV2};
76
use ic_replicated_state::MessageMemoryUsage;
87
use ic_types::{
98
ComputeAllocation, Cycles, InvalidComputeAllocationError, InvalidMemoryAllocationError,
109
MemoryAllocation, PrincipalId,
1110
};
1211
use num_traits::{cast::ToPrimitive, SaturatingSub};
13-
use std::{collections::BTreeMap, convert::TryFrom};
12+
use std::convert::TryFrom;
1413

1514
use crate::canister_manager::types::CanisterManagerError;
1615

@@ -422,46 +421,6 @@ impl ValidatedCanisterSettings {
422421
}
423422
}
424423

425-
#[derive(Clone)]
426-
pub struct EnvironmentVariables {
427-
environment_variables: BTreeMap<String, String>,
428-
}
429-
430-
impl EnvironmentVariables {
431-
pub fn new(environment_variables: BTreeMap<String, String>) -> Self {
432-
Self {
433-
environment_variables,
434-
}
435-
}
436-
437-
pub fn hash(&self) -> [u8; HASH_LENGTH] {
438-
// Create a vector to store the hashes of key-value pairs
439-
let mut hashes: Vec<Vec<u8>> = Vec::new();
440-
441-
// 1. For each key-value pair, hash the key and value, and concatenate the hashes.
442-
for (key, value) in &self.environment_variables {
443-
let mut key_hash = Sha256::hash(key.as_bytes()).to_vec();
444-
let mut value_hash = Sha256::hash(value.as_bytes()).to_vec();
445-
key_hash.append(&mut value_hash);
446-
hashes.push(key_hash);
447-
}
448-
// 2. Sort the concatenated hashes.
449-
hashes.sort();
450-
451-
// 3. Concatenate the sorted hashes, and hash the result.
452-
let mut hasher = Sha256::new();
453-
for hash in hashes {
454-
hasher.write(&hash);
455-
}
456-
457-
hasher.finish()
458-
}
459-
460-
pub fn get_environment_variables(&self) -> BTreeMap<String, String> {
461-
self.environment_variables.clone()
462-
}
463-
}
464-
465424
/// Validates the new canisters settings:
466425
/// - memory allocation:
467426
/// - it cannot be lower than the current canister memory usage.

rs/execution_environment/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ mod types;
1515
pub mod util;
1616

1717
use crate::ingress_filter::IngressFilterServiceImpl;
18-
pub use canister_settings::EnvironmentVariables;
1918
pub use execution_environment::{
2019
as_num_instructions, as_round_instructions, execute_canister, CompilationCostHandling,
2120
ExecuteMessageResult, ExecutionEnvironment, ExecutionResponse, RoundInstructions, RoundLimits,

rs/execution_environment/tests/canister_history.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ use ic00::{
22
CanisterSettingsArgsBuilder, CanisterSnapshotResponse, LoadCanisterSnapshotArgs,
33
TakeCanisterSnapshotArgs,
44
};
5-
use ic_base_types::PrincipalId;
5+
use ic_base_types::{EnvironmentVariables, PrincipalId};
66
use ic_config::flag_status::FlagStatus;
77
use ic_config::{execution_environment::Config as HypervisorConfig, subnet_config::SubnetConfig};
88
use ic_crypto_sha2::Sha256;
99
use ic_error_types::{ErrorCode, UserError};
10-
use ic_execution_environment::EnvironmentVariables;
1110
use ic_management_canister_types_private::CanisterInstallMode::{Install, Reinstall, Upgrade};
1211
use ic_management_canister_types_private::{
1312
self as ic00, CanisterChange, CanisterChangeDetails, CanisterChangeOrigin, CanisterIdRecord,
@@ -1253,12 +1252,15 @@ fn check_environment_variables_for_create_canister_history(
12531252
let canister_state = state.canister_state(&canister_id).unwrap();
12541253
match environment_variables_flag {
12551254
FlagStatus::Enabled => {
1256-
assert_eq!(&canister_state.system_state.environment_variables, env_vars);
1255+
assert_eq!(
1256+
canister_state.system_state.environment_variables,
1257+
EnvironmentVariables::new(env_vars.clone())
1258+
);
12571259
}
12581260
FlagStatus::Disabled => {
12591261
assert_eq!(
12601262
canister_state.system_state.environment_variables,
1261-
BTreeMap::new()
1263+
EnvironmentVariables::new(BTreeMap::new())
12621264
);
12631265
}
12641266
}
@@ -1337,7 +1339,10 @@ fn canister_history_tracking_env_vars_update_settings() {
13371339
// Verify the environment variables of the canister state.
13381340
let state = env.get_latest_state();
13391341
let canister_state = state.canister_state(&canister_id).unwrap();
1340-
assert_eq!(canister_state.system_state.environment_variables, env_vars);
1342+
assert_eq!(
1343+
canister_state.system_state.environment_variables,
1344+
EnvironmentVariables::new(env_vars)
1345+
);
13411346
}
13421347

13431348
#[test]

rs/replica_tests/tests/canister_lifecycle.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,7 @@ fn can_get_canister_information() {
732732
0u128,
733733
Some(DEFAULT_WASM_MEMORY_LIMIT.get()),
734734
0u64,
735+
Default::default(),
735736
)
736737
);
737738

@@ -797,6 +798,7 @@ fn can_get_canister_information() {
797798
0u128,
798799
Some(DEFAULT_WASM_MEMORY_LIMIT.get()),
799800
0u64,
801+
Default::default(),
800802
),
801803
CanisterStatusResultV2::decode(&res).unwrap(),
802804
2 * BALANCE_EPSILON,

rs/replicated_state/src/canister_state/system_state.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
PageMap, StateError,
1616
};
1717
pub use call_context_manager::{CallContext, CallContextAction, CallContextManager, CallOrigin};
18-
use ic_base_types::NumSeconds;
18+
use ic_base_types::{EnvironmentVariables, NumSeconds};
1919
use ic_error_types::RejectCode;
2020
use ic_interfaces::execution_environment::HypervisorError;
2121
use ic_logger::{error, ReplicaLogger};
@@ -405,7 +405,7 @@ pub struct SystemState {
405405
pub snapshots_memory_usage: NumBytes,
406406

407407
/// Environment variables.
408-
pub environment_variables: BTreeMap<String, String>,
408+
pub environment_variables: EnvironmentVariables,
409409
}
410410

411411
/// A wrapper around the different canister statuses.
@@ -849,7 +849,7 @@ impl SystemState {
849849
wasm_memory_limit,
850850
next_snapshot_id,
851851
snapshots_memory_usage,
852-
environment_variables,
852+
environment_variables: EnvironmentVariables::new(environment_variables),
853853
};
854854
system_state.check_invariants().unwrap_or_else(|msg| {
855855
metrics.observe_broken_soft_invariant(msg);

rs/state_manager/src/tip.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1312,7 +1312,11 @@ fn serialize_canister_protos_to_checkpoint_readwrite(
13121312
wasm_memory_limit: canister_state.system_state.wasm_memory_limit,
13131313
next_snapshot_id: canister_state.system_state.next_snapshot_id,
13141314
snapshots_memory_usage: canister_state.system_state.snapshots_memory_usage,
1315-
environment_variables: canister_state.system_state.environment_variables.clone(),
1315+
environment_variables: canister_state
1316+
.system_state
1317+
.environment_variables
1318+
.clone()
1319+
.into(),
13161320
}
13171321
.into(),
13181322
)?;

rs/test_utilities/state/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use ic_base_types::NumSeconds;
1+
use ic_base_types::{EnvironmentVariables, NumSeconds};
22
use ic_btc_replica_types::BitcoinAdapterRequestWrapper;
33
use ic_management_canister_types_private::{
44
CanisterStatusType, EcdsaCurve, EcdsaKeyId, LogVisibilityV2, MasterPublicKeyId,
@@ -471,7 +471,7 @@ impl SystemStateBuilder {
471471
mut self,
472472
environment_variables: BTreeMap<String, String>,
473473
) -> Self {
474-
self.system_state.environment_variables = environment_variables;
474+
self.system_state.environment_variables = EnvironmentVariables::new(environment_variables);
475475
self
476476
}
477477

0 commit comments

Comments
 (0)