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, } #[derive(Debug, Deserialize)] pub struct ImageTags { pub name: String, pub tags: Vec, } 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, Box> { 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::()?; Ok(data.repositories) } pub fn get_image_tags( &self, image_name: &str, ) -> Result> { 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::()?; Ok(data) } pub fn get_image_tag_manifest( &self, image_name: &str, tag: &str, ) -> Result> { 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> { 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(()) } }