From 8e4f8e1c1d89d862c29054753d122e2fd532e53f Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Tue, 15 Jul 2025 11:35:21 +0200 Subject: [PATCH] =?UTF-8?q?Use=20#!/usr/bin/env=20bashio=20#=20shellcheck?= =?UTF-8?q?=20shell=3Dbash=20set=20-euo=20pipefail=20=20CONFIG=5FHOME=3D"/?= =?UTF-8?q?config"=20PGDATA=3D"${PGDATA:-/config/database}"=20export=20PGD?= =?UTF-8?q?ATA=20PG=5FMAJOR=5FVERSION=3D"${PG=5FMAJOR:-15}"=20RESTART=5FFL?= =?UTF-8?q?AG=5FFILE=3D"$CONFIG=5FHOME/restart=5Fneeded"=20=20fix=5Fpermis?= =?UTF-8?q?sions()=20{=20=09mkdir=20-p=20"$PGDATA"=20=09chown=20-R=20postg?= =?UTF-8?q?res:postgres=20"$PGDATA"=20=09chmod=20700=20"$PGDATA"=20=09if?= =?UTF-8?q?=20[=20-d=20/config/backups=20];=20then=20=09=09chown=20-R=20po?= =?UTF-8?q?stgres:postgres=20/config/backups=20=09=09chmod=20700=20/config?= =?UTF-8?q?/backups=20=09fi=20}=20=20chmod=20-R=20755=20"$CONFIG=5FHOME"?= =?UTF-8?q?=20=20RESTART=5FNEEDED=3Dfalse=20=20cd=20/config=20||=20true=20?= =?UTF-8?q?=20get=5Fpgdata=5Fversion()=20{=20=09if=20[=20-f=20"$PGDATA/PG?= =?UTF-8?q?=5FVERSION"=20];=20then=20=09=09cat=20"$PGDATA/PG=5FVERSION"=20?= =?UTF-8?q?=09else=20=09=09bashio::log.error=20"FATAL:=20$PGDATA/PG=5FVERS?= =?UTF-8?q?ION=20not=20found;=20cannot=20determine=20cluster=20version."?= =?UTF-8?q?=20=09=09exit=201=20=09fi=20}=20=20extract=5Fso=5Ffrom=5Fdeb()?= =?UTF-8?q?=20{=20=09local=20debfile=3D"$1"=20=09local=20targetdir=3D"$2"?= =?UTF-8?q?=20=09local=20sofile=3D"$3"=20=09local=20tmpdir=20=09tmpdir=3D$?= =?UTF-8?q?(mktemp=20-d)=20=09dpkg-deb=20-x=20"$debfile"=20"$tmpdir"=20=09?= =?UTF-8?q?find=20"$tmpdir"=20-name=20"$sofile"=20-exec=20cp=20{}=20"$targ?= =?UTF-8?q?etdir"=20\;=20=09rm=20-rf=20"$tmpdir"=20}=20=20install=5Fvchord?= =?UTF-8?q?=5Fand=5Fvectors=5Ffor=5Fold=5Fpg()=20{=20=09local=20old=5Fpgve?= =?UTF-8?q?r=3D"$1"=20=09local=20vectorchord=5Ftag=3D"${VECTORCHORD=5FTAG:?= =?UTF-8?q?-0.3.0}"=20=09local=20pgvectors=5Ftag=3D"${PGVECTORS=5FTAG:-0.3?= =?UTF-8?q?.0}"=20=09case=20"$(uname=20-m)"=20in=20=09x86=5F64=20|=20amd64?= =?UTF-8?q?=20|=20AMD64=20|=20x86-64)=20=09=09targetarch=3Damd64=20=09=09;?= =?UTF-8?q?;=20=09aarch64=20|=20arm64=20|=20ARM64)=20=09=09targetarch=3Dar?= =?UTF-8?q?m64=20=09=09;;=20=09*)=20=09=09echo=20"Unsupported=20architectu?= =?UTF-8?q?re:=20$(uname=20-m)"=20=09=09exit=201=20=09=09;;=20=09esac=20?= =?UTF-8?q?=09local=20vchord=5Furl=20=09local=20vectors=5Furl=20=09local?= =?UTF-8?q?=20vchord=5Fdeb=20=09local=20vectors=5Fdeb=20=09local=20old=5Fp?= =?UTF-8?q?g=5Flib=3D"/usr/lib/postgresql/$old=5Fpgver/lib"=20=20=09mkdir?= =?UTF-8?q?=20-p=20"$old=5Fpg=5Flib"=20=20=09vchord=5Furl=3D"https://githu?= =?UTF-8?q?b.com/tensorchord/VectorChord/releases/download/${vectorchord?= =?UTF-8?q?=5Ftag}/postgresql-${old=5Fpgver}-vchord=5F${vectorchord=5Ftag}?= =?UTF-8?q?-1=5F${targetarch}.deb"=20=09vchord=5Fdeb=3D"/tmp/vchord-${old?= =?UTF-8?q?=5Fpgver}.deb"=20=09bashio::log.info=20"Downloading=20$vchord?= =?UTF-8?q?=5Furl"=20=09wget=20-nv=20-O=20"$vchord=5Fdeb"=20"$vchord=5Furl?= =?UTF-8?q?"=20=09extract=5Fso=5Ffrom=5Fdeb=20"$vchord=5Fdeb"=20"$old=5Fpg?= =?UTF-8?q?=5Flib"=20"vchord.so"=20=09rm=20-f=20"$vchord=5Fdeb"=20=20=09ve?= =?UTF-8?q?ctors=5Furl=3D"https://github.com/tensorchord/pgvecto.rs/releas?= =?UTF-8?q?es/download/v${pgvectors=5Ftag}/vectors-pg${old=5Fpgver}=5F${pg?= =?UTF-8?q?vectors=5Ftag}=5F${targetarch}.deb"=20=09vectors=5Fdeb=3D"/tmp/?= =?UTF-8?q?pgvectors-${old=5Fpgver}.deb"=20=09bashio::log.info=20"Download?= =?UTF-8?q?ing=20$vectors=5Furl"=20=09wget=20-nv=20-O=20"$vectors=5Fdeb"?= =?UTF-8?q?=20"$vectors=5Furl"=20=09extract=5Fso=5Ffrom=5Fdeb=20"$vectors?= =?UTF-8?q?=5Fdeb"=20"$old=5Fpg=5Flib"=20"vectors.so"=20=09rm=20-f=20"$vec?= =?UTF-8?q?tors=5Fdeb"=20}=20=20drop=5Fvectors=5Feverywhere()=20{=20=09loc?= =?UTF-8?q?al=20old=5Fpgver=3D"$1"=20=09fix=5Fpermissions=20=09su=20-=20"$?= =?UTF-8?q?DB=5FUSERNAME"=20-c=20"$BINARIES=5FDIR/$old=5Fpgver/bin/pg=5Fct?= =?UTF-8?q?l=20\=20=20=20=20=20=20=20=20=20=20=20=20=20-w=20-D=20'$PGDATA'?= =?UTF-8?q?=20-o=20\"-c=20config=5Ffile=3D/etc/postgresql/postgresql.conf?= =?UTF-8?q?=20\=20=20=20=20=20=20=20=20=20=20=20=20=20-c=20listen=5Faddres?= =?UTF-8?q?ses=3D''=20-c=20port=3D65432\"=20start"=20=09for=20db=20in=20$(?= =?UTF-8?q?su=20-=20"$DB=5FUSERNAME"=20-c=20\=20=09=09"$BINARIES=5FDIR/$ol?= =?UTF-8?q?d=5Fpgver/bin/psql=20-Atc=20\=20=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20\"SELECT=20datname=20FROM=20pg=5Fdatabase=20WHERE=20datis?= =?UTF-8?q?template=20=3D=20false=20AND=20datallowconn\"");=20do=20=09=09i?= =?UTF-8?q?f=20su=20-=20"$DB=5FUSERNAME"=20-c=20\=20=09=09=09"$BINARIES=5F?= =?UTF-8?q?DIR/$old=5Fpgver/bin/psql=20-d=20$db=20-Atc=20\=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20\"SELECT=201=20FROM=20pg=5Fextension=20?= =?UTF-8?q?WHERE=20extname=3D'vectors'\""=20|=20=09=09=09grep=20-q=201;=20?= =?UTF-8?q?then=20=09=09=09bashio::log.warning=20"Dropping=20extension=20v?= =?UTF-8?q?ectors=20from=20DB=20$db"=20=09=09=09su=20-=20"$DB=5FUSERNAME"?= =?UTF-8?q?=20-c=20\=20=09=09=09=09"$BINARIES=5FDIR/$old=5Fpgver/bin/psql?= =?UTF-8?q?=20-d=20$db=20-c=20\=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20'DROP=20EXTENSION=20vectors=20CASCADE;'"=20=09=09fi=20?= =?UTF-8?q?=09done=20=09su=20-=20"$DB=5FUSERNAME"=20-c=20"$BINARIES=5FDIR/?= =?UTF-8?q?$old=5Fpgver/bin/pg=5Fctl=20-w=20-D=20'$PGDATA'=20stop"=20}=20?= =?UTF-8?q?=20start=5Fpostgres()=20{=20=09bashio::log.info=20"Starting=20P?= =?UTF-8?q?ostgreSQL..."=20=09if=20[=20"$(bashio::info.arch)"=20=3D=20"arm?= =?UTF-8?q?v7"=20];=20then=20=09=09bashio::log.warning=20"ARMv7=20detected?= =?UTF-8?q?:=20Starting=20without=20vectors.so"=20=09=09/usr/local/bin/imm?= =?UTF-8?q?ich-docker-entrypoint.sh=20postgres=20&=20=09=09true=20=09=09ex?= =?UTF-8?q?it=200=20=09else=20=09=09/usr/local/bin/immich-docker-entrypoin?= =?UTF-8?q?t.sh=20postgres=20-c=20config=5Ffile=3D/etc/postgresql/postgres?= =?UTF-8?q?ql.conf=20&=20=09=09true=20=09fi=20}=20=20wait=5Ffor=5Fpostgres?= =?UTF-8?q?()=20{=20=09local=20tries=3D0=20=09while=20!=20pg=5Fisready=20-?= =?UTF-8?q?h=20"$DB=5FHOSTNAME"=20-p=20"$DB=5FPORT"=20-U=20"$DB=5FUSERNAME?= =?UTF-8?q?"=20>/dev/null=202>&1;=20do=20=09=09tries=3D$((tries=20+=201))?= =?UTF-8?q?=20=09=09if=20[=20"$tries"=20-ge=2060=20];=20then=20=09=09=09ba?= =?UTF-8?q?shio::log.error=20"Postgres=20did=20not=20start=20after=202=20m?= =?UTF-8?q?inutes,=20aborting."=20=09=09=09exit=201=20=09=09fi=20=09=09ech?= =?UTF-8?q?o=20"PostgreSQL=20is=20starting=20up...=20($tries/60)"=20=09=09?= =?UTF-8?q?sleep=202=20=09done=20}=20=20restart=5Fimmich=5Faddons=5Fif=5Ff?= =?UTF-8?q?lagged()=20{=20=09if=20[=20-f=20"$RESTART=5FFLAG=5FFILE"=20];?= =?UTF-8?q?=20then=20=09=09bashio::log.warning=20"Detected=20pending=20Imm?= =?UTF-8?q?ich=20add-on=20restart=20flag.=20Restarting=20all=20running=20I?= =?UTF-8?q?mmich=20add-ons..."=20=20=09=09local=20addons=5Fjson=20slug=20f?= =?UTF-8?q?ound=3D0=20=20=09=09#=20Get=20the=20add-ons=20list,=20fail=20on?= =?UTF-8?q?=20HTTP=20errors,=20show=20errors=20if=20API=20call=20fails=20?= =?UTF-8?q?=09=09addons=5Fjson=3D$(curl=20-fsSL=20-H=20"Authorization:=20B?= =?UTF-8?q?earer=20$SUPERVISOR=5FTOKEN"=20http://supervisor/addons)=20||?= =?UTF-8?q?=20{=20=09=09=09bashio::log.error=20"Supervisor=20API=20call=20?= =?UTF-8?q?failed=20or=20unauthorized:=20$addons=5Fjson"=20=09=09=09rm=20-?= =?UTF-8?q?f=20"$RESTART=5FFLAG=5FFILE"=20=09=09=09return=201=20=09=09}=20?= =?UTF-8?q?=20=09=09if=20command=20-v=20jq=20>/dev/null;=20then=20=09=09?= =?UTF-8?q?=09#=20Use=20correct=20JSON=20path=20for=20modern=20Supervisor?= =?UTF-8?q?=20API=20=09=09=09for=20slug=20in=20$(echo=20"$addons=5Fjson"?= =?UTF-8?q?=20|=20jq=20-r=20'.addons[]=20|=20select(.state=3D=3D"started")?= =?UTF-8?q?=20|=20.slug');=20do=20=09=09=09=09if=20[[=20"$slug"=20=3D=3D?= =?UTF-8?q?=20*immich*=20]];=20then=20=09=09=09=09=09bashio::log.info=20"R?= =?UTF-8?q?estarting=20addon=20$slug"=20=09=09=09=09=09curl=20-fsSL=20-X?= =?UTF-8?q?=20POST=20-H=20"Authorization:=20Bearer=20$SUPERVISOR=5FTOKEN"?= =?UTF-8?q?=20\=20=09=09=09=09=09=09"http://supervisor/addons/$slug/restar?= =?UTF-8?q?t"=20=09=09=09=09=09found=3D1=20=09=09=09=09fi=20=09=09=09done?= =?UTF-8?q?=20=09=09else=20=09=09=09#=20Fallback:=20grep/cut=20for=20legac?= =?UTF-8?q?y=20environments,=20less=20robust=20=09=09=09for=20slug=20in=20?= =?UTF-8?q?$(echo=20"$addons=5Fjson"=20|=20grep=20-o=20'"slug":"[^"]*"'=20?= =?UTF-8?q?|=20cut=20-d:=20-f2=20|=20tr=20-d=20'"');=20do=20=09=09=09=09if?= =?UTF-8?q?=20[[=20"$slug"=20=3D=3D=20*immich*=20]];=20then=20=09=09=09=09?= =?UTF-8?q?=09bashio::log.info=20"Restarting=20addon=20$slug"=20=09=09=09?= =?UTF-8?q?=09=09curl=20-fsSL=20-X=20POST=20-H=20"Authorization:=20Bearer?= =?UTF-8?q?=20$SUPERVISOR=5FTOKEN"=20\=20=09=09=09=09=09=09"http://supervi?= =?UTF-8?q?sor/addons/$slug/restart"=20=09=09=09=09=09found=3D1=20=09=09?= =?UTF-8?q?=09=09fi=20=09=09=09done=20=09=09fi=20=20=09=09if=20[=20"$found?= =?UTF-8?q?"=20-eq=200=20];=20then=20=09=09=09bashio::log.info=20"No=20Imm?= =?UTF-8?q?ich-related=20addon=20found=20running."=20=09=09fi=20=09=09rm?= =?UTF-8?q?=20-f=20"$RESTART=5FFLAG=5FFILE"=20=09fi=20}=20=20get=5Favailab?= =?UTF-8?q?le=5Fextension=5Fversion()=20{=20=09local=20extname=3D"$1"=20?= =?UTF-8?q?=09psql=20"postgres://$DB=5FUSERNAME:$DB=5FPASSWORD@$DB=5FHOSTN?= =?UTF-8?q?AME:$DB=5FPORT/postgres"=20-v=20ON=5FERROR=5FSTOP=3D1=20-tAc=20?= =?UTF-8?q?\=20=09=09"SELECT=20default=5Fversion=20FROM=20pg=5Favailable?= =?UTF-8?q?=5Fextensions=20WHERE=20name=20=3D=20'$extname';"=202>/dev/null?= =?UTF-8?q?=20|=20xargs=20}=20=20is=5Fextension=5Favailable()=20{=20=09loc?= =?UTF-8?q?al=20extname=3D"$1"=20=09local=20result=20=09result=3D$(psql=20?= =?UTF-8?q?"postgres://$DB=5FUSERNAME:$DB=5FPASSWORD@$DB=5FHOSTNAME:$DB=5F?= =?UTF-8?q?PORT/postgres"=20-v=20ON=5FERROR=5FSTOP=3D1=20-tAc=20\=20=09=09?= =?UTF-8?q?"SELECT=201=20FROM=20pg=5Favailable=5Fextensions=20WHERE=20name?= =?UTF-8?q?=20=3D=20'$extname';"=202>/dev/null=20|=20xargs)=20=09[[=20"$re?= =?UTF-8?q?sult"=20=3D=3D=20"1"=20]]=20}=20=20get=5Fuser=5Fdatabases()=20{?= =?UTF-8?q?=20=09psql=20"postgres://$DB=5FUSERNAME:$DB=5FPASSWORD@$DB=5FHO?= =?UTF-8?q?STNAME:$DB=5FPORT/postgres"=20-v=20ON=5FERROR=5FSTOP=3D1=20-tAc?= =?UTF-8?q?=20\=20=09=09"SELECT=20datname=20FROM=20pg=5Fdatabase=20WHERE?= =?UTF-8?q?=20datistemplate=20=3D=20false=20AND=20datallowconn=20=3D=20tru?= =?UTF-8?q?e;"=20}=20=20get=5Finstalled=5Fextension=5Fversion()=20{=20=09l?= =?UTF-8?q?ocal=20extname=3D"$1"=20=09local=20dbname=3D"$2"=20=09psql=20"p?= =?UTF-8?q?ostgres://$DB=5FUSERNAME:$DB=5FPASSWORD@$DB=5FHOSTNAME:$DB=5FPO?= =?UTF-8?q?RT/$dbname"=20-v=20ON=5FERROR=5FSTOP=3D1=20-tAc=20\=20=09=09"SE?= =?UTF-8?q?LECT=20extversion=20FROM=20pg=5Fextension=20WHERE=20extname=20?= =?UTF-8?q?=3D=20'$extname';"=202>/dev/null=20|=20xargs=20}=20=20compare?= =?UTF-8?q?=5Fversions()=20{=20=09local=20v1=3D"$1"=20=09local=20v2=3D"$2"?= =?UTF-8?q?=20=09if=20[=20"$v1"=20=3D=20"$v2"=20];=20then=20return=201;=20?= =?UTF-8?q?fi=20=09if=20[=20"$(printf=20'%s\n'=20"$v1"=20"$v2"=20|=20sort?= =?UTF-8?q?=20-V=20|=20head=20-n1)"=20=3D=20"$v1"=20];=20then=20=09=09retu?= =?UTF-8?q?rn=200=20=09fi=20=09return=201=20}=20=20show=5Fdb=5Fextensions(?= =?UTF-8?q?)=20{=20=09bashio::log.info=20"=3D=3D=3D=3D=20PostgreSQL=20data?= =?UTF-8?q?bases=20and=20enabled=20extensions=20=3D=3D=3D=3D"=20=09for=20d?= =?UTF-8?q?b=20in=20$(get=5Fuser=5Fdatabases);=20do=20=09=09bashio::log.in?= =?UTF-8?q?fo=20"Database:=20$db"=20=09=09exts=3D$(psql=20"postgres://$DB?= =?UTF-8?q?=5FUSERNAME:$DB=5FPASSWORD@$DB=5FHOSTNAME:$DB=5FPORT/$db"=20-tA?= =?UTF-8?q?c=20\=20=09=09=09"SELECT=20extname=20||=20'=20(v'=20||=20extver?= =?UTF-8?q?sion=20||=20')'=20FROM=20pg=5Fextension=20ORDER=20BY=20extname;?= =?UTF-8?q?")=20=09=09if=20[=20-n=20"$exts"=20];=20then=20=09=09=09while?= =?UTF-8?q?=20read=20-r=20ext;=20do=20=09=09=09=09[=20-n=20"$ext"=20]=20&&?= =?UTF-8?q?=20bashio::log.info=20"=20=20=20=20-=20$ext"=20=09=09=09done=20?= =?UTF-8?q?<<<"$exts"=20=09=09else=20=09=09=09bashio::log.info=20"=20=20?= =?UTF-8?q?=20=20(no=20extensions=20enabled)"=20=09=09fi=20=09done=20=09ba?= =?UTF-8?q?shio::log.info=20"=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D?= =?UTF-8?q?=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D?= =?UTF-8?q?=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D"=20}=20=20upgrade=5Fextension=5F?= =?UTF-8?q?if=5Fneeded()=20{=20=09local=20extname=3D"$1"=20=09if=20!=20is?= =?UTF-8?q?=5Fextension=5Favailable=20"$extname";=20then=20=09=09bashio::l?= =?UTF-8?q?og.info=20"$extname=20extension=20not=20available=20on=20this?= =?UTF-8?q?=20Postgres=20instance."=20=09=09return=20=09fi=20=09local=20av?= =?UTF-8?q?ailable=5Fversion=20=09available=5Fversion=3D$(get=5Favailable?= =?UTF-8?q?=5Fextension=5Fversion=20"$extname")=20=09if=20[=20-z=20"$avail?= =?UTF-8?q?able=5Fversion"=20];=20then=20=09=09bashio::log.info=20"Could?= =?UTF-8?q?=20not=20determine=20available=20version=20for=20$extname."=20?= =?UTF-8?q?=09=09return=20=09fi=20=09for=20db=20in=20$(get=5Fuser=5Fdataba?= =?UTF-8?q?ses);=20do=20=09=09local=20installed=5Fversion=20=09=09installe?= =?UTF-8?q?d=5Fversion=3D$(get=5Finstalled=5Fextension=5Fversion=20"$extna?= =?UTF-8?q?me"=20"$db")=20=09=09if=20[=20-n=20"$installed=5Fversion"=20];?= =?UTF-8?q?=20then=20=09=09=09if=20compare=5Fversions=20"$installed=5Fvers?= =?UTF-8?q?ion"=20"$available=5Fversion";=20then=20=09=09=09=09bashio::log?= =?UTF-8?q?.info=20"Upgrading=20$extname=20in=20$db=20from=20$installed=5F?= =?UTF-8?q?version=20to=20$available=5Fversion"=20=09=09=09=09if=20psql=20?= =?UTF-8?q?-h=20"$DB=5FHOSTNAME"=20-p=20"$DB=5FPORT"=20-U=20"$DB=5FUSERNAM?= =?UTF-8?q?E"=20-d=20"$db"=20-v=20ON=5FERROR=5FSTOP=3D1=20-c=20"ALTER=20EX?= =?UTF-8?q?TENSION=20$extname=20UPDATE;";=20then=20=09=09=09=09=09bashio::?= =?UTF-8?q?log.info=20"Reindexing=20database=20$db"=20=09=09=09=09=09psql?= =?UTF-8?q?=20-h=20"$DB=5FHOSTNAME"=20-p=20"$DB=5FPORT"=20-U=20"$DB=5FUSER?= =?UTF-8?q?NAME"=20-d=20"$db"=20-v=20ON=5FERROR=5FSTOP=3D1=20-c=20"REINDEX?= =?UTF-8?q?=20DATABASE=20$db;"=20=09=09=09=09=09RESTART=5FNEEDED=3Dtrue=20?= =?UTF-8?q?=09=09=09=09else=20=09=09=09=09=09bashio::log.error=20"Failed?= =?UTF-8?q?=20to=20upgrade=20$extname=20in=20$db.=20Aborting=20startup."?= =?UTF-8?q?=20=09=09=09=09=09exit=201=20=09=09=09=09fi=20=09=09=09else=20?= =?UTF-8?q?=09=09=09=09bashio::log.info=20"$extname=20in=20$db=20already?= =?UTF-8?q?=20at=20latest=20version=20($installed=5Fversion)"=20=09=09=09f?= =?UTF-8?q?i=20=09=09fi=20=09done=20}=20=20upgrade=5Fpostgres=5Fif=5Fneede?= =?UTF-8?q?d()=20{=20=09CLUSTER=5FVERSION=3D$(get=5Fpgdata=5Fversion)=20?= =?UTF-8?q?=09IMAGE=5FVERSION=3D"$PG=5FMAJOR=5FVERSION"=20=20=09if=20[=20"?= =?UTF-8?q?$CLUSTER=5FVERSION"=20!=3D=20"$IMAGE=5FVERSION"=20];=20then=20?= =?UTF-8?q?=09=09bashio::log.warning=20"Postgres=20data=20directory=20vers?= =?UTF-8?q?ion=20is=20$CLUSTER=5FVERSION=20but=20image=20wants=20$IMAGE=5F?= =?UTF-8?q?VERSION.=20Running=20upgrade..."=20=20=09=09export=20DATA=5FDIR?= =?UTF-8?q?=3D"$PGDATA"=20=09=09export=20BINARIES=5FDIR=3D"/usr/lib/postgr?= =?UTF-8?q?esql"=20=09=09export=20BACKUP=5FDIR=3D"/config/backups"=20=09?= =?UTF-8?q?=09export=20PSQL=5FVERSION=3D"$IMAGE=5FVERSION"=20=09=09export?= =?UTF-8?q?=20SUPPORTED=5FPOSTGRES=5FVERSIONS=3D"$CLUSTER=5FVERSION=20$IMA?= =?UTF-8?q?GE=5FVERSION"=20=20=09=09apt-get=20update=20&>/dev/null=20=09?= =?UTF-8?q?=09apt-get=20install=20-y=20procps=20rsync=20"postgresql-$IMAGE?= =?UTF-8?q?=5FVERSION"=20"postgresql-$CLUSTER=5FVERSION"=20=20=09=09if=20[?= =?UTF-8?q?=20!=20-d=20"$BINARIES=5FDIR/$CLUSTER=5FVERSION/bin"=20];=20the?= =?UTF-8?q?n=20=09=09=09bashio::log.error=20"Old=20postgres=20binaries=20n?= =?UTF-8?q?ot=20found=20at=20$BINARIES=5FDIR/$CLUSTER=5FVERSION/bin"=20=09?= =?UTF-8?q?=09=09exit=201=20=09=09fi=20=09=09if=20[=20!=20-d=20"$BINARIES?= =?UTF-8?q?=5FDIR/$IMAGE=5FVERSION/bin"=20];=20then=20=09=09=09bashio::log?= =?UTF-8?q?.error=20"New=20postgres=20binaries=20not=20found=20at=20$BINAR?= =?UTF-8?q?IES=5FDIR/$IMAGE=5FVERSION/bin"=20=09=09=09exit=201=20=09=09fi?= =?UTF-8?q?=20=20=09=09install=5Fvchord=5Fand=5Fvectors=5Ffor=5Fold=5Fpg?= =?UTF-8?q?=20"$CLUSTER=5FVERSION"=20=20=09=09mkdir=20-p=20"$BACKUP=5FDIR"?= =?UTF-8?q?=20=09=09backup=5Ftarget=3D"$BACKUP=5FDIR/postgresql-$CLUSTER?= =?UTF-8?q?=5FVERSION"=20=09=09bashio::log.info=20"Backing=20up=20data=20d?= =?UTF-8?q?irectory=20to=20$backup=5Ftarget..."=20=09=09if=20!=20rsync=20-?= =?UTF-8?q?a=20--delete=20"$PGDATA/"=20"$backup=5Ftarget/";=20then=20=09?= =?UTF-8?q?=09=09bashio::log.error=20"Backup=20with=20rsync=20failed!"=20?= =?UTF-8?q?=09=09=09exit=201=20=09=09fi=20=20=09=09cp=20-n=20--preserve=3D?= =?UTF-8?q?mode=20"/var/postgresql-conf-tpl/postgresql.hdd.conf"=20/etc/po?= =?UTF-8?q?stgresql/postgresql.conf=20=09=09sed=20-i=20"s@##PGDATA@$PGDATA?= =?UTF-8?q?@"=20/etc/postgresql/postgresql.conf=20=20=09=09drop=5Fvectors?= =?UTF-8?q?=5Feverywhere=20"$CLUSTER=5FVERSION"=20=20=09=09fix=5Fpermissio?= =?UTF-8?q?ns=20=20=09=09bashio::log.info=20"Starting=20old=20Postgres=20(?= =?UTF-8?q?$CLUSTER=5FVERSION)=20to=20capture=20encoding/locale=20settings?= =?UTF-8?q?"=20=09=09su=20-=20"$DB=5FUSERNAME"=20-c=20"$BINARIES=5FDIR/$CL?= =?UTF-8?q?USTER=5FVERSION/bin/pg=5Fctl=20-w=20-D=20'$PGDATA'=20-o=20\"-c?= =?UTF-8?q?=20config=5Ffile=3D/etc/postgresql/postgresql.conf\"=20start"?= =?UTF-8?q?=20=20=09=09LC=5FCOLLATE=3D$(su=20-=20"$DB=5FUSERNAME"=20-c=20"?= =?UTF-8?q?$BINARIES=5FDIR/$CLUSTER=5FVERSION/bin/psql=20-d=20postgres=20-?= =?UTF-8?q?Atc=20'SHOW=20LC=5FCOLLATE;'")=20=09=09LC=5FCTYPE=3D$(su=20-=20?= =?UTF-8?q?"$DB=5FUSERNAME"=20-c=20"$BINARIES=5FDIR/$CLUSTER=5FVERSION/bin?= =?UTF-8?q?/psql=20-d=20postgres=20-Atc=20'SHOW=20LC=5FCTYPE;'")=20=09=09E?= =?UTF-8?q?NCODING=3D$(su=20-=20"$DB=5FUSERNAME"=20-c=20"$BINARIES=5FDIR/$?= =?UTF-8?q?CLUSTER=5FVERSION/bin/psql=20-d=20postgres=20-Atc=20'SHOW=20ser?= =?UTF-8?q?ver=5Fencoding;'")=20=20=09=09bashio::log.info=20"Detected=20cl?= =?UTF-8?q?uster:=20LC=5FCOLLATE=3D$LC=5FCOLLATE,=20LC=5FCTYPE=3D$LC=5FCTY?= =?UTF-8?q?PE,=20ENCODING=3D$ENCODING"=20=20=09=09bashio::log.info=20"Stop?= =?UTF-8?q?ping=20old=20Postgres=20($CLUSTER=5FVERSION)"=20=09=09su=20-=20?= =?UTF-8?q?"$DB=5FUSERNAME"=20-c=20"$BINARIES=5FDIR/$CLUSTER=5FVERSION/bin?= =?UTF-8?q?/pg=5Fctl=20-w=20-D=20'$PGDATA'=20-o=20\"-c=20config=5Ffile=3D/?= =?UTF-8?q?etc/postgresql/postgresql.conf\"=20stop"=20=20=09=09rm=20-rf=20?= =?UTF-8?q?"$PGDATA"=20=20=09=09fix=5Fpermissions=20=20=09=09bashio::log.i?= =?UTF-8?q?nfo=20"Initializing=20new=20data=20cluster=20for=20$IMAGE=5FVER?= =?UTF-8?q?SION"=20=09=09su=20-=20"$DB=5FUSERNAME"=20-c=20"$BINARIES=5FDIR?= =?UTF-8?q?/$IMAGE=5FVERSION/bin/initdb=20--encoding=3D$ENCODING=20--lc-co?= =?UTF-8?q?llate=3D$LC=5FCOLLATE=20--lc-ctype=3D$LC=5FCTYPE=20-D=20'$PGDAT?= =?UTF-8?q?A'"=20=20=09=09fix=5Fpermissions=20=20=09=09bashio::log.info=20?= =?UTF-8?q?"Running=20pg=5Fupgrade=20from=20$CLUSTER=5FVERSION=20=E2=86=92?= =?UTF-8?q?=20$IMAGE=5FVERSION"=20=09=09chmod=20700=20"$PGDATA"=20=09=09ch?= =?UTF-8?q?mod=20700=20"$backup=5Ftarget"=20=09=09if=20!=20su=20-=20"$DB?= =?UTF-8?q?=5FUSERNAME"=20-c=20"$BINARIES=5FDIR/$IMAGE=5FVERSION/bin/pg=5F?= =?UTF-8?q?upgrade=20\=20=20=20=20=20=20=20=20=20=20=20=20=20-b=20'$BINARI?= =?UTF-8?q?ES=5FDIR/$CLUSTER=5FVERSION/bin'=20\=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20-B=20'$BINARIES=5FDIR/$IMAGE=5FVERSION/bin'=20\=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20-d=20'$backup=5Ftarget'=20\?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20-D=20'$PGDATA'=20-o=20\"?= =?UTF-8?q?-c=20config=5Ffile=3D/etc/postgresql/postgresql.conf\"=20-O=20\?= =?UTF-8?q?"-c=20config=5Ffile=3D/etc/postgresql/postgresql.conf\"";=20the?= =?UTF-8?q?n=20=09=09=09bashio::log.error=20"pg=5Fupgrade=20failed!"=20=09?= =?UTF-8?q?=09=09exit=201=20=09=09fi=20=20=09=09if=20[=20-f=20"$backup=5Ft?= =?UTF-8?q?arget/postgresql.conf"=20];=20then=20=09=09=09cp=20"$backup=5Ft?= =?UTF-8?q?arget/postgresql.conf"=20"$PGDATA"=20=09=09fi=20=20=09=09if=20[?= =?UTF-8?q?=20-f=20"$backup=5Ftarget/pg=5Fhba.conf"=20];=20then=20=09=09?= =?UTF-8?q?=09cp=20-f=20"$backup=5Ftarget/pg=5Fhba.conf"=20"$PGDATA"=20=09?= =?UTF-8?q?=09fi=20=20=09=09bashio::log.info=20"Upgrade=20completed=20succ?= =?UTF-8?q?essfully."=20=09=09RESTART=5FNEEDED=3Dtrue=20=20=09else=20=09?= =?UTF-8?q?=09bashio::log.info=20"PostgreSQL=20data=20directory=20version?= =?UTF-8?q?=20($CLUSTER=5FVERSION)=20matches=20image=20version=20($IMAGE?= =?UTF-8?q?=5FVERSION)."=20=09fi=20}=20=20check=5Ffor=5Freindex()=20{=20?= =?UTF-8?q?=09local=20log=5Ftail=20=09log=5Ftail=3D$(timeout=2015=20cat=20?= =?UTF-8?q?/proc/1/fd/1=20|=20tail=20-n=205)=20=20=09if=20echo=20"$log=5Ft?= =?UTF-8?q?ail"=20|=20grep=20-q=20"please=20use=20REINDEX=20to=20rebuild?= =?UTF-8?q?=20the=20index";=20then=20=09=09bashio::log.warning=20"REINDEX?= =?UTF-8?q?=20needed,=20starting=20now"=20=09=09for=20db=20in=20$(get=5Fus?= =?UTF-8?q?er=5Fdatabases);=20do=20=09=09=09psql=20-h=20"$DB=5FHOSTNAME"?= =?UTF-8?q?=20-p=20"$DB=5FPORT"=20-U=20"$DB=5FUSERNAME"=20-d=20"$db"=20-v?= =?UTF-8?q?=20ON=5FERROR=5FSTOP=3D1=20-c=20"REINDEX=20DATABASE=20$db;"=20?= =?UTF-8?q?=09=09done=20=09fi=20}=20=20main()=20{=20=09bashio::log.info=20?= =?UTF-8?q?"Checking=20for=20required=20PostgreSQL=20cluster=20upgrade=20b?= =?UTF-8?q?efore=20server=20start..."=20=09if=20[=20-f=20/config/database/?= =?UTF-8?q?PG=5FVERSION=20];=20then=20=09=09upgrade=5Fpostgres=5Fif=5Fneed?= =?UTF-8?q?ed=20=09fi=20=20=09start=5Fpostgres=20=20=09bashio::log.info=20?= =?UTF-8?q?"Waiting=20for=20PostgreSQL=20to=20start..."=20=20=09DB=5FPORT?= =?UTF-8?q?=3D5432=20=09DB=5FHOSTNAME=3Dlocalhost=20=09DB=5FPASSWORD=3D"$(?= =?UTF-8?q?bashio::config=20'POSTGRES=5FPASSWORD')"=20=09DB=5FPASSWORD=3D"?= =?UTF-8?q?$(jq=20-rn=20--arg=20x=20"$DB=5FPASSWORD"=20'$x|@uri')"=20=09DB?= =?UTF-8?q?=5FUSERNAME=3Dpostgres=20=09if=20bashio::config.has=5Fvalue=20"?= =?UTF-8?q?POSTGRES=5FUSER";=20then=20=09=09DB=5FUSERNAME=3D"$(bashio::con?= =?UTF-8?q?fig=20"POSTGRES=5FUSER")"=20=09fi=20=09export=20DB=5FPORT=20DB?= =?UTF-8?q?=5FHOSTNAME=20DB=5FUSERNAME=20DB=5FPASSWORD=20=20=09wait=5Ffor?= =?UTF-8?q?=5Fpostgres=20=09restart=5Fimmich=5Faddons=5Fif=5Fflagged=20=20?= =?UTF-8?q?=09su=20-=20"$DB=5FUSERNAME"=20-c=20"psql=20-d=20postgres=20-c?= =?UTF-8?q?=20'DROP=20EXTENSION=20IF=20EXISTS=20vectors=20CASCADE;'"=20=20?= =?UTF-8?q?=09upgrade=5Fextension=5Fif=5Fneeded=20"vectors"=20=09upgrade?= =?UTF-8?q?=5Fextension=5Fif=5Fneeded=20"vchord"=20=09show=5Fdb=5Fextensio?= =?UTF-8?q?ns=20=20=09if=20[=20"$RESTART=5FNEEDED"=20=3D=20true=20];=20the?= =?UTF-8?q?n=20=09=09bashio::log.warning=20"A=20critical=20update=20(Postg?= =?UTF-8?q?res=20or=20extension)=20occurred.=20Will=20trigger=20Immich=20a?= =?UTF-8?q?dd-on=20restart=20after=20DB=20comes=20back=20up."=20=09=09touc?= =?UTF-8?q?h=20"$RESTART=5FFLAG=5FFILE"=20=09=09bashio::addon.restart=20?= =?UTF-8?q?=09=09exit=200=20=09fi=20=20=09if=20[=20-d=20/config/backups=20?= =?UTF-8?q?];=20then=20=09=09echo=20"Cleaning=20/config/backups=20now=20th?= =?UTF-8?q?at=20upgrade=20is=20done"=20=09=09rm=20-r=20/config/backups=20?= =?UTF-8?q?=09fi=20=20=09check=5Ffor=5Freindex=20&=20=09bashio::log.info?= =?UTF-8?q?=20"All=20initialization/version=20check=20steps=20completed=20?= =?UTF-8?q?successfully!"=20=20}=20=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- postgres_15/rootfs/etc/cont-init.d/99-run.sh | 387 ++++++++++--------- 1 file changed, 214 insertions(+), 173 deletions(-) diff --git a/postgres_15/rootfs/etc/cont-init.d/99-run.sh b/postgres_15/rootfs/etc/cont-init.d/99-run.sh index 1198c6ad2..36419c477 100644 --- a/postgres_15/rootfs/etc/cont-init.d/99-run.sh +++ b/postgres_15/rootfs/etc/cont-init.d/99-run.sh @@ -19,7 +19,9 @@ fix_permissions() { } chmod -R 755 "$CONFIG_HOME" + RESTART_NEEDED=false + cd /config || true get_pgdata_version() { @@ -32,7 +34,9 @@ get_pgdata_version() { } extract_so_from_deb() { - local debfile="$1" targetdir="$2" sofile="$3" + local debfile="$1" + local targetdir="$2" + local sofile="$3" local tmpdir tmpdir=$(mktemp -d) dpkg-deb -x "$debfile" "$tmpdir" @@ -45,28 +49,34 @@ install_vchord_and_vectors_for_old_pg() { local vectorchord_tag="${VECTORCHORD_TAG:-0.3.0}" local pgvectors_tag="${PGVECTORS_TAG:-0.3.0}" case "$(uname -m)" in - x86_64 | amd64 | AMD64 | x86-64) targetarch=amd64 ;; - aarch64 | arm64 | ARM64) targetarch=arm64 ;; + x86_64 | amd64 | AMD64 | x86-64) + targetarch=amd64 + ;; + aarch64 | arm64 | ARM64) + targetarch=arm64 + ;; *) echo "Unsupported architecture: $(uname -m)" exit 1 ;; esac - + local vchord_url + local vectors_url + local vchord_deb + local vectors_deb local old_pg_lib="/usr/lib/postgresql/$old_pgver/lib" + mkdir -p "$old_pg_lib" - # VectorChord - local vchord_deb="/tmp/vchord-${old_pgver}.deb" - local vchord_url="https://github.com/tensorchord/VectorChord/releases/download/${vectorchord_tag}/postgresql-${old_pgver}-vchord_${vectorchord_tag}-1_${targetarch}.deb" + vchord_url="https://github.com/tensorchord/VectorChord/releases/download/${vectorchord_tag}/postgresql-${old_pgver}-vchord_${vectorchord_tag}-1_${targetarch}.deb" + vchord_deb="/tmp/vchord-${old_pgver}.deb" bashio::log.info "Downloading $vchord_url" wget -nv -O "$vchord_deb" "$vchord_url" extract_so_from_deb "$vchord_deb" "$old_pg_lib" "vchord.so" rm -f "$vchord_deb" - # pgvecto.rs - local vectors_deb="/tmp/pgvectors-${old_pgver}.deb" - local vectors_url="https://github.com/tensorchord/pgvecto.rs/releases/download/v${pgvectors_tag}/vectors-pg${old_pgver}_${pgvectors_tag}_${targetarch}.deb" + vectors_url="https://github.com/tensorchord/pgvecto.rs/releases/download/v${pgvectors_tag}/vectors-pg${old_pgver}_${pgvectors_tag}_${targetarch}.deb" + vectors_deb="/tmp/pgvectors-${old_pgver}.deb" bashio::log.info "Downloading $vectors_url" wget -nv -O "$vectors_deb" "$vectors_url" extract_so_from_deb "$vectors_deb" "$old_pg_lib" "vectors.so" @@ -76,25 +86,23 @@ install_vchord_and_vectors_for_old_pg() { drop_vectors_everywhere() { local old_pgver="$1" fix_permissions - - su - postgres -c "$BINARIES_DIR/$old_pgver/bin/pg_ctl -w -D '$PGDATA' \ - -o \"-c config_file=/etc/postgresql/postgresql.conf \ - -c listen_addresses='' -c port=65432\" start" - - for db in $(su - postgres -c \ - "$BINARIES_DIR/$old_pgver/bin/psql -U \"$DB_USERNAME\" -Atc \ - \"SELECT datname FROM pg_database WHERE datistemplate = false AND datallowconn\""); do - if su - postgres -c \ - "$BINARIES_DIR/$old_pgver/bin/psql -U \"$DB_USERNAME\" -d $db -Atc \ - \"SELECT 1 FROM pg_extension WHERE extname='vectors'\"" | grep -q 1; then + su - "$DB_USERNAME" -c "$BINARIES_DIR/$old_pgver/bin/pg_ctl \ + -w -D '$PGDATA' -o \"-c config_file=/etc/postgresql/postgresql.conf \ + -c listen_addresses='' -c port=65432\" start" + for db in $(su - "$DB_USERNAME" -c \ + "$BINARIES_DIR/$old_pgver/bin/psql -Atc \ + \"SELECT datname FROM pg_database WHERE datistemplate = false AND datallowconn\""); do + if su - "$DB_USERNAME" -c \ + "$BINARIES_DIR/$old_pgver/bin/psql -d $db -Atc \ + \"SELECT 1 FROM pg_extension WHERE extname='vectors'\"" | + grep -q 1; then bashio::log.warning "Dropping extension vectors from DB $db" - su - postgres -c \ - "$BINARIES_DIR/$old_pgver/bin/psql -U \"$DB_USERNAME\" -d $db -c \ - 'DROP EXTENSION vectors CASCADE;'" + su - "$DB_USERNAME" -c \ + "$BINARIES_DIR/$old_pgver/bin/psql -d $db -c \ + 'DROP EXTENSION vectors CASCADE;'" fi done - - su - postgres -c "$BINARIES_DIR/$old_pgver/bin/pg_ctl -w -D '$PGDATA' stop" + su - "$DB_USERNAME" -c "$BINARIES_DIR/$old_pgver/bin/pg_ctl -w -D '$PGDATA' stop" } start_postgres() { @@ -102,72 +110,69 @@ start_postgres() { if [ "$(bashio::info.arch)" = "armv7" ]; then bashio::log.warning "ARMv7 detected: Starting without vectors.so" /usr/local/bin/immich-docker-entrypoint.sh postgres & + true + exit 0 else /usr/local/bin/immich-docker-entrypoint.sh postgres -c config_file=/etc/postgresql/postgresql.conf & + true fi - true } wait_for_postgres() { local tries=0 while ! pg_isready -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" >/dev/null 2>&1; do tries=$((tries + 1)) - [ "$tries" -ge 60 ] && { - bashio::log.error "Postgres did not start after 2 minutes, aborting." + if [ "$tries" -ge 60 ]; then + bashio::log.error "Postgres did not start after 2 minutes, aborting." exit 1 - } + fi echo "PostgreSQL is starting up... ($tries/60)" sleep 2 done } restart_immich_addons_if_flagged() { - [ ! -f "$RESTART_FLAG_FILE" ] && return 0 - bashio::log.warning "Detected pending Immich add‑on restart flag. Restarting all running Immich add‑ons…" + if [ -f "$RESTART_FLAG_FILE" ]; then + bashio::log.warning "Detected pending Immich add-on restart flag. Restarting all running Immich add-ons..." - local addons_json found=0 - addons_json=$(curl -fsSL -H "Authorization: Bearer $SUPERVISOR_TOKEN" http://supervisor/addons) || { - bashio::log.error "Supervisor API call failed or unauthorized: $addons_json" + local addons_json slug found=0 + + # Get the add-ons list, fail on HTTP errors, show errors if API call fails + addons_json=$(curl -fsSL -H "Authorization: Bearer $SUPERVISOR_TOKEN" http://supervisor/addons) || { + bashio::log.error "Supervisor API call failed or unauthorized: $addons_json" + rm -f "$RESTART_FLAG_FILE" + return 1 + } + + if command -v jq >/dev/null; then + # Use correct JSON path for modern Supervisor API + for slug in $(echo "$addons_json" | jq -r '.addons[] | select(.state=="started") | .slug'); do + if [[ "$slug" == *immich* ]]; then + bashio::log.info "Restarting addon $slug" + curl -fsSL -X POST -H "Authorization: Bearer $SUPERVISOR_TOKEN" \ + "http://supervisor/addons/$slug/restart" + found=1 + fi + done + else + # Fallback: grep/cut for legacy environments, less robust + for slug in $(echo "$addons_json" | grep -o '"slug":"[^"]*"' | cut -d: -f2 | tr -d '"'); do + if [[ "$slug" == *immich* ]]; then + bashio::log.info "Restarting addon $slug" + curl -fsSL -X POST -H "Authorization: Bearer $SUPERVISOR_TOKEN" \ + "http://supervisor/addons/$slug/restart" + found=1 + fi + done + fi + + if [ "$found" -eq 0 ]; then + bashio::log.info "No Immich-related addon found running." + fi rm -f "$RESTART_FLAG_FILE" - return 1 - } - - if command -v jq >/dev/null; then - for slug in $(echo "$addons_json" | jq -r '.addons[] | select(.state=="started") | .slug'); do - if [[ "$slug" == *immich* ]]; then - bashio::log.info "Restarting addon $slug" - curl -fsSL -X POST -H "Authorization: Bearer $SUPERVISOR_TOKEN" "http://supervisor/addons/$slug/restart" - found=1 - fi - done - else - for slug in $(echo "$addons_json" | grep -o '"slug":"[^"]*"' | cut -d: -f2 | tr -d '"'); do - if [[ "$slug" == *immich* ]]; then - bashio::log.info "Restarting addon $slug" - curl -fsSL -X POST -H "Authorization: Bearer $SUPERVISOR_TOKEN" "http://supervisor/addons/$slug/restart" - found=1 - fi - done fi - - [ "$found" -eq 0 ] && bashio::log.info "No Immich-related addon found running." - rm -f "$RESTART_FLAG_FILE" } -# --------------------------- DB connection setup --------------------------- -DB_PORT=5432 -DB_HOSTNAME=localhost -DB_PASSWORD="$(bashio::config 'POSTGRES_PASSWORD')" -DB_PASSWORD="$(jq -rn --arg x "$DB_PASSWORD" '$x|@uri')" - -if bashio::config.has_value "POSTGRES_USER"; then - DB_USERNAME="$(bashio::config 'POSTGRES_USER')" -else - DB_USERNAME="postgres" -fi -export DB_PORT DB_HOSTNAME DB_USERNAME DB_PASSWORD -# ----------------------------------------------------------------------------- - get_available_extension_version() { local extname="$1" psql "postgres://$DB_USERNAME:$DB_PASSWORD@$DB_HOSTNAME:$DB_PORT/postgres" -v ON_ERROR_STOP=1 -tAc \ @@ -188,15 +193,20 @@ get_user_databases() { } get_installed_extension_version() { - local extname="$1" dbname="$2" + local extname="$1" + local dbname="$2" psql "postgres://$DB_USERNAME:$DB_PASSWORD@$DB_HOSTNAME:$DB_PORT/$dbname" -v ON_ERROR_STOP=1 -tAc \ "SELECT extversion FROM pg_extension WHERE extname = '$extname';" 2>/dev/null | xargs } compare_versions() { - local v1="$1" v2="$2" - [ "$v1" = "$v2" ] && return 1 - [ "$(printf '%s\n' "$v1" "$v2" | sort -V | head -n1)" = "$v1" ] + local v1="$1" + local v2="$2" + if [ "$v1" = "$v2" ]; then return 1; fi + if [ "$(printf '%s\n' "$v1" "$v2" | sort -V | head -n1)" = "$v1" ]; then + return 0 + fi + return 1 } show_db_extensions() { @@ -218,35 +228,33 @@ show_db_extensions() { upgrade_extension_if_needed() { local extname="$1" - is_extension_available "$extname" || { - bashio::log.info "$extname extension not available." + if ! is_extension_available "$extname"; then + bashio::log.info "$extname extension not available on this Postgres instance." return - } - + fi local available_version available_version=$(get_available_extension_version "$extname") - [ -z "$available_version" ] && { + if [ -z "$available_version" ]; then bashio::log.info "Could not determine available version for $extname." return - } - + fi for db in $(get_user_databases); do local installed_version installed_version=$(get_installed_extension_version "$extname" "$db") - [ -z "$installed_version" ] && continue - - if compare_versions "$installed_version" "$available_version"; then - bashio::log.info "Upgrading $extname in $db from $installed_version to $available_version" - if psql -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" -d "$db" -v ON_ERROR_STOP=1 -c "ALTER EXTENSION $extname UPDATE;"; then - bashio::log.info "Reindexing database $db" - psql -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" -d "$db" -v ON_ERROR_STOP=1 -c "REINDEX DATABASE $db;" - RESTART_NEEDED=true + if [ -n "$installed_version" ]; then + if compare_versions "$installed_version" "$available_version"; then + bashio::log.info "Upgrading $extname in $db from $installed_version to $available_version" + if psql -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" -d "$db" -v ON_ERROR_STOP=1 -c "ALTER EXTENSION $extname UPDATE;"; then + bashio::log.info "Reindexing database $db" + psql -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" -d "$db" -v ON_ERROR_STOP=1 -c "REINDEX DATABASE $db;" + RESTART_NEEDED=true + else + bashio::log.error "Failed to upgrade $extname in $db. Aborting startup." + exit 1 + fi else - bashio::log.error "Failed to upgrade $extname in $db. Aborting startup." - exit 1 + bashio::log.info "$extname in $db already at latest version ($installed_version)" fi - else - bashio::log.info "$extname in $db already at latest version ($installed_version)" fi done } @@ -254,105 +262,137 @@ upgrade_extension_if_needed() { upgrade_postgres_if_needed() { CLUSTER_VERSION=$(get_pgdata_version) IMAGE_VERSION="$PG_MAJOR_VERSION" - [ "$CLUSTER_VERSION" = "$IMAGE_VERSION" ] && { + + if [ "$CLUSTER_VERSION" != "$IMAGE_VERSION" ]; then + bashio::log.warning "Postgres data directory version is $CLUSTER_VERSION but image wants $IMAGE_VERSION. Running upgrade..." + + export DATA_DIR="$PGDATA" + export BINARIES_DIR="/usr/lib/postgresql" + export BACKUP_DIR="/config/backups" + export PSQL_VERSION="$IMAGE_VERSION" + export SUPPORTED_POSTGRES_VERSIONS="$CLUSTER_VERSION $IMAGE_VERSION" + + apt-get update &>/dev/null + apt-get install -y procps rsync "postgresql-$IMAGE_VERSION" "postgresql-$CLUSTER_VERSION" + + if [ ! -d "$BINARIES_DIR/$CLUSTER_VERSION/bin" ]; then + bashio::log.error "Old postgres binaries not found at $BINARIES_DIR/$CLUSTER_VERSION/bin" + exit 1 + fi + if [ ! -d "$BINARIES_DIR/$IMAGE_VERSION/bin" ]; then + bashio::log.error "New postgres binaries not found at $BINARIES_DIR/$IMAGE_VERSION/bin" + exit 1 + fi + + install_vchord_and_vectors_for_old_pg "$CLUSTER_VERSION" + + mkdir -p "$BACKUP_DIR" + backup_target="$BACKUP_DIR/postgresql-$CLUSTER_VERSION" + bashio::log.info "Backing up data directory to $backup_target..." + if ! rsync -a --delete "$PGDATA/" "$backup_target/"; then + bashio::log.error "Backup with rsync failed!" + exit 1 + fi + + cp -n --preserve=mode "/var/postgresql-conf-tpl/postgresql.hdd.conf" /etc/postgresql/postgresql.conf + sed -i "s@##PGDATA@$PGDATA@" /etc/postgresql/postgresql.conf + + drop_vectors_everywhere "$CLUSTER_VERSION" + + fix_permissions + + bashio::log.info "Starting old Postgres ($CLUSTER_VERSION) to capture encoding/locale settings" + su - "$DB_USERNAME" -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/pg_ctl -w -D '$PGDATA' -o \"-c config_file=/etc/postgresql/postgresql.conf\" start" + + LC_COLLATE=$(su - "$DB_USERNAME" -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/psql -d postgres -Atc 'SHOW LC_COLLATE;'") + LC_CTYPE=$(su - "$DB_USERNAME" -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/psql -d postgres -Atc 'SHOW LC_CTYPE;'") + ENCODING=$(su - "$DB_USERNAME" -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/psql -d postgres -Atc 'SHOW server_encoding;'") + + bashio::log.info "Detected cluster: LC_COLLATE=$LC_COLLATE, LC_CTYPE=$LC_CTYPE, ENCODING=$ENCODING" + + bashio::log.info "Stopping old Postgres ($CLUSTER_VERSION)" + su - "$DB_USERNAME" -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/pg_ctl -w -D '$PGDATA' -o \"-c config_file=/etc/postgresql/postgresql.conf\" stop" + + rm -rf "$PGDATA" + + fix_permissions + + bashio::log.info "Initializing new data cluster for $IMAGE_VERSION" + su - "$DB_USERNAME" -c "$BINARIES_DIR/$IMAGE_VERSION/bin/initdb --encoding=$ENCODING --lc-collate=$LC_COLLATE --lc-ctype=$LC_CTYPE -D '$PGDATA'" + + fix_permissions + + bashio::log.info "Running pg_upgrade from $CLUSTER_VERSION → $IMAGE_VERSION" + chmod 700 "$PGDATA" + chmod 700 "$backup_target" + if ! su - "$DB_USERNAME" -c "$BINARIES_DIR/$IMAGE_VERSION/bin/pg_upgrade \ + -b '$BINARIES_DIR/$CLUSTER_VERSION/bin' \ + -B '$BINARIES_DIR/$IMAGE_VERSION/bin' \ + -d '$backup_target' \ + -D '$PGDATA' -o \"-c config_file=/etc/postgresql/postgresql.conf\" -O \"-c config_file=/etc/postgresql/postgresql.conf\""; then + bashio::log.error "pg_upgrade failed!" + exit 1 + fi + + if [ -f "$backup_target/postgresql.conf" ]; then + cp "$backup_target/postgresql.conf" "$PGDATA" + fi + + if [ -f "$backup_target/pg_hba.conf" ]; then + cp -f "$backup_target/pg_hba.conf" "$PGDATA" + fi + + bashio::log.info "Upgrade completed successfully." + RESTART_NEEDED=true + + else bashio::log.info "PostgreSQL data directory version ($CLUSTER_VERSION) matches image version ($IMAGE_VERSION)." - return - } - - bashio::log.warning "Postgres data directory version is $CLUSTER_VERSION but image wants $IMAGE_VERSION. Running upgrade..." - export DATA_DIR="$PGDATA" BINARIES_DIR="/usr/lib/postgresql" BACKUP_DIR="/config/backups" - export PSQL_VERSION="$IMAGE_VERSION" SUPPORTED_POSTGRES_VERSIONS="$CLUSTER_VERSION $IMAGE_VERSION" - - apt-get update &>/dev/null - apt-get install -y procps rsync "postgresql-$IMAGE_VERSION" "postgresql-$CLUSTER_VERSION" - - [ -d "$BINARIES_DIR/$CLUSTER_VERSION/bin" ] || { - bashio::log.error "Old postgres binaries missing." - exit 1 - } - [ -d "$BINARIES_DIR/$IMAGE_VERSION/bin" ] || { - bashio::log.error "New postgres binaries missing." - exit 1 - } - - install_vchord_and_vectors_for_old_pg "$CLUSTER_VERSION" - - mkdir -p "$BACKUP_DIR" - local backup_target="$BACKUP_DIR/postgresql-$CLUSTER_VERSION" - bashio::log.info "Backing up data directory to $backup_target..." - rsync -a --delete "$PGDATA/" "$backup_target/" || { - bashio::log.error "Backup with rsync failed!" - exit 1 - } - - cp -n --preserve=mode "/var/postgresql-conf-tpl/postgresql.hdd.conf" /etc/postgresql/postgresql.conf - sed -i "s@##PGDATA@$PGDATA@" /etc/postgresql/postgresql.conf - - drop_vectors_everywhere "$CLUSTER_VERSION" - fix_permissions - - bashio::log.info "Starting old Postgres ($CLUSTER_VERSION) to capture encoding/locale settings" - su - postgres -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/pg_ctl -w -D '$PGDATA' -o \"-c config_file=/etc/postgresql/postgresql.conf\" start" - - LC_COLLATE=$(su - postgres -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/psql -U \"$DB_USERNAME\" -d postgres -Atc 'SHOW LC_COLLATE;'") - LC_CTYPE=$(su - postgres -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/psql -U \"$DB_USERNAME\" -d postgres -Atc 'SHOW LC_CTYPE;'") - ENCODING=$(su - postgres -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/psql -U \"$DB_USERNAME\" -d postgres -Atc 'SHOW server_encoding;'") - bashio::log.info "Detected cluster: LC_COLLATE=$LC_COLLATE, LC_CTYPE=$LC_CTYPE, ENCODING=$ENCODING" - - bashio::log.info "Stopping old Postgres ($CLUSTER_VERSION)" - su - postgres -c "$BINARIES_DIR/$CLUSTER_VERSION/bin/pg_ctl -w -D '$PGDATA' -o \"-c config_file=/etc/postgresql/postgresql.conf\" stop" - - rm -rf "$PGDATA" - fix_permissions - - bashio::log.info "Initializing new data cluster for $IMAGE_VERSION" - su - postgres -c "$BINARIES_DIR/$IMAGE_VERSION/bin/initdb --encoding=$ENCODING --lc-collate=$LC_COLLATE --lc-ctype=$LC_CTYPE -D '$PGDATA'" - fix_permissions - - bashio::log.info "Running pg_upgrade from $CLUSTER_VERSION → $IMAGE_VERSION" - chmod 700 "$PGDATA" "$backup_target" - su - postgres -c "$BINARIES_DIR/$IMAGE_VERSION/bin/pg_upgrade \ - -b '$BINARIES_DIR/$CLUSTER_VERSION/bin' -B '$BINARIES_DIR/$IMAGE_VERSION/bin' \ - -d '$backup_target' -D '$PGDATA' \ - -o \"-c config_file=/etc/postgresql/postgresql.conf\" \ - -O \"-c config_file=/etc/postgresql/postgresql.conf\"" - - [ -f "$backup_target/postgresql.conf" ] && cp "$backup_target/postgresql.conf" "$PGDATA" - [ -f "$backup_target/pg_hba.conf" ] && cp -f "$backup_target/pg_hba.conf" "$PGDATA" - - bashio::log.info "Upgrade completed successfully." - RESTART_NEEDED=true + fi } check_for_reindex() { local log_tail log_tail=$(timeout 15 cat /proc/1/fd/1 | tail -n 5) - echo "$log_tail" | grep -q "please use REINDEX to rebuild the index" || return 0 - bashio::log.warning "REINDEX needed, starting now" - for db in $(get_user_databases); do - psql -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" -d "$db" -v ON_ERROR_STOP=1 -c "REINDEX DATABASE $db;" - done + if echo "$log_tail" | grep -q "please use REINDEX to rebuild the index"; then + bashio::log.warning "REINDEX needed, starting now" + for db in $(get_user_databases); do + psql -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" -d "$db" -v ON_ERROR_STOP=1 -c "REINDEX DATABASE $db;" + done + fi } main() { - bashio::log.info "Checking for required PostgreSQL cluster upgrade before server start…" - [ -f /config/database/PG_VERSION ] && upgrade_postgres_if_needed + bashio::log.info "Checking for required PostgreSQL cluster upgrade before server start..." + if [ -f /config/database/PG_VERSION ]; then + upgrade_postgres_if_needed + fi start_postgres - bashio::log.info "Waiting for PostgreSQL to start…" + + bashio::log.info "Waiting for PostgreSQL to start..." + + DB_PORT=5432 + DB_HOSTNAME=localhost + DB_PASSWORD="$(bashio::config 'POSTGRES_PASSWORD')" + DB_PASSWORD="$(jq -rn --arg x "$DB_PASSWORD" '$x|@uri')" + DB_USERNAME=postgres + if bashio::config.has_value "POSTGRES_USER"; then + DB_USERNAME="$(bashio::config "POSTGRES_USER")" + fi + export DB_PORT DB_HOSTNAME DB_USERNAME DB_PASSWORD + wait_for_postgres restart_immich_addons_if_flagged - # Drop legacy vectors extension (connect as $DB_USERNAME) - su - postgres -c "psql -U \"$DB_USERNAME\" -d postgres -c 'DROP EXTENSION IF EXISTS vectors CASCADE;'" + su - "$DB_USERNAME" -c "psql -d postgres -c 'DROP EXTENSION IF EXISTS vectors CASCADE;'" upgrade_extension_if_needed "vectors" upgrade_extension_if_needed "vchord" show_db_extensions if [ "$RESTART_NEEDED" = true ]; then - bashio::log.warning "A critical update occurred. Restarting Immich add‑on(s) after DB restart." + bashio::log.warning "A critical update (Postgres or extension) occurred. Will trigger Immich add-on restart after DB comes back up." touch "$RESTART_FLAG_FILE" bashio::addon.restart exit 0 @@ -364,7 +404,8 @@ main() { fi check_for_reindex & - bashio::log.info "All initialization / version‑check steps completed successfully!" + bashio::log.info "All initialization/version check steps completed successfully!" + } main