Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/console/commands/debug/casbin.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::configuration::get_configuration;
use actix_web::{rt, post, web, HttpResponse, Result, http::header::ContentType};
use crate::middleware;
//use actix_casbin_auth::casbin::CoreApi;
use casbin::CoreApi;
use sqlx::PgPool;

Expand Down
36 changes: 36 additions & 0 deletions src/console/commands/debug/dockerhub.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use actix_web::{rt, Result};
use crate::helpers::dockerhub::DockerHub;
use crate::forms::project::DockerImage;

use tracing_subscriber::FmtSubscriber;

pub struct DockerhubCommand {
json: String,
}

impl DockerhubCommand {
pub fn new(json: String) -> Self {
Self { json }
}
}

impl crate::console::commands::CallableTrait for DockerhubCommand {
fn call(&self) -> Result<(), Box<dyn std::error::Error>> {
let subscriber = FmtSubscriber::builder()
.with_max_level(tracing::Level::DEBUG)
.finish();
tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed");


rt::System::new().block_on(async {
println!("{}", self.json);
let dockerImage: DockerImage = serde_json::from_str(&self.json)?;
let mut dockerhub = DockerHub::try_from(&dockerImage)?;
let isActive = dockerhub.is_active().await?;

println!("image is active: {isActive}");

Ok(())
})
}
}
2 changes: 2 additions & 0 deletions src/console/commands/debug/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod json;
mod casbin;
mod dockerhub;

pub use json::*;
pub use casbin::*;
pub use dockerhub::*;
7 changes: 7 additions & 0 deletions src/console/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ enum DebugCommands {
#[arg(long)]
subject: String,
},
Dockerhub {
#[arg(long)]
json: String,
}
}

