From ea032a8b8e8a7c8629e9cb6f6f004d86fbededd1 Mon Sep 17 00:00:00 2001 From: andres Date: Sun, 27 Oct 2024 11:52:17 -0500 Subject: [PATCH] fix: Fixes error with manifest fetching on docker hub --- Cargo.lock | 245 +-------------------------------------------- Cargo.toml | 3 +- Makefile | 19 ++-- deb/DEBIAN/control | 2 +- rpm/dispenser.spec | 2 +- src/login.rs | 120 ---------------------- src/main.rs | 1 - src/manifests.rs | 34 ++++--- 8 files changed, 31 insertions(+), 395 deletions(-) delete mode 100644 src/login.rs diff --git a/Cargo.lock b/Cargo.lock index a156419..6f23850 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - [[package]] name = "aho-corasick" version = "1.1.3" @@ -72,21 +66,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "cc" -version = "1.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "clap" version = "4.5.18" @@ -133,18 +112,9 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - [[package]] name = "dispenser" -version = "0.1.0" +version = "0.2.0" dependencies = [ "base64", "clap", @@ -155,7 +125,6 @@ dependencies = [ "serde_json", "signal-hook", "toml", - "ureq", "urlencoding", ] @@ -188,36 +157,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "flate2" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -236,16 +175,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "2.5.0" @@ -286,27 +215,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - [[package]] name = "proc-macro2" version = "1.0.86" @@ -354,53 +262,6 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys", -] - -[[package]] -name = "rustls" -version = "0.23.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" - -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - [[package]] name = "ryu" version = "1.0.18" @@ -454,12 +315,6 @@ dependencies = [ "serde", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook" version = "0.3.17" @@ -479,24 +334,12 @@ dependencies = [ "libc", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - [[package]] name = "syn" version = "2.0.76" @@ -508,21 +351,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml" version = "0.8.19" @@ -557,62 +385,12 @@ dependencies = [ "winnow", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "untrusted" -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", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "serde", - "serde_json", - "url", - "webpki-roots", -] - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "urlencoding" version = "2.1.3" @@ -625,21 +403,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "webpki-roots" -version = "0.26.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -721,9 +484,3 @@ checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 05ec8b6..6dbbb01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dispenser" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT" @@ -14,5 +14,4 @@ serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" signal-hook = "0.3.17" toml = "0.8.19" -ureq = { version = "2.10.1", features = ["json"] } urlencoding = "2.1.3" diff --git a/Makefile b/Makefile index 84c442f..23b4444 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,25 @@ -.PHONY: build-deb build-rpm +.PHONY: build-deb build-rpm build WORK_DIR=$(shell pwd) TARGET_BIN=target/x86_64-unknown-linux-musl/release/dispenser USR_BIN_DEB=deb/usr/local/bin/dispenser USR_BIN_RPM=rpm/usr/local/bin/dispenser -$(TARGET_BIN): +build: CARGO_TARGET_DIR="./target" cargo build --release --target "x86_64-unknown-linux-musl" -$(USR_BIN_RPM): $(TARGET_BIN) - mkdir -p deb/usr/local/bin/ - mv $(TARGET_BIN) $(USR_BIN_RPM) - -$(USR_BIN_DEB): $(TARGET_BIN) +build-deb: build mkdir -p deb/usr/local/bin/ + rm -f $(USR_BIN_DEB) mv $(TARGET_BIN) $(USR_BIN_DEB) - -build-deb: $(USR_BIN_DEB) dpkg-deb --build deb + rm -f dispenser.deb mv deb.deb dispenser.deb -build-rpm: $(USR_BIN_RPM) +build-rpm: build + mkdir -p deb/usr/local/bin/ + rm -f $(USR_BIN_RPM) + mv $(TARGET_BIN) $(USR_BIN_RPM) cp -r rpm/ rpmbuild mkdir -p rpmbuild/opt/dispenser rpmbuild --target=x86_64 --buildroot $(WORK_DIR)/rpmbuild \ diff --git a/deb/DEBIAN/control b/deb/DEBIAN/control index 6153341..bd366db 100644 --- a/deb/DEBIAN/control +++ b/deb/DEBIAN/control @@ -1,5 +1,5 @@ Package: dispenser -Version: 0.1 +Version: 0.2 Maintainer: ixpantia S.A. Architecture: amd64 Description: Continously Deploy services with Docker Compose diff --git a/rpm/dispenser.spec b/rpm/dispenser.spec index 6f8ffd7..c01e042 100644 --- a/rpm/dispenser.spec +++ b/rpm/dispenser.spec @@ -1,5 +1,5 @@ Name: dispenser -Version: 0.1 +Version: 0.2 Release: 0 Summary: Continously Deploy services with Docker Compose License: see /usr/share/doc/dispenser/copyright diff --git a/src/login.rs b/src/login.rs deleted file mode 100644 index fe76d77..0000000 --- a/src/login.rs +++ /dev/null @@ -1,120 +0,0 @@ -use base64::Engine; -use std::collections::HashMap; -use std::env; -use std::error::Error; -use std::fs::File; -use std::io::BufReader; -use std::io::Write; -use std::path::PathBuf; -use std::process::Command; -use std::process::Stdio; - -#[derive(serde::Deserialize, Debug)] -struct AuthEntry { - auth: Option, -} - -#[derive(serde::Deserialize, Debug)] -struct DockerConfig { - auths: Option>, - #[serde(rename = "credsHelpers")] - creds_helpers: Option>, - #[serde(rename = "credsStore")] - creds_store: Option, -} - -fn get_docker_config_path() -> Result> { - let home_dir = env::var("HOME")?; - let docker_config_path = PathBuf::from(home_dir).join(".docker").join("config.json"); - Ok(docker_config_path) -} - -fn read_docker_config() -> Result> { - let docker_config_path = get_docker_config_path()?; - let file = BufReader::new(File::open(docker_config_path)?); - let config: DockerConfig = serde_json::from_reader(file)?; - Ok(config) -} - -#[derive(serde::Deserialize)] -struct CredStoreOutput { - #[serde(rename = "Username")] - username: String, - #[serde(rename = "Secret")] - secret: String, -} - -fn call_credential_helper( - helper: &str, - registry: &str, -) -> Result<(String, String), Box> { - let command = format!("docker-credential-{}", helper); - let mut process = Command::new(command) - .arg("get") - .stderr(Stdio::piped()) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn()?; - - let mut stdin = process.stdin.take().unwrap(); - stdin.write_all(registry.as_bytes())?; - drop(stdin); - - let output = process.wait_with_output()?; - let output_str = String::from_utf8(output.stdout)?; - - let creds: CredStoreOutput = serde_json::from_str(&output_str)?; - let username = urlencoding::encode(&creds.username).to_string(); - let secret = urlencoding::encode(&creds.secret).to_string(); - - Ok((username, secret)) -} - -fn decode_auth(auth: &str) -> Result<(String, String), Box> { - let decoded = base64::prelude::BASE64_STANDARD.decode(auth)?; - let decoded_str = String::from_utf8(decoded)?; - let parts: Vec<&str> = decoded_str.split(':').collect(); - - if parts.len() != 2 { - return Err("Invalid auth format".into()); - } - - Ok((parts[0].to_string(), parts[1].to_string())) -} - -pub fn get_docker_credentials_internal(registry: &str) -> Result<(String, String), Box> { - let config = read_docker_config()?; - - if let Some(cred_helpers) = config.creds_helpers { - if let Some(helper) = cred_helpers.get(registry) { - let helper_str = helper.as_str(); - return call_credential_helper(helper_str, registry); - } - } - - if let Some(helper) = config.creds_store { - let helper_str = helper.as_str(); - return call_credential_helper(helper_str, registry); - } - - // Fallback to plain text credentials from "auths" - if let Some(auths) = config.auths { - if let Some(auth_entry) = auths.get(registry) { - if let Some(auth) = auth_entry.auth.as_ref() { - return decode_auth(auth); - } - } - } - - Err("No credentials found".into()) -} - -pub fn get_docker_credentials(registry: &str) -> (String, String) { - match get_docker_credentials_internal(registry) { - Ok(creds) => creds, - Err(e) => { - log::error!("Error retrieving credentails for {registry}: {e:?}"); - std::process::exit(1); - } - } -} diff --git a/src/main.rs b/src/main.rs index fa3b008..1786c88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ use std::sync::{Arc, Mutex}; mod cli; mod config; mod instance; -mod login; mod manifests; mod master; mod signals; diff --git a/src/manifests.rs b/src/manifests.rs index aecf9e8..7adc0b0 100644 --- a/src/manifests.rs +++ b/src/manifests.rs @@ -1,4 +1,4 @@ -use crate::login::get_docker_credentials; +use std::io::Write; use std::sync::{Arc, Mutex}; #[derive(serde::Deserialize)] @@ -79,10 +79,8 @@ pub enum DockerWatcherStatus { impl DockerWatcher { pub fn initialize(registry: &str, image: &str, tag: &str) -> Self { log::info!("Initializing watch for {registry}/{image}:{tag}"); - let (user, password) = get_docker_credentials(registry); let last_digest = Arc::new(Mutex::new( - get_latest_digest(registry, &user, &password, image, tag) - .expect("There is no initial image digest"), + get_latest_digest(registry, image, tag).expect("There is no initial image digest"), )); let registry = registry.into(); @@ -97,9 +95,7 @@ impl DockerWatcher { } pub fn update(&self) -> DockerWatcherStatus { let last_digest = *self.last_digest.lock().expect("Unable to lock mutex"); - let (user, password) = get_docker_credentials(&self.registry); - let new_sha256 = - get_latest_digest(&self.registry, &user, &password, &self.image, &self.tag); + let new_sha256 = get_latest_digest(&self.registry, &self.image, &self.tag); match new_sha256 { None => DockerWatcherStatus::Deleted, Some(new_sha256) if last_digest == new_sha256 => DockerWatcherStatus::NotUpdated, @@ -117,14 +113,20 @@ impl DockerWatcher { } } -fn get_latest_digest( - registry: &str, - user: &str, - token: &str, - image: &str, - tag: &str, -) -> Option { - let url = format!("https://{user}:{token}@{registry}/v2/{image}/manifests/{tag}"); - let val: DockerManifestsResponse = ureq::get(&url).call().unwrap().into_json().unwrap(); +fn get_latest_digest(registry: &str, image: &str, tag: &str) -> Option { + let output_result = std::process::Command::new("docker") + .args(["manifest", "inspect"]) + .arg(format!("{registry}/{image}:{tag}")) + .output(); + let val: DockerManifestsResponse = match output_result { + Ok(manifest_output) => { + std::io::stdout().write_all(&manifest_output.stdout); + serde_json::from_slice(&manifest_output.stdout).ok()? + } + Err(e) => { + log::error!("Unable to get manifest for {registry}/{image}:{tag}: {e}"); + return None; + } + }; val.get_digest("amd64", "linux") }