mirror of
https://github.com/KevinMidboe/infra-map.git
synced 2026-01-27 19:45:56 +00:00
Compare commits
5 Commits
push-tlvrn
...
push-syrlx
| Author | SHA1 | Date | |
|---|---|---|---|
| 0fc47c9e3f | |||
| 0e8a99a277 | |||
| 76ac71a755 | |||
| 7251753df5 | |||
| 75355c43a8 |
@@ -91,12 +91,15 @@ steps:
|
|||||||
settings:
|
settings:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
repo: ghcr.io/kevinmidboe/varnish-infra-map
|
repo: ghcr.io/kevinmidboe/varnish-infra-map
|
||||||
dockerfile: varnish/Dockerfile
|
contexT: varnish
|
||||||
|
dockerfile: Dockerfile
|
||||||
compress: true
|
compress: true
|
||||||
username:
|
username:
|
||||||
from_secret: GITHUB_USERNAME
|
from_secret: GITHUB_USERNAME
|
||||||
password:
|
password:
|
||||||
from_secret: GHCR_UPLOAD_TOKEN
|
from_secret: GHCR_UPLOAD_TOKEN
|
||||||
|
build_args_from_env:
|
||||||
|
-
|
||||||
tags:
|
tags:
|
||||||
- latest
|
- latest
|
||||||
- ${DRONE_COMMIT_SHA}
|
- ${DRONE_COMMIT_SHA}
|
||||||
@@ -183,6 +186,6 @@ volumes:
|
|||||||
temp: {}
|
temp: {}
|
||||||
---
|
---
|
||||||
kind: signature
|
kind: signature
|
||||||
hmac: 01caa41521eac62356f6fc941cdd489dae8e2c4249bdb4e4dc1a32e101c639b7
|
hmac: 3ba933b1c9b7f6bda1691bfb0335290f461d08cebfc5e9fe60c2f272604189d0
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
|
DATABASE_URL=
|
||||||
|
TRAEFIK_URL=
|
||||||
|
HTTP_HEALTH_ENDPOINTS=
|
||||||
PROXMOX_URL=
|
PROXMOX_URL=
|
||||||
PROXMOX_TOKEN=
|
PROXMOX_TOKEN=
|
||||||
HOMEASSISTANT_URL=
|
HOMEASSISTANT_URL=
|
||||||
HOMEASSISTANT_TOKEN=
|
HOMEASSISTANT_TOKEN=
|
||||||
TRAEFIK_URL=
|
KUBERNETES_SERVICE_HOST=
|
||||||
|
KUBERNETES_SA_TOKEN=
|
||||||
|
KUBERNETES_CA_CERT_PATH=
|
||||||
|
|
||||||
|
|||||||
16
Dockerfile
16
Dockerfile
@@ -1,20 +1,34 @@
|
|||||||
|
# --- Stage 1: Compile svelte-kit project ---
|
||||||
FROM node:22-alpine3.20 AS builder
|
FROM node:22-alpine3.20 AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy source files
|
||||||
COPY src/ src
|
COPY src/ src
|
||||||
COPY static/ static
|
COPY static/ static
|
||||||
COPY package.json yarn.lock svelte.config.js tsconfig.json vite.config.ts ./
|
COPY package.json yarn.lock svelte.config.js tsconfig.json vite.config.ts ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
RUN yarn --frozen-lockfile
|
RUN yarn --frozen-lockfile
|
||||||
|
|
||||||
|
# Build project
|
||||||
|
ENV NODE_ENV=production
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
|
# --- Stage 2: Run project with node ---
|
||||||
FROM node:22-alpine3.20
|
FROM node:22-alpine3.20
|
||||||
|
|
||||||
|
# Copy compiled project files
|
||||||
WORKDIR /opt/infra-map
|
WORKDIR /opt/infra-map
|
||||||
COPY --from=builder /app/build build
|
COPY --from=builder /app/build build
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
ENV NODE_ENV=production
|
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" ]
|
CMD [ "node", "build/index.js" ]
|
||||||
|
|||||||
46
README.md
46
README.md
@@ -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:
|
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
yarn dev
|
||||||
|
|
||||||
# or start the server and open the app in a new browser tab
|
|
||||||
npm run dev -- --open
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
To create a production version of your app:
|
To create a production version to be run from node:
|
||||||
|
|
||||||
```bash
|
```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
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
version: '3.8'
|
version: '3.9'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
|
||||||
build: .
|
|
||||||
container_name: infra-map
|
|
||||||
ports:
|
|
||||||
- '3000:3000' # svelte-kit preview HTTP
|
|
||||||
varnish:
|
varnish:
|
||||||
build: varnish
|
build:
|
||||||
container_name: varnish-cache
|
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:
|
ports:
|
||||||
- '6081:6081' # Varnish HTTP
|
- '6081:6081'
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
env_file: .env # sets container's environment
|
||||||
environment:
|
environment:
|
||||||
- VARNISH_LISTEN_PORT=6081
|
- NODE_ENV=production
|
||||||
command: >
|
- PROTOCOL_HEADER=x-forwarded-proto
|
||||||
varnishd
|
- HOST_HEADER=x-forwarded-host
|
||||||
-F
|
- PORT_HEADER=x-forwarded-port
|
||||||
-f /etc/varnish/default.vcl
|
|
||||||
-s malloc,256m
|
|
||||||
-a :6081
|
|
||||||
|
|||||||
@@ -31,8 +31,6 @@
|
|||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"prettier-plugin-svelte": "^3.3.3",
|
"prettier-plugin-svelte": "^3.3.3",
|
||||||
"sass-embedded": "^1.86.0",
|
"sass-embedded": "^1.86.0",
|
||||||
"sqlite": "^5.1.1",
|
|
||||||
"sqlite3": "^5.1.7",
|
|
||||||
"svelte": "^5.38.2",
|
"svelte": "^5.38.2",
|
||||||
"svelte-check": "^4.0.0",
|
"svelte-check": "^4.0.0",
|
||||||
"sveltekit-sse": "^0.13.16",
|
"sveltekit-sse": "^0.13.16",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import User from '$lib/icons/user.svelte';
|
|
||||||
import { derived } from 'svelte/store';
|
import { derived } from 'svelte/store';
|
||||||
|
|
||||||
// Create a derived store to extract breadcrumb data
|
// Create a derived store to extract breadcrumb data
|
||||||
@@ -9,14 +8,6 @@
|
|||||||
|
|
||||||
return segments.map((segment, index) => {
|
return segments.map((segment, index) => {
|
||||||
let label = decodeURI(segment);
|
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 {
|
return {
|
||||||
label,
|
label,
|
||||||
path: '/' + segments.slice(0, index + 1).join('/')
|
path: '/' + segments.slice(0, index + 1).join('/')
|
||||||
@@ -40,10 +31,6 @@
|
|||||||
<a href={crumb.path}>{crumb.label}</a>
|
<a href={crumb.path}>{crumb.label}</a>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="right">
|
|
||||||
<User />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
import { grey400x225 } from '$lib/utils/staticImageSource';
|
import { grey400x225 } from '$lib/utils/staticImageSource';
|
||||||
import Dialog from './Dialog.svelte';
|
import Dialog from './Dialog.svelte';
|
||||||
|
|
||||||
const IMAGE_PROXY_URL = 'http://localhost:6081';
|
const IMAGE_REFRESH_INTERVAL = 3000;
|
||||||
const IMAGE_REFRESH_INTERVAL = 300;
|
|
||||||
|
|
||||||
let { imageUrl }: { imageUrl: string } = $props();
|
let { imageUrl }: { imageUrl: string } = $props();
|
||||||
let lastUpdated = new Date();
|
let lastUpdated = new Date();
|
||||||
@@ -17,10 +16,15 @@
|
|||||||
function loadBlob(blob: Blob) {
|
function loadBlob(blob: Blob) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
imageSource = reader.result || '';
|
|
||||||
const img = document.getElementById('live-image') as HTMLImageElement;
|
const img = document.getElementById('live-image') as HTMLImageElement;
|
||||||
if (!img) return;
|
if (!img) return;
|
||||||
|
|
||||||
|
imageSource = reader?.result || '';
|
||||||
|
if (imageSource === '') {
|
||||||
|
console.log("no image data, returning")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// set imageSource to image element
|
// set imageSource to image element
|
||||||
img.src = `data:image/jpeg;base64; ${imageSource}`;
|
img.src = `data:image/jpeg;base64; ${imageSource}`;
|
||||||
lastUpdated = new Date();
|
lastUpdated = new Date();
|
||||||
@@ -80,6 +84,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<Dialog title="Live stream of printer" on:close={() => (fullscreen = false)}>
|
<Dialog title="Live stream of printer" on:close={() => (fullscreen = false)}>
|
||||||
<img style="width: 100%;" src={String(imageSource)} id="live-image" />
|
<img style="width: 100%;" src={String(imageSource)} id="live-image" />
|
||||||
|
<span>Last update {timestamp}s ago</span>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<img src={String(grey400x225)} />
|
<img src={String(grey400x225)} />
|
||||||
|
|||||||
@@ -25,8 +25,6 @@
|
|||||||
if (counter + 1 >= colors.length) counter = 1;
|
if (counter + 1 >= colors.length) counter = 1;
|
||||||
else counter += 1;
|
else counter += 1;
|
||||||
|
|
||||||
console.log(counter);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bgColor: colors[counter - 1][0],
|
bgColor: colors[counter - 1][0],
|
||||||
color: colors[counter - 1][1],
|
color: colors[counter - 1][1],
|
||||||
@@ -99,7 +97,6 @@
|
|||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
max-width: 80%;
|
|
||||||
color: #333;
|
color: #333;
|
||||||
|
|
||||||
background-color: #fafafa; /* Subtle background to separate it from the rest */
|
background-color: #fafafa; /* Subtle background to separate it from the rest */
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ const AVAILABLE_RESOURCES = [
|
|||||||
|
|
||||||
export const load: PageServerLoad = async ({ params }) => {
|
export const load: PageServerLoad = async ({ params }) => {
|
||||||
const { resource, uid } = params;
|
const { resource, uid } = params;
|
||||||
console.log('PARAMS:', params);
|
|
||||||
|
|
||||||
if (!AVAILABLE_RESOURCES.includes(resource)) {
|
if (!AVAILABLE_RESOURCES.includes(resource)) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -3,13 +3,11 @@ import { produce } from 'sveltekit-sse';
|
|||||||
|
|
||||||
export function GET({ request }) {
|
export function GET({ request }) {
|
||||||
return produce(async function start({ emit }) {
|
return produce(async function start({ emit }) {
|
||||||
console.log('----- REQUEST -----');
|
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const pod = url.searchParams.get('pod');
|
const pod = url.searchParams.get('pod');
|
||||||
const namespace = url.searchParams.get('namespace');
|
const namespace = url.searchParams.get('namespace');
|
||||||
const container = url.searchParams.get('container');
|
const container = url.searchParams.get('container');
|
||||||
|
|
||||||
console.log('pod, namespace:', pod, namespace);
|
|
||||||
const k8sLogs = createLogStream(pod, namespace, container);
|
const k8sLogs = createLogStream(pod, namespace, container);
|
||||||
k8sLogs.start();
|
k8sLogs.start();
|
||||||
const unsubscribe = k8sLogs.logEmitter.subscribe((msg: string) => {
|
const unsubscribe = k8sLogs.logEmitter.subscribe((msg: string) => {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ async function fetchImage(src: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ url }) => {
|
export const GET: RequestHandler = async ({ url }) => {
|
||||||
console.log('GET');
|
|
||||||
url.pathname = url.pathname.replace('/image/', '');
|
url.pathname = url.pathname.replace('/image/', '');
|
||||||
|
|
||||||
const res = await fetchImage(url.href);
|
const res = await fetchImage(url.href);
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
FROM debian:bullseye
|
# --- Stage 1: Compile varnish w/ vmods ---
|
||||||
|
FROM debian:bullseye-slim AS builder
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
RUN apt-get update && apt-get install -y \
|
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 && \
|
./configure VARNISHSRC=/usr/include/varnish && \
|
||||||
make && make install
|
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
|
EXPOSE 6081
|
||||||
|
|
||||||
CMD ["varnishd", "-F", "-f", "/etc/varnish/default.vcl", "-a", ":6081", "-s", "malloc,512m"]
|
CMD ["varnishd", "-F", "-f", "/etc/varnish/default.vcl", "-a", ":6081", "-s", "malloc,512m"]
|
||||||
|
|
||||||
|
|||||||
@@ -2,21 +2,20 @@ vcl 4.0;
|
|||||||
|
|
||||||
import std;
|
import std;
|
||||||
import digest;
|
import digest;
|
||||||
|
import directors;
|
||||||
|
|
||||||
# include "handlers/ttl-override-handler.vcl";
|
|
||||||
include "includes/x-cache-header.vcl";
|
include "includes/x-cache-header.vcl";
|
||||||
|
|
||||||
include "vcl_deliver.vcl";
|
include "vcl_deliver.vcl";
|
||||||
|
|
||||||
# Define backend pointing to Home Assistant IP
|
# Define backend pointing to Home Assistant IP
|
||||||
backend hass_backend {
|
backend hass_backend {
|
||||||
.host = "10.0.0.82";
|
.host = "{{ getenv `IMAGE_HOST` `homeassistant.local` }}";
|
||||||
.port = "8123";
|
.port = "8123";
|
||||||
}
|
}
|
||||||
|
|
||||||
backend app_frontend {
|
backend app_frontend {
|
||||||
.host = "host.docker.internal";
|
.host = "{{ getenv `PROXY_HOST` `localhost` }}";
|
||||||
.port = "5173";
|
.port = "3000";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub vcl_recv {
|
sub vcl_recv {
|
||||||
@@ -47,6 +46,17 @@ sub vcl_recv {
|
|||||||
unset req.http.Cookie;
|
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 {
|
sub vcl_synth {
|
||||||
if (resp.status == 204) {
|
if (resp.status == 204) {
|
||||||
set resp.http.Access-Control-Allow-Origin = "*";
|
set resp.http.Access-Control-Allow-Origin = "*";
|
||||||
Reference in New Issue
Block a user