From 68b3639a3a8d5edce99e197fc34e7328daf8f2b2 Mon Sep 17 00:00:00 2001 From: Alexandre Date: Sat, 12 Oct 2024 13:33:39 +0200 Subject: [PATCH] test mealie --- zzz_test/CHANGELOG.md | 172 +++++++++++ zzz_test/Dockerfile | 274 ++++++++++++++++++ zzz_test/README.md | 128 ++++++++ zzz_test/apparmor.txt | 59 ++++ zzz_test/build.json | 9 + zzz_test/config.json | 117 ++++++++ zzz_test/icon.png | Bin 0 -> 3628 bytes zzz_test/logo.png | Bin 0 -> 3628 bytes zzz_test/rootfs/etc/cont-init.d/31-nginx.sh | 32 ++ zzz_test/rootfs/etc/nginx/includes/mime.types | 96 ++++++ .../etc/nginx/includes/proxy_params.conf | 16 + .../rootfs/etc/nginx/includes/resolver.conf | 1 + .../etc/nginx/includes/server_params.conf | 6 + .../rootfs/etc/nginx/includes/ssl_params.conf | 9 + .../rootfs/etc/nginx/includes/upstream.conf | 3 + zzz_test/rootfs/etc/nginx/nginx.conf | 78 +++++ .../rootfs/etc/nginx/servers/ingress.conf | 40 +++ zzz_test/rootfs/etc/nginx/servers/ssl.conf | 28 ++ zzz_test/rootfs/run.txt | 125 ++++++++ zzz_test/stats.png | Bin 0 -> 1939 bytes zzz_test/updater.json | 11 + 21 files changed, 1204 insertions(+) create mode 100644 zzz_test/CHANGELOG.md create mode 100644 zzz_test/Dockerfile create mode 100644 zzz_test/README.md create mode 100644 zzz_test/apparmor.txt create mode 100644 zzz_test/build.json create mode 100644 zzz_test/config.json create mode 100644 zzz_test/icon.png create mode 100644 zzz_test/logo.png create mode 100644 zzz_test/rootfs/etc/cont-init.d/31-nginx.sh create mode 100644 zzz_test/rootfs/etc/nginx/includes/mime.types create mode 100644 zzz_test/rootfs/etc/nginx/includes/proxy_params.conf create mode 100644 zzz_test/rootfs/etc/nginx/includes/resolver.conf create mode 100644 zzz_test/rootfs/etc/nginx/includes/server_params.conf create mode 100644 zzz_test/rootfs/etc/nginx/includes/ssl_params.conf create mode 100644 zzz_test/rootfs/etc/nginx/includes/upstream.conf create mode 100644 zzz_test/rootfs/etc/nginx/nginx.conf create mode 100644 zzz_test/rootfs/etc/nginx/servers/ingress.conf create mode 100644 zzz_test/rootfs/etc/nginx/servers/ssl.conf create mode 100644 zzz_test/rootfs/run.txt create mode 100644 zzz_test/stats.png create mode 100644 zzz_test/updater.json diff --git a/zzz_test/CHANGELOG.md b/zzz_test/CHANGELOG.md new file mode 100644 index 000000000..ac668ca28 --- /dev/null +++ b/zzz_test/CHANGELOG.md @@ -0,0 +1,172 @@ +## v2.0-beta (10-10-2024) +- Switched to v2.0 beta, should hopefully solve everyone's issues! + +## v1.12.0-4 (22-09-2024) +- Minor bugs fixed +## v1.12.0-3 (22-09-2024) +- Another version with 1.12 to try to solve issues with config not recognized + +## v1.12.0-2 (25-08-2024) +- BACKUP BEFORE UPDATING !!! +- WARNING : version 1.12 erroneously updated to 2.0. Your database could become corrupted if you update from 1.12. You need to restore your homeassistant config directory before updating to this version Alas there is no easy solution to move back from Mealie 2.0 to 1.2. + +- If you had a backup from mealie : + - make a clean install (rename folder /homeassistant/addons_config/mealie_data to mealie_data.bak) + - restart the latest version of the addon (which will fully reset) and restore your backup +- If you have a backup from homeassistant of the /config folder : + - you should rename the folder /homeassistant/addons_config/mealie_data to mealie_data.bak + - extract your backup + - Copy the /homeassistant/addons_config/mealie_data folder from your backup to the same path in homeassistant +- Wait for the addon to move back to 2.0 to use your database that was upgraded... + +If you have neither, alas Mealie has no way to way back from the upgrade that occurred... For info, I've improved the system to make sure that the data is backuped in the future (this function did not exist when I created the addon) but this doesn't help for this specific issue. + +## v1.12.0 (24-08-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) + +## v1.11.0 (03-08-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) + +## v1.10.2 (06-07-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) + +## v1.9.0 (22-06-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) + +## v1.8.0 (08-06-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) + +## v1.7.0 (25-05-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) + +## v1.6.0 (11-05-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) +## v1.5.1-2 (01-05-2024) +- Minor bugs fixed + +## v1.5.1 (20-04-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) + +## v1.4.0 (06-04-2024) +- Update to latest version from hay-kot/mealie (changelog : https://github.com/hay-kot/mealie/releases) + +## v1.3.2 (16-03-2024) +- Update to latest version from hay-kot/mealie + +## v1.3.1 (09-03-2024) + +- Update to latest version from hay-kot/mealie + +## v1.2.0 (17-02-2024) + +- Update to latest version from hay-kot/mealie + +## v1.1.1 (03-02-2024) + +- Update to latest version from hay-kot/mealie +## v1.0.0-11 (30-01-2024) + +- Fix : incorrect redirect https://github.com/alexbelgium/hassio-addons/issues/1210 + +## v1.0.0-10 (26-01-2024) + +- Fix : .secret permissions denied by allowing again 0 as default user + +## v1.0.0-8 (24-01-2024) + +- Minor bugs fixed + +## v1.0.0-7 (24-01-2024) + +- Feat : exposed DATA_DIR in options to set a custom path + +## v1.0.0-5 (23-01-2024) + +- Fix : avoid spamming of "GET /api/app/about" + +## v1.0.0-4 (23-01-2024) + +- Breaking change : port 9001 (mapped to 9090 by default) both for http and https + +## v1.0.0-3 (22-01-2024) + +- Minor bugs fixed + +## v1.0.0 (22-01-2024) + +- Switch of container to official version 1.0.0 +- Adaptation of ports : please check addon options page +- Root user not anymore supported by upstream image, setting it to root (0:0) will revert to 1000:1000 +- Default user of 1000:1000 + +## v1.0.0-RC1.1 (14-10-2023) + +- Update to latest version from hay-kot/mealie +## v1.0.0-beta-5-4 (20-06-2023) + +- Minor bugs fixed +## v1.0.0-beta-5-3 (07-06-2023) + +- Minor bugs fixed +- Fix : avoid loop when upgrading from <1.0 versions https://github.com/alexbelgium/hassio-addons/issues/856 + +## v1.0.0-beta-5-2 (04-06-2023) + +- Minor bugs fixed + +## v1.0.0-beta-4 (07-05-2023) + +- Minor bugs fixed + +## v1.0.0-beta-3 (11-04-2023) + +- Minor bugs fixed + +## v1.0.0-beta-2 (11-04-2023) + +- Fix : ssl (https://github.com/alexbelgium/hassio-addons/issues/782) +- Implemented healthcheck + +## v1.0.0-beta-1 (07-01-2023) + +- Update to latest version from hay-kot/mealie + +## 1.0.1 (03-01-2023) + +- Migrates data to cp -r /data/\* /config/ to enable usage of new addons +- WARNING : update to supervisor 2022.11 before installing +- Optional passing of env variables by adding them in a config.yml file (see readme) +- Breaking change : amd64 updated to mealie 1.0 +- You'll lose your database : first do a backup from within mealie, then restore after upgrading + +## 1.0.0 (18-06-2022) + +- Update to latest version from hay-kot/mealie + +## 1.0.0.1 (26-05-2022) + +- Update to latest version from hay-kot/mealie +- Add codenotary sign + +## 0.5.6 (04-02-2022) + +- Update to latest version from hay-kot/mealie + +## 0.5.5 (04-02-2022) + +- Update to latest version from hay-kot/mealie +- New standardized logic for Dockerfile build and packages installation + +## 0.5.4 (03-12-2021) + +- Update to latest version from hay-kot/mealie + +## 0.5.3 (31-10-2021) + +- Update to latest version from hay-kot/mealie +- Added ssl option + +## 0.5.2 (26-07-2021) + +- Update to latest version from hay-kot/mealie +- :arrow_up: Initial release diff --git a/zzz_test/Dockerfile b/zzz_test/Dockerfile new file mode 100644 index 000000000..66f31a029 --- /dev/null +++ b/zzz_test/Dockerfile @@ -0,0 +1,274 @@ +#============================# +# ALEXBELGIUM'S DOCKERFILE # +#============================# +# _.------. +# _.-` ('>.-`"""-. +# '.--'` _'` _ .--.) +# -' '-.-';` ` +# ' - _.' ``'--. +# '---` .-'""` +# /` +#=== Home Assistant Addon ===# + +################# +# 1 Build Image # +################# + +ARG BUILD_FROM +ARG BUILD_VERSION +FROM ${BUILD_FROM} AS base-addon + +################## +# 2 Modify Image # +################## + +# Set S6 wait time +ENV S6_CMD_WAIT_FOR_SERVICES=1 \ + S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \ + S6_SERVICES_GRACETIME=0 + +# Correct data path +# hadolint ignore=DL4006 +RUN grep -rl "/app/data" /app | xargs sed -i 's|/app/data|/config/addons_config/mealie_data|g' && \ + sed -i "s|change_user$|# change_user|g" /app/run.sh + +################## +# 3 Install Apps # +################## + +# Add rootfs +COPY rootfs/ / + +# Uses /bin for compatibility purposes +# hadolint ignore=DL4005 +RUN if [ ! -f /bin/sh ] && [ -f /usr/bin/sh ]; then ln -s /usr/bin/sh /bin/sh; fi && \ + if [ ! -f /bin/bash ] && [ -f /usr/bin/bash ]; then ln -s /usr/bin/bash /bin/bash; fi + +# Modules +ARG MODULES="00-banner.sh 01-custom_script.sh" + +# Automatic modules download +ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automodules.sh" "/ha_automodules.sh" +RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh + +# Manual apps +ENV PACKAGES="nginx" + +# Automatic apps & bashio +ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_autoapps.sh" "/ha_autoapps.sh" +RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.sh + +############################################### +# 4 Integrate Mealie Dockerfile - Frontend Build +############################################### + +# Define build arguments for SUB_PATH +ARG SUB_PATH=/mealie_path/ +ENV SUB_PATH=${SUB_PATH} + +# Frontend Builder Stage +FROM node:16 AS mealie-frontend-builder + +WORKDIR /app/frontend + +# Copy frontend source code +COPY ./frontend . + +# Install dependencies +RUN yarn install \ + --prefer-offline \ + --frozen-lockfile \ + --non-interactive \ + --production=false \ + --network-timeout 1000000 + +# Pass SUB_PATH to the build environment +ENV SUB_PATH=${SUB_PATH} + +# Build the frontend +RUN yarn generate + +############################################### +# 5 Integrate Mealie Dockerfile - Python Base and Dependencies +############################################### + +FROM python:3.10-slim AS mealie-python-base + +ENV MEALIE_HOME="/app" + +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PIP_NO_CACHE_DIR=off \ + PIP_DISABLE_PIP_VERSION_CHECK=on \ + PIP_DEFAULT_TIMEOUT=100 \ + POETRY_HOME="/opt/poetry" \ + POETRY_VIRTUALENVS_IN_PROJECT=true \ + POETRY_NO_INTERACTION=1 \ + PYSETUP_PATH="/opt/pysetup" \ + VENV_PATH="/opt/pysetup/.venv" + +# Prepend poetry and venv to PATH +ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH" + +# Create user account +RUN useradd -u 911 -U -d $MEALIE_HOME -s /bin/bash abc \ + && usermod -G users abc \ + && mkdir $MEALIE_HOME + +# Builder Base Image +FROM mealie-python-base AS mealie-builder-base + +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + curl \ + build-essential \ + libpq-dev \ + libwebp-dev \ + # LDAP Dependencies + libsasl2-dev libldap2-dev libssl-dev \ + gnupg gnupg2 gnupg1 \ + && rm -rf /var/lib/apt/lists/* \ + && pip install -U --no-cache-dir pip + +# Install Poetry +ENV POETRY_VERSION=1.3.1 +RUN curl -sSL https://install.python-poetry.org | python3 - + +# Copy project requirement files +WORKDIR $PYSETUP_PATH +COPY ./poetry.lock ./pyproject.toml ./ + +# Install runtime dependencies +RUN poetry install -E pgsql --only main + +# CRFPP Image (Assuming it's needed) +FROM hkotel/crfpp AS crfpp + +RUN echo "crfpp-container" + +# Production Image +FROM mealie-python-base AS mealie-production + +LABEL org.opencontainers.image.source="https://github.com/mealie-recipes/mealie" + +ENV PRODUCTION=true +ENV TESTING=false + +ARG COMMIT +ENV GIT_COMMIT_HASH=${COMMIT} + +RUN apt-get update \ + && apt-get install --no-install-recommends -y \ + gosu \ + iproute2 \ + libldap-common \ + libldap-2.5 \ + && rm -rf /var/lib/apt/lists/* + +# Create directory for Docker Secrets +RUN mkdir -p /run/secrets + +# Copy Poetry and virtual environment from builder-base +COPY --from=mealie-builder-base $POETRY_HOME $POETRY_HOME +COPY --from=mealie-builder-base $PYSETUP_PATH $PYSETUP_PATH + +ENV LD_LIBRARY_PATH=/usr/local/lib + +# Copy CRF++ binaries +COPY --from=crfpp /usr/local/lib/ /usr/local/lib +COPY --from=crfpp /usr/local/bin/crf_learn /usr/local/bin/crf_learn +COPY --from=crfpp /usr/local/bin/crf_test /usr/local/bin/crf_test + +# Copy backend application +COPY ./mealie $MEALIE_HOME/mealie +COPY ./poetry.lock ./pyproject.toml $MEALIE_HOME/ + +# Alembic migrations +COPY ./alembic $MEALIE_HOME/alembic +COPY ./alembic.ini $MEALIE_HOME/ + +# Install Python runtime dependencies +WORKDIR $MEALIE_HOME +RUN . $VENV_PATH/bin/activate && poetry install -E pgsql --only main +WORKDIR / + +# Install CRF++ Models +RUN python $MEALIE_HOME/mealie/scripts/install_model.py + +# Define volumes and environment variables +VOLUME [ "$MEALIE_HOME/data/" ] +ENV APP_PORT=9000 + +EXPOSE ${APP_PORT} + +# Healthcheck +HEALTHCHECK CMD python $MEALIE_HOME/mealie/scripts/healthcheck.py || exit 1 + +# ---------------------------------- +# 6 Integrate Mealie Dockerfile - Copy Frontend + +ENV STATIC_FILES=/spa/static +COPY --from=mealie-frontend-builder /app/frontend/dist ${STATIC_FILES} + +ENV HOST=0.0.0.0 + +EXPOSE ${APP_PORT} + +# ---------------------------------- +# 7 Entrypoint and Scripts + +# Add entrypoint +ENV S6_STAGE2_HOOK=/ha_entrypoint.sh +ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_entrypoint.sh" "/ha_entrypoint.sh" + +# Entrypoint modifications +ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_entrypoint_modif.sh" "/ha_entrypoint_modif.sh" +RUN chmod 777 /ha_entrypoint.sh /ha_entrypoint_modif.sh && /ha_entrypoint_modif.sh && rm /ha_entrypoint_modif.sh + +# Modify run.sh for ARMv7 +RUN \ + # Add custom instructions to run.sh on armv7 + sed -i '1d' /app/run.sh \ + && cat /app/run.sh >> /run.txt \ + && cat /run.txt > /app/run.sh \ + && chmod +x /app/run.sh + +# Copy and set entrypoint script +COPY ./docker/entry.sh $MEALIE_HOME/run.sh + +RUN chmod +x $MEALIE_HOME/run.sh +ENTRYPOINT ["/app/run.sh"] + +############ +# 8 Labels # +############ + +ARG BUILD_ARCH +ARG BUILD_DATE +ARG BUILD_DESCRIPTION +ARG BUILD_NAME +ARG BUILD_REF +ARG BUILD_REPOSITORY +ARG BUILD_VERSION +LABEL \ + io.hass.name="${BUILD_NAME}" \ + io.hass.description="${BUILD_DESCRIPTION}" \ + io.hass.arch="${BUILD_ARCH}" \ + io.hass.type="addon" \ + io.hass.version=${BUILD_VERSION} \ + maintainer="alexbelgium (https://github.com/alexbelgium)" \ + org.opencontainers.image.title="${BUILD_NAME}" \ + org.opencontainers.image.description="${BUILD_DESCRIPTION}" \ + org.opencontainers.image.vendor="Home Assistant Add-ons" \ + org.opencontainers.image.authors="alexbelgium (https://github.com/alexbelgium)" \ + org.opencontainers.image.licenses="MIT" \ + org.opencontainers.image.url="https://github.com/alexbelgium" \ + org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \ + org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \ + org.opencontainers.image.created=${BUILD_DATE} \ + org.opencontainers.image.revision=${BUILD_REF} \ + org.opencontainers.image.version=${BUILD_VERSION} + +################# +# 9 Healthcheck # +################# \ No newline at end of file diff --git a/zzz_test/README.md b/zzz_test/README.md new file mode 100644 index 000000000..7ab590ec8 --- /dev/null +++ b/zzz_test/README.md @@ -0,0 +1,128 @@ +## ⚠ Open Issue : [[Mealie] Unable to locate custom environment variables (opened 2024-08-31)](https://github.com/alexbelgium/hassio-addons/issues/1558) by [@user34756361233](https://github.com/user34756361233) +## ⚠ Open Issue : [🐛 [Mealie] Mealie not recognising login details (opened 2024-09-20)](https://github.com/alexbelgium/hassio-addons/issues/1580) by [@Valve90210](https://github.com/Valve90210) +## ⚠ Open Issue : [🐛 [Mealie] Error when starting braking after upgrading from 1.12.0-2 to 1.12.0-4 (opened 2024-09-24)](https://github.com/alexbelgium/hassio-addons/issues/1583) by [@jack5mikemotown](https://github.com/jack5mikemotown) +## ⚠ Open Issue : [🐛 [Mealie] Not able to restore backup from standalone Mealie 12.2.0 (opened 2024-09-25)](https://github.com/alexbelgium/hassio-addons/issues/1585) by [@phellarv](https://github.com/phellarv) +# Hass.io Add-ons: Mealie + +[![Donate][donation-badge]](https://www.buymeacoffee.com/alexbelgium) +[![Donate][paypal-badge]](https://www.paypal.com/donate/?hosted_button_id=DZFULJZTP3UQA) + +![Version](https://img.shields.io/badge/dynamic/json?label=Version&query=%24.version&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fmealie%2Fconfig.json) +![Ingress](https://img.shields.io/badge/dynamic/json?label=Ingress&query=%24.ingress&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fmealie%2Fconfig.json) +![Arch](https://img.shields.io/badge/dynamic/json?color=success&label=Arch&query=%24.arch&url=https%3A%2F%2Fraw.githubusercontent.com%2Falexbelgium%2Fhassio-addons%2Fmaster%2Fmealie%2Fconfig.json) + +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/9c6cf10bdbba45ecb202d7f579b5be0e)](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) +[![GitHub Super-Linter](https://img.shields.io/github/actions/workflow/status/alexbelgium/hassio-addons/weekly-supelinter.yaml?label=Lint%20code%20base)](https://github.com/alexbelgium/hassio-addons/actions/workflows/weekly-supelinter.yaml) +[![Builder](https://img.shields.io/github/actions/workflow/status/alexbelgium/hassio-addons/onpush_builder.yaml?label=Builder)](https://github.com/alexbelgium/hassio-addons/actions/workflows/onpush_builder.yaml) + +[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 + +Warning : armv7 only supported up to version 0.4.3! It won't be updated with later versions + +_Thanks to everyone having starred my repo! To star it click on the image below, then it will be on top right. Thanks!_ + +[![Stargazers repo roster for @alexbelgium/hassio-addons](https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.github/stars2.svg)](https://github.com/alexbelgium/hassio-addons/stargazers) + +![downloads evolution](https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/mealie/stats.png) + +## About + +Mealie is a self hosted recipe manager and meal planner with a RestAPI backend and a reactive frontend application built in Vue for a pleasant user experience for the whole family. +This addon for mealie 1.0 is based on the combined [docker image](https://hub.docker.com/r/hendrix04/mealie-combined) from hendrix04. +This addon is based on the [docker image](https://hub.docker.com/r/hkotel/mealie) from hay-kot. + +## Configuration + +- Start the addon. Wait a while and check the log for any errors. +- Open yourdomain.com:9925 (where ":9925" is the port configured in the addon). +- Default + - Username: changeme@email.com + - Password: MyPassword + +Options can be configured through two ways : + +- Addon options + +```yaml + "BASE_URL": Optional, external base url + "PGID": user ID + "PUID": "group ID + "certfile": fullchain.pem #ssl certificate, must be located in /ssl + "keyfile": privkey.pem #sslkeyfile, must be located in /ssl + "ssl": ssl: true/false + "ALLOW_SIGNUP": Allow signup of users +``` + +- Config.yaml + Additional options can be configured using the config.yaml file found in /homeassistant/addons_config/xxx-mealie/config.yaml + +The complete list of options can be seen here : https://nightly.mealie.io/documentation/getting-started/installation/backend-config/ + +## Integration with HA + +### Detailed infos (Thanks @michelangelonz) + +Create a restful sensor + +```yaml +sensor: + - platform: rest + resource: "http://###.###.#.#:9090/api/groups/mealplans/today" + method: GET + name: Mealie todays meal + headers: + Authorization: Bearer + value_template: "{{ value_json.value }}" + json_attributes_path: $..recipe + json_attributes: + - name + - id + - totalTime + - prepTime + - performTime + - description + - slug +``` + +Create template sensors from attributes + +```yaml +- name: TodaysDinner + unique_id: sensor.TodaysDinner + state: "{{ state_attr('sensor.mealie_todays_meal', 'name') }}" +- name: TodaysDinnerDescription + unique_id: sensor.DinnerDescription + state: "{{ state_attr('sensor.mealie_todays_meal', 'description') }}" +- name: TodaysDinnerSlug + unique_id: sensor.DinnerSlug + state: "{{ state_attr('sensor.mealie_todays_meal', 'slug') }}" +- name: TodaysDinnerID + unique_id: sensor.DinnerID + state: "{{ state_attr('sensor.mealie_todays_meal', 'id') }}" +``` + +Add a generic camera for image +http://###.###.#.#:9090/api/media/recipes/{{ state_attr('sensor.mealie_todays_meal', 'id') }}/images/min-original.webp + +### Global infos + +Read here : https://hay-kot.github.io/mealie/documentation/community-guide/home-assistant/ + +## Installation + +The installation of this add-on is pretty straightforward and not different in +comparison to installing any other Hass.io add-on. + +1. [Add my Hass.io add-ons repository][repository] to your Hass.io instance. +1. Install this add-on. +1. Click the `Save` button to store your configuration. +1. Start the add-on. +1. Check the logs of the add-on to see if everything went well. +1. Carefully configure the add-on to your preferences, see the official documentation for for that. + +## Support + +If you have in issue with your installation, please be sure to checkout github. + +[repository]: https://github.com/alexbelgium/hassio-addons diff --git a/zzz_test/apparmor.txt b/zzz_test/apparmor.txt new file mode 100644 index 000000000..4b173ddad --- /dev/null +++ b/zzz_test/apparmor.txt @@ -0,0 +1,59 @@ +#include + +profile mealie_addon flags=(attach_disconnected,mediate_deleted) { + #include + + capability, + file, + signal, + mount, + umount, + remount, + network udp, + network tcp, + network dgram, + network stream, + network inet, + network inet6, + network netlink raw, + network unix dgram, + capability setgid, + capability setuid, + + +# S6-Overlay + /init ix, + /run/{s6,s6-rc*,service}/** ix, + /package/** ix, + /command/** ix, + /run/{,**} rwk, + /dev/tty rw, + /bin/** ix, + /usr/bin/** ix, + /usr/lib/bashio/** ix, + /etc/s6/** rix, + /run/s6/** rix, + /etc/services.d/** rwix, + /etc/cont-init.d/** rwix, + /etc/cont-finish.d/** rwix, + /init rix, + /var/run/** mrwkl, + /var/run/ mrwkl, + /dev/i2c-1 mrwkl, + /dev/fuse mrwkl, + /dev/sda1 mrwkl, + /dev/sdb1 mrwkl, + /dev/nvme0 mrwkl, + /dev/nvme1 mrwkl, + /dev/mmcblk0p1 mrwkl, + + # Data access + /data/** rw, + + # suppress ptrace denials when using 'docker ps' or using 'ps' inside a container + ptrace (trace,read) peer=docker-default, + + # docker daemon confinement requires explict allow rule for signal + signal (receive) set=(kill,term) peer=/usr/bin/docker, + +} diff --git a/zzz_test/build.json b/zzz_test/build.json new file mode 100644 index 000000000..3d7c18cce --- /dev/null +++ b/zzz_test/build.json @@ -0,0 +1,9 @@ +{ + "build_from": { + "aarch64": "hkotel/mealie:nightly", + "amd64": "hkotel/mealie:nightly" + }, + "codenotary": { + "signer": "alexandrep.github@gmail.com" + } +} diff --git a/zzz_test/config.json b/zzz_test/config.json new file mode 100644 index 000000000..94785ef37 --- /dev/null +++ b/zzz_test/config.json @@ -0,0 +1,117 @@ +{ + "arch": [ + "aarch64", + "amd64" + ], + "codenotary": "alexandrep.github@gmail.com", + "description": "Mealie is a self hosted recipe manager and meal planner built in Vue", + "devices": [ + "/dev/dri", + "/dev/dri/card0", + "/dev/dri/card1", + "/dev/dri/renderD128", + "/dev/vchiq", + "/dev/video10", + "/dev/video11", + "/dev/video12", + "/dev/video13", + "/dev/video14", + "/dev/video15", + "/dev/video16", + "/dev/ttyUSB0", + "/dev/sda", + "/dev/sdb", + "/dev/sdc", + "/dev/sdd", + "/dev/sde", + "/dev/sdf", + "/dev/sdg", + "/dev/nvme", + "/dev/nvme0n1p1", + "/dev/nvme0n1p2", + "/dev/nvme0n1p3", + "/dev/nvme1n1p1", + "/dev/nvme1n1p2", + "/dev/nvme1n1p3", + "/dev/nvme2n1p1", + "/dev/nvme2n1p2", + "/dev/nvme3n1p3", + "/dev/mmcblk", + "/dev/fuse", + "/dev/sda1", + "/dev/sdb1", + "/dev/sdc1", + "/dev/sdd1", + "/dev/sde1", + "/dev/sdf1", + "/dev/sdg1", + "/dev/sda2", + "/dev/sdb2", + "/dev/sdc2", + "/dev/sdd2", + "/dev/sde2", + "/dev/sdf2", + "/dev/sdg2", + "/dev/sda3", + "/dev/sdb3", + "/dev/sda4", + "/dev/sdb4", + "/dev/sda5", + "/dev/sda6", + "/dev/sda7", + "/dev/sda8", + "/dev/nvme0", + "/dev/nvme1", + "/dev/nvme2" + ], + "environment": { + "DATA_DIR": "/config/addons_config/mealie_data", + "DB_ENGINE": "sqlite", + "MAX_WORKERS": "1", + "WEB_CONCURRENCY": "2", + "WEB_GUNICORN": "true", + "WORKERS_PER_CORE": "0.5" + }, + "image": "ghcr.io/alexbelgium/test-{arch}", + "ingress": true, + "map": [ + "config:rw", + "share:rw", + "ssl:rw" + ], + "name": "Mealie test", + "options": { + "ALLOW_SIGNUP": true, + "BASE_SUBPATH": "/mealie", + "DATA_DIR": "/config/addons_config/mealie_data", + "PGID": 1000, + "PUID": 1000, + "certfile": "fullchain.pem", + "keyfile": "privkey.pem", + "ssl": false + }, + "panel_admin": false, + "panel_icon": "mdi:silverware-fork-knife", + "ports": { + "9001/tcp": 9090 + }, + "ports_description": { + "9001/tcp": "Web interface" + }, + "schema": { + "ALLOW_SIGNUP": "bool", + "BASE_URL": "str?", + "BASE_SUBPATH": "str?", + "DATA_DIR": "str?", + "PGID": "int", + "PUID": "int", + "certfile": "str", + "keyfile": "str", + "ssl": "bool" + }, + "slug": "test", + "udev": true, + "url": "https://github.com/alexbelgium/hassio-addons", + "version": "v2.0-beta_ingress_test", + "webui": "[PROTO:ssl]://[HOST]:[PORT:9001]" +} \ No newline at end of file diff --git a/zzz_test/icon.png b/zzz_test/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..136b3951561b9d987b86bd8e121f02d131140a38 GIT binary patch literal 3628 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 indent) {delete vname[i]}} + if (length($3) > 0) { + vn=""; for (i=0; i/tmpfile + +while IFS= read -r line; do + # Clean output + line="${line//[\"\']/}" + # Check if secret + if [[ "${line}" == *'!secret '* ]]; then + echo "secret detected" + secret=${line#*secret } + # Check if single match + secretnum=$(sed -n "/$secret:/=" /config/secrets.yaml) + [[ $(echo $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" /config/secrets.yaml) + secret=${secret#*: } + line="${line%%=*}='$secret'" + fi + # Data validation + if [[ "$line" =~ ^.+[=].+$ ]]; then + export "$line" + # Show in log + if ! bashio::config.false "verbose"; then bashio::log.blue "$line"; fi + else + bashio::exit.nok "$line does not follow the correct structure. Please check your yaml file." + fi +done <"/tmpfile" + +else +bashio::log.info "No config.yaml found in $CONFIGSOURCE, using default parameters" +fi + +############### +# PERMISSIONS # +############### + +chmod -R 777 /data +mkdir -p "$DATA_DIR" +cd "$DATA_DIR" || true +chown -R "$PUID:$PGID" . +echo "Permissions adapted" + +bashio::log.info "Starting nginx" +nginx & true + +bashio::log.info "Starting app" +fi diff --git a/zzz_test/stats.png b/zzz_test/stats.png new file mode 100644 index 0000000000000000000000000000000000000000..c8a2fc9726ea7a7f40cd6fe527257be6069e6fc2 GIT binary patch literal 1939 zcmV;E2WP)005Q<0{{R3A47^=0003aP)t-s|Ns90 z005w%p#J~>0KfnMfd9Y%{{Zgpz(4@V$N)iU;s3xO0DwTifd4RHfQtYCK!5=Mfd7C0 z)TJsa|Nj6$;Lrd702&$^Gcz+yO-*KIW`BQwnVFfhv$Md!z|73d<>lr7|NrnZGLY_& zt=Q)9Rq){d|L)y_|F*%e?(YBB009300Av6F|9>KjA})(p009300E-zJZ~y>+007O0 z&g%gG|Nj900M60>6qEmdQ1F0&|3v`$fO6@Udhq6qy|-()h70xe+@OFU|D^!#g6@<6 z)7_xmkWfHXYcGHl0Du$}fIt+0K!AW?z<^-?fPeu1fI$DCK>wg%|DbUHz`+0ifdBu% z&9|QL|L~x;&B6b{&A_mH|3IMsAilo70G@MhT!{Yw000SaNLh0L01m_e01m_fl`9S# z000ISNklZJMhf3`SvdcmGS8+iF{dBqR~}koWxPGtv~HN016SApigX00000 z000000000ji1Gc}yBMG;@cn%Lx9qsL@3_5&?`GeUf!laFkMZL^>@EHMH>^LEP5Nd# zo}@$hWBKUb+VH%|(tFT?34Bv~Cu)YHE^9t$f@a@zg zeH{+7jk)v)X2InAy};l!(VQF+ii4&}NXwWS%IOjb?@%1z)0YV+=9ra(7itr)>Nc^r~9%3gMoqE^a!gZ7;sLX z8$xo~JEYGHr?;S8G=-mRLnEmbwd0&VE2U0cc$*)+TLH{vO~ubD`*fNO(p#ZXE``|^QS9jf(tDzG?vqZxiI(0Ot#dxoK6>Y+!+HZ$r}IxN zoh*uC-o!wz9~R|-w_c$n^|JybM&(ZFxHvNqX61J2jwjOC3It3zln2hbFrO~HYsv~- z#;4pY-43MRhEqAD&x^O22cL9w@BO);JTTTVkQl=%h&0dCD(2JgLA`F>lqr$sm|Ep- zP=|CSif203+*_VxpIXIy`T>)*d*!lw%~D(snZ!Vj(ab-XwS(+$q4K1~Z+39F>8HK(;A^*!Mw@J75?=whWubBstQO!AHM=_l27wXf^k)Y7??Gq*|4EZ1x9%XaN=lFHjn#lt@W ztSX(I{+E!KiS4WE|-}FB+XtF2S2JJ2Zd5|M(o)>C_9BTOiG! z8ZBC-Uwf7c_h}d}BeZn!(cjlE!(Mem+J$iq_W5-Fu2s{HtIVDK#7}=8N=sY=xeC&& z>49xK_WRTMsa3;nA*m;hS+@Obeq}x#&U+$>Vx;fmyDI}ZIPZ(6dv|1Y0?s?r;ffrb z_olscIPVUmFGzFgaNeKB(s31K1lmf6@*!~C%jOP8Gam%cU8}x$C?AGaEgi}S!hYAP zCo3o)imL;;Nd9>S$_GR4-iwFCF@y}pT=#&8-FpS;U_ivtd-4Eg+sB*>!)4@sKR>LO0)y|vF5Nh+Bc03XzQy5K5 zUN~im)8DA&5OT+g0^4KgO35WodULLs$M9M8zHgs*7sLKEvSY|r>{3X&Nr!|a(|k|) zj!V1BW0*=MX^If4Qh7*TsdP_Nf#qH0F?pr3(Yo}IxkDMUtzRQe(kg_+^sAshSByDa zc_L%DO2yKyJRxMIirM5bWTmp}XI!=+WLw!g@1x{&-@|?oAF_&RS}7#|L@`9OCn6@w z`EZrmdLOY;SqM|OLZym(B4VgY9byDiU$yKxJvk(Z<7dnBn@An1L`eDxMacK-IDPI= zG%lu)4_7I^p>QEor3xY8a{!hqm6b-$hpJQ}o#S}u?AzhoLuDtf{jgJn1X~Cb6BIFW zK5V5zxl&n3UMVqziJ>ZG%ZI4caWnir0@eb~R|M8q1HC%{&nHF<