mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-11-07 13:48:00 +00:00
refactor(web-app-shopware): make init script idempotent and handle admin via Ansible
- moved init.sh from template to files/ for direct copying and bind mounting - removed hardcoded user creation from init process - added database emptiness check before running system:install - added new task 03_admin.yml to ensure admin user exists and update password/email via Ansible - switched docker exec shell from bash to sh for Alpine compatibility - updated Dockerfile and docker-compose.yml accordingly for mount-based init script
This commit is contained in:
81
roles/web-app-shopware/files/init.sh
Normal file
81
roles/web-app-shopware/files/init.sh
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
# Paths / constants
|
||||
APP_ROOT="/var/www/html"
|
||||
MARKER="$APP_ROOT/.infinito/installed"
|
||||
|
||||
cd "$APP_ROOT"
|
||||
mkdir -p "$APP_ROOT/.infinito"
|
||||
|
||||
echo "[INIT] Checking database via PDO..."
|
||||
php -r '
|
||||
$url = getenv("DATABASE_URL");
|
||||
if (!$url) { fwrite(STDERR, "DATABASE_URL not set\n"); exit(1); }
|
||||
$p = parse_url($url);
|
||||
if (!$p || !isset($p["scheme"])) { fwrite(STDERR, "Invalid DATABASE_URL\n"); exit(1); }
|
||||
$scheme = $p["scheme"];
|
||||
if ($scheme === "mysql" || $scheme === "mariadb") {
|
||||
$host = $p["host"] ?? "localhost";
|
||||
$port = $p["port"] ?? 3306;
|
||||
$db = ltrim($p["path"] ?? "", "/");
|
||||
$user = $p["user"] ?? "";
|
||||
$pass = $p["pass"] ?? "";
|
||||
$dsn = "mysql:host=".$host.";port=".$port.";dbname=".$db.";charset=utf8mb4";
|
||||
} else {
|
||||
fwrite(STDERR, "Unsupported DB scheme: ".$scheme."\n"); exit(1);
|
||||
}
|
||||
$retries = 60;
|
||||
while ($retries-- > 0) {
|
||||
try { $pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_TIMEOUT => 3]); exit(0); }
|
||||
catch (Exception $e) { sleep(2); }
|
||||
}
|
||||
fwrite(STDERR, "DB not reachable\n"); exit(1);
|
||||
'
|
||||
|
||||
if [ ! -f "$MARKER" ]; then
|
||||
echo "[INIT] Checking if database is empty..."
|
||||
# PHP exits: 0 = empty, 100 = non-empty, 1 = error
|
||||
if php -r '
|
||||
$url = getenv("DATABASE_URL");
|
||||
$p = parse_url($url);
|
||||
$db = ltrim($p["path"] ?? "", "/");
|
||||
$dsn = "mysql:host=".($p["host"]??"localhost").";port=".($p["port"]??3306).";dbname=".$db.";charset=utf8mb4";
|
||||
try {
|
||||
$pdo = new PDO($dsn, $p["user"] ?? "", $p["pass"] ?? "");
|
||||
$q = $pdo->query("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=".$pdo->quote($db));
|
||||
$cnt = (int)$q->fetchColumn();
|
||||
if ($cnt === 0) { exit(0); } else { exit(100); }
|
||||
} catch (Exception $e) { fwrite(STDERR, $e->getMessage()."\n"); exit(1); }
|
||||
'; then
|
||||
DBCHK=0
|
||||
else
|
||||
DBCHK=$?
|
||||
fi
|
||||
|
||||
if [ "$DBCHK" -eq 0 ]; then
|
||||
echo "[INIT] Installing Shopware (empty DB detected)..."
|
||||
# IMPORTANT: no --force; let Shopware run its internal steps only on empty DB
|
||||
php -d memory_limit=1024M bin/console system:install --basic-setup --create-database
|
||||
elif [ "$DBCHK" -eq 100 ]; then
|
||||
echo "[INIT] Database is not empty -> skipping system:install"
|
||||
else
|
||||
echo "[INIT] Database check failed (code $DBCHK)"; exit 1
|
||||
fi
|
||||
|
||||
# Safe to run (no-ops when up-to-date)
|
||||
php -d memory_limit=1024M bin/console database:migrate --all || true
|
||||
php -d memory_limit=1024M bin/console database:migrate-destructive --all || true
|
||||
|
||||
# Housekeeping
|
||||
php bin/console cache:clear || true
|
||||
php bin/console dal:refresh:index || true
|
||||
|
||||
# Marker + perms
|
||||
touch "$MARKER"
|
||||
chown -R www-data:www-data "$APP_ROOT"
|
||||
|
||||
echo "[INIT] Done."
|
||||
else
|
||||
echo "[INIT] Marker found, skipping install."
|
||||
fi
|
||||
19
roles/web-app-shopware/tasks/03_admin.yml
Normal file
19
roles/web-app-shopware/tasks/03_admin.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
# Ensures that the admin user exists and always has the desired password
|
||||
- name: "Ensure Shopware admin exists and has the desired password"
|
||||
shell: |
|
||||
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_WEB_CONTAINER }} sh -lc '
|
||||
set -e
|
||||
cd {{ SHOPWARE_ROOT }}
|
||||
php bin/console user:create "{{ users.administrator.username }}" \
|
||||
--admin \
|
||||
--password="{{ users.administrator.password }}" \
|
||||
--firstName="{{ users.administrator.username }}" \
|
||||
--lastName="{{ PRIMARY_DOMAIN | lower }}" \
|
||||
--email="{{ users.administrator.email }}" || true
|
||||
php bin/console user:change-password "{{ users.administrator.username }}" \
|
||||
--password="{{ users.administrator.password }}" || true
|
||||
php bin/console user:update "{{ users.administrator.username }}" \
|
||||
--email="{{ users.administrator.email }}" 2>/dev/null || true
|
||||
'
|
||||
args:
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
@@ -6,9 +6,10 @@
|
||||
docker_compose_flush_handlers: false
|
||||
|
||||
- name: "Deploy {{ SHOPWARE_INIT_HOST }}"
|
||||
template:
|
||||
src: init.sh.j2
|
||||
copy:
|
||||
src: init.sh
|
||||
dest: "{{ SHOPWARE_INIT_HOST }}"
|
||||
mode: "0755"
|
||||
notify:
|
||||
- docker compose up
|
||||
- docker compose build
|
||||
@@ -23,6 +24,9 @@
|
||||
delay: 5
|
||||
timeout: 300
|
||||
|
||||
- name: "Ensure admin user exists with correct password"
|
||||
include_tasks: 03_admin.yml
|
||||
|
||||
- name: "Warm up caches and index"
|
||||
shell: |
|
||||
docker exec -i --user {{ SHOPWARE_USER }} {{ SHOPWARE_WEB_CONTAINER }} bash -lc '
|
||||
|
||||
@@ -83,18 +83,9 @@ RUN set -eux; \
|
||||
printf "framework:\n trusted_proxies: '%%env(TRUSTED_PROXIES)%%'\n" > /var/www/html/config/packages/framework.yaml; \
|
||||
fi
|
||||
|
||||
# Copy the init script that your Compose mounts as volumes/init.sh in the build context
|
||||
COPY --chown=www-data:www-data volumes/init.sh /usr/local/bin/init.sh
|
||||
RUN chmod +x /usr/local/bin/init.sh
|
||||
|
||||
# Drop back to the app user
|
||||
USER www-data
|
||||
|
||||
# Default envs (override via .env / compose env_file)
|
||||
ENV APP_ENV=prod \
|
||||
APP_URL=http://localhost:8000 \
|
||||
TRUSTED_PROXIES=127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||
|
||||
# Expose internal port & add a lightweight healthcheck
|
||||
EXPOSE 8000
|
||||
HEALTHCHECK --interval=30s --timeout=5s --retries=5 --start-period=20s \
|
||||
|
||||
@@ -6,6 +6,7 @@ x-environment: &shopware
|
||||
- media:/var/www/html/public/media
|
||||
- thumbnail:/var/www/html/public/thumbnail
|
||||
- sitemap:/var/www/html/public/sitemap
|
||||
- "{{ SHOPWARE_INIT_HOST }}:{{ SHOPWARE_INIT_DOCKER }}:ro"
|
||||
working_dir: {{ SHOPWARE_ROOT }}
|
||||
|
||||
{% include 'roles/docker-compose/templates/base.yml.j2' %}
|
||||
@@ -20,7 +21,7 @@ x-environment: &shopware
|
||||
{% set docker_restart_policy = DOCKER_RESTART_POLICY %}
|
||||
<<: *shopware
|
||||
container_name: "{{ SHOPWARE_INIT_CONTAINER }}"
|
||||
entrypoint: [ "sh", "/usr/local/bin/init.sh" ]
|
||||
entrypoint: [ "sh", "{{ SHOPWARE_INIT_DOCKER }}" ]
|
||||
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ APP_DEBUG="{{ MODE_DEBUG | ternary(1, 0) }}"
|
||||
|
||||
# Shopware
|
||||
APP_ENV={{ 'dev' if (ENVIRONMENT | lower) == 'development' else 'prod' }}
|
||||
TRUSTED_PROXIES=127.0.0.1
|
||||
#TRUSTED_PROXIES=127.0.0.1
|
||||
INSTANCE_ID={{ application_id }}
|
||||
|
||||
# Database
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
cd {{ SHOPWARE_ROOT }}
|
||||
|
||||
mkdir -p {{ SHOPWARE_ROOT }}/.infinito
|
||||
MARKER="{{ SHOPWARE_ROOT }}/.infinito/installed"
|
||||
|
||||
echo "[INIT] Checking database via PDO..."
|
||||
php -r '
|
||||
$url = getenv("DATABASE_URL");
|
||||
if (!$url) { fwrite(STDERR, "DATABASE_URL not set\n"); exit(1); }
|
||||
$p = parse_url($url);
|
||||
if (!$p || !isset($p["scheme"])) { fwrite(STDERR, "Invalid DATABASE_URL\n"); exit(1); }
|
||||
$scheme = $p["scheme"];
|
||||
if ($scheme === "mysql" || $scheme === "mariadb") {
|
||||
$host = $p["host"] ?? "localhost";
|
||||
$port = $p["port"] ?? 3306;
|
||||
$db = ltrim($p["path"] ?? "", "/");
|
||||
$user = $p["user"] ?? "";
|
||||
$pass = $p["pass"] ?? "";
|
||||
$dsn = "mysql:host=".$host.";port=".$port.";dbname=".$db.";charset=utf8mb4";
|
||||
} else {
|
||||
fwrite(STDERR, "Unsupported DB scheme: ".$scheme."\n"); exit(1);
|
||||
}
|
||||
$retries = 60;
|
||||
while ($retries-- > 0) {
|
||||
try { $pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_TIMEOUT => 3]); exit(0); }
|
||||
catch (Exception $e) { sleep(2); }
|
||||
}
|
||||
fwrite(STDERR, "DB not reachable\n"); exit(1);
|
||||
'
|
||||
|
||||
if [ ! -f "$MARKER" ]; then
|
||||
echo "[INIT] Installing Shopware..."
|
||||
php -d memory_limit=1024M bin/console system:install --basic-setup --create-database --force
|
||||
php -d memory_limit=1024M bin/console database:migrate --all
|
||||
php -d memory_limit=1024M bin/console database:migrate-destructive --all
|
||||
php bin/console user:create "{{ users.administrator.username }}" \
|
||||
--admin --password="{{ users.administrator.password }}" \
|
||||
--firstName="Admin" --lastName="User" --email="{{ users.administrator.email }}" || true
|
||||
php bin/console cache:clear || true
|
||||
php bin/console dal:refresh:index || true
|
||||
touch "$MARKER"
|
||||
chown -R {{ SHOPWARE_USER }}:{{ SHOPWARE_USER }} {{ SHOPWARE_ROOT }}
|
||||
echo "[INIT] Done."
|
||||
else
|
||||
echo "[INIT] Marker found, skipping install."
|
||||
fi
|
||||
Reference in New Issue
Block a user