diff --git a/README.md b/README.md index 3d94089..6c6162f 100644 --- a/README.md +++ b/README.md @@ -349,23 +349,32 @@ You can now run pyMC Repeater from within a [Docker Container](https://www.docke Here is what you'll need to do in order to get the container running: -1. Copy the `config.yaml.example` to `config.yaml` +1. Create the bind mount directories and copy the example config into the + Docker config directory. ```bash -cp ./config.yaml.example ./config.yaml +mkdir -p ./config ./data +cp ./config.yaml.example ./config/config.yaml ``` 2. Run the configuration script and follow the prompts. ```bash -sudo bash ./setup-radio-config.sh +sudo bash ./setup-radio-config.sh ./config ``` -3. Modify the `config.yaml` file with a unique web UI password. This allows you to bypass the `/setup` page when logging for the first time. You can find the value under `repeater.security.admin_password`. Change to _anything_ besides the default of `admin123`. +3. Modify `./config/config.yaml` with a unique web UI password. This allows you to bypass the `/setup` page when logging for the first time. You can find the value under `repeater.security.admin_password`. Change to _anything_ besides the default of `admin123`. 4. Configure the [docker compose](./docker-compose.yml) to your specific hardware and file paths. Be sure to comment-out or delete lines that aren't required for your hardware. Please note that your hardware devices might be at a different path than those listed in the docker compose file. -5. If you are using SPI/GPIO hardware, make sure the `GPIO_GID` and `SPI_GID` +5. Make the bind mount directories writable by the container user. The image + runs as UID/GID `15888` by default unless you override `PUID` and `PGID`. + +```bash +sudo chown -R 15888:15888 ./config ./data +``` + +6. If you are using SPI/GPIO hardware, make sure the `GPIO_GID` and `SPI_GID` values match the numeric group IDs on your host. The compose file defaults to `GPIO_GID=986` and `SPI_GID=989`. @@ -374,7 +383,7 @@ getent group gpio getent group spi ``` -6. Build and start the container. +7. Build and start the container. ```bash docker compose up -d --force-recreate --build diff --git a/docker-compose.yml b/docker-compose.yml index 98a862d..e65766b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,8 +4,8 @@ services: context: . dockerfile: dockerfile args: - PUID: ${PUID:-1000} - PGID: ${PGID:-1000} + PUID: ${PUID:-15888} + PGID: ${PGID:-15888} GPIO_GID: ${GPIO_GID:-986} SPI_GID: ${SPI_GID:-989} container_name: pymc-repeater diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 16788ac..518b1da 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -13,16 +13,38 @@ YQ_CMD="${YQ_CMD:-/usr/local/bin/yq}" mkdir -p "${CONFIG_DIR}" +print_permission_help() { + echo "If you are bind-mounting ./config or ./data, ensure the host paths are writable by ${RUNTIME_USER} (${RUNTIME_UID}:${RUNTIME_GID})." >&2 + echo "For the default image user, run: sudo chown -R ${RUNTIME_UID}:${RUNTIME_GID} ./config ./data" >&2 +} + copy_or_die() { src="$1" dest="$2" if ! cp "${src}" "${dest}"; then echo "Failed to initialize ${dest} from ${src}." >&2 - echo "If you are bind-mounting ./config.yaml, ensure the host path is writable by ${RUNTIME_USER} (${RUNTIME_UID}:${RUNTIME_GID})." >&2 + print_permission_help exit 1 fi } +use_runtime_merged_config() { + src="$1" + runtime_dir="$(mktemp -d /tmp/pymc-repeater-config.XXXXXX)" + runtime_config="${runtime_dir}/config.yaml" + + if ! cp "${src}" "${runtime_config}"; then + echo "Failed to prepare temporary merged config at ${runtime_config}; keeping the existing config." >&2 + return 1 + fi + + CONFIG_PATH="${runtime_config}" + echo "Using merged config from ${CONFIG_PATH} for this container start only." >&2 + echo "Fix the bind-mounted config ownership so future upgrades can persist merged config changes." >&2 + print_permission_help + return 0 +} + merge_config_from_example() { config_path="$1" @@ -62,7 +84,10 @@ merge_config_from_example() { fi if ! cmp -s "${config_path}" "${merged_config}"; then - copy_or_die "${merged_config}" "${config_path}" + if ! cp "${merged_config}" "${config_path}"; then + echo "Failed to update ${config_path} from merged config; the bind-mounted config is not writable." >&2 + use_runtime_merged_config "${merged_config}" || true + fi fi cleanup_merge @@ -70,7 +95,11 @@ merge_config_from_example() { } if [ ! -f "${EXAMPLE_PATH}" ] && [ -f "${BUNDLED_EXAMPLE_PATH}" ]; then - copy_or_die "${BUNDLED_EXAMPLE_PATH}" "${EXAMPLE_PATH}" + if ! cp "${BUNDLED_EXAMPLE_PATH}" "${EXAMPLE_PATH}"; then + echo "Could not copy bundled example config to ${EXAMPLE_PATH}; using bundled example for config merge only." >&2 + print_permission_help + EXAMPLE_PATH="${BUNDLED_EXAMPLE_PATH}" + fi fi if [ -d "${CONFIG_PATH}" ]; then