Compare commits

...

2 commits

Author SHA1 Message Date
Gabriel Simmer 4883c89b36
Use nix to build docker image
Some checks failed
Build Docker Image / arm-docker-build (push) Failing after 4s
2023-07-16 19:24:57 +01:00
Gabriel Simmer 3aea275d8f
Split common functions into lib.rs 2023-07-16 19:20:39 +01:00
6 changed files with 93 additions and 87 deletions

View file

@ -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
View file

@ -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",

View file

@ -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

View file

@ -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
View 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)
}
}

View file

@ -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!()
}