Skip to content

Commit

Permalink
feat(cli): Add github URL to the proposals for new IC version
Browse files Browse the repository at this point in the history
  • Loading branch information
sasa-tomic committed Sep 19, 2023
1 parent 1814a81 commit 4ab357a
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 32 deletions.
4 changes: 2 additions & 2 deletions rs/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ pub(crate) mod version {
/// Specify the commit hash of the version that is being elected.
version: String,

/// RC branch that contains the release commits.
rc_branch_name: String,
/// Git tag for the release.
release_tag: String,
},
}
}
Expand Down
122 changes: 96 additions & 26 deletions rs/cli/src/ic_admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use ic_nns_governance::pb::v1::{ListNeurons, ListNeuronsResponse};
use ic_sys::utility_command::UtilityCommand;
use itertools::Itertools;
use keyring::{Entry, Error};
use log::{error, info};
use log::{error, info, warn};
use regex::Regex;
use reqwest::StatusCode;
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -320,31 +320,52 @@ impl Cli {
self.propose_run(cmd, Default::default(), simulate)
}

pub(crate) async fn prepare_to_propose_to_update_elected_replica_versions(
version: &String,
rc_branch_name: &String,
) -> anyhow::Result<UpdateReplicaVersions> {
let image_path = format!("ic/{}/guest-os/update-img", version);
let download_dir = format!("{}/tmp/{}", std::env::var("HOME").unwrap(), image_path);
fn get_cdn_image_url(version: &String) -> String {
format!(
"https://download.dfinity.systems/ic/{}/guest-os/update-img/update-img.tar.gz",
version
)
}

fn get_github_release_image_url(release_tag: &String) -> String {
format!(
"https://github.com/dfinity/ic/releases/download/{}/update-os-img.tar.gz",
release_tag
)
}

async fn download_file_and_get_sha256(download_url: &String) -> anyhow::Result<String> {
let url = url::Url::parse(download_url)?;
let subdir = format!(
"{}{}",
url.domain().expect("url.domain() is None"),
url.path().to_owned()
);
// replace special characters in subdir with _
let subdir = subdir.replace(|c: char| !c.is_ascii_alphanumeric(), "_");
let download_dir = format!(
"{}/ic/{}",
dirs::download_dir().expect("download_dir is None").as_path().display(),
subdir
);
let download_dir = Path::new(&download_dir);

std::fs::create_dir_all(download_dir)
.unwrap_or_else(|_| panic!("create_dir_all failed for {}", download_dir.display()));

let update_url = format!("https://download.dfinity.systems/{}/update-img.tar.gz", image_path);
let download_image = format!("{}/update-img.tar.gz", download_dir.to_str().unwrap());
let download_image = Path::new(&download_image);

let response = reqwest::get(update_url.clone()).await?;
let response = reqwest::get(download_url.clone()).await?;

if response.status() != StatusCode::RANGE_NOT_SATISFIABLE && !response.status().is_success() {
return Err(anyhow::anyhow!(
"Download failed with http_code {} for {}",
response.status(),
update_url
download_url
));
}
info!("Download {} succeeded {}", update_url, response.status());
info!("Download {} succeeded {}", download_url, response.status());

let mut file = match File::create(download_image) {
Ok(file) => file,
Expand All @@ -354,7 +375,6 @@ impl Cli {
let content = response.bytes().await?;
file.write_all(&content)?;

info!("File created on location: {}", download_image.display());
let mut hasher = Sha256::new();
hasher.update(&content);
let hash = hasher.finalize();
Expand All @@ -363,9 +383,56 @@ impl Cli {
.map(|byte| format!("{:01$x?}", byte, 2))
.collect::<Vec<String>>()
.join("");
info!("SHA256 of update-img.tar.gz: {}", stringified_hash);
info!(
"File saved at {} has sha256 {}",
download_image.display(),
stringified_hash
);
Ok(stringified_hash)
}

pub(crate) async fn prepare_to_propose_to_update_elected_replica_versions(
version: &String,
release_tag: &String,
) -> anyhow::Result<UpdateReplicaVersions> {
let mut expected_hash = None;

let update_urls = vec![
Self::get_cdn_image_url(version),
Self::get_github_release_image_url(release_tag),
];
// Verify that both images have the same SHA256
for update_url in &update_urls {
let downloaded_hash: String = match Self::download_file_and_get_sha256(update_url).await {
Ok(hash) => hash,
Err(err) => {
warn!("Error downloading {}: {}", update_url, err);
continue;
}
};
match &expected_hash {
Some(stringified_hash) => {
// Compare the hash of the downloaded image with the hash of the first image
if &downloaded_hash != stringified_hash {
return Err(anyhow::anyhow!(
"The SHA256 {} of the image downloaded from {} does not match the SHA256 of the first image {}",
downloaded_hash,
update_url,
&stringified_hash
));
}
}
None => {
// This is the first image, so just set the hash
expected_hash = Some(downloaded_hash)
}
}
}
let expected_hash = expected_hash.expect("expected_hash is None");
info!("SHA256 of update-img.tar.gz: {}", expected_hash);

let template = format!(
r#"Elect new replica binary revision [{version}](https://github.com/dfinity/ic/tree/{rc_branch_name})
r#"Elect new replica binary revision [{version}](https://github.com/dfinity/ic/tree/{release_tag})
# Release Notes:
Expand Down Expand Up @@ -413,9 +480,9 @@ must be identical, and must match the SHA256 from the payload of the NNS proposa
))
} else {
Ok(UpdateReplicaVersions {
stringified_hash,
stringified_hash: expected_hash,
summary: edited,
update_url,
update_urls,
})
}
}
Expand All @@ -442,7 +509,7 @@ pub(crate) enum ProposeCommand {
},
UpdateElectedReplicaVersions {
version_to_bless: String,
update_url: String,
update_urls: Vec<String>,
stringified_hash: String,
versions_to_retire: Vec<String>,
},
Expand Down Expand Up @@ -501,18 +568,21 @@ impl ProposeCommand {
Self::RemoveNodes { nodes } => nodes.iter().map(|n| n.to_string()).collect(),
Self::UpdateElectedReplicaVersions {
version_to_bless,
update_url,
update_urls,
stringified_hash,
versions_to_retire,
} => vec![
vec![
"--replica-version-to-elect".to_string(),
version_to_bless.to_string(),
"--release-package-sha256-hex".to_string(),
stringified_hash.to_string(),
"--release-package-urls".to_string(),
update_url.to_string(),
],
[
vec![
"--replica-version-to-elect".to_string(),
version_to_bless.to_string(),
"--release-package-sha256-hex".to_string(),
stringified_hash.to_string(),
"--release-package-urls".to_string(),
],
update_urls.clone(),
]
.concat(),
if !versions_to_retire.is_empty() {
vec![
vec!["--replica-versions-to-unelect".to_string()],
Expand Down
6 changes: 3 additions & 3 deletions rs/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,11 @@ async fn main() -> Result<(), anyhow::Error> {

cli::Commands::Version(cmd) => {
match &cmd.subcommand {
Update { version, rc_branch_name } => {
Update { version, release_tag} => {
let runner = runner::Runner::from_opts(&cli_opts).await?;
let (_, retire_versions) = runner.prepare_versions_to_retire(false).await?;
let ic_admin = ic_admin::Cli::from_opts(&cli_opts, true).await?;
let new_replica_info = ic_admin::Cli::prepare_to_propose_to_update_elected_replica_versions(version, rc_branch_name).await?;
let new_replica_info = ic_admin::Cli::prepare_to_propose_to_update_elected_replica_versions(version, release_tag).await?;
let proposal_title = if retire_versions.is_empty() {
Some(format!("Elect new IC/Replica revision (commit {})", &version[..8]))
} else {
Expand All @@ -185,7 +185,7 @@ async fn main() -> Result<(), anyhow::Error> {

ic_admin.propose_run(ic_admin::ProposeCommand::UpdateElectedReplicaVersions{
version_to_bless: version.to_string(),
update_url: new_replica_info.update_url,
update_urls: new_replica_info.update_urls,
stringified_hash: new_replica_info.stringified_hash,
versions_to_retire: retire_versions.clone(),
}, ic_admin::ProposeOptions{
Expand Down
2 changes: 1 addition & 1 deletion rs/ic-management-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,6 @@ impl Network {
#[derive(Clone)]
pub struct UpdateReplicaVersions {
pub summary: String,
pub update_url: String,
pub update_urls: Vec<String>,
pub stringified_hash: String,
}

0 comments on commit 4ab357a

Please sign in to comment.