Compare commits
2 commits
e9c4c3d0a6
...
4883c89b36
Author | SHA1 | Date | |
---|---|---|---|
Gabriel Simmer | 4883c89b36 | ||
Gabriel Simmer | 3aea275d8f |
|
@ -12,9 +12,9 @@ jobs:
|
|||
uses: https://github.com/RouxAntoine/checkout@v3.5.4
|
||||
with:
|
||||
ref: trunk
|
||||
- name: Build and Push ARM Image
|
||||
uses: https://github.com/docker/build-push-action@v4.1.1
|
||||
with:
|
||||
push: true
|
||||
tags: icr.gmem.ca/dref:arm
|
||||
|
||||
- name: Build Image
|
||||
run: nix build .#docker
|
||||
- name: Load and tag image
|
||||
run: |
|
||||
docker tag $(docker load < result) icr.gmem.ca/dref:arm
|
||||
docker push icr.gmem.ca/dref:arm
|
||||
|
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -170,8 +170,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "docker-rs-dashboard"
|
||||
version = "0.1.0"
|
||||
name = "dref"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-extra",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "docker-rs-dashboard"
|
||||
version = "0.1.0"
|
||||
name = "dref"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
12
flake.nix
12
flake.nix
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
description = "Build a cargo project without extra checks";
|
||||
description = "Docker registry frontend & basic library";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
|
@ -22,7 +22,7 @@
|
|||
};
|
||||
|
||||
craneLib = crane.lib.${system};
|
||||
my-crate = craneLib.buildPackage {
|
||||
dref = craneLib.buildPackage {
|
||||
src = craneLib.cleanCargoSource ./.;
|
||||
|
||||
buildInputs = [
|
||||
|
@ -38,7 +38,7 @@
|
|||
dockerImage = pkgs.dockerTools.buildImage {
|
||||
name = "dref";
|
||||
config = {
|
||||
Cmd = [ "${my-crate}/bin/docker-rs-dashboard" ];
|
||||
Cmd = [ "${dref}/bin/dref" ];
|
||||
ExposedPorts = {
|
||||
"3000/tcp" = {};
|
||||
};
|
||||
|
@ -47,15 +47,15 @@
|
|||
in
|
||||
{
|
||||
checks = {
|
||||
inherit my-crate;
|
||||
inherit dref;
|
||||
};
|
||||
|
||||
apps.default = flake-utils.lib.mkApp {
|
||||
drv = my-crate;
|
||||
drv = dref;
|
||||
};
|
||||
|
||||
packages = rec {
|
||||
bin = my-crate;
|
||||
bin = dref;
|
||||
docker = dockerImage;
|
||||
default = pkgs.symlinkJoin {
|
||||
name = "dref-${bin.version}";
|
||||
|
|
58
src/lib.rs
Normal file
58
src/lib.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{boxed, error};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Registry {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Image {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RichTag {
|
||||
pub name: String,
|
||||
architectures: Vec<String>
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Tags {
|
||||
name: String,
|
||||
tags: Vec<String>
|
||||
}
|
||||
|
||||
impl Registry {
|
||||
pub async fn images(&self) -> Result<Vec<Image>, boxed::Box<dyn error::Error>> {
|
||||
let resq_url = format!("{}/v2/_catalog", self.url);
|
||||
let resp = reqwest::get(resq_url)
|
||||
.await?
|
||||
.json::<HashMap<String, Vec<String>>>()
|
||||
.await?;
|
||||
let i = resp.get("repositories").unwrap().into_iter().map(|i| async {
|
||||
Image{
|
||||
name: i.to_string(),
|
||||
}
|
||||
});
|
||||
let images: Vec<Image> = futures::future::join_all(i).await;
|
||||
Ok(images)
|
||||
}
|
||||
pub async fn image_tags(&self, image: String) -> Result<Vec<RichTag>, boxed::Box<dyn error::Error>> {
|
||||
let resq_url = format!("{}/v2/{}/tags/list", self.url, image);
|
||||
let resp: Tags = reqwest::get(resq_url)
|
||||
.await?
|
||||
.json::<Tags>()
|
||||
.await?;
|
||||
let i = resp.tags.into_iter().map(|i| async move {
|
||||
RichTag{
|
||||
name: i.to_string(),
|
||||
architectures: Vec::new(),
|
||||
}
|
||||
});
|
||||
let tags: Vec<RichTag> = futures::future::join_all(i).await;
|
||||
Ok(tags)
|
||||
}
|
||||
}
|
||||
|
88
src/main.rs
88
src/main.rs
|
@ -2,33 +2,24 @@ mod css;
|
|||
|
||||
use std::{boxed, error, env, collections::{HashMap, self}};
|
||||
use maud::{html, Markup, DOCTYPE};
|
||||
use axum::{Router, routing::get, response::IntoResponse};
|
||||
use futures::{stream::StreamExt, future::join_all};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use axum::{Router, routing::get, response::IntoResponse, extract::State};
|
||||
use dref;
|
||||
|
||||
// To be expanded upon.
|
||||
#[derive(Debug)]
|
||||
struct Image {
|
||||
name: String,
|
||||
tags: Vec<RichTag>,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
struct RichTag {
|
||||
name: String,
|
||||
architectures: Vec<String>
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Tags {
|
||||
name: String,
|
||||
tags: Vec<String>
|
||||
#[derive(Clone)]
|
||||
struct AppState {
|
||||
registry: dref::Registry
|
||||
}
|
||||
|
||||
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
|
||||
async fn main() {
|
||||
let registry = dref::Registry{
|
||||
url: env::var("DREF_REGISTRY").unwrap(),
|
||||
};
|
||||
let state = AppState {registry};
|
||||
// build our application with a single route
|
||||
let app = Router::new()
|
||||
.route("/", get(root)).route("/styles.css", get(css));
|
||||
.route("/", get(root)).route("/styles.css", get(css))
|
||||
.with_state(state);
|
||||
|
||||
// run it with hyper on localhost:3000
|
||||
println!("Running webserver on port :3000");
|
||||
|
@ -48,7 +39,7 @@ async fn css() -> impl IntoResponse {
|
|||
fn header(page_title: &str) -> Markup {
|
||||
html! {
|
||||
(DOCTYPE)
|
||||
meta charset="utf-8";
|
||||
meta charset="utf-8";
|
||||
title { (page_title) }
|
||||
link rel="stylesheet" href="/styles.css";
|
||||
}
|
||||
|
@ -61,29 +52,23 @@ fn footer() -> Markup {
|
|||
}
|
||||
}
|
||||
|
||||
async fn root() -> Markup {
|
||||
let c = get_images().await.unwrap_or_else(|e| panic!("{}", e));
|
||||
async fn root(State(state): State<AppState>) -> Markup {
|
||||
let c = state.registry.images().await.unwrap();
|
||||
html! {
|
||||
(header("/DREF"))
|
||||
body {
|
||||
main {
|
||||
h1 { "/DREF" }
|
||||
hr;
|
||||
@for image in &c {
|
||||
@for image in c {
|
||||
div {
|
||||
details {
|
||||
summary { (image.name) }
|
||||
ul {
|
||||
@for tag in &image.tags {
|
||||
li { (tag.name)
|
||||
// div {
|
||||
// @for arch in &tag.architectures {
|
||||
// span { (arch) }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@for tag in state.registry.image_tags(image.name).await.unwrap() {
|
||||
li { (tag.name) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,40 +77,3 @@ async fn root() -> Markup {
|
|||
(footer())
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_images() -> Result<Vec<Image>, boxed::Box<dyn error::Error>> {
|
||||
let host = env::var("DREF_REGISTRY").unwrap();
|
||||
let resp = reqwest::get(host + "/v2/_catalog")
|
||||
.await?
|
||||
.json::<HashMap<String, Vec<String>>>()
|
||||
.await?;
|
||||
let i = resp.get("repositories").unwrap().into_iter().map(|i| async {
|
||||
let tags = get_tags(i.to_string()).await;
|
||||
Image{
|
||||
name: i.to_string(),
|
||||
tags: tags.unwrap(),
|
||||
}
|
||||
});
|
||||
let images: Vec<Image> = futures::future::join_all(i).await;
|
||||
Ok(images)
|
||||
}
|
||||
|
||||
async fn get_tags(image: String) -> Result<Vec<RichTag>, boxed::Box<dyn error::Error>> {
|
||||
let host = env::var("DREF_REGISTRY").unwrap();
|
||||
let resp: Tags = reqwest::get(host + "/v2/" + &image + "/tags/list")
|
||||
.await?
|
||||
.json::<Tags>()
|
||||
.await?;
|
||||
let i = resp.tags.into_iter().map(|i| async move {
|
||||
RichTag{
|
||||
name: i.to_string(),
|
||||
architectures: Vec::new(),
|
||||
}
|
||||
});
|
||||
let tags: Vec<RichTag> = futures::future::join_all(i).await;
|
||||
Ok(tags)
|
||||
}
|
||||
|
||||
async fn get_platforms(image: &String, tag: String) -> Result<Vec<String>, boxed::Box<dyn error::Error>> {
|
||||
todo!()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue