registry-cleaner/src/api/registry.rs

162 lines
3.7 KiB
Rust

use reqwest;
use serde::Deserialize;
use std::collections::HashMap;
use url::Url;
pub struct Registry<'a> {
pub url: &'a str,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub struct RepositoryList {
pub repositories: Vec<String>,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
pub struct RepositoryTags {
pub name: String,
pub tags: Option<Vec<String>>,
}
#[allow(dead_code, non_snake_case)]
#[derive(Debug, Deserialize)]
pub struct RepositoryTagManifest {
pub name: String,
pub tag: String,
pub history: Vec<HashMap<String, String>>,
#[serde(skip)]
pub ts: i64,
#[serde(skip)]
pub digest: String,
}
#[derive(Debug, Deserialize)]
struct History {
created: Option<String>,
}
impl<'a> Registry<'a> {
pub async fn get_repositories(&self) -> Result<RepositoryList, Box<dyn std::error::Error>> {
let registry_url = Url::parse(self.url).unwrap();
let api_url = registry_url.join("/v2/_catalog").unwrap();
let resp = reqwest::get(api_url)
.await?
.json::<RepositoryList>()
.await?;
Ok(resp)
}
pub async fn get_repository_tags(
&self,
repo: &str,
) -> Result<RepositoryTags, Box<dyn std::error::Error>> {
let registry_url = Url::parse(self.url).unwrap();
let api_url = registry_url
.join(format!("/v2/{}/tags/list", repo).as_str())
.unwrap();
let resp = reqwest::get(api_url).await?;
let data = resp.json::<RepositoryTags>().await?;
Ok(data)
}
pub async fn get_repository_tag_manifest(
&self,
repo: &str,
tag: &str,
) -> Result<RepositoryTagManifest, Box<dyn std::error::Error>> {
let registry_url = Url::parse(self.url).unwrap();
let api_url = registry_url
.join(format!("/v2/{}/manifests/{}", repo, tag).as_str())
.unwrap();
let resp = reqwest::get(api_url.clone()).await?;
// let digest = resp
// .headers()
// .get("Docker-Content-Digest")
// .unwrap()
// .to_str()
// .unwrap()
// .to_string();
let digest = reqwest::Client::new()
.get(api_url.clone())
.header(
reqwest::header::ACCEPT,
"application/vnd.docker.distribution.manifest.v2+json",
)
.send()
.await?
.headers()
.get("Docker-Content-Digest")
.unwrap()
.to_str()
.unwrap()
.to_string();
let mut data = resp.json::<RepositoryTagManifest>().await?;
let ts = data.history.iter().fold(0, |acc, d| {
match d.get("v1Compatibility") {
None => acc,
Some(s) => {
// println!("{}", (*s))
let h: History = serde_json::from_str(s).unwrap_or(History { created: None });
match h.created {
None => acc,
Some(time_str) => {
let result = chrono::DateTime::parse_from_rfc3339(time_str.as_str());
match result {
Ok(t) => {
let tt = t.timestamp();
if acc > tt {
acc
} else {
tt
}
}
Err(_) => acc,
}
}
}
}
}
});
data.history.clear();
data.ts = ts;
data.digest = digest;
Ok(data)
}
pub async fn delete_repository_tag(
&self,
repo: &str,
digest: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let registry_url = Url::parse(self.url).unwrap();
let api_url = registry_url
.join(format!("/v2/{}/manifests/{}", repo, digest).as_str())
.unwrap();
// println!("url:: {}", api_url);
let client = reqwest::Client::new();
client.delete(api_url).send().await?;
// println!("Status : {}", resp.status());
// if resp.status().as_u16() >= 400 {
// }
Ok(())
}
}