bastienwirtz / homer

A very simple static homepage for your server.
https://homer-demo.netlify.app/
Apache License 2.0
9.32k stars 787 forks source link

Token substitution #412

Closed JonSilver closed 2 years ago

JonSilver commented 2 years ago

It would be great to be able to include tokens such as %BASE_URL% in fields in the yaml, to be substituted at runtime with the contents of a matching environment variable.

Happy to contribute a PR if wanted.

Thanks, Jon

fbartels commented 2 years ago

For the base url this does not really seem necessary for me. You can just work with relative urls and the browser will take care of the request going to domain1.com/path or domain2.com/path based on the url you’re accessing Homer from.

Roundaround commented 2 years ago

I like the idea of this - I'd have to think a bit on what tokens would be useful though. I agree that BASE_URL is more or less useless but we surely come up with something

strazto commented 2 years ago

A lot of apps tend to be hosted on separate sub-domain, eg: homer.example.com, app2.example.com , so yeah, base_url would be appropriate, eg

services:
  - name: "Application"
    icon: "fas fa-code-branch"
    # A path to an image can also be provided. Note that icon take precedence if both icon and logo are set.
    # logo: "path/to/logo"
    items:
      - name: "Awesome app"
        logo: "assets/tools/sample.png"
        # Alternatively a fa icon can be provided:
        # icon: "fab fa-jenkins"
        subtitle: "Bookmark example"
        tag: "app"
        # Root_tld
        url: "blog.${root_tld}"
        target: "_blank" # optional html tag target attribute
      - name: "Another one"
        logo: "assets/tools/sample2.png"
        subtitle: "Another application"
        tag: "app"
        # Optional tagstyle
        tagstyle: "is-success"
        url: "auth.${root_tld}"

Personally I literally run my homer configs through a templating program that looks like this:

#!/usr/bin/env bash

repo_root="$(git rev-parse --show-toplevel)"
env_file="${repo_root}/.env"/
echo "env file: $env_file"

root_domain="$(cat ${env_file} | sed -n -e 's/^root_domain=//p')"

echo "root_domain: $root_domain"

function modify_template {
  if [ ! $# -ge 2 ]; then
    echo "Found less than 2 args"
    return
  fi

  local TEMPLATE_FILE="$1"
  local OUTPUT_FILE="$2"

  cat "$TEMPLATE_FILE" | \
    sed "s#\${root_domain}#${root_domain}#g" > "$OUTPUT_FILE" 
}

homer_root="${repo_root}/config/homer/instances"

modify_template "${homer_root}/public/config.template.yml" "${homer_root}/public/assets/config.yml"

modify_template "${homer_root}/private/config.template.yml" "${homer_root}/private/assets/config.yml"

@Roundaround IMO best bet is to be unopinionated about which tokens to use, and to substitute any env var which matches a certain pattern, eg, with the prefix HOMER_TEMPLATE, maybe allow reading from file with HOMER_TEMPLATE_FILE so the following would work

---
version: "2"
services:
  homer:
    image: b4bz/homer
    container_name: homer
    volumes:
      - /your/local/assets/:/www/assets
      - '/your/api/keys/:/keys/:ro'
    ports:
      - 8080:8080
    environment:
        HOMER_TEMPLATE_root_tld: "example.com"
        HOMER_TEMPLATE_FILE_weather_api_key: "/keys/weather"
    restart: unless-stopped

For the config:

---

# Services
# First level array represents a group.
# Leave only a "items" key if not using group (group name, icon & tagstyle are optional, section separation will not be displayed).
services:
  - name: "Application"
    icon: "fas fa-code-branch"
    # A path to an image can also be provided. Note that icon take precedence if both icon and logo are set.
    # logo: "path/to/logo"
    items:
      - name: "Awesome app"
        logo: "assets/tools/sample.png"
        # Alternatively a fa icon can be provided:
        # icon: "fab fa-jenkins"
        subtitle: "Bookmark example"
        tag: "app"
        url: "blog.${root_tld}"
        target: "_blank" # optional html tag target attribute
  - name: "Weather"
    location: "Amsterdam" # your location.
    locationId: "2759794" 
    apikey: "${weather_api_key}" 
    units: "metric" 
    background: "square" 
    type: "OpenWeather"
JonSilver commented 2 years ago

Many applications on local servers are hosted on different ports, so relative paths aren't possible and BASE_URL is essential. Tokenisation from all/any environment variables would be best for ultimate flexibility. Getting caught up with ideas of what's needed or not needed from the limited POV of a single use-case restricts versatility.

Roundaround commented 2 years ago

The problem with an environment variable approach is that they are only available at build time. If we wanted to expose environment variables to the dashboard within the lifespan of the container, we'd have to either build out some kind of API to pass them out to the web app or write some kind of startup script to write the environment vars to a file that can be pulled dynamically similar to the config yamls.

JonSilver commented 2 years ago

Ah I see... In my use-case I don't think I'm limited in this way. I run my containers in a Balena multi-container (docker compose) setup... I get to set my environment variables per device remotely from the Balena dashboard... And I can set them per container, for all containers or for all devices... Then they're automagically available to running code as soon as the container is started. Thus, if yaml was the only reasonable way of getting values into the code, even a startup shell script could do that.

strazto commented 2 years ago

Ah I see... In my use-case I don't think I'm limited in this way. I run my containers in a Balena multi-container (docker compose) setup... I get to set my environment variables per device remotely from the Balena dashboard... And I can set them per container, for all containers or for all devices... Then they're automagically available to running code as soon as the container is started. Thus, if yaml was the only reasonable way of getting values into the code, even a startup shell script could do that.

In that case, see my embedded bash script - it's probably posix friendly and you should be able to use it to substitute in your env vars

bastienwirtz commented 2 years ago

Hey there,

Part of the reason why homer is based on a simple text file is that you can easily use a templating system on it. I used Ansible jinja template to configure & deploy homer. This kind of tool will do a way better job than anything in homer. The way Homer works, it could only replace tokens after parsing the file on the client side, and I don't like the idea. Especially when a simple search & replace (if you don't use a template engine) can do the job. Thanks for sharing your idea @JonSilver!