2026-10-26 11:58:15 +00:00
#!/bin/bash
# deploy/agent-install.sh — 관리 서버 또는 고객 외부 서버에 Node Agent 설치·등록(§28.2·§10.2). HAL 이 /agent/v1/install.sh 로 제공한다.
# curl -fsSL https://hal.ariweb.net/agent/v1/install.sh | bash -s -- --hal https://hal.ariweb.net --token <일회용 토큰> [--role web|mail|backup|control] [--external --site <siteId>] [--app-dir /srv/ariweb/agent]
# 하는 일: node 22+ 확인(없으면 NodeSource 로 설치), agent artifact 를 HAL 에서 받아 <app-dir>/releases/<ver> 에 풀고 current 연결, 등록(토큰 1회), systemd 유닛 ariweb-agent 설치·시작, sudoers 최소 규칙(관리형만).
# 멱등: 다시 실행하면 이미 등록된 Agent 는 재등록하지 않고 코드·유닛만 맞춘다. 토큰 외의 비밀은 출력하지 않는다.
set -euo pipefail
HAL = "" ; TOKEN = "" ; ROLE = "web" ; EXTERNAL = 0; SITE = "" ; APP_DIR = "/srv/ariweb/agent" ; LABEL = " $( hostname) "
while [ $# -gt 0 ] ; do case " $1 " in --hal) HAL = " $2 " ; shift 2;; --token) TOKEN = " $2 " ; shift 2;; --role) ROLE = " $2 " ; shift 2;; --external) EXTERNAL = 1; shift;; --site) SITE = " $2 " ; shift 2;; --app-dir) APP_DIR = " $2 " ; shift 2;; --label) LABEL = " $2 " ; shift 2;; *) echo "알 수 없는 옵션 $1 " >& 2; exit 1;; esac ; done
[ -n " $HAL " ] || { echo "--hal 이 필요합니다" >& 2; exit 1; }
HAL = " ${ HAL %/ } " ; USER_NAME = " $( id -un) "
if ! command -v node >/dev/null 2>& 1 || [ " $( node --version | sed -E 's/^v([0-9]+).*/\1/' ) " -lt 22 ] ; then echo "== node 22 설치" ; curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -n bash - >/dev/null && sudo -n apt-get install -y -q nodejs >/dev/null; fi
NODE_BIN = " $( command -v node) "
echo "== HAL 확인 $HAL " ; HEALTH = " $( curl -fsS " $HAL /api/health" ) " ; VERSION = " $( echo " $HEALTH " | $NODE_BIN -e "let s='';process.stdin.on('data',c=>s+=c).on('end',()=>console.log(JSON.parse(s).bootstrap.releaseVersion||JSON.parse(s).version))" ) "
sudo -n mkdir -p " $APP_DIR /releases/ $VERSION " " $APP_DIR /data" /var/www/ariweb-sites /srv/ariweb/backups; sudo -n chown -R " $USER_NAME : $USER_NAME " " $APP_DIR " /var/www/ariweb-sites /srv/ariweb/backups; chmod 700 " $APP_DIR /data"
if [ ! -f " $APP_DIR /releases/ $VERSION /agent/index.mjs" ] ; then
echo "== agent artifact $VERSION 내려받기"
# 등록 전에는 서명을 만들 수 없으므로 부트스트랩 전용 공개 경로가 아니라 등록 토큰으로 1회 받는다: HAL 의 install.sh 는 토큰과 함께 artifact 를 함께 보낸다(아래 등록 뒤 재시도 경로).
if [ -n " $TOKEN " ] ; then curl -fsS -H "X-Registration-Token: $TOKEN " " $HAL /agent/v1/bootstrap-artifact?module=agent&version= $VERSION " -o /tmp/ariweb-agent-$$ .tgz; tar -xzf /tmp/ariweb-agent-$$ .tgz -C " $APP_DIR /releases/ $VERSION " ; rm -f /tmp/ariweb-agent-$$ .tgz; else echo "코드가 없고 토큰도 없습니다" >& 2; exit 1; fi
fi
2026-10-26 13:56:42 +00:00
# 실행 계정이 다른 도입 모듈 설치(deploy/module-as-user.sh)를 위해 코드 트리는 다른 계정도 읽을 수 있어야 한다 — 호출자의 umask 와 무관하게 맞춘다(실제 환경 결함 수정)
chmod 755 " $APP_DIR " " $APP_DIR /releases" ; chmod -R a+rX " $APP_DIR /releases/ $VERSION "
2026-10-26 11:58:15 +00:00
ln -sfn " $APP_DIR /releases/ $VERSION " " $APP_DIR /current" ; cd " $APP_DIR /current"
export ARIWEB_AGENT_DATA = " $APP_DIR /data"
if [ ! -f " $APP_DIR /data/agent.json" ] ; then [ -n " $TOKEN " ] || { echo "등록되지 않았고 --token 도 없습니다" >& 2; exit 1; } ; echo "== 등록" ; if [ " $EXTERNAL " = "1" ] ; then $NODE_BIN agent/index.mjs register --hal " $HAL " --token " $TOKEN " --external --site " $SITE " --label " $LABEL " ; else $NODE_BIN agent/index.mjs register --hal " $HAL " --token " $TOKEN " --role " $ROLE " --label " $LABEL " ; fi ; else echo "== 이미 등록됨( $( cat " $APP_DIR /data/agent.json" | $NODE_BIN -e "let s='';process.stdin.on('data',c=>s+=c).on('end',()=>console.log(JSON.parse(s).id))" ) ) — 코드·유닛만 갱신" ; fi
echo "== systemd 유닛"
sed -e "s#{{APP_DIR}}# $APP_DIR #g" -e "s#{{USER}}# $USER_NAME #g" -e "s#{{NODE}}# $NODE_BIN #g" -e "s#{{VERSION}}# $VERSION #g" -e "s#{{ENV_LINES}}# $( [ " $EXTERNAL " = "1" ] && echo "Environment=ARIWEB_AGENT_EXTERNAL=1" || echo "" ) #" deploy/units/ariweb-agent.service.tmpl | sudo -n tee /etc/systemd/system/ariweb-agent.service >/dev/null
if [ " $EXTERNAL " = "0" ] ; then sudo -n install -m 440 deploy/sudoers/ariweb-agent /etc/sudoers.d/ariweb-agent && sudo -n visudo -c >/dev/null; sudo -n cp deploy/nginx/awstats.conf /etc/nginx/conf.d/awstats.conf 2>/dev/null && ( sudo -n nginx -t >/dev/null 2>& 1 && sudo -n systemctl reload nginx || true ) ; fi
sudo -n systemctl daemon-reload; sudo -n systemctl enable --now ariweb-agent >/dev/null; sudo -n systemctl restart ariweb-agent; sleep 2
systemctl is-active --quiet ariweb-agent && echo "== 완료: ariweb-agent 실행 중. HAL 운영자 콘솔에서 서버를 승인하면 배치가 가능합니다" || { echo "ariweb-agent 기동 실패 — journalctl -u ariweb-agent" >& 2; exit 1; }