88 lines
5.7 KiB
Bash
Executable File
88 lines
5.7 KiB
Bash
Executable File
#!/bin/bash
|
||
# Первый шаг переноса инстанса на другой куб (DST, по умолчанию loop-3): секреты + перепривязка в визоре.
|
||
# loopctl k8s rebind loop12a40f770b5a
|
||
# Источник = куб из SOURCES, где есть CR; провайдер БД в визоре ищется по host:port из секрета.
|
||
# Не делает: sync, гашение на исходном кубе, DNS (это loopctl k8s move).
|
||
set -euo pipefail
|
||
|
||
ID=${1:?loop id, например loop12a40f770b5a}
|
||
. "$(dirname "$0")/../lib/common.sh"
|
||
|
||
copy_secret() { # $1 имя; копирует с $SRC на $DST без вывода данных
|
||
kubectl --context "$SRC" -n loop get secret "$1" -o json \
|
||
| jq '{apiVersion,kind,type,data,metadata:{name:.metadata.name,namespace:"loop"}}' \
|
||
| kubectl --context "$DST" apply -f - >/dev/null
|
||
echo " $1 скопирован"
|
||
}
|
||
|
||
hash_secrets() { # $1 context
|
||
kubectl --context "$1" -n loop get secret "$ID-db-credentials" "$ID-s3-credentials" "$ID-license" -o json \
|
||
| jq -S '[.items[]|{n:.metadata.name,t:.type,d:.data}]' | shasum | cut -c1-12
|
||
}
|
||
|
||
echo "== $ID"
|
||
# источник = куб, где есть CR (registry неактуален); домен из ingress CR
|
||
for SRC in $SOURCES ""; do
|
||
[ -n "$SRC" ] || { echo "CR $ID не найден ни на одном исходном кубе"; exit 1; }
|
||
DOMAIN=$(kubectl --context "$SRC" -n loop get mattermost "$ID" -o jsonpath='{.spec.ingress.host}' 2>/dev/null) && [ -n "$DOMAIN" ] && break
|
||
done
|
||
SRC_CLUSTER=$(echo "select id from cluster_instance where name='$SRC';" | vsql)
|
||
DST_CLUSTER=$(echo "select id from cluster_instance where name='$DST';" | vsql)
|
||
[ -n "$DST_CLUSTER" ] || { echo "в визоре нет кластера $DST"; exit 1; }
|
||
echo " $DOMAIN $SRC"
|
||
|
||
# база в секрете на исходном кубе уже должна смотреть в Selectel
|
||
DBHOST=$(kubectl --context "$SRC" -n loop get secret "$ID-db-credentials" -o json | jq -r '.data.DB_CONNECTION_STRING|@base64d' | sed -E 's#.*@([^/]+)/.*#\1#')
|
||
echo " БД в секрете: $DBHOST"
|
||
case $DBHOST in *.mdb.yandexcloud.net*) echo "секрет ещё смотрит в Yandex, стоп"; exit 1;; esac
|
||
|
||
# CR с таким именем на $DST быть не должно
|
||
if kubectl --context "$DST" -n loop get mattermost "$ID" >/dev/null 2>&1; then echo "CR уже есть на $DST, стоп"; exit 1; fi
|
||
|
||
# провайдер БД = ON_PREM-провайдер визора с тем же host:port, что в секрете
|
||
PROVIDER=$(echo "select id||'|'||name from database_provider where vendor='ON_PREM' and host_name='${DBHOST%:*}' and host_port::text='${DBHOST##*:}';" | vsql)
|
||
[ "$(grep -c . <<<"$PROVIDER")" = 1 ] || { echo "в визоре не один ON_PREM-провайдер для $DBHOST: '$PROVIDER'"; exit 1; }
|
||
TARGET=${PROVIDER#*|}; PROVIDER=${PROVIDER%%|*}; echo " провайдер: $TARGET"
|
||
|
||
confirm "Скопирую секреты $ID на $DST и перепривяжу инстанс в визоре на $DST." || exit 1
|
||
echo "-- секреты на $DST"
|
||
for s in wildcard-loop.ru-tls private.docker.wilix.dev; do # общие, копируем один раз
|
||
kubectl --context "$DST" -n loop get secret "$s" >/dev/null 2>&1 || copy_secret "$s"
|
||
done
|
||
for s in db-credentials s3-credentials license; do copy_secret "$ID-$s"; done
|
||
H1=$(hash_secrets "$SRC"); H3=$(hash_secrets "$DST")
|
||
[ "$H1" = "$H3" ] || { echo "секреты не совпали: $H1 / $H3"; exit 1; }
|
||
echo " совпадают ($H1)"
|
||
|
||
# свой сертификат (не wildcard): cluster-issuer оставляем, иначе на новом кубе он перестанет продлеваться
|
||
OWN_TLS=$(kubectl --context "$SRC" -n loop get mattermost "$ID" -o jsonpath='{.spec.ingress.tlsSecret}')
|
||
[ "$OWN_TLS" = wildcard-loop.ru-tls ] && OWN_TLS=""
|
||
echo "-- визор"
|
||
TAIL=${ID#loop}
|
||
FOUND=$(printf "select i.id, i.domain, c.name, d.id from loop_instance i join cluster_instance c on c.id=i.cluster_instance_id join database_instance d on d.id=i.database_instance_id where i.id like '%%%s' and i.deleted_at is null;\n" "$TAIL" | vsql)
|
||
[ "$(printf '%s\n' "$FOUND" | grep -c .)" = 1 ] || { echo "в визоре не один инстанс: $FOUND"; exit 1; }
|
||
IFS='|' read -r VID VDOMAIN VCLUSTER DBID <<<"$FOUND"
|
||
echo " $VID $VDOMAIN куб=$VCLUSTER"
|
||
[ "$VDOMAIN" = "$DOMAIN" ] || { echo "домен в визоре другой: $VDOMAIN"; exit 1; }
|
||
|
||
vsql <<SQL
|
||
begin;
|
||
update loop_instance set cluster_instance_id='$DST_CLUSTER', synchronization_status='NOT_SYNCHRONIZED' where id='$VID';
|
||
update database_instance set vendor='ON_PREM',
|
||
database_provider_id='$PROVIDER'
|
||
where id='$DBID';
|
||
-- на целевом кубе traefik; без класса оператор ставит nginx. cluster-issuer убрать: с wildcard он перезапишет wildcard-loop.ru-tls
|
||
delete from loop_instance_annotation where loop_instance_id='$VID'
|
||
and (annotation='kubernetes.io/ingress.class' or (annotation='cert-manager.io/cluster-issuer' and '$OWN_TLS'=''));
|
||
insert into loop_instance_annotation(id, loop_instance_id, annotation, annotation_value)
|
||
values (gen_random_uuid()::text, '$VID', 'kubernetes.io/ingress.class', '${DST_INGRESS_CLASS:-traefik}');
|
||
select i.domain, c.name, p.name, d.vendor from loop_instance i
|
||
join cluster_instance c on c.id=i.cluster_instance_id
|
||
join database_instance d on d.id=i.database_instance_id
|
||
join database_provider p on p.id=d.database_provider_id where i.id='$VID';
|
||
commit;
|
||
SQL
|
||
|
||
echo "Готово. Дальше: loopctl k8s move $ID (env, sync, проверки, прокси, DNS)."
|
||
echo "Откат визора: update loop_instance set cluster_instance_id='$SRC_CLUSTER' where id='$VID';"
|