Skip to content

Commit

Permalink
Merge pull request #46 from ublue-os/tepene/43_registry-info
Browse files Browse the repository at this point in the history
feat(nicegui): add information about available images in container registry (#43)
  • Loading branch information
tepene authored May 15, 2024
2 parents 7f39100 + 12cdc3c commit ed9a36b
Show file tree
Hide file tree
Showing 17 changed files with 445 additions and 14 deletions.
2 changes: 2 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"version": "1.8.2"
}
},
// Additional arguments when starting the container
"runArgs": ["--add-host=host.docker.internal:host-gateway"],
// Create symbolic link for forge data dir mount
"initializeCommand": "${localWorkspaceFolder}/.devcontainer/prepare_mount.sh",
// Container user definition - This is needed for compatibility with podman -> https://github.com/containers/podman/issues/15001#issuecomment-1193321924
Expand Down
14 changes: 14 additions & 0 deletions .devcontainer/install-dev-tools.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ YELLOW="\e[33m"
GREEN="\e[32m"
ENDCOLOR="\e[0m"

# Add Forge DEV DNS entries
echo ""
echo -e "${YELLOW}Adding DNS entries for ublue.local${ENDCOLOR}"
echo ""
DOCKER_HOST=$(getent hosts host.docker.internal | awk '{ print $1 }')
echo "$DOCKER_HOST registry.ublue.local" | sudo tee -a /etc/hosts

## Install SSL certificates
echo ""
echo -e "${YELLOW}Installing SSL certificates${ENDCOLOR}"
echo ""
sudo cp /data/ublue-os_forge-root.pem /usr/local/share/ca-certificates/ublue-os_forge-root.crt
sudo update-ca-certificates --fresh

## Update system
echo ""
echo -e "${YELLOW}Updating OS${ENDCOLOR}"
Expand Down
4 changes: 4 additions & 0 deletions .vscode/cspell_custom.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
aggrid
CHACHA
configmap
Containerfile
containerignore
devcontainer
devcontainers
dotenv
ENDCOLOR
ensurepath
envsubst
filepicker
getent
gitmessage
hostvars
humanfriendly
keygen
LAZYGIT
lightspeed
lineinfile
minica
Mountpoint
naturalsize
nicegui
noarchive
noimageindex
Expand Down
3 changes: 3 additions & 0 deletions anvil/ansible/group_vars/all/container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
forge_container_file: "Containerfile"
forge_container_format: "oci"
4 changes: 2 additions & 2 deletions anvil/ansible/playbooks/project_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
tag: latest
path: "{{ forge_git_repository_destination }}"
build:
file: Containerfile
format: oci
file: "{{ forge_container_file | default('Containerfile') }}"
format: "{{ forge_container_format | default('oci') }}"
pull: false
push: true
push_args:
Expand Down
3 changes: 1 addition & 2 deletions anvil/nicegui/pages/ansible.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
from nicegui import ui
from theme import GuiProgressSpinner
from utils import local_file_picker
from utils.filepicker import local_file_picker

ANSIBLE_EXTRA_VARS = None

Expand Down Expand Up @@ -117,5 +117,4 @@ def content() -> None:
with ui.card().classes("w-full"):
ui.label("Playbook Log").classes("text-h6")
ui.button("Clear Log", on_click=lambda: gui_playbook_log.clear())

gui_playbook_log = ui.log().classes("w-full h-full")
40 changes: 34 additions & 6 deletions anvil/nicegui/pages/registry.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
import pandas
import humanize
from nicegui import ui
import os
from utils.registry import DockerRegistry


## TODO: this should be async but I currently don't know how to implement this without button press
def get_image_info() -> pandas.DataFrame:
registry = DockerRegistry()
all_image_info = registry.get_all_image_info()
if isinstance(all_image_info, list) and len(all_image_info) > 0:
data = pandas.json_normalize(
all_image_info,
record_path=["tags"],
meta=[["name"]],
meta_prefix="image_",
).assign(
size=lambda x: x["manifest.layers"].apply(
lambda layers: sum(layer["size"] for layer in layers)
)
)
data = data[["image_name", "name", "size"]].rename(
columns={"image_name": "image", "name": "tag", "size": "size"}
)
data["size"] = data["size"].apply(humanize.naturalsize)
return data
else:
ui.notify(message="No images found")
data = pandas.DataFrame(columns=["image_name", "tag", "size"])
return data


def content() -> None:
project_root = os.environ['NICEGUI_DIR']
ui.label("Work in progress...").classes("text-h6")
ui.image(project_root + "/pages/assets/work-in-progress.png").classes(
"w-[200%]"
)
with ui.row().classes("w-full"):
with ui.card().classes("w-full"):
ui.label("Image Overview").classes("text-h5")
data = get_image_info()
ui.table.from_pandas(df=data).classes("w-full")
Empty file added anvil/nicegui/utils/__init__.py
Empty file.
File renamed without changes.
65 changes: 65 additions & 0 deletions anvil/nicegui/utils/registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import requests
from nicegui import ui


class DockerRegistry:

def __init__(
self,
*,
registry_url: str = "https://registry.ublue.local",
registry_root_cert: str = "/data/ublue-os_forge-root.pem",
) -> None:
"""
Docker Registry integration for ublue-os forge
"""

self.registry_url = registry_url
self.registry_root_cert = registry_root_cert

def get_repositories(self) -> list:
endpoint = f"{self.registry_url}/v2/_catalog"
response = requests.get(url=endpoint, verify=self.registry_root_cert)
if response.status_code == 200:
repositories = response.json()["repositories"]
else:
with self, ui.notify() as notify:
notify(message=f"Error: {response.text}")
return repositories

def get_image_tags(self, image_name=str) -> dict:
endpoint = f"{self.registry_url}/v2/{image_name}/tags/list"
response = requests.get(url=endpoint, verify=self.registry_root_cert)
if response.status_code == 200:
tags = response.json()["tags"]
else:
with self, ui.notify() as notify:
notify(message=f"Error: {response.text}")
return tags

def get_image_manifest(self, image_name=str, image_tag=str) -> dict:
endpoint = f"{self.registry_url}/v2/{image_name}/manifests/{image_tag}"
headers = {"accept": "application/vnd.oci.image.manifest.v1+json"}
response = requests.get(
url=endpoint, verify=self.registry_root_cert, headers=headers
)
if response.status_code == 200:
manifest = response.json()
else:
with self, ui.notify() as notify:
notify(message=f"Error: {response.text}")
return manifest

def get_all_image_info(self, image_name=str) -> list:
repositories = self.get_repositories()
all_image_info = []
for repository in repositories:
tags = self.get_image_tags(image_name=repository)
for tag in tags:
manifest = self.get_image_manifest(image_name=repository, image_tag=tag)
image_info = {
"name": repository,
"tags": [{"name": tag, "manifest": manifest}],
}
all_image_info.append(image_info)
return all_image_info
Loading

0 comments on commit ed9a36b

Please sign in to comment.