diff --git a/.github/workflows/qualify.yaml b/.github/workflows/qualify.yaml index cb36c13d3..5cc9d7700 100644 --- a/.github/workflows/qualify.yaml +++ b/.github/workflows/qualify.yaml @@ -8,9 +8,11 @@ on: description: "The version that should be qualified" type: string default: "" - +# Run one qualification per commit. +# This means we can have multiple qualifications of different versions +# in parallel but only one qualification of each commit concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.inputs.version || github.ref }} cancel-in-progress: true jobs: diff --git a/Cargo.Bazel.lock b/Cargo.Bazel.lock index aa6471ad1..71f237105 100644 --- a/Cargo.Bazel.lock +++ b/Cargo.Bazel.lock @@ -1,5 +1,5 @@ { - "checksum": "b5ed4499566048c78d1e0b4364d3692e3034477684f320e4461e4c2df1ba0a43", + "checksum": "5ec4fcee4c14e7594d0a1fb9642aa461e4bf174f5045552c66d4a39051d2de00", "crates": { "actix-codec 0.5.2": { "name": "actix-codec", @@ -906,6 +906,56 @@ }, "license": "Zlib" }, + "aes 0.8.4": { + "name": "aes", + "version": "0.8.4", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/aes/0.8.4/download", + "sha256": "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" + } + }, + "targets": [ + { + "Library": { + "crate_name": "aes", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "aes", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "cipher 0.4.4", + "target": "cipher" + } + ], + "selects": { + "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))": [ + { + "id": "cpufeatures 0.2.12", + "target": "cpufeatures" + } + ] + } + }, + "edition": "2021", + "version": "0.8.4" + }, + "license": "MIT OR Apache-2.0" + }, "ahash 0.7.8": { "name": "ahash", "version": "0.7.8", @@ -1526,6 +1576,45 @@ }, "license": "MIT OR Apache-2.0" }, + "arbitrary 1.3.2": { + "name": "arbitrary", + "version": "1.3.2", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/arbitrary/1.3.2/download", + "sha256": "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + } + }, + "targets": [ + { + "Library": { + "crate_name": "arbitrary", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "arbitrary", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "derive_arbitrary 1.3.2", + "target": "derive_arbitrary" + } + ], + "selects": {} + }, + "version": "1.3.2" + }, + "license": "MIT OR Apache-2.0" + }, "arc-swap 1.7.1": { "name": "arc-swap", "version": "1.7.1", @@ -2270,49 +2359,19 @@ }, "license": "MIT" }, - "autocfg 1.3.0": { - "name": "autocfg", - "version": "1.3.0", - "repository": { - "Http": { - "url": "https://static.crates.io/crates/autocfg/1.3.0/download", - "sha256": "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - } - }, - "targets": [ - { - "Library": { - "crate_name": "autocfg", - "crate_root": "src/lib.rs", - "srcs": [ - "**/*.rs" - ] - } - } - ], - "library_target_name": "autocfg", - "common_attrs": { - "compile_data_glob": [ - "**" - ], - "edition": "2015", - "version": "1.3.0" - }, - "license": "Apache-2.0 OR MIT" - }, - "axum 0.6.20": { - "name": "axum", - "version": "0.6.20", + "auto_generate_cdp 0.4.4": { + "name": "auto_generate_cdp", + "version": "0.4.4", "repository": { "Http": { - "url": "https://static.crates.io/crates/axum/0.6.20/download", - "sha256": "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" + "url": "https://static.crates.io/crates/auto_generate_cdp/0.4.4/download", + "sha256": "7af08ed49930c50104b2f1699d257e5053fb1809e370647bde9c58b31d65d417" } }, "targets": [ { "Library": { - "crate_name": "axum", + "crate_name": "auto_generate_cdp", "crate_root": "src/lib.rs", "srcs": [ "**/*.rs" @@ -2329,7 +2388,7 @@ } } ], - "library_target_name": "axum", + "library_target_name": "auto_generate_cdp", "common_attrs": { "compile_data_glob": [ "**" @@ -2337,119 +2396,83 @@ "deps": { "common": [ { - "id": "axum 0.6.20", + "id": "auto_generate_cdp 0.4.4", "target": "build_script_build" }, { - "id": "axum-core 0.3.4", - "target": "axum_core" - }, - { - "id": "bitflags 1.3.2", - "target": "bitflags" - }, - { - "id": "bytes 1.7.1", - "target": "bytes" - }, - { - "id": "futures-util 0.3.30", - "target": "futures_util" - }, - { - "id": "http 0.2.12", - "target": "http" - }, - { - "id": "http-body 0.4.6", - "target": "http_body" - }, - { - "id": "hyper 0.14.30", - "target": "hyper" - }, - { - "id": "itoa 1.0.11", - "target": "itoa" - }, - { - "id": "matchit 0.7.3", - "target": "matchit" - }, - { - "id": "memchr 2.7.4", - "target": "memchr" - }, - { - "id": "mime 0.3.17", - "target": "mime" + "id": "convert_case 0.4.0", + "target": "convert_case" }, { - "id": "percent-encoding 2.3.1", - "target": "percent_encoding" + "id": "proc-macro2 1.0.86", + "target": "proc_macro2" }, { - "id": "pin-project-lite 0.2.14", - "target": "pin_project_lite" + "id": "quote 1.0.36", + "target": "quote" }, { "id": "serde 1.0.206", "target": "serde" }, { - "id": "sync_wrapper 0.1.2", - "target": "sync_wrapper" - }, - { - "id": "tower 0.4.13", - "target": "tower" - }, - { - "id": "tower-layer 0.3.2", - "target": "tower_layer" + "id": "serde_json 1.0.124", + "target": "serde_json" }, { - "id": "tower-service 0.3.2", - "target": "tower_service" + "id": "ureq 2.10.1", + "target": "ureq" } ], "selects": {} }, - "edition": "2021", - "proc_macro_deps": { - "common": [ - { - "id": "async-trait 0.1.81", - "target": "async_trait" - } - ], - "selects": {} - }, - "version": "0.6.20" + "edition": "2018", + "version": "0.4.4" }, "build_script_attrs": { "data_glob": [ "**" - ], - "proc_macro_deps": { - "common": [ - { - "id": "rustversion 1.0.17", - "target": "rustversion" - } - ], - "selects": {} + ] + }, + "license": null + }, + "autocfg 1.3.0": { + "name": "autocfg", + "version": "1.3.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/autocfg/1.3.0/download", + "sha256": "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" } }, - "license": "MIT" + "targets": [ + { + "Library": { + "crate_name": "autocfg", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "autocfg", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "1.3.0" + }, + "license": "Apache-2.0 OR MIT" }, - "axum 0.7.5": { + "axum 0.6.20": { "name": "axum", - "version": "0.7.5", + "version": "0.6.20", "repository": { "Http": { - "url": "https://static.crates.io/crates/axum/0.7.5/download", - "sha256": "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" + "url": "https://static.crates.io/crates/axum/0.6.20/download", + "sha256": "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" } }, "targets": [ @@ -2477,31 +2500,20 @@ "compile_data_glob": [ "**" ], - "crate_features": { - "common": [ - "default", - "form", - "http1", - "json", - "matched-path", - "original-uri", - "query", - "tokio", - "tower-log", - "tracing" - ], - "selects": {} - }, "deps": { "common": [ { - "id": "axum 0.7.5", + "id": "axum 0.6.20", "target": "build_script_build" }, { - "id": "axum-core 0.4.3", + "id": "axum-core 0.3.4", "target": "axum_core" }, + { + "id": "bitflags 1.3.2", + "target": "bitflags" + }, { "id": "bytes 1.7.1", "target": "bytes" @@ -2511,25 +2523,179 @@ "target": "futures_util" }, { - "id": "http 1.1.0", + "id": "http 0.2.12", "target": "http" }, { - "id": "http-body 1.0.1", + "id": "http-body 0.4.6", "target": "http_body" }, { - "id": "http-body-util 0.1.2", - "target": "http_body_util" - }, - { - "id": "hyper 1.4.1", + "id": "hyper 0.14.30", "target": "hyper" }, - { - "id": "hyper-util 0.1.7", - "target": "hyper_util" - }, + { + "id": "itoa 1.0.11", + "target": "itoa" + }, + { + "id": "matchit 0.7.3", + "target": "matchit" + }, + { + "id": "memchr 2.7.4", + "target": "memchr" + }, + { + "id": "mime 0.3.17", + "target": "mime" + }, + { + "id": "percent-encoding 2.3.1", + "target": "percent_encoding" + }, + { + "id": "pin-project-lite 0.2.14", + "target": "pin_project_lite" + }, + { + "id": "serde 1.0.206", + "target": "serde" + }, + { + "id": "sync_wrapper 0.1.2", + "target": "sync_wrapper" + }, + { + "id": "tower 0.4.13", + "target": "tower" + }, + { + "id": "tower-layer 0.3.2", + "target": "tower_layer" + }, + { + "id": "tower-service 0.3.2", + "target": "tower_service" + } + ], + "selects": {} + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "async-trait 0.1.81", + "target": "async_trait" + } + ], + "selects": {} + }, + "version": "0.6.20" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "proc_macro_deps": { + "common": [ + { + "id": "rustversion 1.0.17", + "target": "rustversion" + } + ], + "selects": {} + } + }, + "license": "MIT" + }, + "axum 0.7.5": { + "name": "axum", + "version": "0.7.5", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/axum/0.7.5/download", + "sha256": "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" + } + }, + "targets": [ + { + "Library": { + "crate_name": "axum", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "axum", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "form", + "http1", + "json", + "matched-path", + "original-uri", + "query", + "tokio", + "tower-log", + "tracing" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "axum 0.7.5", + "target": "build_script_build" + }, + { + "id": "axum-core 0.4.3", + "target": "axum_core" + }, + { + "id": "bytes 1.7.1", + "target": "bytes" + }, + { + "id": "futures-util 0.3.30", + "target": "futures_util" + }, + { + "id": "http 1.1.0", + "target": "http" + }, + { + "id": "http-body 1.0.1", + "target": "http_body" + }, + { + "id": "http-body-util 0.1.2", + "target": "http_body_util" + }, + { + "id": "hyper 1.4.1", + "target": "hyper" + }, + { + "id": "hyper-util 0.1.7", + "target": "hyper_util" + }, { "id": "itoa 1.0.11", "target": "itoa" @@ -4627,6 +4793,120 @@ }, "license": "MIT OR Apache-2.0" }, + "bzip2 0.4.4": { + "name": "bzip2", + "version": "0.4.4", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/bzip2/0.4.4/download", + "sha256": "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" + } + }, + "targets": [ + { + "Library": { + "crate_name": "bzip2", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "bzip2", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "bzip2-sys 0.1.11+1.0.8", + "target": "bzip2_sys" + }, + { + "id": "libc 0.2.155", + "target": "libc" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "0.4.4" + }, + "license": "MIT/Apache-2.0" + }, + "bzip2-sys 0.1.11+1.0.8": { + "name": "bzip2-sys", + "version": "0.1.11+1.0.8", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/bzip2-sys/0.1.11+1.0.8/download", + "sha256": "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" + } + }, + "targets": [ + { + "Library": { + "crate_name": "bzip2_sys", + "crate_root": "lib.rs", + "srcs": [ + "**/*.rs" + ] + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "bzip2_sys", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "bzip2-sys 0.1.11+1.0.8", + "target": "build_script_build" + }, + { + "id": "libc 0.2.155", + "target": "libc" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "0.1.11+1.0.8" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cc 1.1.8", + "target": "cc" + }, + { + "id": "pkg-config 0.3.30", + "target": "pkg_config" + } + ], + "selects": {} + }, + "links": "bzip2" + }, + "license": "MIT/Apache-2.0" + }, "cached 0.49.3": { "name": "cached", "version": "0.49.3", @@ -5152,6 +5432,28 @@ "compile_data_glob": [ "**" ], + "crate_features": { + "common": [ + "parallel" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "jobserver 0.1.32", + "target": "jobserver" + } + ], + "selects": { + "cfg(unix)": [ + { + "id": "libc 0.2.155", + "target": "libc" + } + ] + } + }, "edition": "2018", "version": "1.1.8" }, @@ -5442,6 +5744,49 @@ }, "license": "Apache-2.0" }, + "cipher 0.4.4": { + "name": "cipher", + "version": "0.4.4", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/cipher/0.4.4/download", + "sha256": "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" + } + }, + "targets": [ + { + "Library": { + "crate_name": "cipher", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "cipher", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "crypto-common 0.1.6", + "target": "crypto_common" + }, + { + "id": "inout 0.1.3", + "target": "inout" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.4.4" + }, + "license": "MIT OR Apache-2.0" + }, "clap 3.2.25": { "name": "clap", "version": "3.2.25", @@ -6460,6 +6805,36 @@ }, "license": "Apache-2.0 OR MIT" }, + "constant_time_eq 0.3.0": { + "name": "constant_time_eq", + "version": "0.3.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/constant_time_eq/0.3.0/download", + "sha256": "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + } + }, + "targets": [ + { + "Library": { + "crate_name": "constant_time_eq", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "constant_time_eq", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "0.3.0" + }, + "license": "CC0-1.0 OR MIT-0 OR Apache-2.0" + }, "convert_case 0.4.0": { "name": "convert_case", "version": "0.4.0", @@ -6721,6 +7096,75 @@ }, "license": "MIT OR Apache-2.0" }, + "crc 3.2.1": { + "name": "crc", + "version": "3.2.1", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/crc/3.2.1/download", + "sha256": "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" + } + }, + "targets": [ + { + "Library": { + "crate_name": "crc", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "crc", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "crc-catalog 2.4.0", + "target": "crc_catalog" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "3.2.1" + }, + "license": "MIT OR Apache-2.0" + }, + "crc-catalog 2.4.0": { + "name": "crc-catalog", + "version": "2.4.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/crc-catalog/2.4.0/download", + "sha256": "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + } + }, + "targets": [ + { + "Library": { + "crate_name": "crc_catalog", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "crc_catalog", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "2.4.0" + }, + "license": "MIT OR Apache-2.0" + }, "crc32fast 1.4.2": { "name": "crc32fast", "version": "1.4.2", @@ -7059,7 +7503,26 @@ "common": [ "std" ], - "selects": {} + "selects": { + "arm-unknown-linux-gnueabi": [ + "default" + ], + "armv7-linux-androideabi": [ + "default" + ], + "armv7-unknown-linux-gnueabi": [ + "default" + ], + "powerpc-unknown-linux-gnu": [ + "default" + ], + "thumbv7em-none-eabi": [ + "default" + ], + "thumbv8m.main-none-eabi": [ + "default" + ] + } }, "deps": { "common": [ @@ -8130,6 +8593,61 @@ }, "license": "MIT" }, + "darling 0.20.10": { + "name": "darling", + "version": "0.20.10", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/darling/0.20.10/download", + "sha256": "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" + } + }, + "targets": [ + { + "Library": { + "crate_name": "darling", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "darling", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "suggestions" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "darling_core 0.20.10", + "target": "darling_core" + } + ], + "selects": {} + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "darling_macro 0.20.10", + "target": "darling_macro" + } + ], + "selects": {} + }, + "version": "0.20.10" + }, + "license": "MIT" + }, "darling_core 0.13.4": { "name": "darling_core", "version": "0.13.4", @@ -8196,6 +8714,72 @@ }, "license": "MIT" }, + "darling_core 0.20.10": { + "name": "darling_core", + "version": "0.20.10", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/darling_core/0.20.10/download", + "sha256": "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" + } + }, + "targets": [ + { + "Library": { + "crate_name": "darling_core", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "darling_core", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "strsim", + "suggestions" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "fnv 1.0.7", + "target": "fnv" + }, + { + "id": "ident_case 1.0.1", + "target": "ident_case" + }, + { + "id": "proc-macro2 1.0.86", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.36", + "target": "quote" + }, + { + "id": "strsim 0.11.1", + "target": "strsim" + }, + { + "id": "syn 2.0.72", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.20.10" + }, + "license": "MIT" + }, "darling_macro 0.13.4": { "name": "darling_macro", "version": "0.13.4", @@ -8243,6 +8827,53 @@ }, "license": "MIT" }, + "darling_macro 0.20.10": { + "name": "darling_macro", + "version": "0.20.10", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/darling_macro/0.20.10/download", + "sha256": "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "darling_macro", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "darling_macro", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "darling_core 0.20.10", + "target": "darling_core" + }, + { + "id": "quote 1.0.36", + "target": "quote" + }, + { + "id": "syn 2.0.72", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.20.10" + }, + "license": "MIT" + }, "dary_heap 0.3.6": { "name": "dary_heap", "version": "0.3.6", @@ -8510,6 +9141,36 @@ }, "license": null }, + "deflate64 0.1.9": { + "name": "deflate64", + "version": "0.1.9", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/deflate64/0.1.9/download", + "sha256": "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + } + }, + "targets": [ + { + "Library": { + "crate_name": "deflate64", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "deflate64", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "0.1.9" + }, + "license": "MIT" + }, "der 0.7.9": { "name": "der", "version": "0.7.9", @@ -8739,6 +9400,205 @@ }, "license": "MIT/Apache-2.0" }, + "derive_arbitrary 1.3.2": { + "name": "derive_arbitrary", + "version": "1.3.2", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/derive_arbitrary/1.3.2/download", + "sha256": "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "derive_arbitrary", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "derive_arbitrary", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.86", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.36", + "target": "quote" + }, + { + "id": "syn 2.0.72", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.3.2" + }, + "license": "MIT/Apache-2.0" + }, + "derive_builder 0.20.0": { + "name": "derive_builder", + "version": "0.20.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/derive_builder/0.20.0/download", + "sha256": "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" + } + }, + "targets": [ + { + "Library": { + "crate_name": "derive_builder", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "derive_builder", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "edition": "2018", + "proc_macro_deps": { + "common": [ + { + "id": "derive_builder_macro 0.20.0", + "target": "derive_builder_macro" + } + ], + "selects": {} + }, + "version": "0.20.0" + }, + "license": "MIT OR Apache-2.0" + }, + "derive_builder_core 0.20.0": { + "name": "derive_builder_core", + "version": "0.20.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/derive_builder_core/0.20.0/download", + "sha256": "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "derive_builder_core", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "derive_builder_core", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "lib_has_std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "darling 0.20.10", + "target": "darling" + }, + { + "id": "proc-macro2 1.0.86", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.36", + "target": "quote" + }, + { + "id": "syn 2.0.72", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.20.0" + }, + "license": "MIT OR Apache-2.0" + }, + "derive_builder_macro 0.20.0": { + "name": "derive_builder_macro", + "version": "0.20.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/derive_builder_macro/0.20.0/download", + "sha256": "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "derive_builder_macro", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "derive_builder_macro", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "lib_has_std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "derive_builder_core 0.20.0", + "target": "derive_builder_core" + }, + { + "id": "syn 2.0.72", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.20.0" + }, + "license": "MIT OR Apache-2.0" + }, "derive_more 0.99.18": { "name": "derive_more", "version": "0.99.18", @@ -9323,6 +10183,45 @@ }, "license": "MIT OR Apache-2.0" }, + "directories 5.0.1": { + "name": "directories", + "version": "5.0.1", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/directories/5.0.1/download", + "sha256": "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" + } + }, + "targets": [ + { + "Library": { + "crate_name": "directories", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "directories", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "dirs-sys 0.4.1", + "target": "dirs_sys" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "5.0.1" + }, + "license": "MIT OR Apache-2.0" + }, "dirs 5.0.1": { "name": "dirs", "version": "5.0.1", @@ -9805,6 +10704,10 @@ "id": "futures-util 0.3.30", "target": "futures_util" }, + { + "id": "headless_chrome 1.0.12", + "target": "headless_chrome" + }, { "id": "human_bytes 0.4.3", "target": "human_bytes" @@ -13139,6 +14042,165 @@ }, "license": "MIT/Apache-2.0" }, + "headless_chrome 1.0.12": { + "name": "headless_chrome", + "version": "1.0.12", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/headless_chrome/1.0.12/download", + "sha256": "f50752288ae8799c84ed7fc6616611b7493c53d92265198b8a607c7e4256ebd2" + } + }, + "targets": [ + { + "Library": { + "crate_name": "headless_chrome", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "headless_chrome", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "directories", + "fetch", + "ureq", + "walkdir", + "zip" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "anyhow 1.0.86", + "target": "anyhow" + }, + { + "id": "base64 0.22.1", + "target": "base64" + }, + { + "id": "derive_builder 0.20.0", + "target": "derive_builder" + }, + { + "id": "directories 5.0.1", + "target": "directories" + }, + { + "id": "headless_chrome 1.0.12", + "target": "build_script_build" + }, + { + "id": "log 0.4.22", + "target": "log" + }, + { + "id": "rand 0.8.5", + "target": "rand" + }, + { + "id": "regex 1.10.6", + "target": "regex" + }, + { + "id": "serde 1.0.206", + "target": "serde" + }, + { + "id": "serde_json 1.0.124", + "target": "serde_json" + }, + { + "id": "tempfile 3.12.0", + "target": "tempfile" + }, + { + "id": "thiserror 1.0.63", + "target": "thiserror" + }, + { + "id": "tungstenite 0.23.0", + "target": "tungstenite" + }, + { + "id": "ureq 2.10.1", + "target": "ureq" + }, + { + "id": "url 2.5.2", + "target": "url" + }, + { + "id": "walkdir 2.5.0", + "target": "walkdir" + }, + { + "id": "which 6.0.2", + "target": "which" + }, + { + "id": "zip 2.1.3", + "target": "zip" + } + ], + "selects": { + "cfg(windows)": [ + { + "id": "winreg 0.52.0", + "target": "winreg" + } + ] + } + }, + "edition": "2021", + "rustc_env": { + "common": { + "DO_NOT_FORMAT": "1" + }, + "selects": {} + }, + "version": "1.0.12" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "auto_generate_cdp 0.4.4", + "target": "auto_generate_cdp" + } + ], + "selects": {} + }, + "build_script_env": { + "common": { + "DO_NOT_FORMAT": "1" + }, + "selects": {} + } + }, + "license": "MIT" + }, "heck 0.3.3": { "name": "heck", "version": "0.3.3", @@ -25485,6 +26547,45 @@ }, "license": "MIT" }, + "inout 0.1.3": { + "name": "inout", + "version": "0.1.3", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/inout/0.1.3/download", + "sha256": "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" + } + }, + "targets": [ + { + "Library": { + "crate_name": "inout", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "inout", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "generic-array 0.14.7", + "target": "generic_array" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.1.3" + }, + "license": "MIT OR Apache-2.0" + }, "instant 0.1.13": { "name": "instant", "version": "0.1.13", @@ -25855,6 +26956,47 @@ }, "license": "MIT OR Apache-2.0" }, + "jobserver 0.1.32": { + "name": "jobserver", + "version": "0.1.32", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/jobserver/0.1.32/download", + "sha256": "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" + } + }, + "targets": [ + { + "Library": { + "crate_name": "jobserver", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "jobserver", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], + "selects": { + "cfg(unix)": [ + { + "id": "libc 0.2.155", + "target": "libc" + } + ] + } + }, + "edition": "2021", + "version": "0.1.32" + }, + "license": "MIT OR Apache-2.0" + }, "js-sys 0.3.69": { "name": "js-sys", "version": "0.3.69", @@ -26990,6 +28132,36 @@ }, "license": "MIT OR Apache-2.0" }, + "lockfree-object-pool 0.1.6": { + "name": "lockfree-object-pool", + "version": "0.1.6", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/lockfree-object-pool/0.1.6/download", + "sha256": "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" + } + }, + "targets": [ + { + "Library": { + "crate_name": "lockfree_object_pool", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "lockfree_object_pool", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "0.1.6" + }, + "license": "BSL-1.0" + }, "log 0.4.22": { "name": "log", "version": "0.4.22", @@ -27208,6 +28380,55 @@ }, "license": null }, + "lzma-rs 0.3.0": { + "name": "lzma-rs", + "version": "0.3.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/lzma-rs/0.3.0/download", + "sha256": "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" + } + }, + "targets": [ + { + "Library": { + "crate_name": "lzma_rs", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "lzma_rs", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "stream" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "byteorder 1.5.0", + "target": "byteorder" + }, + { + "id": "crc 3.2.1", + "target": "crc" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.3.0" + }, + "license": "MIT" + }, "lzma-sys 0.1.20": { "name": "lzma-sys", "version": "0.1.20", @@ -30681,6 +31902,56 @@ }, "license": "MIT OR Apache-2.0" }, + "pbkdf2 0.12.2": { + "name": "pbkdf2", + "version": "0.12.2", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/pbkdf2/0.12.2/download", + "sha256": "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" + } + }, + "targets": [ + { + "Library": { + "crate_name": "pbkdf2", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "pbkdf2", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "hmac" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "digest 0.10.7", + "target": "digest" + }, + { + "id": "hmac 0.12.1", + "target": "hmac" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.12.2" + }, + "license": "MIT OR Apache-2.0" + }, "pem 1.1.1": { "name": "pem", "version": "1.1.1", @@ -36042,6 +37313,8 @@ ], "crate_features": { "common": [ + "log", + "logging", "ring", "std", "tls12" @@ -36050,6 +37323,10 @@ }, "deps": { "common": [ + { + "id": "log 0.4.22", + "target": "log" + }, { "id": "once_cell 1.19.0", "target": "once_cell" @@ -36628,6 +37905,47 @@ }, "license": "Apache-2.0 OR BSL-1.0" }, + "same-file 1.0.6": { + "name": "same-file", + "version": "1.0.6", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/same-file/1.0.6/download", + "sha256": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" + } + }, + "targets": [ + { + "Library": { + "crate_name": "same_file", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "same_file", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], + "selects": { + "cfg(windows)": [ + { + "id": "winapi-util 0.1.9", + "target": "winapi_util" + } + ] + } + }, + "edition": "2018", + "version": "1.0.6" + }, + "license": "Unlicense/MIT" + }, "schannel 0.1.23": { "name": "schannel", "version": "0.1.23", @@ -38498,6 +39816,42 @@ }, "license": "Apache-2.0 OR MIT" }, + "simd-adler32 0.3.7": { + "name": "simd-adler32", + "version": "0.3.7", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/simd-adler32/0.3.7/download", + "sha256": "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + } + }, + "targets": [ + { + "Library": { + "crate_name": "simd_adler32", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "simd_adler32", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "edition": "2018", + "version": "0.3.7" + }, + "license": "MIT" + }, "simdutf8 0.1.4": { "name": "simdutf8", "version": "0.1.4", @@ -39403,6 +40757,58 @@ }, "license": "MIT OR Apache-2.0" }, + "socks 0.3.4": { + "name": "socks", + "version": "0.3.4", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/socks/0.3.4/download", + "sha256": "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" + } + }, + "targets": [ + { + "Library": { + "crate_name": "socks", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "socks", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "byteorder 1.5.0", + "target": "byteorder" + } + ], + "selects": { + "cfg(unix)": [ + { + "id": "libc 0.2.155", + "target": "libc" + } + ], + "cfg(windows)": [ + { + "id": "winapi 0.3.9", + "target": "winapi" + } + ] + } + }, + "edition": "2015", + "version": "0.3.4" + }, + "license": "MIT/Apache-2.0" + }, "spin 0.9.8": { "name": "spin", "version": "0.9.8", @@ -43023,6 +44429,92 @@ }, "license": "MIT" }, + "tungstenite 0.23.0": { + "name": "tungstenite", + "version": "0.23.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/tungstenite/0.23.0/download", + "sha256": "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" + } + }, + "targets": [ + { + "Library": { + "crate_name": "tungstenite", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "tungstenite", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "data-encoding", + "default", + "handshake", + "http", + "httparse", + "sha1" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "byteorder 1.5.0", + "target": "byteorder" + }, + { + "id": "bytes 1.7.1", + "target": "bytes" + }, + { + "id": "data-encoding 2.6.0", + "target": "data_encoding" + }, + { + "id": "http 1.1.0", + "target": "http" + }, + { + "id": "httparse 1.9.4", + "target": "httparse" + }, + { + "id": "log 0.4.22", + "target": "log" + }, + { + "id": "rand 0.8.5", + "target": "rand" + }, + { + "id": "sha1 0.10.6", + "target": "sha1" + }, + { + "id": "thiserror 1.0.63", + "target": "thiserror" + }, + { + "id": "utf-8 0.7.6", + "target": "utf8" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.23.0" + }, + "license": "MIT OR Apache-2.0" + }, "typed-arena 2.0.2": { "name": "typed-arena", "version": "2.0.2", @@ -43417,6 +44909,87 @@ }, "license": "ISC" }, + "ureq 2.10.1": { + "name": "ureq", + "version": "2.10.1", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ureq/2.10.1/download", + "sha256": "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ureq", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "ureq", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "gzip", + "proxy-from-env", + "socks-proxy", + "tls" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "base64 0.22.1", + "target": "base64" + }, + { + "id": "flate2 1.0.31", + "target": "flate2" + }, + { + "id": "log 0.4.22", + "target": "log" + }, + { + "id": "once_cell 1.19.0", + "target": "once_cell" + }, + { + "id": "rustls 0.23.12", + "target": "rustls" + }, + { + "id": "rustls-pki-types 1.8.0", + "target": "rustls_pki_types" + }, + { + "id": "socks 0.3.4", + "target": "socks" + }, + { + "id": "url 2.5.2", + "target": "url" + }, + { + "id": "webpki-roots 0.26.3", + "target": "webpki_roots" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "2.10.1" + }, + "license": "MIT OR Apache-2.0" + }, "url 2.5.2": { "name": "url", "version": "2.5.2", @@ -43505,6 +45078,36 @@ }, "license": "MIT" }, + "utf-8 0.7.6": { + "name": "utf-8", + "version": "0.7.6", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/utf-8/0.7.6/download", + "sha256": "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + } + }, + "targets": [ + { + "Library": { + "crate_name": "utf8", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "utf8", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "0.7.6" + }, + "license": "MIT OR Apache-2.0" + }, "utf8-width 0.1.7": { "name": "utf8-width", "version": "0.1.7", @@ -43778,6 +45381,52 @@ }, "license": "MIT/Apache-2.0" }, + "walkdir 2.5.0": { + "name": "walkdir", + "version": "2.5.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/walkdir/2.5.0/download", + "sha256": "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" + } + }, + "targets": [ + { + "Library": { + "crate_name": "walkdir", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "walkdir", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "same-file 1.0.6", + "target": "same_file" + } + ], + "selects": { + "cfg(windows)": [ + { + "id": "winapi-util 0.1.9", + "target": "winapi_util" + } + ] + } + }, + "edition": "2018", + "version": "2.5.0" + }, + "license": "Unlicense/MIT" + }, "walrus 0.20.3": { "name": "walrus", "version": "0.20.3", @@ -44643,6 +46292,64 @@ }, "license": "MIT" }, + "which 6.0.2": { + "name": "which", + "version": "6.0.2", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/which/6.0.2/download", + "sha256": "3d9c5ed668ee1f17edb3b627225343d210006a90bb1e3745ce1f30b1fb115075" + } + }, + "targets": [ + { + "Library": { + "crate_name": "which", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "which", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "either 1.13.0", + "target": "either" + } + ], + "selects": { + "cfg(any(unix, target_os = \"wasi\", target_os = \"redox\"))": [ + { + "id": "rustix 0.38.34", + "target": "rustix" + } + ], + "cfg(any(windows, unix, target_os = \"redox\"))": [ + { + "id": "home 0.5.9", + "target": "home" + } + ], + "cfg(windows)": [ + { + "id": "winsafe 0.0.19", + "target": "winsafe" + } + ] + } + }, + "edition": "2021", + "version": "6.0.2" + }, + "license": "MIT" + }, "winapi 0.3.9": { "name": "winapi", "version": "0.3.9", @@ -46144,6 +47851,42 @@ }, "license": "MIT" }, + "winsafe 0.0.19": { + "name": "winsafe", + "version": "0.0.19", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/winsafe/0.0.19/download", + "sha256": "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + } + }, + "targets": [ + { + "Library": { + "crate_name": "winsafe", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "winsafe", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "kernel" + ], + "selects": {} + }, + "edition": "2021", + "version": "0.0.19" + }, + "license": "MIT" + }, "wiremock 0.6.1": { "name": "wiremock", "version": "0.6.1", @@ -46721,6 +48464,179 @@ }, "license": "Apache-2.0 OR MIT" }, + "zip 2.1.3": { + "name": "zip", + "version": "2.1.3", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/zip/2.1.3/download", + "sha256": "775a2b471036342aa69bc5a602bc889cb0a06cda00477d0c69566757d5553d39" + } + }, + "targets": [ + { + "Library": { + "crate_name": "zip", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "src/build.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "zip", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "_deflate-any", + "aes", + "aes-crypto", + "bzip2", + "constant_time_eq", + "default", + "deflate", + "deflate-flate2", + "deflate-zopfli", + "deflate64", + "flate2", + "hmac", + "lzma", + "lzma-rs", + "pbkdf2", + "rand", + "sha1", + "time", + "zeroize", + "zopfli", + "zstd" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "aes 0.8.4", + "target": "aes" + }, + { + "id": "bzip2 0.4.4", + "target": "bzip2" + }, + { + "id": "constant_time_eq 0.3.0", + "target": "constant_time_eq" + }, + { + "id": "crc32fast 1.4.2", + "target": "crc32fast" + }, + { + "id": "deflate64 0.1.9", + "target": "deflate64" + }, + { + "id": "flate2 1.0.31", + "target": "flate2" + }, + { + "id": "hmac 0.12.1", + "target": "hmac" + }, + { + "id": "indexmap 2.3.0", + "target": "indexmap" + }, + { + "id": "lzma-rs 0.3.0", + "target": "lzma_rs" + }, + { + "id": "memchr 2.7.4", + "target": "memchr" + }, + { + "id": "pbkdf2 0.12.2", + "target": "pbkdf2" + }, + { + "id": "rand 0.8.5", + "target": "rand" + }, + { + "id": "sha1 0.10.6", + "target": "sha1" + }, + { + "id": "thiserror 1.0.63", + "target": "thiserror" + }, + { + "id": "time 0.3.36", + "target": "time" + }, + { + "id": "zeroize 1.8.1", + "target": "zeroize" + }, + { + "id": "zip 2.1.3", + "target": "build_script_build" + }, + { + "id": "zopfli 0.8.1", + "target": "zopfli" + }, + { + "id": "zstd 0.13.2", + "target": "zstd" + } + ], + "selects": { + "cfg(any(all(target_arch = \"arm\", target_pointer_width = \"32\"), target_arch = \"mips\", target_arch = \"powerpc\"))": [ + { + "id": "crossbeam-utils 0.8.20", + "target": "crossbeam_utils" + } + ], + "cfg(fuzzing)": [ + { + "id": "arbitrary 1.3.2", + "target": "arbitrary" + } + ] + } + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "displaydoc 0.2.5", + "target": "displaydoc" + } + ], + "selects": {} + }, + "version": "2.1.3" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT" + }, "zipsign-api 0.1.2": { "name": "zipsign-api", "version": "0.1.2", @@ -46767,6 +48683,258 @@ "version": "0.1.2" }, "license": "Apache-2.0 WITH LLVM-exception" + }, + "zopfli 0.8.1": { + "name": "zopfli", + "version": "0.8.1", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/zopfli/0.8.1/download", + "sha256": "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" + } + }, + "targets": [ + { + "Library": { + "crate_name": "zopfli", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "zopfli", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "gzip", + "std", + "zlib" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "bumpalo 3.16.0", + "target": "bumpalo" + }, + { + "id": "crc32fast 1.4.2", + "target": "crc32fast" + }, + { + "id": "lockfree-object-pool 0.1.6", + "target": "lockfree_object_pool" + }, + { + "id": "log 0.4.22", + "target": "log" + }, + { + "id": "once_cell 1.19.0", + "target": "once_cell" + }, + { + "id": "simd-adler32 0.3.7", + "target": "simd_adler32" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.8.1" + }, + "license": "Apache-2.0" + }, + "zstd 0.13.2": { + "name": "zstd", + "version": "0.13.2", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/zstd/0.13.2/download", + "sha256": "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" + } + }, + "targets": [ + { + "Library": { + "crate_name": "zstd", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "zstd", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "zstd-safe 7.2.0", + "target": "zstd_safe" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.13.2" + }, + "license": "MIT" + }, + "zstd-safe 7.2.0": { + "name": "zstd-safe", + "version": "7.2.0", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/zstd-safe/7.2.0/download", + "sha256": "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" + } + }, + "targets": [ + { + "Library": { + "crate_name": "zstd_safe", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "zstd_safe", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "zstd-safe 7.2.0", + "target": "build_script_build" + }, + { + "id": "zstd-sys 2.0.12+zstd.1.5.6", + "target": "zstd_sys" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "7.2.0" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "link_deps": { + "common": [ + { + "id": "zstd-sys 2.0.12+zstd.1.5.6", + "target": "zstd_sys" + } + ], + "selects": {} + } + }, + "license": "MIT/Apache-2.0" + }, + "zstd-sys 2.0.12+zstd.1.5.6": { + "name": "zstd-sys", + "version": "2.0.12+zstd.1.5.6", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/zstd-sys/2.0.12+zstd.1.5.6/download", + "sha256": "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" + } + }, + "targets": [ + { + "Library": { + "crate_name": "zstd_sys", + "crate_root": "src/lib.rs", + "srcs": [ + "**/*.rs" + ] + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": [ + "**/*.rs" + ] + } + } + ], + "library_target_name": "zstd_sys", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "zstd-sys 2.0.12+zstd.1.5.6", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "2.0.12+zstd.1.5.6" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cc 1.1.8", + "target": "cc" + }, + { + "id": "pkg-config 0.3.30", + "target": "pkg_config" + } + ], + "selects": {} + }, + "links": "zstd" + }, + "license": "MIT/Apache-2.0" } }, "binary_crates": [], @@ -46950,6 +49118,14 @@ "x86_64-unknown-linux-gnu" ], "cfg(any())": [], + "cfg(any(all(target_arch = \"arm\", target_pointer_width = \"32\"), target_arch = \"mips\", target_arch = \"powerpc\"))": [ + "arm-unknown-linux-gnueabi", + "armv7-linux-androideabi", + "armv7-unknown-linux-gnueabi", + "powerpc-unknown-linux-gnu", + "thumbv7em-none-eabi", + "thumbv8m.main-none-eabi" + ], "cfg(any(target_arch = \"aarch64\", target_arch = \"arm\", target_arch = \"x86\", target_arch = \"x86_64\"))": [ "aarch64-apple-darwin", "aarch64-apple-ios", @@ -47084,6 +49260,30 @@ "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu" ], + "cfg(any(unix, target_os = \"wasi\", target_os = \"redox\"))": [ + "aarch64-apple-darwin", + "aarch64-apple-ios", + "aarch64-apple-ios-sim", + "aarch64-fuchsia", + "aarch64-linux-android", + "aarch64-unknown-linux-gnu", + "arm-unknown-linux-gnueabi", + "armv7-linux-androideabi", + "armv7-unknown-linux-gnueabi", + "i686-apple-darwin", + "i686-linux-android", + "i686-unknown-freebsd", + "i686-unknown-linux-gnu", + "powerpc-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "wasm32-wasi", + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fuchsia", + "x86_64-linux-android", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu" + ], "cfg(any(windows, unix, target_os = \"redox\"))": [ "aarch64-apple-darwin", "aarch64-apple-ios", @@ -47111,6 +49311,7 @@ "x86_64-unknown-linux-gnu" ], "cfg(curve25519_dalek_backend = \"fiat\")": [], + "cfg(fuzzing)": [], "cfg(not(all(target_arch = \"arm\", target_os = \"none\")))": [ "aarch64-apple-darwin", "aarch64-apple-ios", diff --git a/Cargo.lock b/Cargo.lock index 1fd443aaa..7885928cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,6 +201,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.7.8" @@ -310,6 +321,15 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "arc-swap" version = "1.7.1" @@ -465,6 +485,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_generate_cdp" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7af08ed49930c50104b2f1699d257e5053fb1809e370647bde9c58b31d65d417" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "serde", + "serde_json", + "ureq", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -912,6 +946,27 @@ dependencies = [ "bytes", ] +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "cached" version = "0.49.3" @@ -1047,6 +1102,10 @@ name = "cc" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549" +dependencies = [ + "jobserver", + "libc", +] [[package]] name = "cfg-if" @@ -1102,6 +1161,16 @@ dependencies = [ "half 2.4.1", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "3.2.25" @@ -1308,6 +1377,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "convert_case" version = "0.4.0" @@ -1357,6 +1432,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.2" @@ -1618,8 +1708,18 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core 0.20.10", + "darling_macro 0.20.10", ] [[package]] @@ -1636,17 +1736,42 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.72", +] + [[package]] name = "darling_macro" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ - "darling_core", + "darling_core 0.13.4", "quote", "syn 1.0.109", ] +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core 0.20.10", + "quote", + "syn 2.0.72", +] + [[package]] name = "dary_heap" version = "0.3.6" @@ -1700,6 +1825,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "deflate64" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + [[package]] name = "der" version = "0.7.9" @@ -1746,6 +1877,48 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "derive_builder" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +dependencies = [ + "darling 0.20.10", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +dependencies = [ + "derive_builder_core", + "syn 2.0.72", +] + [[package]] name = "derive_more" version = "0.99.18" @@ -1859,6 +2032,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs" version = "5.0.1" @@ -1958,6 +2140,7 @@ dependencies = [ "fs-err", "futures", "futures-util", + "headless_chrome", "human_bytes", "humantime", "ic-base-types", @@ -2071,7 +2254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f364860e764787163c8c8f58231003839be31276e821e2ad2092ddf496b1aa09" dependencies = [ "tempfile", - "which", + "which 4.4.2", ] [[package]] @@ -2609,6 +2792,33 @@ dependencies = [ "num-traits", ] +[[package]] +name = "headless_chrome" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50752288ae8799c84ed7fc6616611b7493c53d92265198b8a607c7e4256ebd2" +dependencies = [ + "anyhow", + "auto_generate_cdp", + "base64 0.22.1", + "derive_builder", + "directories", + "log", + "rand", + "regex", + "serde", + "serde_json", + "tempfile", + "thiserror", + "tungstenite", + "ureq", + "url", + "walkdir", + "which 6.0.2", + "winreg", + "zip", +] + [[package]] name = "heck" version = "0.3.3" @@ -5203,6 +5413,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.13" @@ -5279,6 +5498,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -5483,6 +5711,12 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "lockfree-object-pool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" + [[package]] name = "log" version = "0.4.22" @@ -5536,6 +5770,16 @@ dependencies = [ "url", ] +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder", + "crc", +] + [[package]] name = "lzma-sys" version = "0.1.20" @@ -6211,6 +6455,16 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac", +] + [[package]] name = "pem" version = "1.1.1" @@ -7260,6 +7514,7 @@ version = "0.23.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ + "log", "once_cell", "ring", "rustls-pki-types", @@ -7351,6 +7606,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.23" @@ -7598,7 +7862,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ - "darling", + "darling 0.13.4", "proc-macro2", "quote", "syn 1.0.109", @@ -7726,6 +7990,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "simdutf8" version = "0.1.4" @@ -7907,6 +8177,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socks" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" +dependencies = [ + "byteorder", + "libc", + "winapi", +] + [[package]] name = "spin" version = "0.9.8" @@ -8621,6 +8902,24 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "utf-8", +] + [[package]] name = "typed-arena" version = "2.0.2" @@ -8690,6 +8989,23 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +dependencies = [ + "base64 0.22.1", + "flate2", + "log", + "once_cell", + "rustls 0.23.12", + "rustls-pki-types", + "socks", + "url", + "webpki-roots", +] + [[package]] name = "url" version = "2.5.2" @@ -8708,6 +9024,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8-width" version = "0.1.7" @@ -8757,6 +9079,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "walrus" version = "0.20.3" @@ -8925,6 +9257,18 @@ dependencies = [ "rustix", ] +[[package]] +name = "which" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d9c5ed668ee1f17edb3b627225343d210006a90bb1e3745ce1f30b1fb115075" +dependencies = [ + "either", + "home", + "rustix", + "winsafe", +] + [[package]] name = "winapi" version = "0.3.9" @@ -9132,6 +9476,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wiremock" version = "0.6.1" @@ -9255,6 +9605,35 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "zip" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775a2b471036342aa69bc5a602bc889cb0a06cda00477d0c69566757d5553d39" +dependencies = [ + "aes", + "arbitrary", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "deflate64", + "displaydoc", + "flate2", + "hmac", + "indexmap 2.3.0", + "lzma-rs", + "memchr", + "pbkdf2", + "rand", + "sha1", + "thiserror", + "time", + "zeroize", + "zopfli", + "zstd", +] + [[package]] name = "zipsign-api" version = "0.1.2" @@ -9265,3 +9644,45 @@ dependencies = [ "ed25519-dalek", "thiserror", ] + +[[package]] +name = "zopfli" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +dependencies = [ + "bumpalo", + "crc32fast", + "lockfree-object-pool", + "log", + "once_cell", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.12+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 0ec2ab448..827a64a06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -201,6 +201,9 @@ urlencoding = "2.1.3" warp = "0.3" wiremock = "0.6.0" human_bytes = "0.4" +headless_chrome = { version = "1.0.12", features = [ + "fetch", +], default-features = false } # dre-canisters dependencies ic-cdk-timers = { git = "https://github.com/dfinity/cdk-rs.git", rev = "59795716487fbb8a9910ac503bcea1e0cb08c932" } diff --git a/bazel/external_crates.bzl b/bazel/external_crates.bzl index 1e56c211c..f75da47e1 100644 --- a/bazel/external_crates.bzl +++ b/bazel/external_crates.bzl @@ -4,6 +4,14 @@ def external_crates_repository(): crates_repository( name = "crate_index_dre", annotations = { + "headless_chrome": [crate.annotation( + rustc_env = { + "DO_NOT_FORMAT": "1", + }, + build_script_env = { + "DO_NOT_FORMAT": "1", + }, + )], "ic-adapter-metrics-service": [crate.annotation( build_script_data = [ "@com_google_protobuf//:protoc", diff --git a/rs/cli/BUILD.bazel b/rs/cli/BUILD.bazel index eaf99247c..859482719 100644 --- a/rs/cli/BUILD.bazel +++ b/rs/cli/BUILD.bazel @@ -1,6 +1,6 @@ load("@crate_index_dre//:defs.bzl", "aliases", "all_crate_deps") load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test", "rust_library") -load("@rules_rust//cargo:defs.bzl", "cargo_build_script") +load("@rules_rust//cargo:defs.bzl", "cargo_build_script", "cargo_dep_env") DEPS = [ "//rs/ic-canisters", @@ -34,7 +34,7 @@ rust_binary( ), deps = all_crate_deps( normal = True, - ) + DEPS + ["//rs/cli:dre-lib", ":build_script"], + ) + DEPS + ["//rs/cli:dre-lib", ":build_script"] ) rust_library( diff --git a/rs/cli/Cargo.toml b/rs/cli/Cargo.toml index 33250f156..f7780e07d 100644 --- a/rs/cli/Cargo.toml +++ b/rs/cli/Cargo.toml @@ -66,7 +66,7 @@ spinners = { workspace = true } strum = { workspace = true } tabled = { workspace = true } tabular = { workspace = true } -tempfile = "3.10.1" +tempfile = { workspace = true } tokio = { workspace = true } url = { workspace = true } humantime = { workspace = true } @@ -75,6 +75,7 @@ cryptoki = { workspace = true } keyring = { workspace = true } comfy-table = { workspace = true } human_bytes = { workspace = true } +headless_chrome = { workspace = true } [dev-dependencies] actix-rt = { workspace = true } diff --git a/rs/cli/src/commands/qualify/execute.rs b/rs/cli/src/commands/qualify/execute.rs index 9365edc7f..53dcfbbb6 100644 --- a/rs/cli/src/commands/qualify/execute.rs +++ b/rs/cli/src/commands/qualify/execute.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use clap::Args; use ic_management_types::Network; use serde_json::Value; @@ -31,6 +33,13 @@ pub struct Execute { /// Prometheus compliant endpoint #[clap(long)] pub prometheus_endpoint: String, + + /// Artifacts path + #[clap(long)] + pub artifacts: Option, + + /// Grafana url, needed if `artifacts` are present + pub grafana_url: Option, } impl ExecutableCommand for Execute { @@ -38,7 +47,15 @@ impl ExecutableCommand for Execute { IcAdminRequirement::Detect } - fn validate(&self, _cmd: &mut clap::Command) {} + fn validate(&self, cmd: &mut clap::Command) { + if self.artifacts.is_some() && self.grafana_url.is_none() { + cmd.error( + clap::error::ErrorKind::InvalidValue, + "`grafana_url` is mandatory if `artifacts` are to be exported", + ) + .exit() + } + } async fn execute(&self, ctx: crate::ctx::DreContext) -> anyhow::Result<()> { if ctx.network().eq(&Network::mainnet_unchecked().unwrap()) { @@ -65,13 +82,18 @@ impl ExecutableCommand for Execute { } }; - let qualification_executor = QualificationExecutorBuilder::new(ctx) + let mut qualification_executor = QualificationExecutorBuilder::new(ctx) .with_step_range(self.step_range.clone().unwrap_or_default()) .with_from_version(from_version) .with_to_version(self.version.clone()) .with_deployment_namge(self.deployment_name.clone()) - .with_prometheus_endpoint(self.prometheus_endpoint.clone()) - .build(); - qualification_executor.execute().await + .with_prometheus_endpoint(self.prometheus_endpoint.clone()); + if let Some(path) = &self.artifacts { + qualification_executor = qualification_executor.with_artifacts(path.to_owned()); + }; + if let Some(grafana_url) = &self.grafana_url { + qualification_executor = qualification_executor.with_grafana_endpoint(grafana_url.to_owned()); + } + qualification_executor.build()?.execute().await } } diff --git a/rs/cli/src/commands/qualify/list.rs b/rs/cli/src/commands/qualify/list.rs index 2a5c00bb9..3f343a87e 100644 --- a/rs/cli/src/commands/qualify/list.rs +++ b/rs/cli/src/commands/qualify/list.rs @@ -23,7 +23,7 @@ impl ExecutableCommand for List { async fn execute(&self, ctx: crate::ctx::DreContext) -> anyhow::Result<()> { let qualification_executor = QualificationExecutorBuilder::new(ctx) .with_step_range(self.step_range.clone().unwrap_or_default()) - .build(); + .build()?; qualification_executor.list(); Ok(()) diff --git a/rs/cli/src/qualification/ensure_blessed_versions.rs b/rs/cli/src/qualification/ensure_blessed_versions.rs index 667e52f04..3e52de84b 100644 --- a/rs/cli/src/qualification/ensure_blessed_versions.rs +++ b/rs/cli/src/qualification/ensure_blessed_versions.rs @@ -3,12 +3,11 @@ use comfy_table::CellAlignment; use itertools::Itertools; use crate::{ - ctx::DreContext, ic_admin::{ProposeCommand, ProposeOptions}, qualification::Step, }; -use super::{comfy_table_util::Table, print_table}; +use super::{comfy_table_util::Table, util::StepCtx}; pub struct EnsureBlessedRevisions { pub version: String, @@ -23,8 +22,8 @@ impl Step for EnsureBlessedRevisions { "ensure_blessed_revision".to_string() } - async fn execute(&self, ctx: &DreContext) -> anyhow::Result<()> { - let registry = ctx.registry().await; + async fn execute(&self, ctx: &StepCtx) -> anyhow::Result<()> { + let registry = ctx.dre_ctx().registry().await; let blessed_versions = registry.elected_guestos()?; if blessed_versions.contains(&self.version) { @@ -34,7 +33,8 @@ impl Step for EnsureBlessedRevisions { // Place proposal let place_proposal = || async { - ctx.ic_admin() + ctx.dre_ctx() + .ic_admin() .propose_run( ProposeCommand::ReviseElectedVersions { release_artifact: ic_management_types::Artifact::GuestOs, @@ -69,7 +69,7 @@ impl Step for EnsureBlessedRevisions { .with_rows(blessed_versions.iter().map(|ver| vec![ver.to_string()]).collect_vec()) .to_table(); - print_table(table); + ctx.print_table(table); Ok(()) } } diff --git a/rs/cli/src/qualification/mod.rs b/rs/cli/src/qualification/mod.rs index 088114ced..286c643ab 100644 --- a/rs/cli/src/qualification/mod.rs +++ b/rs/cli/src/qualification/mod.rs @@ -1,27 +1,18 @@ -use std::{ - io::{Read, Write}, - os::unix::fs::PermissionsExt, - path::PathBuf, - rc::Rc, - str::FromStr, - time::Duration, -}; +use std::{path::PathBuf, time::Duration}; use backon::{ExponentialBuilder, Retryable}; -use chrono::Utc; use comfy_table::CellAlignment; use comfy_table_util::Table; use ensure_blessed_versions::EnsureBlessedRevisions; -use flate2::bufread::GzDecoder; -use ic_management_backend::lazy_registry::LazyRegistry; use ic_registry_subnet_type::SubnetType; use itertools::Itertools; -use reqwest::ClientBuilder; use retire_blessed_versions::RetireBlessedVersions; use run_workload_test::Workload; use run_xnet_test::RunXnetTest; +use step::{OrderedStep, Step, Steps}; use upgrade_deployment_canister::UpgradeDeploymentCanisters; use upgrade_subnets::{Action, UpgradeSubnets}; +use util::StepCtx; use crate::ctx::DreContext; @@ -30,20 +21,16 @@ mod ensure_blessed_versions; mod retire_blessed_versions; mod run_workload_test; mod run_xnet_test; +mod step; mod upgrade_deployment_canister; mod upgrade_subnets; +mod util; pub struct QualificationExecutor { steps: Vec, - dre_ctx: DreContext, from_version: String, to_version: String, -} - -struct OrderedStep { - index: usize, - should_skip: bool, - step: Steps, + step_ctx: StepCtx, } pub struct QualificationExecutorBuilder { @@ -53,6 +40,8 @@ pub struct QualificationExecutorBuilder { step_range: String, deployment_name: String, prometheus_endpoint: String, + artifacts: Option, + grafana_endpoint: Option, } impl QualificationExecutorBuilder { @@ -64,6 +53,8 @@ impl QualificationExecutorBuilder { step_range: "".to_string(), deployment_name: "".to_string(), prometheus_endpoint: "".to_string(), + artifacts: None, + grafana_endpoint: None, } } @@ -87,13 +78,27 @@ impl QualificationExecutorBuilder { Self { prometheus_endpoint, ..self } } - pub fn build(self) -> QualificationExecutor { + pub fn with_artifacts(self, path: PathBuf) -> Self { + Self { + artifacts: Some(path), + ..self + } + } + + pub fn with_grafana_endpoint(self, grafana_endpoint: String) -> Self { + Self { + grafana_endpoint: Some(grafana_endpoint), + ..self + } + } + + pub fn build(self) -> anyhow::Result { QualificationExecutor::_new(self) } } impl QualificationExecutor { - fn _new(ctx: QualificationExecutorBuilder) -> Self { + fn _new(ctx: QualificationExecutorBuilder) -> anyhow::Result { let steps = vec![ // Ensure the beginning version is blessed // This step will be skipped for testnet runs, but may be @@ -163,6 +168,7 @@ impl QualificationExecutor { // TODO: add artifacts exporting Steps::RunXnetTest(RunXnetTest { version: ctx.to_version.clone(), + deployment_name: ctx.deployment_name.clone(), }), // Since the initial testnet is spunup with disk-img // retire the initial version. @@ -204,6 +210,7 @@ impl QualificationExecutor { // TODO: add artifacts exporting Steps::RunXnetTest(RunXnetTest { version: ctx.from_version.clone(), + deployment_name: ctx.deployment_name.clone(), }), ]; @@ -228,7 +235,7 @@ impl QualificationExecutor { }; let end_index = if end_index > steps.len() - 1 { steps.len() - 1 } else { end_index }; - Self { + Ok(Self { steps: steps .into_iter() .enumerate() @@ -238,10 +245,10 @@ impl QualificationExecutor { step: s, }) .collect_vec(), - dre_ctx: ctx.dre_ctx, + step_ctx: StepCtx::new(ctx.dre_ctx, ctx.artifacts, ctx.grafana_endpoint)?, from_version: ctx.from_version, to_version: ctx.to_version, - } + }) } pub fn list(&self) { @@ -267,240 +274,57 @@ impl QualificationExecutor { ) .to_table(); - println!("{}", table) + self.step_ctx.print_table(table) } pub async fn execute(&self) -> anyhow::Result<()> { - print_text("This qualification run will execute the following steps:".to_string()); + self.print_text("This qualification run will execute the following steps:".to_string()); self.list(); - print_text(format!("Running qualification from version {} to {}", self.from_version, self.to_version)); - print_text(format!("Starting execution of {} steps:", self.steps.len())); + self.print_text(format!("Running qualification from version {} to {}", self.from_version, self.to_version)); + self.print_text(format!("Starting execution of {} steps:", self.steps.len())); for ordered_step in &self.steps { if ordered_step.should_skip { - print_text(format!( + self.print_text(format!( "Skipping step {} due to skip-range: `{}`", ordered_step.index, ordered_step.step.name() )); continue; } - print_text(format!("Executing step {}: `{}`", ordered_step.index, ordered_step.step.name())); + self.print_text(format!("Executing step {}: `{}`", ordered_step.index, ordered_step.step.name())); - let step_future = || async { ordered_step.step.execute(&self.dre_ctx).await }; - step_future.retry(&ExponentialBuilder::default()).await?; + let step_future = || async { ordered_step.step.execute(&self.step_ctx).await }; + if let Err(e) = step_future.retry(&ExponentialBuilder::default()).await { + self.print_text(format!("Failed to execute step {}: {:?}", ordered_step.step.name(), e)); + anyhow::bail!(e) + } - print_text(format!("Executed step {}: `{}`", ordered_step.index, ordered_step.step.name())); + self.print_text(format!("Executed step {}: `{}`", ordered_step.index, ordered_step.step.name())); - let registry = self.dre_ctx.registry().await; - print_text(format!("Syncing with registry after step {}", ordered_step.index)); + let registry = self.step_ctx.dre_ctx().registry().await; + self.print_text(format!("Syncing with registry after step {}", ordered_step.index)); let sync_registry = || async { registry.sync_with_nns().await }; // If the system subnet downgraded it could be some time until it boots up - sync_registry + if let Err(e) = sync_registry .retry( &ExponentialBuilder::default() .with_max_times(10) .with_max_delay(Duration::from_secs(5 * 60)), ) - .await?; + .await + { + self.print_text(format!("Failed to sync with registry: {:?}", e)); + anyhow::bail!(e) + } } - print_text(format!("Qualification of {} finished successfully!", self.to_version)); + self.print_text(format!("Qualification of {} finished successfully!", self.to_version)); Ok(()) } -} - -enum Steps { - EnsureBlessedVersions(EnsureBlessedRevisions), - UpgradeDeploymentCanisters(UpgradeDeploymentCanisters), - UpgradeSubnets(UpgradeSubnets), - RetireBlessedVersions(RetireBlessedVersions), - RunWorkloadTest(Workload), - RunXnetTest(RunXnetTest), -} - -pub trait Step { - fn help(&self) -> String; - - fn name(&self) -> String; - - async fn execute(&self, ctx: &DreContext) -> anyhow::Result<()>; -} - -impl Step for Steps { - fn help(&self) -> String { - match &self { - Steps::EnsureBlessedVersions(c) => c.help(), - Steps::UpgradeDeploymentCanisters(c) => c.help(), - Steps::UpgradeSubnets(c) => c.help(), - Steps::RetireBlessedVersions(c) => c.help(), - Steps::RunWorkloadTest(c) => c.help(), - Steps::RunXnetTest(c) => c.help(), - } - } - - fn name(&self) -> String { - match &self { - Steps::EnsureBlessedVersions(c) => c.name(), - Steps::UpgradeDeploymentCanisters(c) => c.name(), - Steps::UpgradeSubnets(c) => c.name(), - Steps::RetireBlessedVersions(c) => c.name(), - Steps::RunWorkloadTest(c) => c.name(), - Steps::RunXnetTest(c) => c.name(), - } - } - - async fn execute(&self, ctx: &DreContext) -> anyhow::Result<()> { - match &self { - Steps::EnsureBlessedVersions(c) => c.execute(ctx).await, - Steps::UpgradeDeploymentCanisters(c) => c.execute(ctx).await, - Steps::UpgradeSubnets(c) => c.execute(ctx).await, - Steps::RetireBlessedVersions(c) => c.execute(ctx).await, - Steps::RunWorkloadTest(c) => c.execute(ctx).await, - Steps::RunXnetTest(c) => c.execute(ctx).await, - } - } -} - -const REQWEST_TIMEOUT: Duration = Duration::from_secs(30); -const IC_EXECUTABLES_DIR: &str = "ic-executables"; -pub async fn download_canister(canister: &str, version: &str) -> anyhow::Result { - let client = ClientBuilder::new().timeout(REQWEST_TIMEOUT).build()?; - - let cache = dirs::cache_dir().ok_or(anyhow::anyhow!("Can't cache dir"))?.join(IC_EXECUTABLES_DIR); - if !cache.exists() { - std::fs::create_dir_all(&cache)?; - } - - let artifact_path = cache.join(format!("{}/{}.{}", canister, canister, version)); - let artifact_dir = artifact_path.parent().unwrap(); - if !artifact_dir.exists() { - std::fs::create_dir(artifact_dir)?; - } - - let canister_path = PathBuf::from_str(&format!("{}.wasm", artifact_path.display())).map_err(|e| anyhow::anyhow!(e))?; - - if canister_path.exists() { - print_text(format!("Canister `{}` data already present", canister)); - return Ok(canister_path); - } - - let url = format!("https://download.dfinity.systems/ic/{}/canisters/{}.wasm.gz", version, canister); - - print_text(format!("Downloading: {}", url)); - let response = client.get(&url).send().await?.error_for_status()?.bytes().await?; - let mut d = GzDecoder::new(&response[..]); - let mut collector: Vec = vec![]; - let mut file = std::fs::File::create(&canister_path)?; - d.read_to_end(&mut collector)?; - - file.write_all(&collector)?; - print_text(format!("Downloaded: {}", &url)); - Ok(canister_path) -} - -pub async fn download_executable(executable: &str, version: &str) -> anyhow::Result { - let client = ClientBuilder::new().timeout(REQWEST_TIMEOUT).build()?; - - let cache = dirs::cache_dir().ok_or(anyhow::anyhow!("Can't cache dir"))?.join(IC_EXECUTABLES_DIR); - if !cache.exists() { - std::fs::create_dir_all(&cache)?; - } - let exe_path = cache.join(format!("{}/{}.{}", executable, executable, version)); - let artifact_dir = exe_path.parent().unwrap(); - if !artifact_dir.exists() { - std::fs::create_dir(artifact_dir)?; + fn print_text(&self, message: String) { + self.step_ctx.print_text(message) } - - if exe_path.exists() && exe_path.is_file() { - let permissions = exe_path.metadata()?.permissions(); - let is_executable = permissions.mode() & 0o111 != 0; - if is_executable { - print_text(format!("Executable `{}` already present and executable", executable)); - return Ok(exe_path); - } - } - - let url = format!( - "https://download.dfinity.systems/ic/{}/binaries/x86_64-{}/{}.gz", - version, - match std::env::consts::OS { - "linux" => "linux", - "macos" => "darwin", - s => return Err(anyhow::anyhow!("Unsupported os: {}", s)), - }, - executable - ); - - print_text(format!("Downloading: {}", url)); - let response = client.get(&url).send().await?.error_for_status()?.bytes().await?; - let mut d = GzDecoder::new(&response[..]); - let mut collector: Vec = vec![]; - let mut file = std::fs::File::create(&exe_path)?; - d.read_to_end(&mut collector)?; - - file.write_all(&collector)?; - print_text(format!("Downloaded: {}", &url)); - - file.set_permissions(PermissionsExt::from_mode(0o774))?; - print_text(format!("Created executable: {}", exe_path.display())); - Ok(exe_path) -} - -pub async fn print_subnet_versions(registry: Rc) -> anyhow::Result<()> { - let subnets = registry.subnets().await?; - - let subnets = subnets.values(); - let unassigned = registry.unassigned_nodes_replica_version()?; - let table = Table::new() - .with_columns(&[ - ("Subnet type", CellAlignment::Left), - ("Subnet Id", CellAlignment::Center), - ("Version", CellAlignment::Center), - ]) - .with_rows( - subnets - .map(|s| { - vec![ - match s.subnet_type { - SubnetType::Application => "application".to_string(), - SubnetType::System => "system".to_string(), - SubnetType::VerifiedApplication => "verified-app".to_string(), - }, - s.principal.to_string(), - s.replica_version.clone(), - ] - }) - .chain(vec![vec!["unassigned".to_string(), "unassigned".to_string(), unassigned.to_string()]]) - .collect_vec(), - ) - .to_table(); - - print_table(table); - - Ok(()) -} - -pub fn print_text(message: String) { - _print_with_time(message, false) -} - -pub fn print_table(table: comfy_table::Table) { - _print_with_time(format!("{}", table), true) -} - -fn _print_with_time(message: String, add_new_line: bool) { - let current_time = Utc::now(); - - println!( - "[{}]{}{}", - current_time, - match add_new_line { - true => '\n', - false => ' ', - }, - message - ) } diff --git a/rs/cli/src/qualification/retire_blessed_versions.rs b/rs/cli/src/qualification/retire_blessed_versions.rs index d8474e80f..d0314191f 100644 --- a/rs/cli/src/qualification/retire_blessed_versions.rs +++ b/rs/cli/src/qualification/retire_blessed_versions.rs @@ -2,12 +2,9 @@ use backon::{ExponentialBuilder, Retryable}; use comfy_table::CellAlignment; use itertools::Itertools; -use crate::{ - ctx::DreContext, - ic_admin::{ProposeCommand, ProposeOptions}, -}; +use crate::ic_admin::{ProposeCommand, ProposeOptions}; -use super::{comfy_table_util::Table, print_table, print_text, Step}; +use super::{comfy_table_util::Table, step::Step, util::StepCtx}; pub struct RetireBlessedVersions { pub versions: Vec, @@ -22,8 +19,8 @@ impl Step for RetireBlessedVersions { "retire_blessed_versions".to_string() } - async fn execute(&self, ctx: &DreContext) -> anyhow::Result<()> { - let registry = ctx.registry().await; + async fn execute(&self, ctx: &StepCtx) -> anyhow::Result<()> { + let registry = ctx.dre_ctx().registry().await; let blessed_versions = registry.elected_guestos()?; let mut to_unelect = vec![]; @@ -33,12 +30,13 @@ impl Step for RetireBlessedVersions { } } if to_unelect.is_empty() { - print_text(format!("Versions {} are not blessed, skipping step", self.versions.iter().join(","))); + ctx.print_text(format!("Versions {} are not blessed, skipping step", self.versions.iter().join(","))); return Ok(()); } let place_proposal = || async { - ctx.ic_admin() + ctx.dre_ctx() + .ic_admin() .propose_run( ProposeCommand::ReviseElectedVersions { release_artifact: ic_management_types::Artifact::GuestOs, @@ -65,7 +63,7 @@ impl Step for RetireBlessedVersions { .with_rows(blessed_versions.iter().map(|ver| vec![ver.to_string()]).collect_vec()) .to_table(); - print_table(table); + ctx.print_table(table); Ok(()) } diff --git a/rs/cli/src/qualification/run_workload_test.rs b/rs/cli/src/qualification/run_workload_test.rs index d3c80a2ab..8323f1e9d 100644 --- a/rs/cli/src/qualification/run_workload_test.rs +++ b/rs/cli/src/qualification/run_workload_test.rs @@ -8,9 +8,11 @@ use reqwest::ClientBuilder; use serde_json::Value; use tokio::process::Command; -use crate::ctx::DreContext; - -use super::{comfy_table_util::Table, download_executable, print_table, print_text, Step, REQWEST_TIMEOUT}; +use super::{ + comfy_table_util::Table, + step::Step, + util::{StepCtx, REQWEST_TIMEOUT}, +}; const IC_WORKLOAD_GENERATOR: &str = "ic-workload-generator"; @@ -32,10 +34,10 @@ impl Step for Workload { "workload_test".to_string() } - async fn execute(&self, ctx: &DreContext) -> anyhow::Result<()> { - let wg_binary = download_executable(IC_WORKLOAD_GENERATOR, &self.version).await?; + async fn execute(&self, ctx: &StepCtx) -> anyhow::Result<()> { + let wg_binary = ctx.download_executable(IC_WORKLOAD_GENERATOR, &self.version).await?; - let subnets = ctx.registry().await.subnets().await?; + let subnets = ctx.dre_ctx().registry().await.subnets().await?; let subnet = subnets .values() .find(|s| s.subnet_type.eq(&SubnetType::Application)) @@ -53,7 +55,7 @@ impl Step for Workload { format!("--ingress-timeout-secs={}", TIMEOUT), ]; - print_text(format!("Spawning the command: {} {}", wg_binary.display(), args.iter().join(" "))); + ctx.print_text(format!("Spawning the command: {} {}", wg_binary.display(), args.iter().join(" "))); // Possible `ulimit` issue let start = Utc::now(); @@ -65,6 +67,17 @@ impl Step for Workload { anyhow::bail!("Failed to run workload test with status code: {}", status.code().unwrap_or_default()) } + // No need to stop the qualification if taking picture fails + if let Err(e) = ctx.capture_progress_clock( + self.deployment_name.to_string(), + &subnet.principal, + Some(start.timestamp()), + Some(end.timestamp()), + "workload_test", + ) { + ctx.print_text(format!("Failed to capture progress clock: {:?}", e)) + }; + match ensure_finalization_rate_for_subnet( &self.deployment_name, end.timestamp(), @@ -72,6 +85,7 @@ impl Step for Workload { &all_ipv6, &self.prometheus_endpoint, &SubnetType::Application, + ctx, ) .await? { @@ -89,6 +103,7 @@ async fn ensure_finalization_rate_for_subnet( ips: &[Ipv6Addr], prom_endpoint: &str, subnet_type: &SubnetType, + ctx: &StepCtx, ) -> anyhow::Result { let client = ClientBuilder::new().timeout(REQWEST_TIMEOUT).build()?; let metrics_hosts = ips.iter().map(|ip| format!("\\\\[{}\\\\]:9090", ip)).join("|"); @@ -103,9 +118,9 @@ async fn ensure_finalization_rate_for_subnet( .get(prom_endpoint) .header("Accept", "application/json") .query(&[("time", end_timestamp.to_string()), ("query", query)]); - print_text(format!("Running query: {:?}", request)); + ctx.print_text(format!("Running query: {:?}", request)); let response = request.send().await?.error_for_status()?.json::().await?; - print_text(format!("Received response: \n{}", serde_json::to_string_pretty(&response)?)); + ctx.print_text(format!("Received response: \n{}", serde_json::to_string_pretty(&response)?)); let finalization_rate = response["data"]["result"][0]["value"][1] .as_str() @@ -118,18 +133,7 @@ async fn ensure_finalization_rate_for_subnet( .with_rows(vec![vec![expected_finalization_rate.to_string(), finalization_rate.to_string()]]) .to_table(); - print_table(table); - - // Capture the image of grafana links - // logging.info("Check the Grafana dashboard (adjust the subnets if necessary)")) - // logging.info( - // "Grafana URL: https://grafana.testnet.dfinity.network/d/ic-progress-clock/ic-progress-clock?orgId=1&var-ic=%s&refresh=30s", - // deployment_name, - // ) - // logging.info( - // "Grafana URL: https://grafana.testnet.dfinity.network/d/execution-metrics/execution-metrics?orgId=1&var-ic=%s", - // deployment_name, - // ) + ctx.print_table(table); Ok(finalization_rate >= expected_finalization_rate) } diff --git a/rs/cli/src/qualification/run_xnet_test.rs b/rs/cli/src/qualification/run_xnet_test.rs index da6a0cf77..8514599db 100644 --- a/rs/cli/src/qualification/run_xnet_test.rs +++ b/rs/cli/src/qualification/run_xnet_test.rs @@ -1,10 +1,11 @@ use std::{os::unix::fs::PermissionsExt, time::Duration}; +use chrono::Utc; use ic_registry_subnet_type::SubnetType; use itertools::Itertools; use tokio::process::Command; -use super::{download_canister, download_executable, print_text, Step}; +use super::{step::Step, util::StepCtx}; const E2E_TEST_DRIVER: &str = "e2e-test-driver"; const XNET_TEST_CANISTER: &str = "xnet-test-canister"; @@ -19,6 +20,7 @@ const XNET_TEST_NUMBER: &str = "4.3"; pub struct RunXnetTest { pub version: String, + pub deployment_name: String, } impl Step for RunXnetTest { @@ -30,7 +32,7 @@ impl Step for RunXnetTest { "xnet_test".to_string() } - async fn execute(&self, ctx: &crate::ctx::DreContext) -> anyhow::Result<()> { + async fn execute(&self, ctx: &StepCtx) -> anyhow::Result<()> { let key = dirs::home_dir() .ok_or(anyhow::anyhow!("Cannot get home directory"))? .join(XNET_PRINCIPAL_PATH); @@ -41,10 +43,10 @@ impl Step for RunXnetTest { let file = std::fs::File::open(&key)?; file.set_permissions(PermissionsExt::from_mode(0o400))?; - let e2e_bin = download_executable(E2E_TEST_DRIVER, &self.version).await?; - let wasm_path = download_canister(XNET_TEST_CANISTER, &self.version).await?; + let e2e_bin = ctx.download_executable(E2E_TEST_DRIVER, &self.version).await?; + let wasm_path = ctx.download_canister(XNET_TEST_CANISTER, &self.version).await?; - let registry = ctx.registry().await; + let registry = ctx.dre_ctx().registry().await; let subnet = registry.subnets().await?; let subnet = subnet .values() @@ -71,18 +73,31 @@ impl Step for RunXnetTest { XNET_TEST_NUMBER.to_string(), ]; - print_text(format!( + ctx.print_text(format!( "Running command: XNET_TEST_CANISTER_WASM_PATH={} {} {}", wasm_path.display(), e2e_bin.display(), args.iter().join(" ") )); + let start = Utc::now(); let status = Command::new(e2e_bin) .args(args) .env("XNET_TEST_CANISTER_WASM_PATH", wasm_path.display().to_string()) .status() .await?; + let end = Utc::now(); + + // No need to stop the qualification if taking picture fails + if let Err(e) = ctx.capture_progress_clock( + self.deployment_name.to_string(), + &subnet.principal, + Some(start.timestamp()), + Some(end.timestamp()), + "xnet_test", + ) { + ctx.print_text(format!("Failed to capture progress clock: {:?}", e)) + } if !status.success() { anyhow::bail!("Failed to run xnet test with status code: {}", status.code().unwrap_or_default()) diff --git a/rs/cli/src/qualification/step.rs b/rs/cli/src/qualification/step.rs new file mode 100644 index 000000000..7c37c327f --- /dev/null +++ b/rs/cli/src/qualification/step.rs @@ -0,0 +1,62 @@ +use super::{ + ensure_blessed_versions::EnsureBlessedRevisions, retire_blessed_versions::RetireBlessedVersions, run_workload_test::Workload, + run_xnet_test::RunXnetTest, upgrade_deployment_canister::UpgradeDeploymentCanisters, upgrade_subnets::UpgradeSubnets, util::StepCtx, +}; + +pub struct OrderedStep { + pub index: usize, + pub should_skip: bool, + pub step: Steps, +} + +pub enum Steps { + EnsureBlessedVersions(EnsureBlessedRevisions), + UpgradeDeploymentCanisters(UpgradeDeploymentCanisters), + UpgradeSubnets(UpgradeSubnets), + RetireBlessedVersions(RetireBlessedVersions), + RunWorkloadTest(Workload), + RunXnetTest(RunXnetTest), +} + +pub trait Step { + fn help(&self) -> String; + + fn name(&self) -> String; + + async fn execute(&self, ctx: &StepCtx) -> anyhow::Result<()>; +} + +impl Step for Steps { + fn help(&self) -> String { + match &self { + Steps::EnsureBlessedVersions(c) => c.help(), + Steps::UpgradeDeploymentCanisters(c) => c.help(), + Steps::UpgradeSubnets(c) => c.help(), + Steps::RetireBlessedVersions(c) => c.help(), + Steps::RunWorkloadTest(c) => c.help(), + Steps::RunXnetTest(c) => c.help(), + } + } + + fn name(&self) -> String { + match &self { + Steps::EnsureBlessedVersions(c) => c.name(), + Steps::UpgradeDeploymentCanisters(c) => c.name(), + Steps::UpgradeSubnets(c) => c.name(), + Steps::RetireBlessedVersions(c) => c.name(), + Steps::RunWorkloadTest(c) => c.name(), + Steps::RunXnetTest(c) => c.name(), + } + } + + async fn execute(&self, ctx: &StepCtx) -> anyhow::Result<()> { + match &self { + Steps::EnsureBlessedVersions(c) => c.execute(ctx).await, + Steps::UpgradeDeploymentCanisters(c) => c.execute(ctx).await, + Steps::UpgradeSubnets(c) => c.execute(ctx).await, + Steps::RetireBlessedVersions(c) => c.execute(ctx).await, + Steps::RunWorkloadTest(c) => c.execute(ctx).await, + Steps::RunXnetTest(c) => c.execute(ctx).await, + } + } +} diff --git a/rs/cli/src/qualification/upgrade_deployment_canister.rs b/rs/cli/src/qualification/upgrade_deployment_canister.rs index dc1e482b8..5ba150dea 100644 --- a/rs/cli/src/qualification/upgrade_deployment_canister.rs +++ b/rs/cli/src/qualification/upgrade_deployment_canister.rs @@ -1,8 +1,6 @@ use ic_nns_constants::ALL_NNS_CANISTER_IDS; -use crate::ctx::DreContext; - -use super::{print_text, Step}; +use super::{step::Step, util::StepCtx}; pub struct UpgradeDeploymentCanisters {} @@ -15,9 +13,9 @@ impl Step for UpgradeDeploymentCanisters { "update_deployment_canisters".to_string() } - async fn execute(&self, _ctx: &DreContext) -> anyhow::Result<()> { + async fn execute(&self, ctx: &StepCtx) -> anyhow::Result<()> { for canister_id in ALL_NNS_CANISTER_IDS { - print_text(format!("Checking version of canister with id {}", canister_id)) + ctx.print_text(format!("Checking version of canister with id {}", canister_id)) } Ok(()) diff --git a/rs/cli/src/qualification/upgrade_subnets.rs b/rs/cli/src/qualification/upgrade_subnets.rs index 7ff09ac47..f8ce60750 100644 --- a/rs/cli/src/qualification/upgrade_subnets.rs +++ b/rs/cli/src/qualification/upgrade_subnets.rs @@ -1,20 +1,18 @@ -use std::{fmt::Display, rc::Rc, time::Duration}; +use std::{fmt::Display, time::Duration}; use backon::{ExponentialBuilder, Retryable}; use comfy_table::CellAlignment; -use ic_management_backend::lazy_registry::LazyRegistry; use ic_registry_subnet_type::SubnetType; use ic_types::PrincipalId; use itertools::Itertools; use reqwest::ClientBuilder; use crate::{ - ctx::DreContext, ic_admin::{ProposeCommand, ProposeOptions}, - qualification::{comfy_table_util::Table, print_table}, + qualification::comfy_table_util::Table, }; -use super::{print_subnet_versions, print_text, Step}; +use super::{step::Step, util::StepCtx}; pub struct UpgradeSubnets { pub subnet_type: Option, @@ -72,26 +70,26 @@ impl Step for UpgradeSubnets { ) } - async fn execute(&self, ctx: &DreContext) -> anyhow::Result<()> { - let registry = ctx.registry().await; + async fn execute(&self, ctx: &StepCtx) -> anyhow::Result<()> { + let registry = ctx.dre_ctx().registry().await; let subnets = registry.subnets().await?; - print_text(format!("Found total of {} nodes", registry.nodes().await?.len())); - print_subnet_versions(registry.clone()).await?; + ctx.print_text(format!("Found total of {} nodes", registry.nodes().await?.len())); + ctx.print_subnet_versions().await?; if let Some(subnet_type) = &self.subnet_type { for subnet in subnets .values() .filter(|s| s.subnet_type.eq(subnet_type) && !s.replica_version.eq(&self.to_version)) { - let registry = ctx.registry().await; - print_text(format!( + ctx.print_text(format!( "Upgrading subnet {}: {} -> {}", subnet.principal, &subnet.replica_version, &self.to_version )); // Place proposal let place_proposal = || async { - ctx.ic_admin() + ctx.dre_ctx() + .ic_admin() .propose_run( ProposeCommand::DeployGuestosToAllSubnetNodes { subnet: subnet.principal, @@ -107,32 +105,33 @@ impl Step for UpgradeSubnets { }; place_proposal.retry(&ExponentialBuilder::default()).await?; - print_text(format!("Placed proposal for subnet {}", subnet.principal)); + ctx.print_text(format!("Placed proposal for subnet {}", subnet.principal)); // Wait for the version to be active on the subnet - wait_for_subnet_revision(registry.clone(), Some(subnet.principal), &self.to_version).await?; + wait_for_subnet_revision(ctx, Some(subnet.principal), &self.to_version).await?; - print_text(format!( + ctx.print_text(format!( "Subnet {} successfully upgraded to version {}", subnet.principal, &self.to_version )); - print_subnet_versions(registry.clone()).await?; + ctx.print_subnet_versions().await?; } } else { - let registry = ctx.registry().await; + let registry = ctx.dre_ctx().registry().await; let unassigned_nodes_version = registry.unassigned_nodes_replica_version()?; if unassigned_nodes_version.to_string() == self.to_version { - print_text(format!("Unassigned nodes are already on {}, skipping", self.to_version)); + ctx.print_text(format!("Unassigned nodes are already on {}, skipping", self.to_version)); return Ok(()); } - print_text(format!( + ctx.print_text(format!( "Upgrading unassigned version: {} -> {}", &unassigned_nodes_version, &self.to_version )); let place_proposal = || async { - ctx.ic_admin() + ctx.dre_ctx() + .ic_admin() .propose_run( ProposeCommand::DeployGuestosToAllUnassignedNodes { replica_version: self.to_version.clone(), @@ -148,11 +147,11 @@ impl Step for UpgradeSubnets { place_proposal.retry(&ExponentialBuilder::default()).await?; - wait_for_subnet_revision(registry.clone(), None, &self.to_version).await?; + wait_for_subnet_revision(ctx, None, &self.to_version).await?; - print_text(format!("Unassigned nodes successfully upgraded to version {}", &self.to_version)); + ctx.print_text(format!("Unassigned nodes successfully upgraded to version {}", &self.to_version)); - print_subnet_versions(registry.clone()).await?; + ctx.print_subnet_versions().await?; } Ok(()) @@ -164,11 +163,12 @@ const SLEEP: Duration = Duration::from_secs(10); const TIMEOUT: Duration = Duration::from_secs(60); const PLACEHOLDER: &str = "upgrading..."; -async fn wait_for_subnet_revision(registry: Rc, subnet: Option, revision: &str) -> anyhow::Result<()> { +async fn wait_for_subnet_revision(ctx: &StepCtx, subnet: Option, revision: &str) -> anyhow::Result<()> { let client = ClientBuilder::new().connect_timeout(TIMEOUT).build()?; + let registry = ctx.dre_ctx().registry().await; for i in 0..MAX_TRIES { tokio::time::sleep(SLEEP).await; - print_text(format!( + ctx.print_text(format!( "- {} - Checking if {} on {}", i, match &subnet { @@ -179,7 +179,7 @@ async fn wait_for_subnet_revision(registry: Rc, subnet: Option, subnet: Option match r.text().await { Ok(r) => r, Err(e) => { - print_text(format!("Received error {}, skipping...", e)); + ctx.print_text(format!("Received error {}, skipping...", e)); continue; } }, Err(e) => { - print_text(format!("Received error {}, skipping...", e)); + ctx.print_text(format!("Received error {}, skipping...", e)); continue; } }, Err(e) => { - print_text(format!("Received error {}, skipping...", e)); + ctx.print_text(format!("Received error {}, skipping...", e)); continue; } }; @@ -229,7 +229,7 @@ async fn wait_for_subnet_revision(registry: Rc, subnet: Option, + log_path: Option, + client: Client, + grafana_url: Option, +} + +impl StepCtx { + pub fn new(dre_ctx: DreContext, artifacts: Option, grafana_url: Option) -> anyhow::Result { + let artifacts_of_run = artifacts.as_ref().map(|t| { + if let Err(e) = std::fs::create_dir_all(t) { + panic!("Couldn't create dir {}: {:?}", t.display(), e) + } + t.clone() + }); + Ok(Self { + dre_ctx, + log_path: artifacts_of_run.as_ref().map(|t| { + let path = t.join("run.log"); + if let Err(e) = OpenOptions::new().write(true).truncate(true).create(true).open(&path) { + panic!("Couldn't create file {}: {:?}", path.display(), e) + }; + path + }), + artifacts: artifacts_of_run, + client: ClientBuilder::new().timeout(REQWEST_TIMEOUT).build()?, + grafana_url, + }) + } + + pub fn dre_ctx(&self) -> &DreContext { + &self.dre_ctx + } + + pub async fn download_canister(&self, canister: &str, version: &str) -> anyhow::Result { + let cache = dirs::cache_dir().ok_or(anyhow::anyhow!("Can't cache dir"))?.join(IC_EXECUTABLES_DIR); + if !cache.exists() { + std::fs::create_dir_all(&cache)?; + } + + let artifact_path = cache.join(format!("{}/{}.{}", canister, canister, version)); + let artifact_dir = artifact_path.parent().unwrap(); + if !artifact_dir.exists() { + std::fs::create_dir(artifact_dir)?; + } + + let canister_path = PathBuf::from_str(&format!("{}.wasm", artifact_path.display())).map_err(|e| anyhow::anyhow!(e))?; + + if canister_path.exists() { + self.print_text(format!("Canister `{}` data already present", canister)); + return Ok(canister_path); + } + + let url = format!("https://download.dfinity.systems/ic/{}/canisters/{}.wasm.gz", version, canister); + + self.print_text(format!("Downloading: {}", url)); + let response = self.client.get(&url).send().await?.error_for_status()?.bytes().await?; + let mut d = GzDecoder::new(&response[..]); + let mut collector: Vec = vec![]; + let mut file = std::fs::File::create(&canister_path)?; + d.read_to_end(&mut collector)?; + + file.write_all(&collector)?; + self.print_text(format!("Downloaded: {}", &url)); + Ok(canister_path) + } + + pub async fn download_executable(&self, executable: &str, version: &str) -> anyhow::Result { + let cache = dirs::cache_dir().ok_or(anyhow::anyhow!("Can't cache dir"))?.join(IC_EXECUTABLES_DIR); + if !cache.exists() { + std::fs::create_dir_all(&cache)?; + } + + let exe_path = cache.join(format!("{}/{}.{}", executable, executable, version)); + let artifact_dir = exe_path.parent().unwrap(); + if !artifact_dir.exists() { + std::fs::create_dir(artifact_dir)?; + } + + if exe_path.exists() && exe_path.is_file() { + let permissions = exe_path.metadata()?.permissions(); + let is_executable = permissions.mode() & 0o111 != 0; + if is_executable { + self.print_text(format!("Executable `{}` already present and executable", executable)); + return Ok(exe_path); + } + } + + let url = format!( + "https://download.dfinity.systems/ic/{}/binaries/x86_64-{}/{}.gz", + version, + match std::env::consts::OS { + "linux" => "linux", + "macos" => "darwin", + s => return Err(anyhow::anyhow!("Unsupported os: {}", s)), + }, + executable + ); + + self.print_text(format!("Downloading: {}", url)); + let response = self.client.get(&url).send().await?.error_for_status()?.bytes().await?; + let mut d = GzDecoder::new(&response[..]); + let mut collector: Vec = vec![]; + let mut file = std::fs::File::create(&exe_path)?; + d.read_to_end(&mut collector)?; + + file.write_all(&collector)?; + self.print_text(format!("Downloaded: {}", &url)); + + file.set_permissions(PermissionsExt::from_mode(0o774))?; + self.print_text(format!("Created executable: {}", exe_path.display())); + Ok(exe_path) + } + + pub async fn print_subnet_versions(&self) -> anyhow::Result<()> { + let registry = self.dre_ctx.registry().await; + let subnets = registry.subnets().await?; + + let subnets = subnets.values(); + let unassigned = registry.unassigned_nodes_replica_version()?; + let table = Table::new() + .with_columns(&[ + ("Subnet type", CellAlignment::Left), + ("Subnet Id", CellAlignment::Center), + ("Version", CellAlignment::Center), + ]) + .with_rows( + subnets + .map(|s| { + vec![ + match s.subnet_type { + SubnetType::Application => "application".to_string(), + SubnetType::System => "system".to_string(), + SubnetType::VerifiedApplication => "verified-app".to_string(), + }, + s.principal.to_string(), + s.replica_version.clone(), + ] + }) + .chain(vec![vec!["unassigned".to_string(), "unassigned".to_string(), unassigned.to_string()]]) + .collect_vec(), + ) + .to_table(); + + self.print_table(table); + + Ok(()) + } + + pub fn print_text(&self, message: String) { + self._print_with_time(message, false) + } + + pub fn print_table(&self, table: comfy_table::Table) { + self._print_with_time(format!("{}", table), true) + } + + fn _print_with_time(&self, message: String, add_new_line: bool) { + let current_time = Utc::now(); + let formatted = format!( + "[{}]{}{}", + current_time, + match add_new_line { + true => '\n', + false => ' ', + }, + message + ); + + if let Some(log_path) = &self.log_path { + let mut file = match OpenOptions::new().append(true).open(log_path) { + Ok(f) => f, + Err(e) => panic!("Couldn't open file {}: {:?}", log_path.display(), e), + }; + if let Err(e) = writeln!(file, "{}", formatted) { + panic!("Couldn't append to file {}: {:?}", log_path.display(), e) + } + } + + println!("{}", formatted) + } + + pub fn capture_progress_clock( + &self, + deployment_name: String, + subnet: &PrincipalId, + from: Option, + to: Option, + path_suffix: &str, + ) -> anyhow::Result<()> { + let (url, artifacts) = match (self.grafana_url.as_ref(), self.artifacts.as_ref()) { + (Some(url), Some(artifacts)) => (url, artifacts), + _ => return Ok(()), + }; + + let timestamp = match from { + Some(t) => t.to_string(), + None => Utc::now().timestamp().to_string(), + }; + + let browser = Browser::new(LaunchOptionsBuilder::default().window_size(Some((1920, 1080))).build()?)?; + let tab = browser.new_tab()?; + + for panel in Panel::iter() { + let mut url = Url::parse(url)?.join(panel.get_dashboard())?; + url.set_query(Some( + &[ + ("var-ic", deployment_name.to_string()), + ("var-ic_subnet", subnet.to_string()), + ( + "from", + match from { + Some(f) => (f * 1000).to_string(), + None => "now-1h".to_owned(), + }, + ), + ( + "to", + match to { + Some(t) => (t * 1000).to_string(), + None => "now".to_owned(), + }, + ), + ("orgId", "1".to_owned()), + ("viewPanel", panel.into()), + ] + .iter() + .map(|(k, v)| format!("{}={}", k, v)) + .join("&"), + )); + + let destination = artifacts.join(format!("{}-{}-{}.png", panel.get_name(), path_suffix, timestamp)); + self.print_text(format!("Capturing screen from link: {}", url)); + + tab.navigate_to(url.as_str())?; + std::thread::sleep(Duration::from_secs(5)); + let data = tab.capture_screenshot(Page::CaptureScreenshotFormatOption::Png, None, None, true)?; + std::fs::write(&destination, data)?; + + self.print_text(format!("Captured image and saved to: {}", destination.display())) + } + + Ok(()) + } +} + +#[derive(Clone, Copy, EnumIter, Default)] +enum Panel { + #[default] + FinalizationRate, + RunningReplicas, +} + +impl Panel { + fn get_name(&self) -> &str { + match self { + Panel::FinalizationRate => "FinalizationRate", + Panel::RunningReplicas => "RunningReplicas", + } + } + + fn get_dashboard(&self) -> &str { + match self { + Panel::FinalizationRate => "/d/ic-progress-clock/ic-progress-clock", + Panel::RunningReplicas => "/d/ic-progress-clock/ic-progress-clock", + } + } +} + +impl From for String { + fn from(value: Panel) -> Self { + match value { + Panel::FinalizationRate => "4", + Panel::RunningReplicas => "32", + } + .to_string() + } +} diff --git a/rs/qualifier/src/cli.rs b/rs/qualifier/src/cli.rs index f67a08edc..44ca7dbe5 100644 --- a/rs/qualifier/src/cli.rs +++ b/rs/qualifier/src/cli.rs @@ -36,6 +36,11 @@ pub struct Args { /// result in rebuilding of image #[clap(long)] pub skip_pull: bool, + + /// Specify the steps to run + /// A range can be: `4`, `3..`, `..3, `1..3` + #[clap(long)] + pub step_range: Option, } impl Args { @@ -50,6 +55,7 @@ impl Args { } std::fs::write(&path, key_pair.to_pem()).map_err(|e| anyhow::anyhow!(e))?; + // TODO: When we upgrade ic repo there will be a constant for this Ok((449479075714955186, path)) } diff --git a/rs/qualifier/src/ict_util.rs b/rs/qualifier/src/ict_util.rs index 4ed6ac485..853f63a18 100644 --- a/rs/qualifier/src/ict_util.rs +++ b/rs/qualifier/src/ict_util.rs @@ -34,6 +34,7 @@ pub async fn ict(ic_git: PathBuf, config: String, token: CancellationToken, send &ic_config.display().to_string(), ]; + info!("From directory: {}", ic_git.display()); info!("Running command: {} {}", command, args.iter().join(" ")); let mut child = Command::new(command) .args(args) diff --git a/rs/qualifier/src/main.rs b/rs/qualifier/src/main.rs index e9ecad655..4eebabf1f 100644 --- a/rs/qualifier/src/main.rs +++ b/rs/qualifier/src/main.rs @@ -1,4 +1,4 @@ -use std::{fmt::Display, time::Duration}; +use std::{fmt::Display, path::PathBuf, str::FromStr, time::Duration}; use clap::Parser; use cli::Args; @@ -13,6 +13,7 @@ use log::info; use qualify_util::qualify; use reqwest::ClientBuilder; use serde_json::Value; +use std::io::Write; use tokio::sync::mpsc; use tokio_util::sync::CancellationToken; @@ -138,6 +139,18 @@ async fn main() -> anyhow::Result<()> { let token = CancellationToken::new(); let (sender, mut receiver) = mpsc::channel(2); + let artifacts = PathBuf::from_str("/tmp/qualifier-artifacts")?.join(&args.version_to_qualify); + info!("Will store artifacts in: {}", artifacts.display()); + std::fs::create_dir_all(&artifacts)?; + if artifacts.exists() { + info!("Making sure artifact store is empty"); + std::fs::remove_dir_all(&artifacts)?; + std::fs::create_dir(&artifacts)?; + } + + let mut file = std::fs::File::create_new(artifacts.join("ic-config.json"))?; + writeln!(file, "{}", &config)?; + tokio::select! { res = ict(args.ic_repo_path.clone(), config, token.clone(), sender) => res?, res = qualify( @@ -147,6 +160,8 @@ async fn main() -> anyhow::Result<()> { NETWORK_NAME, initial_version, args.version_to_qualify.to_string(), + artifacts, + args.step_range ) => res? }; diff --git a/rs/qualifier/src/qualify_util.rs b/rs/qualifier/src/qualify_util.rs index f0f9d811c..9ca9379d4 100644 --- a/rs/qualifier/src/qualify_util.rs +++ b/rs/qualifier/src/qualify_util.rs @@ -9,6 +9,7 @@ use ic_management_backend::registry::local_registry_path; use ic_management_types::Network; use itertools::Itertools; use log::info; +use serde::Serialize; use serde_json::Value; use tokio::sync::mpsc::Receiver; use url::Url; @@ -22,12 +23,23 @@ pub async fn qualify( network_name: &str, from_version: String, to_version: String, + artifacts: PathBuf, + step_range: Option, ) -> anyhow::Result<()> { // Run dre to qualify with correct parameters info!("Awaiting logs path..."); let data = receiver.recv().await.ok_or(anyhow::anyhow!("Failed to recv data"))?; - - info!("Received logs: {}", data); + let log_path = match data { + Message::Log(line) => { + let log_path = line + .split_once('/') + .map(|(_, last)| format!("/{}", last[..last.len() - 1].to_owned())) + .ok_or(anyhow::anyhow!("Expected log line"))?; + info!("Log file path: {}", log_path); + PathBuf::from_str(&log_path)? + } + _ => anyhow::bail!("Expected Log line instead of data"), + }; info!("Awaiting config..."); let data = receiver.recv().await.ok_or(anyhow::anyhow!("Failed to recv data"))?; @@ -38,7 +50,7 @@ pub async fn qualify( }; let config = Config::from_str(&config)?; - info!("Received following config: {:#?}", config); + info!("Received following config: {}", serde_json::to_string_pretty(&config)?); info!("Running qualification..."); // At this point we are going to run so we need to remove previous @@ -65,9 +77,11 @@ pub async fn qualify( subcommand: dre::commands::qualify::Subcommands::Execute(Execute { version: to_version, from_version: Some(from_version), - step_range: None, + step_range, deployment_name: config.deployment_name, prometheus_endpoint: config.prometheus_url, + artifacts: Some(artifacts.clone()), + grafana_url: Some(config.grafana_url), }), }), verbose: false, @@ -75,16 +89,20 @@ pub async fn qualify( }; let ctx = DreContext::from_args(&args).await?; - args.execute(ctx).await + args.execute(ctx).await?; + + std::fs::copy(&log_path, artifacts.join("farm-driver.log"))?; + Ok(()) } -#[derive(Debug)] +#[derive(Debug, Serialize)] #[allow(dead_code)] struct Config { deployment_name: String, kibana_url: String, nns_urls: Vec, prometheus_url: String, + grafana_url: String, } impl FromStr for Config { @@ -118,6 +136,7 @@ impl FromStr for Config { let config = Self { prometheus_url: format!("http://prometheus.{}.testnet.farm.dfinity.systems/api/v1/query", deployment_name), + grafana_url: format!("http://grafana.{}.testnet.farm.dfinity.systems/", deployment_name), deployment_name, kibana_url: parsed["kibana_url"]["url"] .as_str()