6 Commits

16 changed files with 476 additions and 1135 deletions

View File

@@ -1,7 +1,7 @@
---
kind: pipeline
type: docker
name: Build
name: Build app
platform:
os: linux
@@ -26,7 +26,7 @@ steps:
---
kind: pipeline
type: docker
name: Publish
name: Publish app to gchr
platform:
os: linux
@@ -64,14 +64,11 @@ depends_on:
---
kind: pipeline
type: docker
name: Publish
name: Publish varnish image
platform:
os: linux
arch: amd64
kind: pipeline
type: docker
name: config-check
steps:
- name: check-config
@@ -79,11 +76,11 @@ steps:
commands:
- git fetch --no-tags --depth=2
- |
if git diff --quiet HEAD^ HEAD -- varnish/default.vcl; then
if git diff-tree --no-commit-id --name-only -r HEAD | grep -qE '(\.drone.yml|(varnish/.+(vcl|tmpl)(\n|$)))'; then
echo "Changes detected in varnish config"
else
echo "No changes in varnish config file, skipping..."
exit 78 # exit code 78 = skip in Drone
else
echo "Changes detected in varnish config"
fi
- name: Publish varnish to ghcr
@@ -91,12 +88,16 @@ steps:
settings:
registry: ghcr.io
repo: ghcr.io/kevinmidboe/varnish-infra-map
dockerfile: varnish/Dockerfile
contexT: varnish
dockerfile: Dockerfile
compress: true
username:
from_secret: GITHUB_USERNAME
password:
from_secret: GHCR_UPLOAD_TOKEN
build_args_from_env:
- IMAGE_HOST
- IMAGE_PROXY
tags:
- latest
- ${DRONE_COMMIT_SHA}
@@ -110,13 +111,11 @@ trigger:
branch:
- main
- update
depends_on:
- Build
---
kind: pipeline
type: docker
name: Deploy
name: Deploy to kubernetes
platform:
os: linux
@@ -183,6 +182,4 @@ volumes:
temp: {}
---
kind: signature
hmac: 01caa41521eac62356f6fc941cdd489dae8e2c4249bdb4e4dc1a32e101c639b7
...
hmac: 3ba933b1c9b7f6bda1691bfb0335290f461d08cebfc5e9fe60c2f272604189d0

View File

@@ -1,5 +1,11 @@
DATABASE_URL=
TRAEFIK_URL=
HTTP_HEALTH_ENDPOINTS=
PROXMOX_URL=
PROXMOX_TOKEN=
HOMEASSISTANT_URL=
HOMEASSISTANT_TOKEN=
TRAEFIK_URL=
KUBERNETES_SERVICE_HOST=
KUBERNETES_SA_TOKEN=
KUBERNETES_CA_CERT_PATH=

View File

@@ -9,8 +9,9 @@ metadata:
spec:
ports:
- port: 80
name: http
protocol: TCP
targetPort: 3000
targetPort: 6081
selector:
app: infra-map
sessionAffinity: None

View File

@@ -1,20 +1,34 @@
# --- Stage 1: Compile svelte-kit project ---
FROM node:22-alpine3.20 AS builder
WORKDIR /app
# Copy source files
COPY src/ src
COPY static/ static
COPY package.json yarn.lock svelte.config.js tsconfig.json vite.config.ts ./
# Install dependencies
RUN yarn --frozen-lockfile
# Build project
ENV NODE_ENV=production
RUN yarn build
# --- Stage 2: Run project with node ---
FROM node:22-alpine3.20
# Copy compiled project files
WORKDIR /opt/infra-map
COPY --from=builder /app/build build
EXPOSE 3000
ENV NODE_ENV=production
# Install dependencies
RUN yarn install --frozen-lockfile
RUN yarn add @sveltejs/kit
EXPOSE 3000
ENV PORT=3000
CMD [ "node", "build/index.js" ]

View File

