test
This commit is contained in:
97
.templates/.README.md
Normal file
97
.templates/.README.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Home assistant add-on: alexbelgium
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
|
||||
[![Donate][donation-badge]](https://www.buymeacoffee.com/alexbelgium)
|
||||
[![Donate][paypal-badge]](https://www.paypal.com/donate/?hosted_button_id=DZFULJZTP3UQA)
|
||||

|
||||
|
||||
[donation-badge]: https://img.shields.io/badge/Buy%20me%20a%20coffee%20(no%20paypal)-%23d32f2f?logo=buy-me-a-coffee&style=flat&logoColor=white
|
||||
[paypal-badge]: https://img.shields.io/badge/Buy%20me%20a%20coffee%20with%20Paypal-0070BA?logo=paypal&style=flat&logoColor=white
|
||||
|
||||
[](https://www.codacy.com/gh/alexbelgium/hassio-addons/dashboard?utm_source=github.com&utm_medium=referral&utm_content=alexbelgium/hassio-addons&utm_campaign=Badge_Grade)
|
||||
[](https://github.com/alexbelgium/hassio-addons/actions/workflows/weekly-supelinter.yaml)
|
||||
[](https://github.com/alexbelgium/hassio-addons/actions/workflows/onpush_builder.yaml)
|
||||
[](https://github.com/alexbelgium/hassio-addons/actions/workflows/weekly_stats.yaml)
|
||||
|
||||
[support-badge]: https://camo.githubusercontent.com/f4dbb995049f512fdc97fcc9e022ac243fa38c408510df9d46c7467d0970d959/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f537570706f72742d7468726561642d677265656e2e737667
|
||||
|
||||
_Thanks to everyone having starred my repo! To star it click on the image below, then it will be on top right. Thanks!_
|
||||
|
||||
[](https://github.com/alexbelgium/hassio-addons/stargazers)
|
||||
|
||||
_Thanks to all contributors !_
|
||||
|
||||
[](https://github.com/alexbelgium/hassio-addons/graphs/contributors)
|
||||
|
||||
Stargazers locations :
|
||||
|
||||

|
||||
|
||||
## About
|
||||
|
||||
Home Assistant allows anyone to create add-on repositories to share their
|
||||
add-ons for Home Assistant easily. This repository is one of those repositories,
|
||||
providing extra Home Assistant add-ons for your installation.
|
||||
|
||||
The primary goal of this project is to provide you (as a Home Assistant user)
|
||||
with additional, high quality, add-ons that allow you to take your automated
|
||||
home to the next level.
|
||||
|
||||
## Installation
|
||||
|
||||
[![Add repository on my Home Assistant][repository-badge]][repository-url]
|
||||
|
||||
If you want to do add the repository manually, please follow the procedure highlighted in the [Home Assistant website](https://home-assistant.io/hassio/installing_third_party_addons). Use the following URL to add this repository: https://github.com/alexbelgium/hassio-addons
|
||||
|
||||
## Statistics
|
||||
|
||||
### Number of addons
|
||||
|
||||
- In the repository : %%STATS_ADDONS%%
|
||||
- Installed : %%STATS_DOWNLOADS%%
|
||||
|
||||
### Top 3
|
||||
|
||||
1. %%STATS_ONE%%
|
||||
2. %%STATS_TWO%%
|
||||
3. %%STATS_THREE%%
|
||||
|
||||
### Architectures used
|
||||
|
||||
- %%STATS_AMD64%%
|
||||
- %%STATS_AARCH64%%
|
||||
- %%STATS_ARMV7%%
|
||||
|
||||
### Stars evolution
|
||||
|
||||
[](https://star-history.com/#alexbelgium/hassio-addons&Date)
|
||||
|
||||
## Add-ons provided by this repository
|
||||
|
||||
%%ADDONS_LIST%%
|
||||
|
||||
## Support
|
||||
|
||||
Got questions?
|
||||
|
||||
You have several options to get them answered:
|
||||
|
||||
- The Home Assistant [Community Forum][forum].
|
||||
- This repository issues list
|
||||
|
||||
[aarch64-badge]: https://img.shields.io/badge/aarch64--green.svg?logo=arm
|
||||
[amd64-badge]: https://img.shields.io/badge/amd64--green.svg?logo=amd
|
||||
[armv7-badge]: https://img.shields.io/badge/armv7--green.svg?logo=arm
|
||||
[aarch64no-badge]: https://img.shields.io/badge/aarch64--orange.svg?logo=arm
|
||||
[amd64no-badge]: https://img.shields.io/badge/amd64--orange.svg?logo=amd
|
||||
[armv7no-badge]: https://img.shields.io/badge/armv7--orange.svg?logo=arm
|
||||
[ingress-badge]: https://img.shields.io/badge/-ingress-blueviolet.svg?logo=Ingress
|
||||
[mariadb-badge]: https://img.shields.io/badge/Service-MariaDB-green.svg?logo=mariadb&logoColor=white
|
||||
[mqtt-badge]: https://img.shields.io/badge/Service-MQTT-green.svg?logo=chromecast&logoColor=white
|
||||
[localdisks-badge]: https://img.shields.io/badge/Mounts-localdisks-blue.svg
|
||||
[smb-badge]: https://img.shields.io/badge/Mounts-networkdisks-blue.svg
|
||||
[full_access-badge]: https://img.shields.io/badge/Requires-full_access-orange.svg
|
||||
[forum]: https://community.home-assistant.io/t/alexbelgium-repo-60-addons
|
||||
[repository-badge]: https://img.shields.io/badge/Add%20repository%20to%20my-Home%20Assistant-41BDF5?logo=home-assistant&style=for-the-badge
|
||||
[repository-url]: https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Falexbelgium%2Fhassio-addons
|
51
.templates/00-aaa_dockerfile_backup.sh
Normal file
51
.templates/00-aaa_dockerfile_backup.sh
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# If dockerfile failed install manually
|
||||
|
||||
##############################
|
||||
# Automatic modules download #
|
||||
##############################
|
||||
if [ -e "/MODULESFILE" ]; then
|
||||
MODULES=$(< /MODULESFILE)
|
||||
MODULES="${MODULES:-00-banner.sh}"
|
||||
echo "Executing modules script : $MODULES"
|
||||
|
||||
if ! command -v bash > /dev/null 2> /dev/null; then (apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null; fi \
|
||||
&& if ! command -v curl > /dev/null 2> /dev/null; then (apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null; fi \
|
||||
&& apt-get update && apt-get install -yqq --no-install-recommends ca-certificates || apk add --no-cache ca-certificates > /dev/null || true \
|
||||
&& mkdir -p /etc/cont-init.d \
|
||||
&& for scripts in $MODULES; do echo "$scripts" && curl -f -L -s -S "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/$scripts" -o /etc/cont-init.d/"$scripts" && [ "$(sed -n '/\/bin/p;q' /etc/cont-init.d/"$scripts")" != "" ] || (echo "script failed to install $scripts" && exit 1); done \
|
||||
&& chmod -R 755 /etc/cont-init.d
|
||||
fi
|
||||
|
||||
#######################
|
||||
# Automatic installer #
|
||||
#######################
|
||||
if [ -e "/ENVFILE" ]; then
|
||||
PACKAGES=$(< /ENVFILE)
|
||||
echo "Executing dependency script with custom elements : $PACKAGES"
|
||||
|
||||
if ! command -v bash > /dev/null 2> /dev/null; then (apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null; fi \
|
||||
&& if ! command -v curl > /dev/null 2> /dev/null; then (apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null; fi \
|
||||
&& curl -f -L -s -S "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automatic_packages.sh" --output /ha_automatic_packages.sh \
|
||||
&& chmod 755 /ha_automatic_packages.sh \
|
||||
&& eval /./ha_automatic_packages.sh "${PACKAGES:-}" \
|
||||
&& rm /ha_automatic_packages.sh
|
||||
fi
|
||||
|
||||
if [ -e "/MODULESFILE" ] && [ ! -f /ha_entrypoint.sh ]; then
|
||||
for scripts in $MODULES; do
|
||||
echo "$scripts : executing"
|
||||
chown "$(id -u)":"$(id -g)" /etc/cont-init.d/"$scripts"
|
||||
chmod a+x /etc/cont-init.d/"$scripts"
|
||||
/./etc/cont-init.d/"$scripts" || echo "/etc/cont-init.d/$scripts: exiting $?"
|
||||
rm /etc/cont-init.d/"$scripts"
|
||||
done | tac
|
||||
fi
|
||||
|
||||
#######################
|
||||
# Correct permissions #
|
||||
#######################
|
||||
[ -d /etc/services.d ] && chmod -R 777 /etc/services.d
|
||||
[ -d /etc/cont-init.d ] && chmod -R 777 /etc/cont-init.d
|
85
.templates/00-banner.sh
Normal file
85
.templates/00-banner.sh
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash disable=SC2016
|
||||
set -e
|
||||
# ==============================================================================
|
||||
# Displays a simple add-on banner on startup
|
||||
# ==============================================================================
|
||||
|
||||
if ! bashio::supervisor.ping 2> /dev/null; then
|
||||
# Degraded mode if no homeassistant
|
||||
bashio::log.blue \
|
||||
'-----------------------------------------------------------'
|
||||
bashio::log.blue "Starting addon without HA support"
|
||||
bashio::log.blue "Version : ${BUILD_VERSION:-1.0}"
|
||||
bashio::log.blue "Please use Docker Compose for env variables"
|
||||
bashio::log.blue \
|
||||
'-----------------------------------------------------------'
|
||||
# Use environment variables instead of addon options
|
||||
echo "... convert scripts to use environment variables instead of addon options"
|
||||
while IFS= read -r scripts; do
|
||||
[[ "$scripts" == *"00-banner.sh"* ]] && continue
|
||||
sed -i -e 's/bashio::config.has_value[[:space:]]*["'"'"']\([^"'"'"']*\)["'"'"']/[ ! -z "${\1:-}" ]/g' \
|
||||
-e 's/bashio::config.true[[:space:]]*["'"'"']\([^"'"'"']*\)["'"'"']/[ ! -z "${\1:-}" ] \&\& [ "${\1:-}" = "true" ]/g' \
|
||||
-e 's/\$(bashio::config[[:space:]]*["'"'"']\([^"'"'"']*\)["'"'"'])/${\1:-}/g' \
|
||||
-e 's/\$(bashio::addon.port[[:space:]]*["'"'"']\([0-9]*\)["'"'"'])/${\1:-}/g' \
|
||||
-e 's/bashio::config.require.ssl/true/g' \
|
||||
-e 's/\$(bashio::addon.ingress_port)/""/g' \
|
||||
-e 's/\$(bashio::addon.ingress_entry)/""/g' \
|
||||
-e 's/\$(bashio::addon.ip_address)/""/g' "$scripts"
|
||||
done < <(grep -srl "bashio" /etc/cont-init.d /custom-services.d /etc/services.d /etc/s6-overlay)
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bashio::log.blue \
|
||||
'-----------------------------------------------------------'
|
||||
bashio::log.blue " Add-on: $(bashio::addon.name)"
|
||||
bashio::log.blue " $(bashio::addon.description)"
|
||||
bashio::log.blue \
|
||||
'-----------------------------------------------------------'
|
||||
|
||||
bashio::log.blue " Add-on version: $(bashio::addon.version)"
|
||||
if bashio::var.true "$(bashio::addon.update_available)"; then
|
||||
bashio::log.magenta ' There is an update available for this add-on!'
|
||||
bashio::log.magenta \
|
||||
" Latest add-on version: $(bashio::addon.version_latest)"
|
||||
bashio::log.magenta ' Please consider upgrading as soon as possible.'
|
||||
else
|
||||
bashio::log.green ' You are running the latest version of this add-on.'
|
||||
fi
|
||||
|
||||
bashio::log.blue " System: $(bashio::info.operating_system)"
|
||||
bashio::log.blue " Architecture: $(bashio::info.arch) / $(bashio::info.machine)"
|
||||
bashio::log.blue " Home Assistant Core: $(bashio::info.homeassistant)"
|
||||
bashio::log.blue " Home Assistant Supervisor: $(bashio::info.supervisor)"
|
||||
|
||||
bashio::log.blue \
|
||||
'-----------------------------------------------------------'
|
||||
bashio::log.blue \
|
||||
' Please, share the above information when looking for help'
|
||||
bashio::log.blue \
|
||||
' or support in, e.g., GitHub, forums'
|
||||
bashio::log.blue \
|
||||
'-----------------------------------------------------------'
|
||||
bashio::log.green \
|
||||
' Provided by: https://github.com/alexbelgium/hassio-addons '
|
||||
bashio::log.blue \
|
||||
'-----------------------------------------------------------'
|
||||
|
||||
# ==============================================================================
|
||||
# Global actions for all addons
|
||||
# ==============================================================================
|
||||
if bashio::config.has_value "PUID" && bashio::config.has_value "PGID" && id abc &> /dev/null; then
|
||||
bashio::log.green ' Defining permissions for main user : '
|
||||
PUID="$(bashio::config "PUID")"
|
||||
PGID="$(bashio::config "PGID")"
|
||||
usermod -o -u "$PUID" abc
|
||||
groupmod -o -g "$PGID" abc
|
||||
bashio::log.blue "User UID: $(id -u abc)"
|
||||
bashio::log.blue "User GID: $(id -g abc)"
|
||||
|
||||
bashio::log.blue \
|
||||
'-----------------------------------------------------------'
|
||||
fi
|
||||
|
||||
# Clean bashrc file safely
|
||||
if [ -f ~/.bashrc ]; then : > ~/.bashrc; fi
|
8
.templates/00-bettercomments.sh
Normal file
8
.templates/00-bettercomments.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Color comments
|
||||
#! Red
|
||||
#? Question
|
||||
#// Done
|
||||
#todo To do
|
||||
#* Green
|
19
.templates/00-deprecated.sh
Normal file
19
.templates/00-deprecated.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
# ==============================================================================
|
||||
# Displays a simple add-on banner on startup
|
||||
# ==============================================================================
|
||||
|
||||
echo ""
|
||||
bashio::log.yellow "####################"
|
||||
bashio::log.yellow "# ADDON deprecated #"
|
||||
bashio::log.yellow "####################"
|
||||
echo ""
|
||||
bashio::log.yellow "This addon is now supported in the official HA community repository. You should migrate your data as soon as possible! This addon will not be supported and updates might stop in the future."
|
||||
bashio::log.yellow "You'll likely get better support as the official community is supported by the HA devs ! If some features from the official add-on are missing you should raise a request on the ha community add-ons repo"
|
||||
bashio::log.yellow "Thanks for all users over the years !"
|
||||
echo ""
|
||||
|
||||
sleep 5
|
131
.templates/00-global_var.sh
Normal file
131
.templates/00-global_var.sh
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
if ! bashio::supervisor.ping 2> /dev/null; then
|
||||
echo "..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
###################################
|
||||
# Export all addon options as env #
|
||||
###################################
|
||||
|
||||
# For all keys in options.json
|
||||
JSONSOURCE="/data/options.json"
|
||||
|
||||
# Define secrets location
|
||||
if [ -f /homeassistant/secrets.yaml ]; then
|
||||
SECRETSOURCE="/homeassistant/secrets.yaml"
|
||||
elif [ -f /config/secrets.yaml ]; then
|
||||
SECRETSOURCE="/config/secrets.yaml"
|
||||
else
|
||||
SECRETSOURCE="false"
|
||||
fi
|
||||
|
||||
# Export keys as env variables
|
||||
# echo "All addon options were exported as variables"
|
||||
mapfile -t arr < <(jq -r 'keys[]' "${JSONSOURCE}")
|
||||
|
||||
# Escape special characters using printf and enclose in double quotes
|
||||
sanitize_variable() {
|
||||
local raw="$1"
|
||||
local escaped
|
||||
if [[ "$raw" == \[* ]]; then
|
||||
echo "One of your options is an array, skipping"
|
||||
return
|
||||
fi
|
||||
printf -v escaped '%q' "$raw"
|
||||
# Do not espace spaces
|
||||
escaped="${escaped//\\ / }"
|
||||
if [[ "$raw" == "$escaped" ]]; then
|
||||
printf '%s' "$raw"
|
||||
else
|
||||
printf '%s' "$escaped"
|
||||
fi
|
||||
}
|
||||
|
||||
for KEYS in "${arr[@]}"; do
|
||||
# export key
|
||||
VALUE=$(jq -r --raw-output ".\"$KEYS\"" "$JSONSOURCE")
|
||||
# Check if the value is an array
|
||||
if [[ "$VALUE" == \[* ]]; then
|
||||
bashio::log.warning "One of your option is an array, skipping"
|
||||
else
|
||||
# Sanitize variable
|
||||
VALUE=$(sanitize_variable "$VALUE")
|
||||
# If value is empty, returns an empty value
|
||||
if [[ -z "$VALUE" ]]; then
|
||||
line="${KEYS}=''"
|
||||
else
|
||||
# Continue for single values
|
||||
line="${KEYS}='${VALUE//\'/\'\\\'\'}'"
|
||||
fi
|
||||
# Check if secret
|
||||
if [[ "${line}" == *"!secret "* ]]; then
|
||||
echo "secret detected"
|
||||
# Get argument
|
||||
secret=${line#*secret }
|
||||
# Remove trailing ' or "
|
||||
secret="${secret%[\"\']}"
|
||||
# Stop if secret file not mounted
|
||||
if [[ "$SECRETSOURCE" == "false" ]]; then
|
||||
bashio::log.warning "Homeassistant config not mounted, secrets are not supported"
|
||||
continue
|
||||
fi
|
||||
# Check if single match
|
||||
secretnum=$(sed -n "/$secret:/=" "$SECRETSOURCE")
|
||||
[[ "$secretnum" == *' '* ]] && bashio::exit.nok "There are multiple matches for your password name. Please check your secrets.yaml file"
|
||||
# Get text
|
||||
secret=$(sed -n "/$secret:/p" "$SECRETSOURCE")
|
||||
secret=${secret#*: }
|
||||
line="${line%%=*}='$secret'"
|
||||
VALUE="$secret"
|
||||
fi
|
||||
# text
|
||||
if bashio::config.false "verbose" || [[ "${KEYS,,}" == *"pass"* ]]; then
|
||||
bashio::log.blue "${KEYS}=******"
|
||||
else
|
||||
bashio::log.blue "$line"
|
||||
fi
|
||||
|
||||
######################################
|
||||
# Export the variable to run scripts #
|
||||
######################################
|
||||
# shellcheck disable=SC2163
|
||||
export "$line"
|
||||
# export to python
|
||||
if command -v "python3" &> /dev/null; then
|
||||
[ ! -f /env.py ] && echo "import os" > /env.py
|
||||
# Escape \
|
||||
VALUEPY="${VALUE//\\/\\\\}"
|
||||
# Avoid " and '
|
||||
VALUEPY="${VALUEPY//[\"\']/}"
|
||||
echo "os.environ['${KEYS}'] = '$VALUEPY'" >> /env.py
|
||||
python3 /env.py
|
||||
fi
|
||||
# set .env
|
||||
echo "$line" >> /.env || true
|
||||
# set /etc/environment
|
||||
mkdir -p /etc
|
||||
echo "$line" >> /etc/environment
|
||||
# For non s6
|
||||
if cat /etc/services.d/*/*run* &> /dev/null; then sed -i "1a export $line" /etc/services.d/*/*run* 2> /dev/null; fi
|
||||
if cat /etc/cont-init.d/*.sh &> /dev/null; then sed -i "1a export $line" /etc/cont-init.d/*.sh 2> /dev/null; fi
|
||||
# For s6
|
||||
if [ -d /var/run/s6/container_environment ]; then printf "%s" "${VALUE}" > /var/run/s6/container_environment/"${KEYS}"; fi
|
||||
echo "export ${KEYS}='${VALUE}'" >> ~/.bashrc
|
||||
fi
|
||||
done
|
||||
|
||||
################
|
||||
# Set timezone #
|
||||
################
|
||||
set +eu
|
||||
|
||||
if [ -n "$TZ" ] && [ -f /etc/localtime ]; then
|
||||
if [ -f /usr/share/zoneinfo/"$TZ" ]; then
|
||||
echo "Timezone set from $(cat /etc/timezone) to $TZ"
|
||||
ln -snf /usr/share/zoneinfo/"$TZ" /etc/localtime && echo "$TZ" > /etc/timezone
|
||||
fi
|
||||
fi
|
@@ -109,4 +109,4 @@ if bashio::config.has_value 'localdisks'; then
|
||||
)
|
||||
done
|
||||
|
||||
fi
|
||||
fi
|
||||
|
357
.templates/00-smb_mounts.sh
Normal file
357
.templates/00-smb_mounts.sh
Normal file
@@ -0,0 +1,357 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
# shellcheck disable=
|
||||
set -e
|
||||
|
||||
if ! bashio::supervisor.ping 2> /dev/null; then
|
||||
bashio::log.blue "Disabled : please use another method"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bashio::log.notice "This script is used to mount remote smb/cifs/nfs shares. Instructions here : https://github.com/alexbelgium/hassio-addons/wiki/Mounting-remote-shares-in-Addons"
|
||||
|
||||
####################
|
||||
# DEFINE FUNCTIONS #
|
||||
####################
|
||||
|
||||
test_mount() {
|
||||
|
||||
# Set initial test
|
||||
MOUNTED=false
|
||||
ERROR_MOUNT=false
|
||||
|
||||
# Exit if not mounted
|
||||
if ! mountpoint -q /mnt/"$diskname"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Exit if can't write
|
||||
[[ -e "/mnt/$diskname/testaze" ]] && rm -r "/mnt/$diskname/testaze"
|
||||
# shellcheck disable=SC2015
|
||||
mkdir "/mnt/$diskname/testaze" && touch "/mnt/$diskname/testaze/testaze" && rm -r "/mnt/$diskname/testaze" || ERROR_MOUNT=true
|
||||
|
||||
# Only CIFS has the noserverino fallback
|
||||
if [[ "$ERROR_MOUNT" == "true" && "$FSTYPE" == "cifs" ]]; then
|
||||
# Test write permissions
|
||||
if [[ "$MOUNTOPTIONS" == *"noserverino"* ]]; then
|
||||
bashio::log.fatal "Disk is mounted, however unable to write in the shared disk. Please check UID/GID for permissions, and if the share is rw"
|
||||
else
|
||||
MOUNTOPTIONS="$MOUNTOPTIONS,noserverino"
|
||||
echo "... testing with noserverino"
|
||||
mount_drive "$MOUNTOPTIONS"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set correctly mounted bit
|
||||
MOUNTED=true
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
mount_drive() {
|
||||
|
||||
# Define options
|
||||
MOUNTED=true
|
||||
MOUNTOPTIONS="$1"
|
||||
|
||||
# Try mounting (type depends on detected FSTYPE)
|
||||
if [[ "$FSTYPE" == "cifs" ]]; then
|
||||
mount -t cifs -o "$MOUNTOPTIONS" "$disk" /mnt/"$diskname" 2> ERRORCODE || MOUNTED=false
|
||||
elif [[ "$FSTYPE" == "nfs" ]]; then
|
||||
mount -t nfs -o "$MOUNTOPTIONS" "$disk" /mnt/"$diskname" 2> ERRORCODE || MOUNTED=false
|
||||
fi
|
||||
|
||||
# Test if successful
|
||||
if [[ "$MOUNTED" == "true" ]]; then
|
||||
# shellcheck disable=SC2015
|
||||
test_mount
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
####################
|
||||
# MOUNT NETWORK SHARES #
|
||||
####################
|
||||
|
||||
if bashio::config.has_value 'networkdisks'; then
|
||||
|
||||
# Alert message that it is a new code
|
||||
if [[ "$(date +"%Y%m%d")" -lt "20240201" ]]; then
|
||||
bashio::log.warning "------------------------"
|
||||
bashio::log.warning "This is a new code, please report any issues on https://github.com/alexbelgium/hassio-addons"
|
||||
bashio::log.warning "------------------------"
|
||||
fi
|
||||
|
||||
echo 'Mounting network share(s)...'
|
||||
|
||||
####################
|
||||
# Define variables #
|
||||
####################
|
||||
|
||||
# Set variables
|
||||
MOREDISKS=$(bashio::config 'networkdisks')
|
||||
USERNAME=$(bashio::config 'cifsusername')
|
||||
PASSWORD=$(bashio::config 'cifspassword')
|
||||
SMBVERS=""
|
||||
SECVERS=""
|
||||
CHARSET=",iocharset=utf8"
|
||||
|
||||
# Clean data (keeps NFS entries intact)
|
||||
MOREDISKS=${MOREDISKS// \/\//,\/\/}
|
||||
MOREDISKS=${MOREDISKS//, /,}
|
||||
MOREDISKS=${MOREDISKS// /"\040"}
|
||||
|
||||
# Is domain set (CIFS only)
|
||||
DOMAIN=""
|
||||
DOMAINCLIENT=""
|
||||
if bashio::config.has_value 'cifsdomain'; then
|
||||
echo "... using domain $(bashio::config 'cifsdomain')"
|
||||
DOMAIN=",domain=$(bashio::config 'cifsdomain')"
|
||||
DOMAINCLIENT="--workgroup=$(bashio::config 'cifsdomain')"
|
||||
fi
|
||||
|
||||
# Is UID/GID set (used for CIFS mount options)
|
||||
PUID=",uid=$(id -u)"
|
||||
PGID=",gid=$(id -g)"
|
||||
if bashio::config.has_value 'PUID' && bashio::config.has_value 'PGID'; then
|
||||
echo "... using PUID $(bashio::config 'PUID') and PGID $(bashio::config 'PGID')"
|
||||
PUID=",uid=$(bashio::config 'PUID')"
|
||||
PGID=",gid=$(bashio::config 'PGID')"
|
||||
fi
|
||||
|
||||
##################
|
||||
# Mounting disks #
|
||||
##################
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
for disk in ${MOREDISKS//,/ }; do # Separate comma separated values
|
||||
|
||||
# Clean name of network share
|
||||
# shellcheck disable=SC2116,SC2001
|
||||
disk=$(echo $disk | sed "s,/$,,") # Remove / at end of name
|
||||
disk="${disk//"\040"/ }" # replace \040 with space
|
||||
|
||||
# Detect filesystem type by pattern (CIFS: //ip/share ; NFS: ip:/export[/path] or nfs://ip:/export[/path])
|
||||
FSTYPE="cifs"
|
||||
if [[ "$disk" =~ ^nfs:// ]]; then
|
||||
FSTYPE="nfs"
|
||||
disk="${disk#nfs://}"
|
||||
elif [[ "$disk" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:/.+ ]]; then
|
||||
FSTYPE="nfs"
|
||||
fi
|
||||
|
||||
# Determine server for reachability checks
|
||||
if [[ "$FSTYPE" == "cifs" ]]; then
|
||||
server="$(echo "$disk" | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+")"
|
||||
else
|
||||
server="${disk%%:*}"
|
||||
fi
|
||||
|
||||
diskname="$disk"
|
||||
diskname="${diskname//\\//}" # replace \ with /
|
||||
diskname="${diskname##*/}" # Get only last part of the name
|
||||
MOUNTED=false
|
||||
SMBVERS_FORCE=""
|
||||
SECVERS_FORCE=""
|
||||
|
||||
# Start
|
||||
echo "... mounting ($FSTYPE) $disk"
|
||||
|
||||
# Data validation
|
||||
if [[ "$FSTYPE" == "cifs" ]]; then
|
||||
if [[ ! "$disk" =~ ^.*+[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+[/]+.*+$ ]]; then
|
||||
bashio::log.fatal "...... the structure of your \"networkdisks\" option : \"$disk\" doesn't seem correct, please use a structure like //123.12.12.12/sharedfolder,//123.12.12.12/sharedfolder2. If you don't use it, you can simply remove the text, this will avoid this error message in the future."
|
||||
touch ERRORCODE
|
||||
continue
|
||||
fi
|
||||
else
|
||||
if [[ ! "$disk" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:/.+ ]]; then
|
||||
bashio::log.fatal "...... invalid NFS path \"$disk\". Use a structure like 123.12.12.12:/export/path"
|
||||
touch ERRORCODE
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Prepare mount point
|
||||
mkdir -p /mnt/"$diskname"
|
||||
chown root:root /mnt/"$diskname"
|
||||
|
||||
# Quickly try to mount with defaults
|
||||
if [[ "$FSTYPE" == "cifs" ]]; then
|
||||
mount_drive "rw,file_mode=0775,dir_mode=0775,username=${USERNAME},password=${PASSWORD},nobrl${SMBVERS}${SECVERS}${PUID}${PGID}${CHARSET}${DOMAIN}"
|
||||
elif [[ "$FSTYPE" == "nfs" ]]; then
|
||||
mount_drive "rw,nfsvers=4.2,proto=tcp,hard,timeo=600,retrans=2"
|
||||
fi
|
||||
|
||||
# Deeper analysis if failed
|
||||
if [ "$MOUNTED" = false ]; then
|
||||
|
||||
if [[ "$FSTYPE" == "cifs" ]]; then
|
||||
|
||||
# Does server exist (SMB port 445)
|
||||
output="$(nmap -F $server -T5 -oG -)"
|
||||
if ! echo "$output" | grep 445/open &> /dev/null; then
|
||||
if echo "$output" | grep /open &> /dev/null; then
|
||||
bashio::log.fatal "...... $server is reachable but SMB port not opened, stopping script"
|
||||
touch ERRORCODE
|
||||
continue
|
||||
else
|
||||
bashio::log.fatal "...... fatal : $server not reachable, is it correct"
|
||||
touch ERRORCODE
|
||||
continue
|
||||
fi
|
||||
else
|
||||
echo "...... $server is confirmed reachable"
|
||||
fi
|
||||
|
||||
# Are credentials correct
|
||||
OUTPUT="$(smbclient -t 2 -L "$disk" -U "$USERNAME"%"$PASSWORD" -c "exit" $DOMAINCLIENT 2>&1 || true)"
|
||||
if echo "$OUTPUT" | grep -q "LOGON_FAILURE"; then
|
||||
bashio::log.fatal "...... incorrect Username, Password, or Domain! Script will stop."
|
||||
touch ERRORCODE
|
||||
# Should there be a workgroup
|
||||
if ! smbclient -t 2 -L $disk -N $DOMAINCLIENT -c "exit" &> /dev/null; then
|
||||
bashio::log.fatal "...... perhaps a workgroup must be specified"
|
||||
touch ERRORCODE
|
||||
fi
|
||||
continue
|
||||
elif echo "$OUTPUT" | grep -q "tree connect failed" || echo "$OUTPUT" | grep -q "NT_STATUS_CONNECTION_DISCONNECTED"; then
|
||||
echo "... using SMBv1"
|
||||
bashio::log.warning "...... share reachable only with legacy SMBv1 (NT1) negotiation. Forcing SMBv1 options."
|
||||
SMBVERS_FORCE=",vers=1.0"
|
||||
SECVERS_FORCE=",sec=ntlm"
|
||||
elif ! echo "$OUTPUT" | grep -q "Disk"; then
|
||||
echo "... testing path"
|
||||
bashio::log.fatal "...... no shares found. Invalid or inaccessible SMB path?"
|
||||
else
|
||||
echo "...... credentials are valid"
|
||||
fi
|
||||
|
||||
# Extracting SMB versions and normalize output
|
||||
# shellcheck disable=SC2210,SC2094
|
||||
SMBVERS="$(nmap --script smb-protocols "$server" -p 445 2> 1 | awk '/ [0-9]/' | awk '{print $NF}' | cut -c -3 | sort -V | tail -n 1 || true)"
|
||||
# Avoid :
|
||||
SMBVERS="${SMBVERS/:/.}"
|
||||
# Manage output
|
||||
if [ -n "$SMBVERS" ]; then
|
||||
case $SMBVERS in
|
||||
"202" | "200" | "20")
|
||||
SMBVERS="2.0"
|
||||
;;
|
||||
21)
|
||||
SMBVERS="2.1"
|
||||
;;
|
||||
302)
|
||||
SMBVERS="3.02"
|
||||
;;
|
||||
311)
|
||||
SMBVERS="3.1.1"
|
||||
;;
|
||||
"3.1")
|
||||
echo "SMB 3.1 detected, converting to 3.0"
|
||||
SMBVERS="3.0"
|
||||
;;
|
||||
esac
|
||||
echo "...... SMB version detected : $SMBVERS"
|
||||
SMBVERS=",vers=$SMBVERS"
|
||||
elif smbclient -t 2 -L "$server" -m NT1 -N $DOMAINCLIENT &> /dev/null; then
|
||||
echo "...... SMB version : only SMBv1 is supported, this can lead to issues"
|
||||
SECVERS=",sec=ntlm"
|
||||
SMBVERS=",vers=1.0"
|
||||
else
|
||||
echo "...... SMB version : couldn't detect, default used"
|
||||
SMBVERS=""
|
||||
fi
|
||||
|
||||
# Apply forced SMBv1 options when initial connection required NT1 fallback
|
||||
if [[ -n "$SMBVERS_FORCE" ]]; then
|
||||
if [[ -z "$SMBVERS" ]]; then
|
||||
SMBVERS="$SMBVERS_FORCE"
|
||||
fi
|
||||
if [[ -z "$SECVERS" ]]; then
|
||||
SECVERS="$SECVERS_FORCE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure the Samba client allows SMBv1 when those options are required
|
||||
if [[ "${SMBVERS}${SMBVERS_FORCE}" == *"vers=1.0"* ]]; then
|
||||
if [[ -f /etc/samba/smb.conf ]]; then
|
||||
bashio::log.warning "...... enabling SMBv1 support in Samba client configuration"
|
||||
sed -i '/\[global\]/!b;n;/client min protocol = NT1/!a\
|
||||
client min protocol = NT1' /etc/samba/smb.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
# Test with different security versions
|
||||
#######################################
|
||||
for SECVERS in "$SECVERS" ",sec=ntlmv2" ",sec=ntlmssp" ",sec=ntlmsspi" ",sec=krb5i" ",sec=krb5" ",sec=ntlm" ",sec=ntlmv2i"; do
|
||||
if [ "$MOUNTED" = false ]; then
|
||||
mount_drive "rw,file_mode=0775,dir_mode=0775,username=${USERNAME},password=${PASSWORD},nobrl${SMBVERS}${SECVERS}${PUID}${PGID}${CHARSET}${DOMAIN}"
|
||||
fi
|
||||
done
|
||||
|
||||
elif [[ "$FSTYPE" == "nfs" ]]; then
|
||||
# Add NFS-specific port check (2049) similar to SMB (445)
|
||||
output="$(nmap -F $server -T5 -oG -)"
|
||||
if ! echo "$output" | grep -E '(2049|111)/open' &> /dev/null; then
|
||||
bashio::log.fatal "...... $server is reachable but NFS ports not open"
|
||||
continue
|
||||
fi
|
||||
# NFS fallback attempts: try common versions until one works
|
||||
for NFVER in 4.2 4.1 4 3; do
|
||||
if [ "$MOUNTED" = false ]; then
|
||||
mount_drive "rw,nfsvers=${NFVER},proto=tcp"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# Messages
|
||||
if [ "$MOUNTED" = true ]; then
|
||||
|
||||
bashio::log.info "...... $disk successfully mounted to /mnt/$diskname with options ${MOUNTOPTIONS/$PASSWORD/XXXXXXXXXX}"
|
||||
# Remove errorcode
|
||||
if [ -f ERRORCODE ]; then
|
||||
rm ERRORCODE
|
||||
fi
|
||||
|
||||
# Alert if smbv1
|
||||
if [[ "$FSTYPE" == "cifs" && "$MOUNTOPTIONS" == *"1.0"* ]]; then
|
||||
bashio::log.warning ""
|
||||
bashio::log.warning "Your smb system requires smbv1. This is an obsolete protocol. Please correct this to prevent issues."
|
||||
bashio::log.warning ""
|
||||
fi
|
||||
|
||||
else
|
||||
# Mounting failed messages
|
||||
if [[ "$FSTYPE" == "cifs" ]]; then
|
||||
bashio::log.fatal "Error, unable to mount $disk to /mnt/$diskname with username $USERNAME, $PASSWORD. Please check your remote share path, username, password, domain, try putting 0 in UID and GID"
|
||||
bashio::log.fatal "Here is some debugging info :"
|
||||
smbclient -t 2 -L $disk -U "$USERNAME%$PASSWORD" -c "exit"
|
||||
SMBVERS=""
|
||||
SECVERS=""
|
||||
PUID=""
|
||||
PGID=""
|
||||
CHARSET=""
|
||||
mount_drive "rw,file_mode=0775,dir_mode=0775,username=${USERNAME},password=${PASSWORD},nobrl${SMBVERS}${SECVERS}${PUID}${PGID}${CHARSET}${DOMAIN}"
|
||||
elif [[ "$FSTYPE" == "nfs" ]]; then
|
||||
bashio::log.fatal "Error, unable to mount NFS share $disk to /mnt/$diskname. Please check the export path and that NFS server allows this client (and NFSv4)."
|
||||
# last-ditch try with very basic options
|
||||
mount_drive "rw"
|
||||
fi
|
||||
|
||||
bashio::log.fatal "Error read : $(< ERRORCODE), addon will stop in 1 min"
|
||||
|
||||
# clean folder
|
||||
umount "/mnt/$diskname" 2> /dev/null || true
|
||||
rmdir "/mnt/$diskname" || true
|
||||
|
||||
# Stop addon
|
||||
bashio::addon.stop
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
fi
|
202
.templates/01-config_yaml.sh
Normal file
202
.templates/01-config_yaml.sh
Normal file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
|
||||
##################
|
||||
# INITIALIZATION #
|
||||
##################
|
||||
|
||||
# Disable if config not present
|
||||
if [ ! -d /config ] || ! bashio::supervisor.ping 2> /dev/null; then
|
||||
echo "..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Define slug
|
||||
slug="${HOSTNAME/-/_}"
|
||||
slug="${slug#*_}"
|
||||
|
||||
# Check type of config folder
|
||||
if [ ! -f /config/configuration.yaml ] && [ ! -f /config/configuration.json ]; then
|
||||
# New config location
|
||||
CONFIGLOCATION="/config"
|
||||
CONFIGFILEBROWSER="/addon_configs/${HOSTNAME/-/_}/config.yaml"
|
||||
else
|
||||
# Legacy config location
|
||||
CONFIGLOCATION="/config/addons_config/${slug}"
|
||||
CONFIGFILEBROWSER="/homeassistant/addons_config/$slug/config.yaml"
|
||||
fi
|
||||
|
||||
# Default location
|
||||
mkdir -p "$CONFIGLOCATION" || true
|
||||
CONFIGSOURCE="$CONFIGLOCATION"/config.yaml
|
||||
|
||||
# Is there a custom path
|
||||
if bashio::config.has_value 'CONFIG_LOCATION'; then
|
||||
CONFIGSOURCE=$(bashio::config "CONFIG_LOCATION")
|
||||
if [[ "$CONFIGSOURCE" == *"."* ]]; then
|
||||
CONFIGSOURCE=$(dirname "$CONFIGSOURCE")
|
||||
fi
|
||||
# If does not end by config.yaml, remove trailing slash and add config.yaml
|
||||
if [[ "$CONFIGSOURCE" != *".yaml" ]]; then
|
||||
CONFIGSOURCE="${CONFIGSOURCE%/}"/config.yaml
|
||||
fi
|
||||
# Check if config is located in an acceptable location
|
||||
LOCATIONOK=""
|
||||
for location in "/share" "/config" "/data"; do
|
||||
if [[ "$CONFIGSOURCE" == "$location"* ]]; then
|
||||
LOCATIONOK=true
|
||||
fi
|
||||
done
|
||||
if [ -z "$LOCATIONOK" ]; then
|
||||
bashio::log.red "Watch-out: your CONFIG_LOCATION values can only be set in /share, /config or /data (internal to addon). It will be reset to the default location: $CONFIGLOCATION/config.yaml"
|
||||
CONFIGSOURCE="$CONFIGLOCATION"/config.yaml
|
||||
fi
|
||||
fi
|
||||
|
||||
# Migrate if needed
|
||||
if [[ "$CONFIGLOCATION" == "/config" ]]; then
|
||||
# Migrate file
|
||||
if [ -f "/homeassistant/addons_config/${slug}/config.yaml" ] && [ ! -L "/homeassistant/addons_config/${slug}" ]; then
|
||||
echo "Migrating config.yaml to new config location"
|
||||
mv "/homeassistant/addons_config/${slug}/config.yaml" /config/config.yaml
|
||||
fi
|
||||
# Migrate option
|
||||
if [[ "$(bashio::config "CONFIG_LOCATION")" == "/config/addons_config"* ]] && [ -f /config/config.yaml ]; then
|
||||
bashio::addon.option "CONFIG_LOCATION" "/config/config.yaml"
|
||||
CONFIGSOURCE="/config/config.yaml"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$CONFIGSOURCE" != *".yaml" ]]; then
|
||||
bashio::log.error "Something is going wrong in the config location, quitting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Permissions
|
||||
if [[ "$CONFIGSOURCE" == *".yaml" ]]; then
|
||||
echo "Setting permissions for the config.yaml directory"
|
||||
mkdir -p "$(dirname "${CONFIGSOURCE}")"
|
||||
chmod -R 755 "$(dirname "${CONFIGSOURCE}")" 2> /dev/null
|
||||
fi
|
||||
|
||||
####################
|
||||
# LOAD CONFIG.YAML #
|
||||
####################
|
||||
|
||||
echo ""
|
||||
bashio::log.green "Load environment variables from $CONFIGSOURCE if existing"
|
||||
if [[ "$CONFIGSOURCE" == "/config"* ]]; then
|
||||
bashio::log.green "If accessing the file with filebrowser it should be mapped to $CONFIGFILEBROWSER"
|
||||
else
|
||||
bashio::log.green "If accessing the file with filebrowser it should be mapped to $CONFIGSOURCE"
|
||||
fi
|
||||
bashio::log.green "---------------------------------------------------------"
|
||||
bashio::log.notice "This script is used to export custom environment variables at start of the addon. Instructions here : https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon"
|
||||
echo ""
|
||||
|
||||
# Check if config file is there, or create one from template
|
||||
if [ ! -f "$CONFIGSOURCE" ]; then
|
||||
echo "... no config file, creating one from template. Please customize the file in $CONFIGSOURCE before restarting."
|
||||
# Create folder
|
||||
mkdir -p "$(dirname "${CONFIGSOURCE}")"
|
||||
# Placing template in config
|
||||
if [ -f /templates/config.yaml ]; then
|
||||
# Use available template
|
||||
cp /templates/config.yaml "$(dirname "${CONFIGSOURCE}")"
|
||||
else
|
||||
# Download template
|
||||
TEMPLATESOURCE="https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/config.template"
|
||||
curl -f -L -s -S "$TEMPLATESOURCE" --output "$CONFIGSOURCE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if there are lines to read
|
||||
cp "$CONFIGSOURCE" /tempenv
|
||||
sed -i '/^#/d' /tempenv
|
||||
sed -i '/^[[:space:]]*$/d' /tempenv
|
||||
sed -i '/^$/d' /tempenv
|
||||
echo "" >> /tempenv
|
||||
|
||||
# Exit if empty
|
||||
if [ ! -s /tempenv ]; then
|
||||
bashio::log.green "... no env variables found, exiting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if yaml is valid
|
||||
EXIT_CODE=0
|
||||
yamllint -d relaxed /tempenv &> ERROR || EXIT_CODE=$?
|
||||
if [ "$EXIT_CODE" != 0 ]; then
|
||||
cat ERROR
|
||||
bashio::log.yellow "... config file has an invalid yaml format. Please check the file in $CONFIGSOURCE. Errors list above."
|
||||
fi
|
||||
|
||||
# converts yaml to variables
|
||||
sed -i 's/: /=/' /tempenv
|
||||
|
||||
# Look where secrets.yaml is located
|
||||
SECRETSFILE="/config/secrets.yaml"
|
||||
if [ ! -f "$SECRETSFILE" ]; then SECRETSFILE="/homeassistant/secrets.yaml"; fi
|
||||
|
||||
while IFS= read -r line; do
|
||||
# Skip empty lines
|
||||
if [[ -z "$line" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if secret
|
||||
if [[ "$line" == *!secret* ]]; then
|
||||
echo "Secret detected"
|
||||
if [ ! -f "$SECRETSFILE" ]; then
|
||||
bashio::log.fatal "Secrets file not found in $SECRETSFILE, $line skipped"
|
||||
continue
|
||||
fi
|
||||
secret=$(echo "$line" | sed 's/.*!secret \(.*\)/\1/')
|
||||
# Check if single match
|
||||
secretnum=$(sed -n "/$secret:/=" "$SECRETSFILE")
|
||||
if [[ $(echo "$secretnum" | grep -q ' ') ]]; then
|
||||
bashio::exit.nok "There are multiple matches for your password name. Please check your secrets.yaml file"
|
||||
fi
|
||||
# Get text
|
||||
secret_value=$(sed -n "/$secret:/s/.*: //p" "$SECRETSFILE")
|
||||
line="${line%%=*}='$secret_value'"
|
||||
fi
|
||||
|
||||
# Data validation
|
||||
if [[ "$line" =~ ^[^[:space:]]+.+[=].+$ ]]; then
|
||||
# extract keys and values
|
||||
KEYS="${line%%=*}"
|
||||
VALUE="${line#*=}"
|
||||
# Check if VALUE is quoted
|
||||
#if [[ "$VALUE" != \"*\" ]] && [[ "$VALUE" != \'*\' ]]; then
|
||||
# VALUE="\"$VALUE\""
|
||||
#fi
|
||||
line="${KEYS}=${VALUE}"
|
||||
export "$line"
|
||||
# export to python
|
||||
if command -v "python3" &> /dev/null; then
|
||||
[ ! -f /env.py ] && echo "import os" > /env.py
|
||||
# Escape single quotes in VALUE
|
||||
VALUE_ESCAPED="${VALUE//\'/\'\"\'\"\'}"
|
||||
echo "os.environ['${KEYS}'] = '${VALUE_ESCAPED}'" >> /env.py
|
||||
python3 /env.py
|
||||
fi
|
||||
# set .env
|
||||
echo "$line" >> /.env
|
||||
# set environment
|
||||
mkdir -p /etc
|
||||
echo "$line" >> /etc/environment
|
||||
# Export to scripts
|
||||
if cat /etc/services.d/*/*run* &> /dev/null; then sed -i "1a export $line" /etc/services.d/*/*run* 2> /dev/null; fi
|
||||
if cat /etc/cont-init.d/*run* &> /dev/null; then sed -i "1a export $line" /etc/cont-init.d/*run* 2> /dev/null; fi
|
||||
# For s6
|
||||
if [ -d /var/run/s6/container_environment ]; then printf "%s" "${VALUE}" > /var/run/s6/container_environment/"${KEYS}"; fi
|
||||
echo "export $line" >> ~/.bashrc
|
||||
# Show in log
|
||||
if ! bashio::config.false "verbose"; then bashio::log.blue "$line"; fi
|
||||
else
|
||||
bashio::log.red "Skipping line that does not follow the correct structure: $line"
|
||||
fi
|
||||
done < "/tempenv"
|
||||
|
||||
rm /tempenv
|
66
.templates/01-custom_script.sh
Normal file
66
.templates/01-custom_script.sh
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
##################
|
||||
# INITIALIZATION #
|
||||
##################
|
||||
|
||||
# Exit if /config is not mounted or HA not used
|
||||
if [ ! -d /config ] || ! bashio::supervisor.ping 2> /dev/null; then
|
||||
echo "..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Define slug
|
||||
slug="${HOSTNAME/-/_}"
|
||||
slug="${slug#*_}"
|
||||
|
||||
# Check type of config folder
|
||||
if [ ! -f /config/configuration.yaml ] && [ ! -f /config/configuration.json ]; then
|
||||
# New config location
|
||||
CONFIGLOCATION="/config"
|
||||
CONFIGFILEBROWSER="/addon_configs/${HOSTNAME/-/_}/$slug.sh"
|
||||
else
|
||||
# Legacy config location
|
||||
CONFIGLOCATION="/config/addons_autoscripts"
|
||||
CONFIGFILEBROWSER="/homeassistant/addons_autoscripts/$slug.sh"
|
||||
fi
|
||||
|
||||
# Default location
|
||||
mkdir -p "$CONFIGLOCATION" || true
|
||||
CONFIGSOURCE="$CONFIGLOCATION/$slug.sh"
|
||||
|
||||
bashio::log.notice "This script is used to run custom commands at start of the addon. Instructions here : https://github.com/alexbelgium/hassio-addons/wiki/Running-custom-scripts-in-Addons"
|
||||
bashio::log.green "Execute $CONFIGFILEBROWSER if existing"
|
||||
|
||||
# Download template if no script found and exit
|
||||
if [ ! -f "$CONFIGSOURCE" ]; then
|
||||
TEMPLATESOURCE="https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/script.template"
|
||||
curl -f -L -s -S "$TEMPLATESOURCE" --output "$CONFIGSOURCE" || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Convert scripts to linux
|
||||
dos2unix "$CONFIGSOURCE" &> /dev/null || true
|
||||
chmod +x "$CONFIGSOURCE"
|
||||
|
||||
# Get current shebang, if not available use another
|
||||
currentshebang="$(sed -n '1{s/^#![[:blank:]]*//p;q}' "$CONFIGSOURCE")"
|
||||
if [ ! -f "${currentshebang%% *}" ]; then
|
||||
for shebang in "/command/with-contenv bashio" "/usr/bin/env bashio" "/usr/bin/bashio" "/bin/bash" "/bin/sh"; do if [ -f "${shebang%% *}" ]; then break; fi; done
|
||||
sed -i "s|$currentshebang|$shebang|g" "$CONFIGSOURCE"
|
||||
fi
|
||||
|
||||
# Check if there is actual commands
|
||||
while IFS= read -r line; do
|
||||
# Remove leading and trailing whitespaces
|
||||
line="$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
||||
|
||||
# Check if line is not empty and does not start with #
|
||||
if [[ -n "$line" ]] && [[ ! "$line" =~ ^# ]]; then
|
||||
bashio::log.green "... script found, executing"
|
||||
/."$CONFIGSOURCE"
|
||||
break
|
||||
fi
|
||||
done < "$CONFIGSOURCE"
|
46
.templates/19-json_repair.sh
Normal file
46
.templates/19-json_repair.sh
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
# shellchek disable=SC2015
|
||||
|
||||
JSONTOCHECK='/config/transmission/settings.json'
|
||||
JSONSOURCE='/defaults/settings.json'
|
||||
|
||||
# If json already exists
|
||||
if [ -f "${JSONTOCHECK}" ]; then
|
||||
# Variables
|
||||
echo "Checking settings.json format"
|
||||
|
||||
# Check if json file valid or not
|
||||
jq . -S "${JSONTOCHECK}" &> /dev/null && ERROR=false || ERROR=true
|
||||
if [ "$ERROR" = true ]; then
|
||||
bashio::log.fatal "Settings.json structure is abnormal, restoring options from scratch. Your old file is renamed as settings.json_old"
|
||||
mv "${JSONSOURCE}" "${JSONSOURCE}"_old
|
||||
cp "${JSONSOURCE}" "${JSONTOCHECK}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get the default keys from the original file
|
||||
mapfile -t arr < <(jq -r 'keys[]' "${JSONSOURCE}")
|
||||
|
||||
# Check if all keys are still there, or add them
|
||||
# spellcheck disable=SC2068
|
||||
for KEYS in "${arr[@]}"; do
|
||||
# Check if key exists
|
||||
KEYSTHERE=$(jq "has(\"${KEYS}\")" "${JSONTOCHECK}")
|
||||
if [ "$KEYSTHERE" != "true" ]; then
|
||||
#Fetch initial value
|
||||
JSONSOURCEVALUE=$(jq -r ".\"$KEYS\"" "${JSONSOURCE}")
|
||||
#Add key
|
||||
sed -i "3 i\"${KEYS}\": \"${JSONSOURCEVALUE}\"," "${JSONTOCHECK}"
|
||||
# Message
|
||||
bashio::log.warning "${KEYS} was missing from your settings.json, it was added with the default value ${JSONSOURCEVALUE}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Show structure in a nice way
|
||||
jq . -S "${JSONTOCHECK}" | cat > temp.json && mv temp.json "${JSONTOCHECK}"
|
||||
|
||||
# Message
|
||||
bashio::log.info "Your settings.json was checked and seems perfectly normal!"
|
||||
fi
|
35
.templates/90-disable_ingress.sh
Normal file
35
.templates/90-disable_ingress.sh
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
# Disables ingress and sets a default index
|
||||
|
||||
# Disable Ingress
|
||||
if bashio::config.true "ingress_disabled"; then
|
||||
bashio::log.warning "Ingress is disabled. You'll need to connect using ip:port"
|
||||
|
||||
# Adapt ingress.conf
|
||||
sed -i "/root/d" /etc/nginx/servers/ingress.conf
|
||||
sed -i "/proxy_pass/i root /etc;" /etc/nginx/servers/ingress.conf
|
||||
sed -i "/proxy_pass/i try_files '' /ingress.html =404;" /etc/nginx/servers/ingress.conf
|
||||
sed -i "/proxy_pass/d" /etc/nginx/servers/ingress.conf
|
||||
|
||||
# Create index.html
|
||||
touch /etc/ingress.html
|
||||
cat > /etc/ingress.html << EOF
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ingress is disabled!</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="your_class"></div>
|
||||
<p style="background-color:black;color:yellow">
|
||||
Ingress was disabled by the user. Please connect using ip:port or
|
||||
re-enable in the addons options.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
EOF
|
||||
fi
|
43
.templates/90-dns_set.sh
Normal file
43
.templates/90-dns_set.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
###############
|
||||
# DNS SETTING #
|
||||
###############
|
||||
|
||||
# Avoid usage of local dns such as adguard home or pihole\n"
|
||||
|
||||
if bashio::config.has_value 'DNS_server'; then
|
||||
# Define variables
|
||||
DNSSERVER=$(bashio::config 'DNS_server')
|
||||
DNS=""
|
||||
DNSLIST=""
|
||||
|
||||
# Get DNS servers
|
||||
# shellcheck disable=SC2086
|
||||
for server in ${DNSSERVER//,/ }; do # Separate comma separated values
|
||||
# Only add DNS if successful
|
||||
if ping -c 1 "$server" &> /dev/null; then
|
||||
DNS="${DNS}nameserver $server\n"
|
||||
DNSLIST="$server $DNSLIST"
|
||||
else
|
||||
bashio::log.warning "DNS $server was requested but can't be pinged. It won't be used"
|
||||
fi
|
||||
done
|
||||
|
||||
# Only add DNS if there are DNS set
|
||||
# shellcheck disable=SC2236
|
||||
if [[ -n "${DNS:-}" ]]; then
|
||||
# Write resolv.conf
|
||||
# shellcheck disable=SC2059
|
||||
printf "${DNS}" > /etc/resolv.conf
|
||||
chmod 644 /etc/resolv.conf
|
||||
bashio::log.info "DNS SERVERS set to $DNSLIST"
|
||||
else
|
||||
bashio::log.warning "No valid DNS were found. Using default router (or HA) dns servers."
|
||||
fi
|
||||
|
||||
else
|
||||
bashio::log.info "DNS Servers option empty. Using default router (or HA) dns servers."
|
||||
fi
|
14
.templates/91-silent.sh
Normal file
14
.templates/91-silent.sh
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
###############
|
||||
# SILENT MODE #
|
||||
###############
|
||||
|
||||
if bashio::config.true 'silent'; then
|
||||
APPEND=' > /dev/null'
|
||||
sed -i '$s|$|'"$APPEND"'|' /etc/services.d/*/run &> /dev/null || true
|
||||
sed -i '$s|$|'"$APPEND"'|' /etc/cont-init.d/*/*run* &> /dev/null || true
|
||||
bashio::log.info 'Silent mode activated, all logs from emby server are hidden. Disable this option if you need to troubleshoot the addon.'
|
||||
fi
|
172
.templates/91-universal_graphic_drivers.sh
Normal file
172
.templates/91-universal_graphic_drivers.sh
Normal file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env bashio
|
||||
set -e
|
||||
|
||||
if bashio::config.has_value "graphic_driver"; then
|
||||
|
||||
# Origin : https://github.com/wumingjieno1/photoprism-test/blob/main/scripts/dist/install-gpu.sh
|
||||
# abort if not executed as root
|
||||
if [[ $(id -u) != "0" ]]; then
|
||||
# shellcheck disable=SC2128
|
||||
bashio::log.fatal "Error: Run $(basename "${BASH_SOURCE}") as root" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get installer type
|
||||
if [ -f /usr/bin/apt ]; then
|
||||
bashio::log.info "... Distribution detected : Debian/Ubuntu"
|
||||
apt-get install -yqq software-properties-common > /dev/null
|
||||
add-apt-repository ppa:kisak/kisak-mesa > /dev/null
|
||||
apt-get update > /dev/null
|
||||
apt-get install -yqq mesa
|
||||
elif [ -f /usr/bin/apk ]; then
|
||||
bashio::log.info "... Distribution detected : Alpine"
|
||||
fi
|
||||
|
||||
# Detect GPU
|
||||
# shellcheck disable=SC2207
|
||||
GPU_DETECTED=($(lshw -c display -json 2> /dev/null | jq -r '.[].configuration.driver'))
|
||||
bashio::log.info "... GPU detected: ${GPU_DETECTED[*]}"
|
||||
graphic_driver=""
|
||||
|
||||
# Get arch type
|
||||
BUILD_ARCH="$(uname -m)"
|
||||
case "$BUILD_ARCH" in
|
||||
amd64 | AMD64 | x86_64 | x86-64)
|
||||
BUILD_ARCH=amd64
|
||||
;;
|
||||
|
||||
arm64 | ARM64 | aarch64)
|
||||
BUILD_ARCH=arm64
|
||||
graphic_driver=aarch64_rpi
|
||||
;;
|
||||
|
||||
arm | ARM | aarch | armv7l | armhf)
|
||||
bashio::log.fatal "Unsupported Machine Architecture: $BUILD_ARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
|
||||
*)
|
||||
bashio::log.fatal "Unsupported Machine Architecture: $BUILD_ARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
bashio::log.info "... architecture detected: ${BUILD_ARCH}"
|
||||
|
||||
#graphic_driver="$(bashio::config "graphic_driver")"
|
||||
case "$graphic_driver" in
|
||||
x64_AMD)
|
||||
if [[ "$BUILD_ARCH" != amd64 ]]; then bashio::log.fatal "Wrong architecture, $graphic_driver doesn't support $BUILD_ARCH"; fi
|
||||
[ -f /usr/bin/apt ] && DOCKER_MODS=linuxserver/mods:jellyfin-amd && run_mods > /dev/null && bashio::log.green "... done"
|
||||
[ -f /usr/bin/apk ] && apk add --no-cache mesa-dri-classic mesa-vdpau-gallium linux-firmware-radeon > /dev/null && bashio::log.green "... done"
|
||||
;;
|
||||
|
||||
x64_NVIDIA)
|
||||
if [[ "$BUILD_ARCH" != amd64 ]]; then bashio::log.fatal "Wrong architecture, $graphic_driver doesn't support $BUILD_ARCH"; fi
|
||||
[ -f /usr/bin/apk ] && apk add --no-cache linux-firmware-radeon > /dev/null && bashio::log.green "... done"
|
||||
[ -f /usr/bin/apt ] && apt-get -yqq install libcuda1 libnvcuvid1 libnvidia-encode1 nvidia-opencl-icd nvidia-vdpau-driver nvidia-driver-libs nvidia-kernel-dkms libva2 vainfo libva-wayland2 > /dev/null && bashio::log.green "... done"
|
||||
;;
|
||||
|
||||
x64_Intel)
|
||||
if [[ "$BUILD_ARCH" != amd64 ]]; then bashio::log.fatal "Wrong architecture, $graphic_driver doesn't support $BUILD_ARCH"; fi
|
||||
[ -f /usr/bin/apk ] && apk add --no-cache opencl mesa-dri-gallium mesa-vulkan-intel mesa-dri-intel intel-media-driver > /dev/null && bashio::log.green "... done"
|
||||
[ -f /usr/bin/apt ] && DOCKER_MODS=linuxserver/mods:jellyfin-opencl-intel && run_mods && apt-get -yqq install intel-opencl-icd intel-media-va-driver-non-free i965-va-driver-shaders mesa-va-drivers libmfx1 libva2 vainfo libva-wayland2 > /dev/null && bashio::log.green "... done"
|
||||
;;
|
||||
|
||||
aarch64_rpi)
|
||||
if [[ "$BUILD_ARCH" != arm64 ]]; then bashio::log.fatal "Wrong architecture, $graphic_driver doesn't support $BUILD_ARCH"; fi
|
||||
bashio::log.info "Installing Rpi graphic drivers"
|
||||
[ -f /usr/bin/apk ] && apk add --no-cache mesa-dri-vc4 mesa-dri-swrast mesa-gbm xf86-video-fbdev > /dev/null && bashio::log.green "... done"
|
||||
[ -f /usr/bin/apt ] && apt-get -yqq install libgles2-mesa libgles2-mesa-dev xorg-dev > /dev/null && bashio::log.green "... done"
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Main run logic
|
||||
run_mods() {
|
||||
echo "[mod-init] Attempting to run Docker Modification Logic"
|
||||
for DOCKER_MOD in $(echo "${DOCKER_MODS}" | tr '|' '\n'); do
|
||||
# Support alternative endpoints
|
||||
if [[ ${DOCKER_MOD} == ghcr.io/* ]] || [[ ${DOCKER_MOD} == linuxserver/* ]]; then
|
||||
DOCKER_MOD="${DOCKER_MOD#ghcr.io/*}"
|
||||
ENDPOINT="${DOCKER_MOD%%:*}"
|
||||
USERNAME="${DOCKER_MOD%%/*}"
|
||||
REPO="${ENDPOINT#*/}"
|
||||
TAG="${DOCKER_MOD#*:}"
|
||||
if [[ ${TAG} == "${DOCKER_MOD}" ]]; then
|
||||
TAG="latest"
|
||||
fi
|
||||
FILENAME="${USERNAME}.${REPO}.${TAG}"
|
||||
AUTH_URL="https://ghcr.io/token?scope=repository%3A${USERNAME}%2F${REPO}%3Apull"
|
||||
MANIFEST_URL="https://ghcr.io/v2/${ENDPOINT}/manifests/${TAG}"
|
||||
BLOB_URL="https://ghcr.io/v2/${ENDPOINT}/blobs/"
|
||||
MODE="ghcr"
|
||||
else
|
||||
ENDPOINT="${DOCKER_MOD%%:*}"
|
||||
USERNAME="${DOCKER_MOD%%/*}"
|
||||
REPO="${ENDPOINT#*/}"
|
||||
TAG="${DOCKER_MOD#*:}"
|
||||
if [[ ${TAG} == "${DOCKER_MOD}" ]]; then
|
||||
TAG="latest"
|
||||
fi
|
||||
FILENAME="${USERNAME}.${REPO}.${TAG}"
|
||||
AUTH_URL="https://auth.docker.io/token?service=registry.docker.io&scope=repository:${ENDPOINT}:pull"
|
||||
MANIFEST_URL="https://registry-1.docker.io/v2/${ENDPOINT}/manifests/${TAG}"
|
||||
BLOB_URL="https://registry-1.docker.io/v2/${ENDPOINT}/blobs/"
|
||||
MODE="dockerhub"
|
||||
fi
|
||||
# Kill off modification logic if any of the usernames are banned
|
||||
for BANNED in $(curl -s https://raw.githubusercontent.com/linuxserver/docker-mods/master/blacklist.txt); do
|
||||
if [[ "${BANNED,,}" == "${USERNAME,,}" ]]; then
|
||||
if [[ -z ${RUN_BANNED_MODS+x} ]]; then
|
||||
echo "[mod-init] ${DOCKER_MOD} is banned from use due to reported abuse aborting mod logic"
|
||||
return
|
||||
else
|
||||
echo "[mod-init] You have chosen to run banned mods ${DOCKER_MOD} will be applied"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "[mod-init] Applying ${DOCKER_MOD} files to container"
|
||||
# Get Dockerhub token for api operations
|
||||
TOKEN="$(
|
||||
curl -f --retry 10 --retry-max-time 60 --retry-connrefused \
|
||||
--silent \
|
||||
--header 'GET' \
|
||||
"${AUTH_URL}" \
|
||||
| jq -r '.token'
|
||||
)"
|
||||
# Determine first and only layer of image
|
||||
SHALAYER=$(get_blob_sha "${MODE}" "${TOKEN}" "${MANIFEST_URL}")
|
||||
# Check if we have allready applied this layer
|
||||
if [[ -f "/${FILENAME}" ]] && [[ "${SHALAYER}" == "$(cat /"${FILENAME}")" ]]; then
|
||||
echo "[mod-init] ${DOCKER_MOD} at ${SHALAYER} has been previously applied skipping"
|
||||
else
|
||||
# Download and extract layer to /
|
||||
curl -f --retry 10 --retry-max-time 60 --retry-connrefused \
|
||||
--silent \
|
||||
--location \
|
||||
--request GET \
|
||||
--header "Authorization: Bearer ${TOKEN}" \
|
||||
"${BLOB_URL}${SHALAYER}" -o \
|
||||
/modtarball.tar.xz
|
||||
mkdir -p /tmp/mod
|
||||
tar xzf /modtarball.tar.xz -C /tmp/mod
|
||||
if [[ -d /tmp/mod/etc/s6-overlay ]]; then
|
||||
if [[ -d /tmp/mod/etc/cont-init.d ]]; then
|
||||
rm -rf /tmp/mod/etc/cont-init.d
|
||||
fi
|
||||
if [[ -d /tmp/mod/etc/services.d ]]; then
|
||||
rm -rf /tmp/mod/etc/services.d
|
||||
fi
|
||||
fi
|
||||
shopt -s dotglob
|
||||
cp -R /tmp/mod/* /
|
||||
shopt -u dotglob
|
||||
rm -rf /tmp/mod
|
||||
rm -rf /modtarball.tar.xz
|
||||
echo "${SHALAYER}" > "/${FILENAME}"
|
||||
echo "[mod-init] ${DOCKER_MOD} applied to container"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
fi
|
10
.templates/99-custom_script.sh
Normal file
10
.templates/99-custom_script.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
CONFIGSOURCE=$(bashio::config "CONFIG_LOCATION")
|
||||
CONFIGSOURCE="$(dirname "${CONFIGSOURCE}")"
|
||||
|
||||
if [ -f "$CONFIGSOURCE"/script.sh ]; then
|
||||
"$CONFIGSOURCE"./script.sh
|
||||
fi
|
444
.templates/bashio-standalone.sh
Normal file
444
.templates/bashio-standalone.sh
Normal file
@@ -0,0 +1,444 @@
|
||||
# /usr/local/lib/bashio-standalone.sh
|
||||
# shellcheck shell=bash
|
||||
# Minimal bashio compatibility layer for running Home Assistant add-ons
|
||||
# as standalone containers (no Supervisor). It overrides common bashio::*
|
||||
# functions to source config from ENV (and optionally a JSON file).
|
||||
# Load it conditionally in your entry script when supervisor isn't reachable.
|
||||
|
||||
# -------- internals ----------------------------------------------------------
|
||||
|
||||
# Whether to emit ANSI colors (disabled if not a TTY)
|
||||
if [ -t 1 ]; then
|
||||
_BASHIO_COLOR=1
|
||||
else
|
||||
_BASHIO_COLOR=0
|
||||
fi
|
||||
|
||||
_bashio_color() {
|
||||
# $1=name; returns ANSI sequence or empty
|
||||
if [ "$_BASHIO_COLOR" != "1" ]; then return 0; fi
|
||||
case "$1" in
|
||||
blue) printf '\033[34m' ;;
|
||||
green) printf '\033[32m' ;;
|
||||
yellow) printf '\033[33m' ;;
|
||||
red) printf '\033[31m' ;;
|
||||
magenta) printf '\033[35m' ;;
|
||||
reset) printf '\033[0m' ;;
|
||||
esac
|
||||
}
|
||||
|
||||
_bashio_log() {
|
||||
# $1=color name, $2...=msg
|
||||
local c="$1"
|
||||
shift
|
||||
local pre
|
||||
pre="$(_bashio_color "$c")"
|
||||
local rst
|
||||
rst="$(_bashio_color reset)"
|
||||
printf '%s%s%s\n' "$pre" "$*" "$rst"
|
||||
}
|
||||
|
||||
# Optional JSON options source (single flat object or nested).
|
||||
# Set STANDALONE_OPTIONS_JSON to a path (e.g., /data/options.json).
|
||||
# If jq is present, keys can be fetched as .key or .nested.key
|
||||
_bashio_json_get() {
|
||||
# $1=key (dot.notation). echoes value or empty; returns 0 always
|
||||
local key="${1:-}"
|
||||
local file="${STANDALONE_OPTIONS_JSON:-}"
|
||||
if [ -z "$file" ] || [ ! -f "$file" ] || ! command -v jq > /dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
# jq -r returns "null" for missing; convert to empty
|
||||
local val
|
||||
val="$(jq -er --arg k "$key" '. as $r | getpath(($k|split("."))) // empty' "$file" 2> /dev/null || true)"
|
||||
[ "$val" = "null" ] && val=""
|
||||
printf '%s' "$val"
|
||||
}
|
||||
|
||||
# Map a bashio "key" to an env var name.
|
||||
# Order tried:
|
||||
# 1) exact as-is
|
||||
# 2) uppercase exact
|
||||
# 3) dot->underscore, dash->underscore (upper & lower)
|
||||
# 4) with prefixes: CFG_, CONFIG_, ADDON_, OPTION_, OPT_
|
||||
_bashio_env_get() {
|
||||
# $1=key
|
||||
local key="${1:-}"
|
||||
[ -z "$key" ] && return 0
|
||||
|
||||
local variants=()
|
||||
variants+=("$key")
|
||||
variants+=("$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')")
|
||||
variants+=("$(printf '%s' "$key" | tr '.' '_' | tr '-' '_')")
|
||||
variants+=("$(printf '%s' "$key" | tr '.' '_' | tr '-' '_' | tr '[:lower:]' '[:upper:]')")
|
||||
|
||||
local prefixes=(""
|
||||
"CFG_" "CONFIG_" "ADDON_" "OPTION_" "OPT_")
|
||||
|
||||
local v p name
|
||||
for v in "${variants[@]}"; do
|
||||
for p in "${prefixes[@]}"; do
|
||||
name="${p}${v}"
|
||||
if [ -n "${!name+x}" ]; then
|
||||
printf '%s' "${!name}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# Helper: true/false parsing
|
||||
_bashio_is_true() {
|
||||
# $1=value
|
||||
case "${1:-}" in
|
||||
1 | true | TRUE | yes | YES | on | On) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Net wait using /dev/tcp (POSIX bash) with a timeout
|
||||
_bashio_tcp_wait() {
|
||||
# $1=host $2=port $3=timeout(s, default 30)
|
||||
local host="$1" port="$2" to="${3:-30}"
|
||||
local start now
|
||||
start="$(date +%s)"
|
||||
while :; do
|
||||
if exec 3<> "/dev/tcp/${host}/${port}" 2> /dev/null; then
|
||||
exec 3>&- 3<&-
|
||||
return 0
|
||||
fi
|
||||
now="$(date +%s)"
|
||||
if [ $((now - start)) -ge "$to" ]; then
|
||||
return 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
# -------- logs ---------------------------------------------------------------
|
||||
|
||||
bashio::log.blue() { _bashio_log blue "$*"; }
|
||||
bashio::log.green() { _bashio_log green "$*"; }
|
||||
bashio::log.yellow() { _bashio_log yellow "$*"; }
|
||||
bashio::log.red() { _bashio_log red "$*"; }
|
||||
bashio::log.magenta() { _bashio_log magenta "$*"; }
|
||||
|
||||
# compatibility aliases often used
|
||||
bashio::log.info() { bashio::log.blue "$@"; }
|
||||
bashio::log.warning() { bashio::log.yellow "$@"; }
|
||||
bashio::log.error() { bashio::log.red "$@"; }
|
||||
bashio::log.debug() { printf '%s\n' "$*"; }
|
||||
|
||||
# -------- supervisor & addon meta -------------------------------------------
|
||||
|
||||
# In standalone, "ping" always fails unless forced
|
||||
bashio::supervisor.ping() {
|
||||
if _bashio_is_true "${STANDALONE_FORCE_SUPERVISOR_PING:-}"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Add-on metadata (use env or sensible defaults)
|
||||
bashio::addon.name() { printf '%s' "${ADDON_NAME:-Standalone container}"; }
|
||||
bashio::addon.description() { printf '%s' "${ADDON_DESCRIPTION:-Running without Home Assistant Supervisor}"; }
|
||||
bashio::addon.version() { printf '%s' "${BUILD_VERSION:-1.0}"; }
|
||||
bashio::addon.version_latest() { printf '%s' "${ADDON_VERSION_LATEST:-${BUILD_VERSION:-1.0}}"; }
|
||||
bashio::addon.update_available() {
|
||||
if [ "${ADDON_VERSION_LATEST:-}" != "" ] && [ "${ADDON_VERSION_LATEST:-}" != "${BUILD_VERSION:-}" ]; then
|
||||
printf '%s' "true"
|
||||
return 0
|
||||
fi
|
||||
printf '%s' "false"
|
||||
}
|
||||
bashio::addon.ingress_port() { printf '%s' "${ADDON_INGRESS_PORT:-}"; }
|
||||
bashio::addon.ingress_entry() { printf '%s' "${ADDON_INGRESS_ENTRY:-}"; }
|
||||
bashio::addon.ip_address() { printf '%s' "${ADDON_IP_ADDRESS:-}"; }
|
||||
|
||||
# Ports:
|
||||
# - numeric arg "8080" -> env PORT_8080 or ADDON_PORT_8080, falling back to the number
|
||||
# - non-numeric "WEB_PORT" -> resolve as config/env key
|
||||
bashio::addon.port() {
|
||||
local arg="${1:-}"
|
||||
if [[ "$arg" =~ ^[0-9]+$ ]]; then
|
||||
local v
|
||||
v="$(_bashio_env_get "PORT_${arg}")"
|
||||
[ -z "$v" ] && v="$(_bashio_env_get "ADDON_PORT_${arg}")"
|
||||
printf '%s' "${v:-$arg}"
|
||||
else
|
||||
printf '%s' "$(_bashio_env_get "$arg")"
|
||||
fi
|
||||
}
|
||||
|
||||
# -------- system info --------------------------------------------------------
|
||||
|
||||
bashio::info.operating_system() {
|
||||
if [ -r /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
printf '%s' "${PRETTY_NAME:-${NAME:-Linux}}"
|
||||
else
|
||||
printf '%s' "Linux"
|
||||
fi
|
||||
}
|
||||
bashio::info.arch() { uname -m; }
|
||||
bashio::info.machine() { uname -m; }
|
||||
bashio::info.homeassistant() { printf '%s' "standalone"; }
|
||||
bashio::info.supervisor() { printf '%s' "standalone"; }
|
||||
|
||||
# -------- config -------------------------------------------------------------
|
||||
|
||||
# Primary getter:
|
||||
# 1) ENV (several name variants/prefixes)
|
||||
# 2) JSON file via STANDALONE_OPTIONS_JSON (jq required)
|
||||
bashio::config() {
|
||||
local key="${1:-}"
|
||||
local v
|
||||
v="$(_bashio_env_get "$key")"
|
||||
if [ -z "$v" ]; then
|
||||
v="$(_bashio_json_get "$key")"
|
||||
fi
|
||||
printf '%s' "${v:-}"
|
||||
}
|
||||
|
||||
bashio::config.has_value() {
|
||||
local k="$1"
|
||||
[ -n "$(bashio::config "$k")" ]
|
||||
}
|
||||
bashio::config.true() {
|
||||
local k="$1"
|
||||
_bashio_is_true "$(bashio::config "$k")"
|
||||
}
|
||||
|
||||
# Some add-ons call "require.ssl" (noop by default)
|
||||
bashio::config.require.ssl() { printf '%s' "${REQUIRE_SSL:-true}"; }
|
||||
|
||||
# -------- variables & fs helpers --------------------------------------------
|
||||
|
||||
bashio::var.true() { _bashio_is_true "${1:-}"; }
|
||||
bashio::var.has_value() { [ -n "${1:-}" ]; }
|
||||
|
||||
bashio::fs.directory_exists() { [ -d "$1" ]; }
|
||||
|
||||
# -------- network/services ---------------------------------------------------
|
||||
|
||||
# Wait for TCP service: bashio::net.wait_for host port [timeout]
|
||||
bashio::net.wait_for() {
|
||||
local host="$1" port="$2" to="${3:-30}"
|
||||
_bashio_tcp_wait "$host" "$port" "$to"
|
||||
}
|
||||
|
||||
# Discovery stubs; map to common env names, or JSON:
|
||||
# Usage patterns seen:
|
||||
# bashio::services "mqtt" "host"
|
||||
# bashio::services "mysql" "port"
|
||||
bashio::services() {
|
||||
local svc="${1:-}" key="${2:-}"
|
||||
[ -z "$svc" ] && return 0
|
||||
local upper svc_upper var v
|
||||
upper="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
|
||||
svc_upper="$(printf '%s' "$svc" | tr '[:lower:]' '[:upper:]')"
|
||||
|
||||
# Common mappings
|
||||
case "$svc_upper:$upper" in
|
||||
MQTT:HOST) var="MQTT_HOST" ;;
|
||||
MQTT:PORT) var="MQTT_PORT" ;;
|
||||
MQTT:USERNAME) var="MQTT_USER" ;;
|
||||
MQTT:PASSWORD) var="MQTT_PASSWORD" ;;
|
||||
MQTT:TLS) var="MQTT_TLS" ;;
|
||||
MYSQL:HOST | MARIADB:HOST) var="DB_HOST" ;;
|
||||
MYSQL:PORT | MARIADB:PORT) var="DB_PORT" ;;
|
||||
MYSQL:USERNAME | MARIADB:USERNAME) var="DB_USER" ;;
|
||||
MYSQL:PASSWORD | MARIADB:PASSWORD) var="DB_PASSWORD" ;;
|
||||
MYSQL:DATABASE | MARIADB:DATABASE) var="DB_NAME" ;;
|
||||
*) var="${svc_upper}_${upper}" ;;
|
||||
esac
|
||||
|
||||
v="$(_bashio_env_get "$var")"
|
||||
if [ -z "$v" ] && [ -n "${STANDALONE_OPTIONS_JSON:-}" ]; then
|
||||
v="$(_bashio_json_get "services.${svc}.${key}")"
|
||||
[ -z "$v" ] && v="$(_bashio_json_get "${svc}.${key}")"
|
||||
fi
|
||||
printf '%s' "${v:-}"
|
||||
}
|
||||
|
||||
# ----- extras for broader compatibility --------------------------------------
|
||||
|
||||
# Simple cache (used by add-ons & bashio itself)
|
||||
_BASHIO_CACHE_DIR="${BASHIO_CACHE_DIR:-/tmp/.bashio}"
|
||||
mkdir -p "$_BASHIO_CACHE_DIR"
|
||||
|
||||
bashio::cache.exists() { [ -f "$_BASHIO_CACHE_DIR/${1}.cache" ]; }
|
||||
bashio::cache.get() { [ -f "$_BASHIO_CACHE_DIR/${1}.cache" ] && cat "$_BASHIO_CACHE_DIR/${1}.cache"; }
|
||||
bashio::cache.set() {
|
||||
mkdir -p "$_BASHIO_CACHE_DIR"
|
||||
printf '%s' "${2:-}" > "$_BASHIO_CACHE_DIR/${1}.cache"
|
||||
}
|
||||
|
||||
# Filesystem helpers frequently used
|
||||
bashio::fs.file_exists() { [ -f "$1" ]; }
|
||||
bashio::fs.directory_exists() { [ -d "$1" ]; } # already defined earlier; keep if present
|
||||
bashio::fs.file_contains() {
|
||||
local f="$1" p="$2"
|
||||
[ -f "$f" ] && grep -q -- "$p" "$f"
|
||||
}
|
||||
|
||||
# jq wrapper (some add-ons call bashio::jq)
|
||||
bashio::jq() { command -v jq > /dev/null 2>&1 && jq "$@"; }
|
||||
|
||||
# env presence (even if empty) used by config.exists
|
||||
_bashio_env_has() {
|
||||
local key="$1" p v name
|
||||
[ -z "$key" ] && return 1
|
||||
local variants=(
|
||||
"$key"
|
||||
"$(printf '%s' "$key" | tr '.' '_')"
|
||||
"$(printf '%s' "$key" | tr '.' '_' | tr '[:lower:]' '[:upper:]')"
|
||||
"$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
|
||||
)
|
||||
for v in "${variants[@]}"; do
|
||||
for p in "" "CFG_" "CONFIG_" "ADDON_" "OPTION_" "OPT_"; do
|
||||
name="${p}${v}"
|
||||
if [ -n "${!name+x}" ]; then # defined, even if empty
|
||||
printf '%s' "$name"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# config.exists : key is present (env or JSON), even if value is empty
|
||||
bashio::config.exists() {
|
||||
local key="$1" file="${STANDALONE_OPTIONS_JSON:-}"
|
||||
_bashio_env_has "$key" && return 0
|
||||
if [ -n "$file" ] && command -v jq > /dev/null 2>&1; then
|
||||
jq -e --arg k "$key" 'haspath(($k|split(".")))' "$file" > /dev/null 2>&1
|
||||
return $?
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# addon.option : write/delete option in JSON when possible; fallback no-op/env
|
||||
bashio::addon.option() {
|
||||
local key="$1" value="${2-__BASHIO_UNSET__}" file="${STANDALONE_OPTIONS_JSON:-}"
|
||||
if [ -n "$file" ] && command -v jq > /dev/null 2>&1; then
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
if [ "$value" = "__BASHIO_UNSET__" ]; then
|
||||
jq --arg k "$key" 'delpath(($k|split(".")))' "$file" > "$tmp" && mv "$tmp" "$file"
|
||||
else
|
||||
jq --arg k "$key" --arg v "$value" 'setpath(($k|split(".")); $v)' "$file" > "$tmp" && mv "$tmp" "$file"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
# Fallbacks: export as env or treat delete as no-op
|
||||
if [ "$value" != "__BASHIO_UNSET__" ]; then
|
||||
export "$(printf '%s' "$key" | tr '.' '_' | tr '-' '_')"="$value"
|
||||
fi
|
||||
}
|
||||
|
||||
# services.available : check if we can resolve at least a host for the service
|
||||
bashio::services.available() {
|
||||
local svc="$1" host
|
||||
host="$(bashio::services "$svc" "host")"
|
||||
[ -n "$host" ]
|
||||
}
|
||||
|
||||
# var helpers
|
||||
bashio::var.false() { ! _bashio_is_true "${1:-}"; }
|
||||
bashio::var.has_value() { [ -n "${1:-}" ]; } # already present; keep if defined
|
||||
|
||||
# exits used by many add-ons
|
||||
bashio::exit.ok() { exit 0; }
|
||||
bashio::exit.nok() {
|
||||
local m="${1:-}"
|
||||
[ -n "$m" ] && bashio::log.red "$m"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# core.check : Supervisor does a config check; allow an overridable command
|
||||
# Set STANDALONE_CORE_CHECK_CMD="hass --script check_config -c /config" to enable
|
||||
bashio::core.check() {
|
||||
if [ -n "${STANDALONE_CORE_CHECK_CMD:-}" ]; then
|
||||
eval "$STANDALONE_CORE_CHECK_CMD"
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# --- improvements & extra shims ---------------------------------------------
|
||||
|
||||
# Respect NO_COLOR and dumb terminals
|
||||
if [ -n "${NO_COLOR:-}" ] || [ "${TERM:-}" = "dumb" ]; then
|
||||
_BASHIO_COLOR=0
|
||||
fi
|
||||
|
||||
# net.wait_for: prefer nc if available, fallback to /dev/tcp
|
||||
_bashio_tcp_wait_nc() {
|
||||
# $1=host $2=port $3=timeout(s)
|
||||
command -v nc > /dev/null 2>&1 || return 1
|
||||
local host="$1" port="$2" to="${3:-30}"
|
||||
# BusyBox and OpenBSD nc differ; cover both styles
|
||||
nc -z -w "$to" "$host" "$port" 2> /dev/null || nc -z "$host" "$port" 2> /dev/null
|
||||
}
|
||||
bashio::net.wait_for() {
|
||||
local host="$1" port="$2" to="${3:-30}"
|
||||
_bashio_tcp_wait_nc "$host" "$port" "$to" && return 0
|
||||
_bashio_tcp_wait "$host" "$port" "$to"
|
||||
}
|
||||
|
||||
# DNS helper: bashio::dns.host <hostname> -> prints an IP (or empty)
|
||||
bashio::dns.host() {
|
||||
local h="${1:-}"
|
||||
[ -z "$h" ] && return 1
|
||||
if command -v getent > /dev/null 2>&1; then
|
||||
getent ahostsv4 "$h" | awk '{print $1; exit}'
|
||||
else
|
||||
# fallback: try busybox nslookup
|
||||
nslookup "$h" 2> /dev/null | awk '/^Address: /{print $2; exit}'
|
||||
fi
|
||||
}
|
||||
|
||||
# Hostname
|
||||
bashio::host.hostname() {
|
||||
command -v hostname > /dev/null 2>&1 && hostname || printf '%s' "${HOSTNAME:-unknown}"
|
||||
}
|
||||
|
||||
# Home Assistant token (no Supervisor; read from env or JSON)
|
||||
bashio::homeassistant.token() {
|
||||
local t="${HOMEASSISTANT_TOKEN:-${HASS_TOKEN:-}}"
|
||||
if [ -z "$t" ] && [ -n "${STANDALONE_OPTIONS_JSON:-}" ] && command -v jq > /dev/null 2>&1; then
|
||||
t="$(jq -er '.homeassistant.token // empty' "$STANDALONE_OPTIONS_JSON" 2> /dev/null || true)"
|
||||
fi
|
||||
printf '%s' "${t:-}"
|
||||
}
|
||||
|
||||
# config.array:
|
||||
# Accepts CSV ("a,b,c"), space/newline-separated text, or JSON array ["a","b"].
|
||||
# Prints one item per line (common pattern in add-ons: `mapfile -t arr < <(bashio::config.array key)`).
|
||||
bashio::config.array() {
|
||||
local key="${1:-}" raw val
|
||||
raw="$(bashio::config "$key")"
|
||||
[ -z "$raw" ] && return 0
|
||||
|
||||
# JSON array?
|
||||
if command -v jq > /dev/null 2>&1 && printf '%s' "$raw" | jq -e . > /dev/null 2>&1; then
|
||||
printf '%s' "$raw" | jq -r '.[]' 2> /dev/null && return 0
|
||||
fi
|
||||
|
||||
# CSV -> newline
|
||||
if printf '%s' "$raw" | grep -q ','; then
|
||||
printf '%s' "$raw" | tr ',' '\n'
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Already space/newline-separated
|
||||
printf '%s\n' "$raw"
|
||||
}
|
||||
|
||||
# Optional: common require.* shims (treat as advisory in standalone)
|
||||
bashio::config.require.username() { :; }
|
||||
bashio::config.require.password() { :; }
|
||||
bashio::config.require.port() { :; }
|
||||
|
||||
# -------- end ----------------------------------------------------------------
|
14
.templates/config.template
Normal file
14
.templates/config.template
Normal file
@@ -0,0 +1,14 @@
|
||||
#============================#
|
||||
# ALEXBELGIUM'S ENV INJECTOR #
|
||||
#============================#
|
||||
#
|
||||
# All env variables set in this file will be enabled in the app
|
||||
# This allows enabling more options that normally available in the addon options
|
||||
# This file must be filled according to the yaml format.
|
||||
# If the format is invalid, the addon will note an error.
|
||||
# To validate your yaml, you can use the free online tool http://www.yamllint.com/
|
||||
# You can use env both for the addon, and for bashio. For bashio, use BASHIO_LOG_LEVEL instead of LOG_LEVEL
|
||||
|
||||
# EXAMPLE of the format (you need to remove the # for it to become active)
|
||||
# TZ: Europe/Paris
|
||||
|
28
.templates/ha_autoapps.sh
Normal file
28
.templates/ha_autoapps.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2015
|
||||
set -e
|
||||
|
||||
##############################
|
||||
# Automatic apps download #
|
||||
##############################
|
||||
|
||||
PACKAGES="$1"
|
||||
echo "To install : $PACKAGES"
|
||||
|
||||
# Install bash if needed
|
||||
if ! command -v bash > /dev/null 2> /dev/null; then
|
||||
(apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null
|
||||
fi
|
||||
|
||||
# Install curl if needed
|
||||
if ! command -v curl > /dev/null 2> /dev/null; then
|
||||
(apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null
|
||||
fi
|
||||
|
||||
# Call apps installer script if needed
|
||||
curl -f -L -S "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automatic_packages.sh" --output /ha_automatic_packages.sh
|
||||
chmod 755 /ha_automatic_packages.sh
|
||||
eval /./ha_automatic_packages.sh "${PACKAGES:-}"
|
||||
|
||||
# Clean
|
||||
rm /ha_automatic_packages.sh
|
283
.templates/ha_automatic_packages.sh
Normal file
283
.templates/ha_automatic_packages.sh
Normal file
@@ -0,0 +1,283 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
########
|
||||
# INIT #
|
||||
########
|
||||
|
||||
#Verbose or not
|
||||
VERBOSE=false
|
||||
#Avoid fails on non declared variables
|
||||
set +u 2> /dev/null || true
|
||||
#If no packages, empty
|
||||
PACKAGES="${*:-}"
|
||||
#Avoids messages if non interactive
|
||||
(echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections) &> /dev/null || true
|
||||
|
||||
[ "$VERBOSE" = true ] && echo "ENV : $PACKAGES"
|
||||
|
||||
############################
|
||||
# CHECK WHICH BASE IS USED #
|
||||
############################
|
||||
|
||||
if command -v "apk" &> /dev/null; then
|
||||
# If apk based
|
||||
[ "$VERBOSE" = true ] && echo "apk based"
|
||||
PACKMANAGER="apk"
|
||||
elif command -v "apt" &> /dev/null; then
|
||||
# If apt-get based
|
||||
[ "$VERBOSE" = true ] && echo "apt based"
|
||||
PACKMANAGER="apt"
|
||||
elif command -v "pacman" &> /dev/null; then
|
||||
# If apt-get based
|
||||
[ "$VERBOSE" = true ] && echo "pacman based"
|
||||
PACKMANAGER="pacman"
|
||||
fi
|
||||
|
||||
###################
|
||||
# DEFINE PACKAGES #
|
||||
###################
|
||||
|
||||
# ADD GENERAL ELEMENTS
|
||||
######################
|
||||
|
||||
PACKAGES="$PACKAGES jq curl ca-certificates"
|
||||
|
||||
# FOR EACH SCRIPT, SELECT PACKAGES
|
||||
##################################
|
||||
|
||||
# Scripts
|
||||
for files in "/etc/cont-init.d" "/etc/services.d"; do
|
||||
# Next directory if does not exists
|
||||
if ! ls $files 1> /dev/null 2>&1; then continue; fi
|
||||
|
||||
# Test each possible command
|
||||
COMMAND="nginx"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES nginx"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES nginx"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES nginx"
|
||||
if ls /etc/nginx 1> /dev/null 2>&1; then mv /etc/nginx /etc/nginx2; fi
|
||||
fi
|
||||
|
||||
COMMAND="mount"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND"; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES exfatprogs ntfs-3g ntfs-3g-progs squashfs-tools fuse lsblk"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES exfat* ntfs* squashfs-tools util-linux"
|
||||
#[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES ntfs-3g"
|
||||
fi
|
||||
|
||||
COMMAND="ping"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES iputils"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES iputils-ping"
|
||||
#[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES iputils"
|
||||
fi
|
||||
|
||||
COMMAND="nmap"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND"; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES nmap nmap-scripts"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES nmap"
|
||||
#[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES iputils"
|
||||
fi
|
||||
|
||||
COMMAND="cifs"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND"; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES cifs-utils keyutils"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES cifs-utils keyutils"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES cifs-utils keyutils"
|
||||
fi
|
||||
|
||||
COMMAND="nfs"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND"; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES nfs-utils"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES nfs-common"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES nfs-utils"
|
||||
fi
|
||||
|
||||
COMMAND="smbclient"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES samba samba-client ntfs-3g"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES samba smbclient ntfs-3g"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES samba smbclient"
|
||||
fi
|
||||
|
||||
COMMAND="dos2unix"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES dos2unix"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES dos2unix"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES dos2unix"
|
||||
fi
|
||||
|
||||
COMMAND="openvpn"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES coreutils openvpn"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES coreutils openvpn"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES coreutils openvpn"
|
||||
fi
|
||||
|
||||
COMMAND="jq"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES jq"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES jq"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES jq"
|
||||
fi
|
||||
|
||||
COMMAND="yamllint"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES yamllint"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES yamllint"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES yamllint"
|
||||
fi
|
||||
|
||||
COMMAND="git"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES git"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES git"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES git"
|
||||
fi
|
||||
|
||||
COMMAND="sponge"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES moreutils"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES moreutils"
|
||||
[ "$PACKMANAGER" = "pacman " ] && PACKAGES="$PACKAGES moreutils"
|
||||
fi
|
||||
|
||||
COMMAND="sqlite3"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES sqlite"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES sqlite3"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES sqlite3"
|
||||
fi
|
||||
|
||||
COMMAND="pip"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES py3-pip"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES pip"
|
||||
[ "$PACKMANAGER" = "pacman" ] && PACKAGES="$PACKAGES pip"
|
||||
fi
|
||||
|
||||
COMMAND="wget"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && PACKAGES="$PACKAGES wget"
|
||||
[ "$PACKMANAGER" = "apt" ] && PACKAGES="$PACKAGES wget"
|
||||
[ "$PACKMANAGER" = "wget" ] && PACKAGES="$PACKAGES wget"
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
####################
|
||||
# INSTALL ELEMENTS #
|
||||
####################
|
||||
|
||||
# Install apps
|
||||
[ "$VERBOSE" = true ] && echo "installing packages $PACKAGES"
|
||||
if [ "$PACKMANAGER" = "apt" ]; then apt-get update > /dev/null; fi
|
||||
if [ "$PACKMANAGER" = "pacman" ]; then pacman -Sy > /dev/null; fi
|
||||
|
||||
# Install apps one by one to allow failures
|
||||
# shellcheck disable=SC2086
|
||||
for packagestoinstall in $PACKAGES; do
|
||||
[ "$VERBOSE" = true ] && echo "... $packagestoinstall"
|
||||
if [ "$PACKMANAGER" = "apk" ]; then
|
||||
apk add --no-cache "$packagestoinstall" &> /dev/null || (echo "Error : $packagestoinstall not found" && touch /ERROR)
|
||||
elif [ "$PACKMANAGER" = "apt" ]; then
|
||||
apt-get install -yqq --no-install-recommends "$packagestoinstall" &> /dev/null || (echo "Error : $packagestoinstall not found" && touch /ERROR)
|
||||
elif [ "$PACKMANAGER" = "pacman" ]; then
|
||||
pacman --noconfirm -S "$packagestoinstall" &> /dev/null || (echo "Error : $packagestoinstall not found" && touch /ERROR)
|
||||
fi
|
||||
[ "$VERBOSE" = true ] && echo "... $packagestoinstall done"
|
||||
done
|
||||
|
||||
# Clean after install
|
||||
[ "$VERBOSE" = true ] && echo "Cleaning apt cache"
|
||||
if [ "$PACKMANAGER" = "apt" ]; then apt-get clean > /dev/null; fi
|
||||
|
||||
# Replace nginx if installed
|
||||
if ls /etc/nginx2 1> /dev/null 2>&1; then
|
||||
[ "$VERBOSE" = true ] && echo "replace nginx2"
|
||||
rm -r /etc/nginx
|
||||
mv /etc/nginx2 /etc/nginx
|
||||
mkdir -p /var/log/nginx
|
||||
touch /var/log/nginx/error.log
|
||||
fi
|
||||
|
||||
#######################
|
||||
# INSTALL MANUAL APPS #
|
||||
#######################
|
||||
|
||||
# Install micro texteditor
|
||||
curl https://getmic.ro | bash || true
|
||||
mv micro /usr/bin || true
|
||||
micro -plugin install bounce || true
|
||||
micro -plugin install filemanager || true
|
||||
|
||||
for files in "/etc/services.d" "/etc/cont-init.d"; do
|
||||
|
||||
# Next directory if does not exists
|
||||
if ! ls $files 1> /dev/null 2>&1; then continue; fi
|
||||
|
||||
# Bashio
|
||||
if grep -q -rnw "$files/" -e 'bashio' && [ ! -f "/usr/bin/bashio" ]; then
|
||||
[ "$VERBOSE" = true ] && echo "install bashio"
|
||||
BASHIO_VERSION="0.14.3"
|
||||
mkdir -p /tmp/bashio
|
||||
curl -f -L -s -S "https://github.com/hassio-addons/bashio/archive/v${BASHIO_VERSION}.tar.gz" | tar -xzf - --strip 1 -C /tmp/bashio
|
||||
mv /tmp/bashio/lib /usr/lib/bashio
|
||||
ln -s /usr/lib/bashio/bashio /usr/bin/bashio
|
||||
rm -rf /tmp/bashio
|
||||
fi
|
||||
|
||||
# Lastversion
|
||||
COMMAND="lastversion"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "install $COMMAND"
|
||||
pip install $COMMAND
|
||||
fi
|
||||
|
||||
# Tempio
|
||||
if grep -q -rnw "$files/" -e 'tempio' && [ ! -f "/usr/bin/tempio" ]; then
|
||||
[ "$VERBOSE" = true ] && echo "install tempio"
|
||||
TEMPIO_VERSION="2021.09.0"
|
||||
BUILD_ARCH="$(bashio::info.arch)"
|
||||
curl -f -L -f -s -o /usr/bin/tempio "https://github.com/home-assistant/tempio/releases/download/${TEMPIO_VERSION}/tempio_${BUILD_ARCH}"
|
||||
chmod a+x /usr/bin/tempio
|
||||
fi
|
||||
|
||||
# Mustache
|
||||
COMMAND="mustache"
|
||||
if grep -q -rnw "$files/" -e "$COMMAND" && ! command -v $COMMAND &> /dev/null; then
|
||||
[ "$VERBOSE" = true ] && echo "$COMMAND required"
|
||||
[ "$PACKMANAGER" = "apk" ] && apk add --no-cache go npm \
|
||||
&& apk upgrade --no-cache \
|
||||
&& apk add --no-cache --virtual .build-deps build-base git go \
|
||||
&& go get -u github.com/quantumew/mustache-cli \
|
||||
&& cp "$GOPATH"/bin/* /usr/bin/ \
|
||||
&& rm -rf "$GOPATH" /var/cache/apk/* /tmp/src \
|
||||
&& apk del .build-deps xz build-base
|
||||
[ "$PACKMANAGER" = "apt" ] && apt-get update \
|
||||
&& apt-get install -yqq go npm node-mustache
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if [ -f /ERROR ]; then
|
||||
exit 1
|
||||
fi
|
36
.templates/ha_automodules.sh
Normal file
36
.templates/ha_automodules.sh
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2015
|
||||
set -e
|
||||
|
||||
##############################
|
||||
# Automatic modules download #
|
||||
##############################
|
||||
|
||||
MODULES="$1"
|
||||
MODULES="$MODULES 00-banner.sh 01-custom_script.sh 01-config_yaml.sh 00-global_var.sh"
|
||||
echo "To download : $MODULES"
|
||||
|
||||
# Install bash if not available
|
||||
if ! command -v bash > /dev/null 2> /dev/null; then
|
||||
(apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null
|
||||
fi
|
||||
|
||||
# Install curl if not available
|
||||
if ! command -v curl > /dev/null 2> /dev/null; then
|
||||
(apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null
|
||||
fi
|
||||
|
||||
# Install ca-certificates if not available
|
||||
apt-get update && apt-get install -yqq --no-install-recommends ca-certificates || apk add --no-cache ca-certificates > /dev/null || true
|
||||
|
||||
# Create folder for scripts
|
||||
mkdir -p /etc/cont-init.d
|
||||
|
||||
# Download scripts
|
||||
for scripts in $MODULES; do
|
||||
echo "$scripts" && curl -f -L -s -S "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/$scripts" -o /etc/cont-init.d/"$scripts" \
|
||||
&& [ "$(sed -n '/\/bin/p;q' /etc/cont-init.d/"$scripts")" != "" ] \
|
||||
|| (echo "script failed to install $scripts" && exit 1)
|
||||
done
|
||||
|
||||
chmod -R 755 /etc/cont-init.d
|
152
.templates/ha_entrypoint.sh
Normal file
152
.templates/ha_entrypoint.sh
Normal file
@@ -0,0 +1,152 @@
|
||||
#!/command/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
|
||||
# Detect if this is PID1 (main container process) — do this once at the start
|
||||
PID1=false
|
||||
if [ "$$" -eq 1 ]; then
|
||||
PID1=true
|
||||
echo "Starting as entrypoint"
|
||||
# Allow s6 commands
|
||||
if [ -d /command ]; then
|
||||
ln -sf /command/* /usr/bin/
|
||||
fi
|
||||
else
|
||||
echo "Starting custom scripts"
|
||||
fi
|
||||
|
||||
######################
|
||||
# Select the shebang #
|
||||
######################
|
||||
|
||||
# List of candidate shebangs, prioritize with-contenv if PID1
|
||||
candidate_shebangs=()
|
||||
if $PID1; then
|
||||
candidate_shebangs+=("/command/with-contenv bashio" "/usr/bin/with-contenv bashio")
|
||||
fi
|
||||
candidate_shebangs+=(
|
||||
"/usr/bin/env bashio"
|
||||
"/usr/bin/bashio"
|
||||
"/usr/bin/bash"
|
||||
"/usr/bin/sh"
|
||||
"/bin/bash"
|
||||
"/bin/sh"
|
||||
)
|
||||
|
||||
# Find the first valid shebang interpreter in candidate list
|
||||
shebang=""
|
||||
for candidate in "${candidate_shebangs[@]}"; do
|
||||
command_path="${candidate%% *}"
|
||||
# Test if command exists and can actually execute a shell command (for shells)
|
||||
if [ -x "$command_path" ]; then
|
||||
# Try as both 'sh -c' and 'bashio echo' style
|
||||
if "$command_path" -c 'echo yes' > /dev/null 2>&1 || "$command_path" echo "yes" > /dev/null 2>&1; then
|
||||
shebang="$candidate"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ -z "$shebang" ]; then
|
||||
echo "ERROR: No valid shebang found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
####################
|
||||
# Starting scripts #
|
||||
####################
|
||||
|
||||
# Loop through /etc/cont-init.d/* scripts and execute them
|
||||
for SCRIPTS in /etc/cont-init.d/*; do
|
||||
[ -e "$SCRIPTS" ] || continue
|
||||
echo "$SCRIPTS: executing"
|
||||
|
||||
# Check if run as root (UID 0)
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
# Fix permissions for root user
|
||||
chown "$(id -u)":"$(id -g)" "$SCRIPTS"
|
||||
chmod a+x "$SCRIPTS"
|
||||
else
|
||||
echo -e "\e[38;5;214m$(date) WARNING: Script executed with user $(id -u):$(id -g), things can break and chown won't work\e[0m"
|
||||
# Disable chown and chmod commands inside the script for non-root users
|
||||
sed -i "s/^\s*chown /true # chown /g" "$SCRIPTS"
|
||||
sed -i "s/^\s*chmod /true # chmod /g" "$SCRIPTS"
|
||||
fi
|
||||
|
||||
# Prepare to run
|
||||
sed -i "1s|^.*|#!$shebang|" "$SCRIPTS"
|
||||
chmod +x "$SCRIPTS"
|
||||
|
||||
# Optionally use 'source' to share env variables, when requested
|
||||
if [ "${ha_entry_source:-null}" = true ]; then
|
||||
# Replace exit with return, so sourced scripts can return errors
|
||||
sed -i -E 's/^\s*exit ([0-9]+)/return \1 \|\| exit \1/g' "$SCRIPTS"
|
||||
sed -i 's/bashio::exit\.nok/return 1/g' "$SCRIPTS"
|
||||
sed -i 's/bashio::exit\.ok/return 0/g' "$SCRIPTS"
|
||||
# shellcheck disable=SC1090
|
||||
source "$SCRIPTS" || echo -e "\033[0;31mError\033[0m : $SCRIPTS exiting $?"
|
||||
else
|
||||
"$SCRIPTS" || echo -e "\033[0;31mError\033[0m : $SCRIPTS exiting $?"
|
||||
fi
|
||||
|
||||
# Cleanup after execution
|
||||
sed -i '1a echo "Script already ran" && exit 0' "$SCRIPTS"
|
||||
done
|
||||
|
||||
# Start run scripts in services.d and s6-overlay/s6-rc.d if PID1
|
||||
if $PID1; then
|
||||
# Run services
|
||||
shopt -s nullglob
|
||||
for runfile in /etc/services.d/*/run /etc/s6-overlay/s6-rc.d/*/run; do
|
||||
[ -f "$runfile" ] || continue
|
||||
echo "Starting: $runfile"
|
||||
sed -i "1s|^.*|#!$shebang|" "$runfile"
|
||||
chmod +x "$runfile"
|
||||
(exec "$runfile") &
|
||||
true
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
######################
|
||||
# Starting container #
|
||||
######################
|
||||
|
||||
# If this is PID 1, keep alive and manage sigterm for clean shutdown
|
||||
if $PID1; then
|
||||
echo " "
|
||||
echo -e "\033[0;32mEverything started!\033[0m"
|
||||
terminate() {
|
||||
echo "Termination signal received, forwarding to subprocesses..."
|
||||
# Terminate all direct child processes
|
||||
if command -v pgrep &> /dev/null; then
|
||||
for pid in $(pgrep -P $$); do
|
||||
echo "Terminating child PID $pid"
|
||||
kill -TERM "$pid" 2> /dev/null || echo "Failed to terminate PID $pid"
|
||||
done
|
||||
else
|
||||
# Fallback: Scan /proc for children
|
||||
for pid in /proc/[0-9]*/; do
|
||||
pid=${pid#/proc/}
|
||||
pid=${pid%/}
|
||||
if [[ "$pid" -ne 1 ]] && grep -q "^PPid:\s*$$" "/proc/$pid/status" 2> /dev/null; then
|
||||
echo "Terminating child PID $pid"
|
||||
kill -TERM "$pid" 2> /dev/null || echo "Failed to terminate PID $pid"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
wait
|
||||
echo "All subprocesses terminated. Exiting."
|
||||
exit 0
|
||||
}
|
||||
trap terminate SIGTERM SIGINT
|
||||
# Main keep-alive loop
|
||||
while :; do
|
||||
sleep infinity &
|
||||
wait $!
|
||||
done
|
||||
else
|
||||
echo " "
|
||||
echo -e "\033[0;32mStarting the upstream container\033[0m"
|
||||
echo " "
|
||||
# Launch optional mods script if present
|
||||
if [ -f /docker-mods ]; then exec /docker-mods; fi
|
||||
fi
|
62
.templates/ha_entrypoint_modif.sh
Normal file
62
.templates/ha_entrypoint_modif.sh
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
##########################################
|
||||
# Global modifications before entrypoint #
|
||||
##########################################
|
||||
|
||||
# Corrects permissions for s6 v3
|
||||
################################
|
||||
|
||||
PUID="${PUID:-0}"
|
||||
PGID="${PGID:-0}"
|
||||
|
||||
if [ -f /ha_entrypoint.sh ]; then
|
||||
chown -R "$PUID:$PGID" /ha_entrypoint.sh
|
||||
chmod -R 755 /ha_entrypoint.sh
|
||||
fi
|
||||
|
||||
if [ -d /etc/cont-init.d ]; then
|
||||
chown -R "$PUID:$PGID" /etc/cont-init.d
|
||||
chmod -R 755 /etc/cont-init.d
|
||||
fi
|
||||
|
||||
if [ -d /etc/services.d ]; then
|
||||
chown -R "$PUID:$PGID" /etc/services.d
|
||||
chmod -R 755 /etc/services.d
|
||||
fi
|
||||
|
||||
if [ -d /etc/s6-rc.d ]; then
|
||||
chown -R "$PUID:$PGID" /etc/s6-rc.d
|
||||
chmod -R 755 /etc/s6-rc.d
|
||||
fi
|
||||
|
||||
# Correct shebang in entrypoint
|
||||
###############################
|
||||
|
||||
# Make s6 contenv if needed
|
||||
mkdir -p /run/s6/container_environment
|
||||
|
||||
# Check if shebang exists
|
||||
for shebang in "/command/with-contenv bashio" "/usr/bin/env bashio" "/usr/bin/with-contenv bashio" "/usr/bin/bashio" "/usr/bin/bash" "/usr/bin/sh" "/bin/bash" "/bin/sh"; do
|
||||
command_path="${shebang%% *}"
|
||||
if [ -x "$command_path" ] && "$command_path" echo "yes" > /dev/null 2>&1; then
|
||||
echo "Valid shebang: $shebang"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Define shebang
|
||||
sed -i "s|/command/with-contenv bashio|$shebang|g" /ha_entrypoint.sh
|
||||
|
||||
# Correct for scripts
|
||||
for string in "/command/with-contenv bashio" "/usr/bin/with-contenv bashio"; do
|
||||
grep -sril "$string" /etc/cont-init.d /etc/services.d /etc/s6-overlay/s6-rc.d | while read -r files; do
|
||||
sed -i "s|$string|$shebang|g" "$files"
|
||||
done
|
||||
done
|
||||
|
||||
# Avoid interference with LOG_LEVEL used in the app
|
||||
if [ -f /usr/lib/bashio/bashio.sh ]; then
|
||||
sed -i 's|{LOG_LEVEL:|{BASHIO_LOG_LEVEL:|g' /usr/lib/bashio/bashio.sh
|
||||
fi
|
68
.templates/ha_lsio.sh
Normal file
68
.templates/ha_lsio.sh
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/bin/sh
|
||||
# shellcheck disable=SC2013,SC2016,SC2236
|
||||
set -e
|
||||
|
||||
#############################
|
||||
# Modify global lsio images #
|
||||
#############################
|
||||
|
||||
# Set variable
|
||||
CONFIGLOCATION="${1:-/config}"
|
||||
echo "Setting config to $CONFIGLOCATION"
|
||||
|
||||
# Avoid custom-init.d duplications
|
||||
for file in $(grep -sril 'Potential tampering with custom' /etc/cont-init.d /etc/services.d /etc/s6-overlay/s6-rc.d); do
|
||||
rm -f "$file"
|
||||
done
|
||||
|
||||
# If custom config
|
||||
if [ "$CONFIGLOCATION" != "/config" ]; then
|
||||
|
||||
# Create new config folder if needed
|
||||
for file in $(grep -srl "PUID" /etc/cont-init.d /etc/s6-overlay/s6-rc.d); do
|
||||
sed -i "1a mkdir -p $CONFIGLOCATION" "$file"
|
||||
done
|
||||
|
||||
# Correct config location
|
||||
for file in $(grep -Esril "/config[ '\"/]|/config\$" /etc /defaults); do
|
||||
sed -Ei "s=(/config)+(/| |$|\"|\')=$CONFIGLOCATION\2=g" "$file"
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
# Allow UID and GID setting
|
||||
for file in $(grep -srl "PUID" /etc/cont-init.d /etc/s6-overlay/s6-rc.d); do
|
||||
sed -i 's/bash/bashio/g' "$file" && sed -i '1a PUID="$(if bashio::config.has_value "PUID"; then bashio::config "PUID"; else echo "0"; fi)"' "$file"
|
||||
sed -i '1a PGID="$(if bashio::config.has_value "PGID"; then bashio::config "PGID"; else echo "0"; fi)"' "$file"
|
||||
done
|
||||
|
||||
# Avoid chmod /config if ha config mounted
|
||||
if [ -f /config/configuration.yaml ] || [ -f /config/configuration.json ]; then
|
||||
for file in /etc/services.d/*/* /etc/cont-init.d/* /etc/s6-overlay/s6-rc.d/*/*; do
|
||||
if [ -f "$file" ] && [ -n "$(awk '/chown.*abc:abc.*\\/,/.*\/config( |$)/{print FILENAME}' "$file")" ]; then
|
||||
sed -i "s|/config$|/data|g" "$file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Send crond logs to addon logs
|
||||
if [ -f /etc/s6-overlay/s6-rc.d/svc-cron/run ]; then
|
||||
sed -i "/exec busybox crond/c exec busybox crond -f -S -L /proc/1/fd/1" /etc/s6-overlay/s6-rc.d/svc-cron/run
|
||||
sed -i "/exec \/usr\/sbin\/cron/c exec /usr/sbin/cron -f &>/proc/1/fd/1" /etc/s6-overlay/s6-rc.d/svc-cron/run
|
||||
fi
|
||||
|
||||
# variables not found
|
||||
for file in $(grep -srl "/usr/bin" /etc/cont-init.d /etc/s6-overlay/s6-rc.d); do
|
||||
sed -i "1a set +u" "$file"
|
||||
done
|
||||
|
||||
# Allow running abc as user 1
|
||||
sed -i '/usermod/ s/$/ 2>\/dev\/null || true/' /etc/s6-overlay/s6-rc.d/init-adduser/run
|
||||
sed -i '/groupmod/ s/$/ 2>\/dev\/null || true/' /etc/s6-overlay/s6-rc.d/init-adduser/run
|
||||
|
||||
# Replace lsiown if not found
|
||||
if [ ! -f /usr/bin/lsiown ]; then
|
||||
for file in $(grep -sril "lsiown" /etc); do
|
||||
sed -i "s|lsiown|chown|g" "$file"
|
||||
done
|
||||
fi
|
9
.templates/script.template
Normal file
9
.templates/script.template
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
|
||||
#################
|
||||
# CODE INJECTOR #
|
||||
#################
|
||||
|
||||
# Any commands written in this bash script will be executed at addon start
|
||||
# See guide here : https://github.com/alexbelgium/hassio-addons/wiki/Add%E2%80%90ons-feature-:-customisation
|
9
.templates/show_text_color
Normal file
9
.templates/show_text_color
Normal file
@@ -0,0 +1,9 @@
|
||||
#Define colors
|
||||
red=1
|
||||
green=2
|
||||
yellow=3
|
||||
blue=4
|
||||
violet=5
|
||||
teal=6
|
||||
echo "$(tput setaf $red)ENV exported : $word$(tput sgr0)"
|
||||
echo -e "\033[0;31mError\033[0m : Text"
|
@@ -4,6 +4,13 @@ FROM $BUILD_FROM
|
||||
# Add env
|
||||
ENV LANG C.UTF-8
|
||||
|
||||
# Set S6 wait time
|
||||
ENV S6_CMD_WAIT_FOR_SERVICES=1 \
|
||||
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
||||
S6_SERVICES_GRACETIME=0
|
||||
|
||||
USER root
|
||||
|
||||
# Setup base
|
||||
RUN \
|
||||
apk add --no-cache samba \
|
||||
|
Reference in New Issue
Block a user