init
This commit is contained in:
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
# Selectel DNS v2 для зоны loop.ru
|
||||
# loopctl dns show metrosamara -> текущая запись
|
||||
# loopctl dns ttl metrosamara 60 -> сменить TTL
|
||||
# loopctl dns cname metrosamara l3.clusters.loop.ru -> сменить CNAME (TTL сохраняется), нет записи — создать
|
||||
# Доступ в DNS_ENV (по умолчанию ~/.selectel-dns.env, chmod 600), имена как в rc.sh из панели Selectel:
|
||||
# export OS_USER_DOMAIN_NAME=<номер аккаунта> OS_PROJECT_NAME=<проект> OS_USERNAME=<пользователь> OS_PASSWORD=<пароль>
|
||||
set -euo pipefail
|
||||
. "$(dirname "$0")/../lib/common.sh"
|
||||
# файл с паролем не исполняем (source печатал пароль при ошибке в строке), а разбираем: [export ]KEY=VALUE
|
||||
while IFS= read -r l; do
|
||||
l=${l#export }; [[ $l =~ ^(OS_[A-Z_]+)=(.*)$ ]] || continue
|
||||
v=${BASH_REMATCH[2]}; v=${v#[\"\']}; v=${v%[\"\']}; printf -v "${BASH_REMATCH[1]}" '%s' "$v"
|
||||
done < "$DNS_ENV"
|
||||
ZONE=${ZONE:-loop.ru}
|
||||
API=https://api.selectel.ru/domains/v2
|
||||
|
||||
CMD=${1:?show|ttl|cname}
|
||||
[ "$CMD" = show ] || confirm "Изменю DNS: ${2:-} $CMD ${3:-}." || exit 1; NAME=${2:?поддомен, например metrosamara}; VAL=${3:-}
|
||||
FQDN="$NAME.$ZONE."
|
||||
|
||||
AUTH=$(curl -sS --connect-timeout 15 --retry 3 --retry-all-errors -D - https://cloud.api.selcloud.ru/identity/v3/auth/tokens \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "$(jq -nc --arg a "$OS_USER_DOMAIN_NAME" --arg p "${OS_PROJECT_NAME:-}" --arg pid "${OS_PROJECT_ID:-}" --arg u "$OS_USERNAME" --arg pw "$OS_PASSWORD" \
|
||||
'{auth:{identity:{methods:["password"],password:{user:{name:$u,domain:{name:$a},password:$pw}}},
|
||||
scope:{project:(if $pid!="" then {id:$pid} else {name:$p,domain:{name:$a}} end)}}}')")
|
||||
TOKEN=$(echo "$AUTH" | awk 'tolower($1)=="x-subject-token:"{print $2}' | tr -d '\r')
|
||||
[ -n "$TOKEN" ] || { echo "не получил токен: $(echo "$AUTH" | head -1) $(echo "$AUTH" | tail -1 | cut -c1-300)"
|
||||
echo "аккаунт=$OS_USER_DOMAIN_NAME проект=${OS_PROJECT_NAME:-} пользователь=$OS_USERNAME пароль=${#OS_PASSWORD} симв."
|
||||
# вход без проекта: если тут 201, то логин/пароль верные, а нет доступа к проекту
|
||||
UT=$(curl -sS -D - -o /dev/null https://cloud.api.selcloud.ru/identity/v3/auth/tokens \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "$(jq -nc --arg a "$OS_USER_DOMAIN_NAME" --arg u "$OS_USERNAME" --arg pw "$OS_PASSWORD" \
|
||||
'{auth:{identity:{methods:["password"],password:{user:{name:$u,domain:{name:$a},password:$pw}}}}}')" \
|
||||
| awk 'tolower($1)=="x-subject-token:"{print $2}' | tr -d '\r')
|
||||
[ -n "$UT" ] || { echo "логин/пароль не подходят"; exit 1; }
|
||||
echo "логин/пароль верные; доступные проекты (OS_PROJECT_ID / OS_PROJECT_NAME):"
|
||||
curl -sS -H "X-Auth-Token: $UT" https://cloud.api.selcloud.ru/identity/v3/auth/projects | jq -r '.projects[]|" \(.id) \(.name)"'
|
||||
exit 1; }
|
||||
api() { curl -sS --fail-with-body --connect-timeout 15 --retry 3 --retry-all-errors -H "X-Auth-Token: $TOKEN" -H 'Content-Type: application/json' "$@"; }
|
||||
|
||||
ZID=$(api "$API/zones?filter=$ZONE" | jq -r --arg z "$ZONE." '.result[]|select(.name==$z).id')
|
||||
[ -n "$ZID" ] || { echo "зона $ZONE не найдена"; exit 1; }
|
||||
RR=$(api "$API/zones/$ZID/rrset?name=$FQDN&limit=1000" | jq -c --arg n "$FQDN" '[.result[]|select(.name==$n)]')
|
||||
echo "$RR" | jq -r '.[]|"\(.name) \(.ttl) \(.type) \([.records[].content]|join(","))"'
|
||||
[ "$CMD" = show ] && exit 0
|
||||
|
||||
if [ "$CMD" = cname ] && [ "$(echo "$RR" | jq length)" = 0 ]; then
|
||||
# своей записи нет (домен резолвится через wildcard *.loop.ru) -> создаём CNAME
|
||||
[ -n "$VAL" ] || { echo "не указано значение"; exit 1; }
|
||||
echo "своей записи нет (wildcard), создаю: $FQDN CNAME ${VAL%.}. TTL 3600"
|
||||
api -X POST "$API/zones/$ZID/rrset" -w '%{http_code}\n' \
|
||||
-d "$(jq -nc --arg n "$FQDN" --arg c "${VAL%.}." '{name:$n, type:"CNAME", ttl:3600, records:[{content:$c}]}')"
|
||||
api "$API/zones/$ZID/rrset?name=$FQDN" | jq -r --arg n "$FQDN" '.result[]|select(.name==$n)|"стало: \(.name) \(.ttl) \(.type) \([.records[].content]|join(","))"'
|
||||
exit 0
|
||||
fi
|
||||
[ "$(echo "$RR" | jq length)" = 1 ] && [ "$(echo "$RR" | jq -r '.[0].type')" = CNAME ] || { echo "ожидалась одна CNAME-запись, стоп"; exit 1; }
|
||||
RID=$(echo "$RR" | jq -r '.[0].id')
|
||||
[ -n "$VAL" ] || { echo "не указано значение"; exit 1; }
|
||||
case $CMD in
|
||||
ttl) BODY=$(echo "$RR" | jq -c --argjson t "${VAL:?ttl}" '{ttl:$t, records:.[0].records}') ;;
|
||||
cname) BODY=$(echo "$RR" | jq -c --arg c "${VAL%.}." '{ttl:.[0].ttl, records:[{content:$c}]}') ;;
|
||||
*) echo "show|ttl|cname"; exit 1 ;;
|
||||
esac
|
||||
api -X PATCH "$API/zones/$ZID/rrset/$RID" -d "$BODY" -w '%{http_code}\n'
|
||||
api "$API/zones/$ZID/rrset?name=$FQDN" | jq -r --arg n "$FQDN" '.result[]|select(.name==$n)|"стало: \(.name) \(.ttl) \(.type) \([.records[].content]|join(","))"'
|
||||
Reference in New Issue
Block a user