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
|
uses: https://github.com/RouxAntoine/checkout@v3.5.4
|
||||||
with:
|
with:
|
||||||
ref: trunk
|
ref: trunk
|
||||||
- name: Build and Push ARM Image
|
- name: Build Image
|
||||||
uses: https://github.com/docker/build-push-action@v4.1.1
|
run: nix build .#docker
|
||||||
with:
|
- name: Load and tag image
|
||||||
push: true
|
run: |
|
||||||
tags: icr.gmem.ca/dref:arm
|
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"
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "docker-rs-dashboard"
|
name = "dref"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-extra",
|
"axum-extra",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "docker-rs-dashboard"
|
name = "dref"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# 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 = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
craneLib = crane.lib.${system};
|
craneLib = crane.lib.${system};
|
||||||
my-crate = craneLib.buildPackage {
|
dref = craneLib.buildPackage {
|
||||||
src = craneLib.cleanCargoSource ./.;
|
src = craneLib.cleanCargoSource ./.;
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
dockerImage = pkgs.dockerTools.buildImage {
|
dockerImage = pkgs.dockerTools.buildImage {
|
||||||
name = "dref";
|
name = "dref";
|
||||||
config = {
|
config = {
|
||||||
Cmd = [ "${my-crate}/bin/docker-rs-dashboard" ];
|
Cmd = [ "${dref}/bin/dref" ];
|
||||||
ExposedPorts = {
|
ExposedPorts = {
|
||||||
"3000/tcp" = {};
|
"3000/tcp" = {};
|
||||||
};
|
};
|
||||||
|
@ -47,15 +47,15 @@
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
checks = {
|
checks = {
|
||||||
inherit my-crate;
|
inherit dref;
|
||||||
};
|
};
|
||||||
|
|
||||||
apps.default = flake-utils.lib.mkApp {
|
apps.default = flake-utils.lib.mkApp {
|
||||||
drv = my-crate;
|
drv = dref;
|
||||||
};
|
};
|
||||||
|
|
||||||
packages = rec {
|
packages = rec {
|
||||||
bin = my-crate;
|
bin = dref;
|
||||||
docker = dockerImage;
|
docker = dockerImage;
|
||||||
default = pkgs.symlinkJoin {
|
default = pkgs.symlinkJoin {
|
||||||
name = "dref-${bin.version}";
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
84
src/main.rs
84
src/main.rs
|
@ -2,33 +2,24 @@ mod css;
|
||||||
|
|
||||||
use std::{boxed, error, env, collections::{HashMap, self}};
|
use std::{boxed, error, env, collections::{HashMap, self}};
|
||||||
use maud::{html, Markup, DOCTYPE};
|
use maud::{html, Markup, DOCTYPE};
|
||||||
use axum::{Router, routing::get, response::IntoResponse};
|
use axum::{Router, routing::get, response::IntoResponse, extract::State};
|
||||||
use futures::{stream::StreamExt, future::join_all};
|
use dref;
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
// To be expanded upon.
|
#[derive(Clone)]
|
||||||
#[derive(Debug)]
|
struct AppState {
|
||||||
struct Image {
|
registry: dref::Registry
|
||||||
name: String,
|
|
||||||
tags: Vec<RichTag>,
|
|
||||||
}
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct RichTag {
|
|
||||||
name: String,
|
|
||||||
architectures: Vec<String>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Tags {
|
|
||||||
name: String,
|
|
||||||
tags: Vec<String>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
|
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
let registry = dref::Registry{
|
||||||
|
url: env::var("DREF_REGISTRY").unwrap(),
|
||||||
|
};
|
||||||
|
let state = AppState {registry};
|
||||||
// build our application with a single route
|
// build our application with a single route
|
||||||
let app = Router::new()
|
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
|
// run it with hyper on localhost:3000
|
||||||
println!("Running webserver on port :3000");
|
println!("Running webserver on port :3000");
|
||||||
|
@ -61,27 +52,21 @@ fn footer() -> Markup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn root() -> Markup {
|
async fn root(State(state): State<AppState>) -> Markup {
|
||||||
let c = get_images().await.unwrap_or_else(|e| panic!("{}", e));
|
let c = state.registry.images().await.unwrap();
|
||||||
html! {
|
html! {
|
||||||
(header("/DREF"))
|
(header("/DREF"))
|
||||||
body {
|
body {
|
||||||
main {
|
main {
|
||||||
h1 { "/DREF" }
|
h1 { "/DREF" }
|
||||||
hr;
|
hr;
|
||||||
@for image in &c {
|
@for image in c {
|
||||||
div {
|
div {
|
||||||
details {
|
details {
|
||||||
summary { (image.name) }
|
summary { (image.name) }
|
||||||
ul {
|
ul {
|
||||||
@for tag in &image.tags {
|
@for tag in state.registry.image_tags(image.name).await.unwrap() {
|
||||||
li { (tag.name)
|
li { (tag.name) }
|
||||||
// div {
|
|
||||||
// @for arch in &tag.architectures {
|
|
||||||
// span { (arch) }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,40 +77,3 @@ async fn root() -> Markup {
|
||||||
(footer())
|
(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