Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support for targetting arbitrary IC network on the cli #302

Merged
merged 17 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ build:lint --config=clippy

build:ci --progress_report_interval=30

build --nosandbox_default_allow_network
build --sandbox_default_allow_network
build --incompatible_strict_action_env # use an environment with a static value for PATH and do not inherit LD_LIBRARY_PATH

# default to optimized and unstripped binaries.
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"yaml.schemas": {
"release-index-shema.json": "release-index.yaml"
}
},
"rust-analyzer.showUnlinkedFileNotification": false
}
19 changes: 18 additions & 1 deletion Cargo.Bazel.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"checksum": "31058f9f66529f2b114e4c4508e3cc6dbf7243335ca17851bca859ae720bcccd",
"checksum": "b6737f3f6bdb970486578a3c4c615afe6fd16e0bf32c3930b649d568c6be06c5",
"crates": {
"actix-codec 0.5.2": {
"name": "actix-codec",
Expand Down Expand Up @@ -22116,6 +22116,10 @@
"id": "chrono 0.4.37",
"target": "chrono"
},
{
"id": "futures 0.3.30",
"target": "futures"
},
{
"id": "ic-base-types 0.9.0",
"target": "ic_base_types"
Expand Down Expand Up @@ -22152,13 +22156,26 @@
"id": "strum 0.26.2",
"target": "strum"
},
{
"id": "tokio 1.36.0",
"target": "tokio"
},
{
"id": "url 2.5.0",
"target": "url"
}
],
"selects": {}
},
"deps_dev": {
"common": [
{
"id": "wiremock 0.6.0",
"target": "wiremock"
}
],
"selects": {}
},
"edition": "2021",
"proc_macro_deps": {
"common": [
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ tokio = { version = "1.2.0", features = ["full"] }
url = "2.5.0"
urlencoding = "2.1.0"
warp = "0.3"
wiremock = "0.6.0"


[profile.release]
Expand Down
6 changes: 3 additions & 3 deletions dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
},
"scripts": {
"dev-staging": "concurrently \"yarn start\" \"yarn start-backend\" \"yarn start-rust-backend-staging\"",
"start-rust-backend-staging": "cd .. && BACKEND_PORT=8081 RUST_BACKTRACE=1 NETWORK=staging NNS_URL=http://[2600:3000:6100:200:5000:b0ff:fe8e:6b7b]:8080 cargo watch -C rs/ic-management-backend -x 'run --release --color=always'",
"start-rust-backend-staging": "cd .. && BACKEND_PORT=8081 RUST_BACKTRACE=1 cargo watch -C rs/ic-management-backend -x 'run --release --color=always -- --network staging'",
"dev-mainnet": "concurrently \"yarn start\" \"yarn start-backend\" \"yarn start-rust-backend-mainnet\"",
"start-rust-backend-mainnet": "cd .. && RUST_BACKTRACE=1 NETWORK=mainnet NNS_URL=https://ic0.app cargo watch -C rs/ic-management-backend -x 'run --release --color=always'",
"start-rust-backend-mainnet": "cd .. && RUST_BACKTRACE=1 cargo watch -C rs/ic-management-backend -x 'run --release --color=always -- --network mainnet'",
"dev": "concurrently \"yarn start\" \"yarn start-backend\" \"yarn start-rust-backend-staging\" \"yarn start-rust-backend-mainnet\"",
"start": "yarn workspace app start",
"start-backend": "yarn workspace backend start",
Expand Down Expand Up @@ -71,4 +71,4 @@
]
},
"dependencies": {}
}
}
2 changes: 1 addition & 1 deletion rs/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ url = { workspace = true }
tempfile = "3.10.0"

[dev-dependencies]
wiremock = "0.6.0"
wiremock = { workspace = true }

[[bin]]
name = "dre"
Expand Down
81 changes: 36 additions & 45 deletions rs/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use clap::{Parser, Subcommand};
use clap_num::maybe_hex;
use ic_base_types::PrincipalId;
use ic_management_types::{Artifact, Network};
use log::error;
use url::Url;

use crate::detect_neuron::{detect_hsm_auth, detect_neuron, Auth, Neuron};
use crate::detect_neuron::Neuron;

// For more info about the version setup, look at https://docs.rs/clap/latest/clap/struct.Command.html#method.version
#[derive(Parser, Clone, Default)]
Expand Down Expand Up @@ -38,9 +38,14 @@ pub struct Opts {
#[clap(long, env = "VERBOSE", global = true)]
pub verbose: bool,

// Specify the target network: "mainnet" (default), "staging", or NNS URL
// Specify the target network: "mainnet" (default), "staging", or a testnet name
#[clap(long, env = "NETWORK", default_value = "mainnet")]
pub network: Network,
pub network: String,

// NNS_URLs for the target network, comma separated.
// The argument is mandatory for testnets, and is optional for mainnet and staging
#[clap(long, env = "NNS_URLS", aliases = &["registry-url", "nns-url"], value_delimiter = ',')]
pub nns_urls: Vec<Url>,

#[clap(subcommand)]
pub subcommand: Commands,
Expand Down Expand Up @@ -409,11 +414,11 @@ pub mod nodes {
}

#[derive(Clone)]
pub struct Cli {
pub ic_admin: Option<String>,
pub nns_url: url::Url,
pub struct ParsedCli {
pub network: Network,
pub ic_admin_bin_path: Option<String>,
pub yes: bool,
pub neuron: Option<Neuron>,
pub neuron: Neuron,
}

#[derive(Clone)]
Expand All @@ -427,15 +432,11 @@ pub struct UpdateVersion {
pub versions_to_retire: Option<Vec<String>>,
}

impl Cli {
pub fn get_neuron(&self) -> &Option<Neuron> {
impl ParsedCli {
pub fn get_neuron(&self) -> &Neuron {
&self.neuron
}

pub fn get_nns_url(&self) -> &url::Url {
&self.nns_url
}

pub fn get_update_cmd_args(update_version: &UpdateVersion) -> Vec<String> {
[
[
Expand All @@ -462,39 +463,29 @@ impl Cli {
}

pub async fn from_opts(opts: &Opts, require_authentication: bool) -> anyhow::Result<Self> {
let nns_url = opts.network.get_url();
let neuron = if let Some(id) = opts.neuron_id {
Some(Neuron {
id,
auth: if let Some(path) = opts.private_key_pem.clone() {
Auth::Keyfile { path }
} else if let (Some(slot), Some(pin), Some(key_id)) =
(opts.hsm_slot, opts.hsm_pin.clone(), opts.hsm_key_id.clone())
{
Auth::Hsm { pin, slot, key_id }
} else {
detect_hsm_auth()?
.ok_or_else(|| anyhow::anyhow!("No valid authentication method found for neuron: {id}"))?
},
})
} else if require_authentication {
// Early warn if there will be a problem because a neuron was not detected.
match detect_neuron(nns_url.clone()).await {
Ok(Some(n)) => Some(n),
Ok(None) => {
error!("No neuron detected. Your HSM device is not detectable (or override variables HSM_PIN, HSM_SLOT, HSM_KEY_ID are incorrectly set); your variables NEURON_ID, PRIVATE_KEY_PEM might not be defined either.");
None
},
Err(e) => return Err(anyhow::anyhow!("Failed to detect neuron: {}. Your HSM device is not detectable (or override variables HSM_PIN, HSM_SLOT, HSM_KEY_ID are incorrectly set); your variables NEURON_ID, PRIVATE_KEY_PEM might not be defined either.", e)),
}
} else {
None
};
Ok(Cli {
let network = Network::new(&opts.network, &opts.nns_urls).await.map_err(|e| {
anyhow::anyhow!(
"Failed to parse network from name {} and NNS urls {:?}. Error: {}",
opts.network,
opts.nns_urls,
e
)
})?;
let neuron = Neuron::new(
&network,
require_authentication,
opts.neuron_id,
opts.private_key_pem.clone(),
opts.hsm_slot.clone(),
opts.hsm_pin.clone(),
opts.hsm_key_id.clone(),
)
.await?;
Ok(ParsedCli {
network: network,
yes: opts.yes,
neuron,
ic_admin: opts.ic_admin.clone(),
nns_url,
ic_admin_bin_path: opts.ic_admin.clone(),
})
}
}
28 changes: 15 additions & 13 deletions rs/cli/src/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct DashboardBackendClient {
impl DashboardBackendClient {
// Only used in tests, which should be cleaned up together with this code.
#[allow(dead_code)]
pub fn new(network: Network, dev: bool) -> DashboardBackendClient {
pub fn new(network: &Network, dev: bool) -> DashboardBackendClient {
Self {
url: reqwest::Url::parse(if !dev {
"https://dashboard.internal.dfinity.network/"
Expand All @@ -28,16 +28,12 @@ impl DashboardBackendClient {
.expect("invalid base url")
.join("api/proxy/registry/")
.expect("failed to join url")
.join(match network {
Network::Mainnet => "mainnet/",
Network::Staging => "staging/",
Network::Url(_) => "/",
})
.join(&network.name)
.expect("failed to join url"),
}
}

pub fn new_with_network_url(url: String) -> Self {
pub fn new_with_backend_url(url: String) -> Self {
Self {
url: reqwest::Url::parse(&url).unwrap(),
}
Expand Down Expand Up @@ -154,22 +150,28 @@ impl RESTRequestBuilder for reqwest::RequestBuilder {
mod tests {
use super::*;

#[test]
fn dashboard_backend_client_url() {
#[tokio::test]
async fn dashboard_backend_client_url() {
let mainnet = Network::new("mainnet", &vec![])
.await
.expect("failed to create mainnet network");
let staging = Network::new("staging", &vec![])
.await
.expect("failed to create staging network");
assert_eq!(
DashboardBackendClient::new(Network::Mainnet, false).url.to_string(),
DashboardBackendClient::new(&mainnet, false).url.to_string(),
"https://dashboard.internal.dfinity.network/api/proxy/registry/mainnet/"
);
assert_eq!(
DashboardBackendClient::new(Network::Staging, false).url.to_string(),
DashboardBackendClient::new(&staging, false).url.to_string(),
"https://dashboard.internal.dfinity.network/api/proxy/registry/staging/"
);
assert_eq!(
DashboardBackendClient::new(Network::Mainnet, true).url.to_string(),
DashboardBackendClient::new(&mainnet, true).url.to_string(),
"http://localhost:17000/api/proxy/registry/mainnet/"
);
assert_eq!(
DashboardBackendClient::new(Network::Staging, true).url.to_string(),
DashboardBackendClient::new(&staging, true).url.to_string(),
"http://localhost:17000/api/proxy/registry/staging/"
);
}
Expand Down
Loading
Loading