#[derive(Debug, Subcommand)]
Expand Down Expand Up @@ -76,6 +80,9 @@ fn get_command(cli: Cli) -> Result<Box<dyn stacker::console::commands::CallableT
DebugCommands::Casbin { action, path, subject } => Ok(Box::new(
stacker::console::commands::debug::CasbinCommand::new(action, path, subject),
)),
DebugCommands::Dockerhub { json } => Ok(Box::new(
stacker::console::commands::debug::DockerhubCommand::new(json),
)),
},
Commands::MQ { command} => match command {
AppMqCommands::Listen {} => Ok(Box::new(
Expand Down
105 changes: 44 additions & 61 deletions src/helpers/dockerhub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde_valid::Validate;

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
pub struct DockerHubToken {
pub token: Option<String>,
pub token: String,
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize, Validate)]
Expand Down Expand Up @@ -104,30 +104,38 @@ pub struct DockerHub<'a> {
}

impl<'a> DockerHub<'a> {
pub async fn login(&'a self) -> Result<DockerHubToken, String> {
let endpoint = "https://hub.docker.com/v2/users/login";

#[tracing::instrument(name = "Dockerhub login.")]
pub async fn login(&'a self) -> Result<String, String> {
if self.creds.password.is_empty() {
return Err("Password is empty".to_string());
}

if self.creds.username.is_empty() {
return Err("Username is empty".to_string());
}

let url = "https://hub.docker.com/v2/users/login";
reqwest::Client::new()
.post(endpoint)
.post(url)
.json(&self.creds)
.send()
.await
.map_err(|err| format!("{:?}", err))?
.json::<DockerHubToken>()
.await
.map(|dockerHubToken| dockerHubToken.token)
.map_err(|err| format!("{:?}", err))
}

#[tracing::instrument(name = "Lookup public repos")]
pub async fn lookup_public_repos(&'a self) -> Result<bool, String> {

let url = format!("https://hub.docker.com/v2/repositories/{}", self.repos);
tracing::debug!("Validate public repository {:?}", &url);
let client = reqwest::Client::new()
.get(&url)
.header("Accept", "application/json");
let client = self.set_token(client).await?;
client
.send()

client.send()
.await
.map_err(|err| {
let msg = format!("🟥Error response {:?}", err);
Expand All @@ -149,29 +157,23 @@ impl<'a> DockerHub<'a> {
.results
.into_iter()
.any(|repo| repo.status == Some(1));
tracing::debug!("✅ Image is active. url: {:?}", &url);
tracing::debug!("✅ Public mage is active. url: {:?}", &url);
active
} else {
tracing::debug!("🟥 Image tag is not active, url: {:?}", &url);
tracing::debug!("🟥 Public image tag is not active, url: {:?}", &url);
false
}
})
}

#[tracing::instrument(name = "Lookup official repos")]
pub async fn lookup_official_repos(&'a self) -> Result<bool, String> {
// search in official library repositories
let url = format!("https://hub.docker.com/v2/repositories/library/{}/tags", self.repos);
return self.lookup(&url).await;
}

pub async fn lookup(&'a self, url: &String) -> Result<bool, String> {
tracing::debug!("Search official repos {:?}", url);
let client = reqwest::Client::new()
.get(url)
.header("Accept", "application/json");
let client = self.set_token(client).await?;
client
.send()

client.send()
.await
.map_err(|err| format!("🟥{}", err))?
.json::<OfficialRepoResults>()
Expand All @@ -190,32 +192,35 @@ impl<'a> DockerHub<'a> {
.any(|tag| {
tracing::debug!("official: {:?}", tag);
if "active".to_string() == tag.tag_status {
tracing::debug!("✅ Image is active");
true
} else {
false
}
});
tracing::debug!("✅ search official repos result is {:?}", result);
tracing::debug!("✅ Official mage is active. url: {:?}", result);
result
} else {
tracing::debug!("🟥 Image tag is not active");
tracing::debug!("🟥 Official image tag is not active");
false
}
})
}

#[tracing::instrument(name = "Lookup private repos")]
pub async fn lookup_private_repo(&'a self) -> Result<bool, String> {
let token = self.login().await?;

let url = format!(
"https://hub.docker.com/v2/namespaces/{}/repositories/{}/tags",
&self.creds.username, &self.repos
);
tracing::debug!("Validate image {:?}", url);

tracing::debug!("Search private repos {:?}", url);
let client = reqwest::Client::new()
.get(url)
.header("Accept", "application/json");
let client = self.set_token(client).await?;
client

client.bearer_auth(token)
.send()
.await
.map_err(|err| format!("🟥{}", err))?
Expand All @@ -233,15 +238,15 @@ impl<'a> DockerHub<'a> {
.results
.into_iter()
.any(|tag| tag.tag_status.contains("active"));
tracing::debug!("✅ Image is active");
return active;
} else {
tracing::debug!("🟥 Image tag is not active");
false
}
})
}
pub async fn is_active(&'a mut self) -> Result<bool, String> {

pub async fn is_active(&'a self) -> Result<bool, String> {
// if namespace/user is not set change endpoint and return a different response

// let n = self.repos
Expand All @@ -262,45 +267,23 @@ impl<'a> DockerHub<'a> {
// }
// }

if self.creds.username.is_empty() {

if Ok(true) == self.lookup_official_repos().await {
tracing::debug!("official: true");
return Ok(true);
} else {
tracing::debug!("official: false");
};
tokio::select! {
Ok(true) = self.lookup_official_repos() => {
tracing::debug!("official: true");
return Ok(true);
}

if Ok(true) == self.lookup_public_repos().await {
Ok(true) = self.lookup_public_repos() => {
tracing::debug!("public: true");
return Ok(true);
};

Ok(false)

} else {
}

if Ok(true) == self.lookup_private_repo().await {
Ok(true) = self.lookup_private_repo() => {
tracing::debug!("private: true");
return Ok(true);
};

Ok(false)
}
}

pub async fn set_token(&'a self, client: RequestBuilder) -> Result<RequestBuilder, String> {
if self.creds.password.is_empty() {
tracing::debug!("Password is empty. Image should be public");
return Ok(client);
} else {
}
tracing::debug!("Password is set. Login..");
let token = self.login().await?;
}

match token.token {
None => Ok(client),
Some(token) => Ok(client.bearer_auth(token)),
else => { return Ok(false); }
}
}
}
Expand Down Expand Up @@ -362,4 +345,4 @@ impl<'a> TryFrom<&'a DockerImage> for DockerHub<'a> {

Ok(hub)
}
}
}
2 changes: 1 addition & 1 deletion tests/dockerhub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ async fn test_docker_named_volume() {
container_path: Some("/var/www/flaskdata".to_owned()),
};

let cv:ComposeVolume = volume.into();
let cv:ComposeVolume = (&volume).into();
println!("ComposeVolume: {:?}", cv);
println!("{:?}", cv.driver_opts);
assert_eq!(Some("flask-data".to_string()), cv.name);
Expand Down