Skip to main content

Non-Interactive Script

This script is a simplified and automated way to manage your canisters (install, reinstall, or upgrade) using the CLI with minimal setup. However, before using it, you must modify the script to suit your specific use case. Here's what you need to update:


What You Need to Modify

  1. Root Canister ID:

    • Replace the placeholder ROOT_CANISTER_ID="" with the principal ID of your root canister. The root canister is the one that manages the other canisters.
  2. Target Canister ID:

    • Replace the placeholder CANISTER_ID="" with the principal ID of the canister you want to manage (install, reinstall, or upgrade).
  3. WASM Module Path:

    • Update the variable WASM_MODULE_PATH="wasm/path-to-wasm.wasm.gz" with the correct path to the WASM module you want to deploy to the target canister.

Choosing the Operation

The script supports the following operations:

  1. Reinstall:

    ./scripts/upgrade_canister.sh reinstall '(record { field1 = value1; field2 = value2 })'
  2. Install:

    ./scripts/upgrade_canister.sh install '(record { field1 = value1; field2 = value2 })'
  3. Upgrade:

    ./scripts/upgrade_canister.sh upgrade '(record { field1 = value1; field2 = value2 })'

Steps to Use the Script

  1. Modify the Script:

    • Open the script in a text editor.
    • Update ROOT_CANISTER_ID, CANISTER_ID, and WASM_MODULE_PATH with the appropriate values for your project.
  2. Run the Script:

    • Execute the script with the desired operation and optional Candid arguments:
      ./scripts/upgrade_canister.sh install '(record { field1 = value1; field2 = value2 })'
    • If no arguments are required, pass (null):
      ./scripts/upgrade_canister.sh upgrade '(null)'

The Script

#!/bin/bash

# Variables
ROOT_CANISTER_ID="aaaaa-aa" # Toolkit root canister ID
CANISTER_ID="aaaaa-aa" # Target canister ID
WASM_MODULE_PATH="PATH_TO_WASM.wasm.gz" # Path to the WASM module file
REPL_SCRIPT="upgrade_canister.repl" # Temporary ic-repl script file
TEMP_PEM_FILE="temp_identity.pem" # Temporary PEM file for the identity
IDENTITY=$(dfx identity whoami) # Get the current DFX identity name

# Helper function to display usage
usage() {
echo "Usage: $0 <operation> [candid_arguments]"
echo "Example: $0 install '(record { field1 = value1; field2 = \"value2\" })'"
exit 1
}

# Helper function to clean up temporary files
cleanup() {
rm -f "$REPL_SCRIPT" "$TEMP_PEM_FILE"
}

# Validate arguments
if [[ $# -lt 1 ]]; then
usage
fi

# Parse arguments
OPERATION=$1
CANDID_ARGS=${2:-"(null)"} # Default to (null) if no Candid arguments are provided

# Validate operation
if [[ "$OPERATION" != "install" && "$OPERATION" != "upgrade" && "$OPERATION" != "reinstall" ]]; then
echo "Invalid operation: $OPERATION. Valid options are: install, upgrade, reinstall."
exit 1
fi

# Check if the WASM file exists
if [[ ! -f "$WASM_MODULE_PATH" ]]; then
echo "Error: WASM module not found at $WASM_MODULE_PATH."
exit 1
fi

# Check governance status
GOV_STATUS=$(dfx canister call $ROOT_CANISTER_ID --ic get_config --output json | jq -r '.Ok.governance_enabled')
if [[ $? -ne 0 ]]; then
echo "Error: Failed to check governance status."
exit 1
fi

echo "Governance status: $GOV_STATUS"

# Export the current identity
dfx identity export "$IDENTITY" > "$TEMP_PEM_FILE"
if [[ $? -ne 0 ]]; then
echo "Error: Failed to export identity for '$IDENTITY'. Ensure DFX is properly configured."
cleanup
exit 1
fi

# Encode the Candid arguments
ENCODED_ARGS=$(didc encode "$CANDID_ARGS" --format blob)
if [[ $? -ne 0 ]]; then
echo "Error: Failed to encode Candid arguments. Please check the syntax."
cleanup
exit 1
fi

# Generate ic-repl script based on governance status
if [[ "$GOV_STATUS" == "true" ]]; then
echo "Governance is enabled. Using create_proposal."

POST_PROPOSAL=$(cat <<EOF
(record {
title = "$OPERATION canister";
summary = "Proposal to $OPERATION canister $CANISTER_ID.";
url = "";
action = variant {
ManageCanister = variant {
Upgrade = record {
mode = variant { $OPERATION };
canister_id = principal "$CANISTER_ID";
wasm = file("$WASM_MODULE_PATH");
args = opt $ENCODED_ARGS;
}
}
}
})
EOF
)

cat > "$REPL_SCRIPT" <<EOF
#!/usr/bin/ic-repl

identity file("$TEMP_PEM_FILE");
let root_canister = principal "$ROOT_CANISTER_ID";
call root_canister.create_proposal($POST_PROPOSAL);
EOF

echo "Proposal form canister $OPERATION created successfully."

else
echo "Governance is not enabled. Proceeding with ${OPERATION}_canister."

cat > "$REPL_SCRIPT" <<EOF
#!/usr/bin/ic-repl

identity file("$TEMP_PEM_FILE");
let root_canister = principal "$ROOT_CANISTER_ID";
let canister_id = principal "$CANISTER_ID";
let wasm_blob = file("$WASM_MODULE_PATH");
let args_blob = $ENCODED_ARGS;
call root_canister.${OPERATION}_canister(canister_id, wasm_blob, opt args_blob);
EOF

echo "$OPERATION operation completed successfully."
fi

# Execute the ic-repl script
echo "Executing $OPERATION on canister $CANISTER_ID..."
ic-repl -r ic "$REPL_SCRIPT"

# Clean up temporary files
cleanup

echo "Script execution completed."

Notes

  • The script dynamically generates and runs an ic-repl script for the specified operation.
  • It validates the inputs and ensures dependencies are installed before execution.
  • Ideal for automating repetitive canister management tasks in CI/CD pipelines.