@@ -61,20 +61,50 @@ Follow hass documentation on generating a api token: https://developers.home-ass
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
yarn dev
```
## Building
To create a production version of your app:
To create a production version to be run from node:
```bash
npm run build
yarn build
```
You can preview the production build with `npm run preview`.
To preview either use vite to serve or execute node entrypoint:
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
```bash
yarn preview
```
or
```bash
node build/index.js
```
## Run using docker
The application is configure to be used either standalone or behind a webserver. To build the svelte-application docker image run:
> NB! Remember to configure .env, which is automatically picked up by docker-compose. Set and override for both containers in this file.
Svelte-kit application:
```bash
docker build -t infra-map .
```
Varnish cache:
```bash
cd varnish
docker build -t infra-varnish-cache .
```
Or both using docker compose:
```bash
docker compose up
```

View File

@@ -1,21 +1,26 @@
version: '3.8'
version: '3.9'
services:
app:
build: .
container_name: infra-map
ports:
- '3000:3000' # svelte-kit preview HTTP
varnish:
build: varnish
container_name: varnish-cache
build:
context: varnish
dockerfile: Dockerfile
args:
# sets build variables. Overridden by env, but has sane defaults
IMAGE_HOST: ${IMAGE_HOST:-homeassistant.local}
PROXY_HOST: ${PROXY_HOST:-app}
ports:
- '6081:6081' # Varnish HTTP
- '6081:6081'
depends_on:
- app
app:
build:
context: .
dockerfile: Dockerfile
env_file: .env # sets container's environment
environment:
- VARNISH_LISTEN_PORT=6081
command: >
varnishd
-F
-f /etc/varnish/default.vcl
-s malloc,256m
-a :6081
- NODE_ENV=production
- PROTOCOL_HEADER=x-forwarded-proto
- HOST_HEADER=x-forwarded-host
- PORT_HEADER=x-forwarded-port

View File

@@ -31,8 +31,6 @@
"prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.3",
"sass-embedded": "^1.86.0",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.7",
"svelte": "^5.38.2",
"svelte-check": "^4.0.0",
"sveltekit-sse": "^0.13.16",

View File

@@ -1,6 +1,5 @@
<script lang="ts">
import { page } from '$app/stores';
import User from '$lib/icons/user.svelte';
import { derived } from 'svelte/store';
// Create a derived store to extract breadcrumb data
@@ -9,14 +8,6 @@
return segments.map((segment, index) => {
let label = decodeURI(segment);
// if not uuid pattern, this is weird order of ops
/*
if (!segment.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)) {
label = label.replace(/-/g, ' ')
}
*/
return {
label,
path: '/' + segments.slice(0, index + 1).join('/')
@@ -40,10 +31,6 @@
<a href={crumb.path}>{crumb.label}</a>
{/each}
</div>
<div class="right">
<User />
</div>
</div>
<style lang="scss">

View File

@@ -3,8 +3,7 @@
import { grey400x225 } from '$lib/utils/staticImageSource';
import Dialog from './Dialog.svelte';
const IMAGE_PROXY_URL = 'http://localhost:6081';
const IMAGE_REFRESH_INTERVAL = 300;
const IMAGE_REFRESH_INTERVAL = 3000;
let { imageUrl }: { imageUrl: string } = $props();
let lastUpdated = new Date();
@@ -17,10 +16,15 @@
function loadBlob(blob: Blob) {
const reader = new FileReader();
reader.onloadend = () => {
imageSource = reader.result || '';
const img = document.getElementById('live-image') as HTMLImageElement;
if (!img) return;
imageSource = reader?.result || '';
if (imageSource === '') {
console.log("no image data, returning")
return
}
// set imageSource to image element
img.src = `data:image/jpeg;base64; ${imageSource}`;
lastUpdated = new Date();
@@ -80,6 +84,7 @@
{:else}
<Dialog title="Live stream of printer" on:close={() => (fullscreen = false)}>
<img style="width: 100%;" src={String(imageSource)} id="live-image" />
<span>Last update {timestamp}s ago</span>
</Dialog>
<img src={String(grey400x225)} />

View File

@@ -25,8 +25,6 @@
if (counter + 1 >= colors.length) counter = 1;
else counter += 1;
console.log(counter);
return {
bgColor: colors[counter - 1][0],
color: colors[counter - 1][1],
@@ -99,7 +97,6 @@
font-size: 1.1rem;
line-height: 1.4;
line-height: 1.7;
max-width: 80%;
color: #333;
background-color: #fafafa; /* Subtle background to separate it from the rest */

View File

@@ -13,7 +13,6 @@ const AVAILABLE_RESOURCES = [
export const load: PageServerLoad = async ({ params }) => {
const { resource, uid } = params;
console.log('PARAMS:', params);
if (!AVAILABLE_RESOURCES.includes(resource)) {
return {

View File

@@ -3,13 +3,11 @@ import { produce } from 'sveltekit-sse';
export function GET({ request }) {
return produce(async function start({ emit }) {
console.log('----- REQUEST -----');
const url = new URL(request.url);
const pod = url.searchParams.get('pod');
const namespace = url.searchParams.get('namespace');
const container = url.searchParams.get('container');
console.log('pod, namespace:', pod, namespace);
const k8sLogs = createLogStream(pod, namespace, container);
k8sLogs.start();
const unsubscribe = k8sLogs.logEmitter.subscribe((msg: string) => {

View File

@@ -23,7 +23,6 @@ async function fetchImage(src: string) {
}
export const GET: RequestHandler = async ({ url }) => {
console.log('GET');
url.pathname = url.pathname.replace('/image/', '');
const res = await fetchImage(url.href);

View File

@@ -1,4 +1,5 @@
FROM debian:bullseye
# --- Stage 1: Compile varnish w/ vmods ---
FROM debian:bullseye-slim AS builder
# Install dependencies
RUN apt-get update && apt-get install -y \
@@ -21,9 +22,36 @@ RUN git clone https://github.com/varnish/libvmod-digest.git /opt/libvmod-digest
./configure VARNISHSRC=/usr/include/varnish && \
make && make install
COPY . /etc/varnish/
# --- Stage 2: Runtime image ---
FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y \
curl gnupg apt-transport-https lsb-release && \
curl -fsSL https://packagecloud.io/varnishcache/varnish73/gpgkey | gpg --dearmor -o /usr/share/keyrings/varnish.gpg && \
echo "deb [signed-by=/usr/share/keyrings/varnish.gpg] https://packagecloud.io/varnishcache/varnish73/debian/ $(lsb_release -cs) main" \
> /etc/apt/sources.list.d/varnish.list && \
apt-get update && apt-get install -y varnish libmhash2 && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# Copy VMOD from builder
COPY --from=builder /usr/lib/varnish/vmods/* /usr/lib/varnish/vmods/
# Copy gomplate from official image
COPY --from=hairyhenderson/gomplate:stable /gomplate /bin/gomplate
# Copy configuration
COPY default.vcl.tmpl /etc/varnish/
COPY *.vcl /etc/varnish/
COPY includes /etc/varnish/includes
# Set variables for *.tmpl files
ARG PROXY_HOST=$PROXY_HOST
ARG IMAGE_HOST=$IMAGE_HOST
# Generate VCL
RUN gomplate -f /etc/varnish/default.vcl.tmpl -o /etc/varnish/default.vcl
RUN rm /etc/varnish/default.vcl.tmpl
EXPOSE 6081
CMD ["varnishd", "-F", "-f", "/etc/varnish/default.vcl", "-a", ":6081", "-s", "malloc,512m"]

View File

@@ -2,21 +2,20 @@ vcl 4.0;
import std;
import digest;
import directors;
# include "handlers/ttl-override-handler.vcl";
include "includes/x-cache-header.vcl";
include "vcl_deliver.vcl";
# Define backend pointing to Home Assistant IP
backend hass_backend {
.host = "10.0.0.82";
.host = "{{ getenv `IMAGE_HOST` `homeassistant.local` }}";
.port = "8123";
}
backend app_frontend {
.host = "host.docker.internal";
.port = "5173";
.host = "{{ getenv `PROXY_HOST` `localhost` }}";
.port = "3000";
}
sub vcl_recv {
@@ -47,6 +46,17 @@ sub vcl_recv {
unset req.http.Cookie;
}
// Svelte-kit needs to distinguish between it's own files and the Host header.
// The X-Forwarded-* headers below are to tell svelte-kit where it's local files are,
// and the Host header is included in the returned html & js referencing the external
// domain or proxy requested by client.
// https://svelte.dev/docs/kit/adapter-node#Environment-variables-ORIGIN-PROTOCOL_HEADER-HOST_HEADER-and-PORT_HEADER
sub vcl_backend_fetch {
set bereq.http.X-Forwarded-Host = "localhost";
set bereq.http.X-Forwarded-Port = "3000";
set bereq.http.X-Forwarded-Proto = "http";
}
sub vcl_synth {
if (resp.status == 204) {
set resp.http.Access-Control-Allow-Origin = "*";

1385
yarn.lock

File diff suppressed because it is too large Load Diff