update
This commit is contained in:
parent
8c4096882c
commit
a8d59e48d1
1077
Cargo.lock
generated
Normal file
1077
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,3 +6,10 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crossterm = "0.22.1"
|
||||
reqwest = { version = "0.11", features = ["json", "blocking"] }
|
||||
serde = {version = "1.0.136", features = ["derive"]}
|
||||
serde_json = "1.0.78"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tui = "0.17.0"
|
||||
|
||||
|
28
src/main.rs
28
src/main.rs
@ -1,3 +1,31 @@
|
||||
mod registry;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
|
||||
let r = registry::api::Registry {
|
||||
endpoint: "https://docker.mtfos.xyz".to_string(),
|
||||
user: "".to_string(),
|
||||
password: "".to_string(),
|
||||
};
|
||||
|
||||
// let images = r.list_images().unwrap();
|
||||
|
||||
// println!("images ::: {:?}", images);
|
||||
|
||||
// let tags = r.get_image_tags("mtfos/go-bot").unwrap();
|
||||
|
||||
// println!("tags ::: {:?}", tags);
|
||||
|
||||
let digest = match r.get_image_tag_manifest("demo/node-hello", "v1") {
|
||||
Ok(digest) => digest,
|
||||
Err(e) => panic!("digest err ::: {:?}", e),
|
||||
};
|
||||
|
||||
println!("digest ::: {:?}", digest);
|
||||
|
||||
match r.delete_image_tag("demo/node-hello", &digest) {
|
||||
Ok(_) => println!("deleted"),
|
||||
Err(e) => println!("error ::: {:?}", e),
|
||||
};
|
||||
}
|
||||
|
154
src/registry/api.rs
Normal file
154
src/registry/api.rs
Normal file
@ -0,0 +1,154 @@
|
||||
use reqwest;
|
||||
use serde::Deserialize;
|
||||
// use serde_json;
|
||||
|
||||
#[warn(dead_code)]
|
||||
pub struct Registry {
|
||||
pub endpoint: String,
|
||||
pub user: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct RegistryRepository {
|
||||
repositories: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ImageTags {
|
||||
pub name: String,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
impl Registry {
|
||||
fn get_request(&self, method: &str, path: &str) -> reqwest::blocking::RequestBuilder {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
let url = format!("{}{}", self.endpoint, path);
|
||||
|
||||
let mut m = match method {
|
||||
"GET" => client.get(&url),
|
||||
"POST" => client.post(&url),
|
||||
"PUT" => client.put(&url),
|
||||
"DELETE" => client.delete(&url),
|
||||
_ => panic!("Unsupported method"),
|
||||
};
|
||||
|
||||
if (self.user.len() > 0) && (self.password.len() > 0) {
|
||||
m = m.basic_auth(&self.user, Some(&self.password));
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
pub fn list_images(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
|
||||
let url = "/v2/_catalog";
|
||||
let builder = self.get_request("GET", &url);
|
||||
let resp = builder.send()?;
|
||||
|
||||
let headers = resp.headers().to_owned();
|
||||
|
||||
if !headers
|
||||
.get("Content-Type")
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.starts_with("application/json")
|
||||
{
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"Invalid Content-Type",
|
||||
)));
|
||||
}
|
||||
|
||||
let data = resp.json::<RegistryRepository>()?;
|
||||
|
||||
Ok(data.repositories)
|
||||
}
|
||||
|
||||
pub fn get_image_tags(
|
||||
&self,
|
||||
image_name: &str,
|
||||
) -> Result<ImageTags, Box<dyn std::error::Error>> {
|
||||
let url = format!("/v2/{}/tags/list", image_name);
|
||||
|
||||
let builder = self.get_request("GET", &url);
|
||||
|
||||
let resp = builder.send()?;
|
||||
|
||||
let headers = resp.headers().to_owned();
|
||||
|
||||
println!("\n{:?}\n", headers);
|
||||
|
||||
if !headers
|
||||
.get("Content-Type")
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.starts_with("application/json")
|
||||
{
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"Invalid Content-Type",
|
||||
)));
|
||||
}
|
||||
|
||||
let data = resp.json::<ImageTags>()?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn get_image_tag_manifest(
|
||||
&self,
|
||||
image_name: &str,
|
||||
tag: &str,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let url = format!("/v2/{}/manifests/{}", image_name, tag);
|
||||
|
||||
let mut builder = self.get_request("GET", &url);
|
||||
|
||||
builder = builder.header(
|
||||
reqwest::header::ACCEPT,
|
||||
"application/vnd.docker.distribution.manifest.v2+json",
|
||||
);
|
||||
let resp = builder.send()?;
|
||||
|
||||
if !resp.status().is_success() {
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"request failed",
|
||||
)));
|
||||
}
|
||||
|
||||
let headers = resp.headers().to_owned();
|
||||
|
||||
let digest = headers
|
||||
.get("Docker-Content-Digest")
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
Ok(digest)
|
||||
}
|
||||
|
||||
pub fn delete_image_tag(
|
||||
&self,
|
||||
image_name: &str,
|
||||
digest: &str,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let url = format!("/v2/{}/manifests/{}", image_name, digest);
|
||||
|
||||
let builder = self.get_request("DELETE", &url);
|
||||
|
||||
let resp = builder.send()?;
|
||||
|
||||
if !resp.status().is_success() {
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"request failed",
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
1
src/registry/mod.rs
Normal file
1
src/registry/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod api;
|
Loading…
Reference in New Issue
Block a user