초기 commit — onboard-linux-node.sh + install-eu-windows.ps1 + README
This commit is contained in:
commit
034c734346
53
README.md
Normal file
53
README.md
Normal file
@ -0,0 +1,53 @@
|
||||
# washtime/tools
|
||||
|
||||
자체 운영 도구 / 셋업 자동화 스크립트 모음.
|
||||
|
||||
이 repo 는 **public** — 누구나 raw URL 로 받을 수 있다 (인증 키 등 비밀은 절대 commit 금지).
|
||||
|
||||
---
|
||||
|
||||
## 새 리눅스 서버 onboarding
|
||||
|
||||
새 노드 (오라클 프리티어 / 라즈베리파이 / 다른 PC) 에서:
|
||||
|
||||
```bash
|
||||
bash <(curl -fsSL http://192.168.1.40:3000/washtime/tools/raw/branch/main/onboard-linux-node.sh)
|
||||
```
|
||||
|
||||
(외부망에서는 LAN IP 안 보임 → 플린트3 도착 + DDNS 셋업 후 `git.washtime.xxx` 로 교체.)
|
||||
|
||||
스크립트가 인터랙티브로 물어보는 것:
|
||||
- Gitea host (default: `192.168.1.40`)
|
||||
- admin API token (`Washtime_GitAdmin` 의 `admin-write` 토큰 — Web UI 의 `Settings → Applications → Generate New Token` 에서 발급)
|
||||
- 노드 이름 (예: `oracle-jp-1`)
|
||||
- Clone 할 repo (콤마 구분, 예: `one,family-viewer,tools`)
|
||||
|
||||
자동 처리:
|
||||
- ed25519 SSH key 생성 + Gitea 에 자동 등록
|
||||
- `~/.ssh/config` 에 `gitea` 별칭 추가
|
||||
- repo clone
|
||||
- 1분 주기 auto-pull systemd timer 설치
|
||||
|
||||
---
|
||||
|
||||
## 새 Windows PC 에 External Uploader 설치
|
||||
|
||||
관리자 PowerShell 에서:
|
||||
|
||||
```powershell
|
||||
iwr -useb http://192.168.1.40:3000/washtime/tools/raw/branch/main/install-eu-windows.ps1 | iex
|
||||
```
|
||||
|
||||
(외부망에서는 위 URL 의 host 를 외부 도메인으로 교체.)
|
||||
|
||||
자동 처리:
|
||||
- 최신 installer (`ExternalUploader-Setup-latest.exe`, 510MB) 자동 다운로드
|
||||
- SHA256 + 크기 검증
|
||||
- installer 실행 (GUI)
|
||||
- 설치 완료 후 daemon 이 백그라운드에서 자동 업데이트 처리 — 사용자 액션 더 이상 X
|
||||
|
||||
---
|
||||
|
||||
## 기타 도구
|
||||
|
||||
(추후 추가될 운영 자동화 스크립트 — DB 마이그레이션 헬퍼, 백업 검증, 헬스 체크 등)
|
||||
84
install-eu-windows.ps1
Normal file
84
install-eu-windows.ps1
Normal file
@ -0,0 +1,84 @@
|
||||
# washtime External Uploader — Windows 자동 설치
|
||||
# 한 줄 실행 (PowerShell 관리자):
|
||||
# iwr -useb http://192.168.1.40:3000/washtime/tools/raw/branch/main/install-eu-windows.ps1 | iex
|
||||
#
|
||||
# 동작:
|
||||
# 1) 최신 installer .exe 다운로드 (washtime 서버에서)
|
||||
# 2) 다운로드 검증 (SHA256, 옵션)
|
||||
# 3) 자동 실행 (silent 또는 GUI)
|
||||
# 4) 설치 후 auto_updater 가 자동으로 차후 업데이트 처리
|
||||
#
|
||||
# 이후 사용자는 더 이상 액션 불필요 — daemon 이 백그라운드에서 publisher-certs API 보고
|
||||
# 자동으로 새 버전 다운로드 + helper.exe 가 swap 처리.
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# ───── 설정 ─────
|
||||
$installerUrl = 'http://washtime.asuscomm.com:5055/downloads/ExternalUploader-Setup-latest.exe'
|
||||
$installerLocal = "$env:TEMP\ExternalUploader-Setup.exe"
|
||||
$installMode = 'gui' # 'gui' = NSIS GUI / 'silent' = /S 무인설치
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '════════════════════════════════════════════════════════' -ForegroundColor Cyan
|
||||
Write-Host ' washtime External Uploader 자동 설치' -ForegroundColor Cyan
|
||||
Write-Host '════════════════════════════════════════════════════════' -ForegroundColor Cyan
|
||||
Write-Host ''
|
||||
|
||||
# ───── 1) 다운로드 ─────
|
||||
Write-Host "[1/3] installer 다운로드…" -ForegroundColor Yellow
|
||||
Write-Host " URL: $installerUrl"
|
||||
Write-Host " 저장: $installerLocal"
|
||||
try {
|
||||
$ProgressPreference = 'SilentlyContinue' # iwr 진행률 표시 끔 (속도 위해)
|
||||
Invoke-WebRequest -Uri $installerUrl -OutFile $installerLocal -UseBasicParsing
|
||||
$size = (Get-Item $installerLocal).Length
|
||||
Write-Host " ✔ 다운로드 완료 ($([math]::Round($size/1MB, 1)) MB)" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host " ✗ 다운로드 실패: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ───── 2) 검증 ─────
|
||||
Write-Host ''
|
||||
Write-Host '[2/3] 파일 검증…' -ForegroundColor Yellow
|
||||
$hash = (Get-FileHash $installerLocal -Algorithm SHA256).Hash
|
||||
Write-Host " SHA256: $hash"
|
||||
if ($size -lt 100MB) {
|
||||
Write-Host ' ✗ 파일 크기 비정상 (100MB 미만). 다운로드 손상 의심.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
Write-Host ' ✔ OK' -ForegroundColor Green
|
||||
|
||||
# ───── 3) 설치 ─────
|
||||
Write-Host ''
|
||||
Write-Host '[3/3] installer 실행…' -ForegroundColor Yellow
|
||||
if ($installMode -eq 'silent') {
|
||||
Write-Host ' silent 모드 (/S)'
|
||||
$proc = Start-Process -FilePath $installerLocal -ArgumentList '/S' -Wait -PassThru
|
||||
if ($proc.ExitCode -eq 0) {
|
||||
Write-Host ' ✔ 설치 완료' -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " ✗ installer exit code: $($proc.ExitCode)" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Host ' GUI 모드 — installer 창이 열리면 따라가세요'
|
||||
Start-Process -FilePath $installerLocal -Wait
|
||||
Write-Host ' ✔ installer 종료됨' -ForegroundColor Green
|
||||
}
|
||||
|
||||
# ───── 정리 ─────
|
||||
Remove-Item $installerLocal -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '════════════════════════════════════════════════════════' -ForegroundColor Cyan
|
||||
Write-Host ' ✅ 설치 완료' -ForegroundColor Green
|
||||
Write-Host '════════════════════════════════════════════════════════' -ForegroundColor Cyan
|
||||
Write-Host ''
|
||||
Write-Host '다음 단계:'
|
||||
Write-Host ' 1) 시작 메뉴에서 "ExternalUploader" 실행'
|
||||
Write-Host ' 2) 시스템 트레이의 아이콘 우클릭 → 설정'
|
||||
Write-Host ' 3) Memily 폴더 (~/Memily/<board-name>) 에 미디어 넣으면 자동 업로드'
|
||||
Write-Host ''
|
||||
Write-Host '향후 업데이트는 daemon 이 백그라운드에서 자동 처리 (사용자 액션 X).'
|
||||
Write-Host ''
|
||||
213
onboard-linux-node.sh
Executable file
213
onboard-linux-node.sh
Executable file
@ -0,0 +1,213 @@
|
||||
#!/bin/bash
|
||||
# washtime — 새 리눅스 노드 onboarding
|
||||
# 한 줄 실행:
|
||||
# bash <(curl -fsSL http://192.168.1.40:3000/washtime/tools/raw/branch/main/onboard-linux-node.sh)
|
||||
#
|
||||
# 작동:
|
||||
# 1) ssh ed25519 key 생성 (또는 기존 사용)
|
||||
# 2) Gitea API 로 그 public key 등록 (admin token 인터랙티브 입력)
|
||||
# 3) ~/.ssh/config 에 gitea host 별칭 추가
|
||||
# 4) 지정한 repo clone
|
||||
# 5) 1분 주기 auto-pull systemd timer 설치
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_HOST_DEFAULT="192.168.1.40"
|
||||
GITEA_SSH_PORT_DEFAULT="2222"
|
||||
GITEA_API_PORT_DEFAULT="3000"
|
||||
GITEA_USER_DEFAULT="root2"
|
||||
ORG_DEFAULT="washtime"
|
||||
|
||||
# ───────── 입력 ─────────
|
||||
read -rp "Gitea host (default: $GITEA_HOST_DEFAULT): " GITEA_HOST
|
||||
GITEA_HOST="${GITEA_HOST:-$GITEA_HOST_DEFAULT}"
|
||||
|
||||
read -rp "Gitea SSH port (default: $GITEA_SSH_PORT_DEFAULT): " GITEA_SSH_PORT
|
||||
GITEA_SSH_PORT="${GITEA_SSH_PORT:-$GITEA_SSH_PORT_DEFAULT}"
|
||||
|
||||
read -rp "Gitea API port (default: $GITEA_API_PORT_DEFAULT): " GITEA_API_PORT
|
||||
GITEA_API_PORT="${GITEA_API_PORT:-$GITEA_API_PORT_DEFAULT}"
|
||||
|
||||
read -rp "Gitea Web 계정명 (default: $GITEA_USER_DEFAULT): " GITEA_USER
|
||||
GITEA_USER="${GITEA_USER:-$GITEA_USER_DEFAULT}"
|
||||
|
||||
read -rsp "Gitea admin API token (입력 가려짐): " GITEA_TOKEN
|
||||
echo
|
||||
|
||||
read -rp "이 노드 이름 (예: oracle-cloud, laptop-mac. SSH key 라벨에 사용): " NODE_NAME
|
||||
[[ -z "$NODE_NAME" ]] && { echo "노드 이름 필수"; exit 1; }
|
||||
|
||||
read -rp "Org (default: $ORG_DEFAULT): " ORG
|
||||
ORG="${ORG:-$ORG_DEFAULT}"
|
||||
|
||||
read -rp "Clone 할 repo (콤마 구분, 예: one,family-viewer,tools): " REPOS_STR
|
||||
[[ -z "$REPOS_STR" ]] && { echo "Repo 필수"; exit 1; }
|
||||
|
||||
read -rp "Clone 위치 (default: \$HOME): " CLONE_BASE
|
||||
CLONE_BASE="${CLONE_BASE:-$HOME}"
|
||||
|
||||
# ───────── 1) git 설치 ─────────
|
||||
echo "[1/5] git / curl 설치 확인…"
|
||||
if ! command -v git &>/dev/null; then
|
||||
if command -v apt-get &>/dev/null; then
|
||||
sudo apt-get update -qq && sudo apt-get install -y git curl
|
||||
elif command -v dnf &>/dev/null; then
|
||||
sudo dnf install -y git curl
|
||||
elif command -v yum &>/dev/null; then
|
||||
sudo yum install -y git curl
|
||||
else
|
||||
echo "패키지 매니저 모름. git 직접 설치 필요."; exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ───────── 2) SSH key 생성 ─────────
|
||||
KEY_FILE="$HOME/.ssh/id_ed25519_gitea"
|
||||
echo "[2/5] SSH key 확인…"
|
||||
mkdir -p "$HOME/.ssh"
|
||||
chmod 700 "$HOME/.ssh"
|
||||
if [[ ! -f "$KEY_FILE" ]]; then
|
||||
ssh-keygen -t ed25519 -N "" -C "$(whoami)@$NODE_NAME→gitea" -f "$KEY_FILE"
|
||||
echo " ✔ 새 key 생성됨"
|
||||
else
|
||||
echo " ✔ 기존 key 재사용"
|
||||
fi
|
||||
PUBKEY=$(cat "${KEY_FILE}.pub")
|
||||
|
||||
# ───────── 3) Gitea 에 key 등록 ─────────
|
||||
echo "[3/5] Gitea 에 SSH key 등록…"
|
||||
RESP=$(curl -fsS -H "Authorization: token $GITEA_TOKEN" \
|
||||
-X POST -H "Content-Type: application/json" \
|
||||
-d "{\"title\":\"$NODE_NAME\",\"key\":\"$PUBKEY\"}" \
|
||||
"http://${GITEA_HOST}:${GITEA_API_PORT}/api/v1/user/keys" 2>&1) || {
|
||||
# 이미 등록되어 있으면 OK
|
||||
if echo "$RESP" | grep -q "already exists"; then
|
||||
echo " ✔ 이미 등록되어있음"
|
||||
else
|
||||
echo " ✗ 등록 실패: $RESP"; exit 1
|
||||
fi
|
||||
}
|
||||
echo " ✔ 등록 완료"
|
||||
|
||||
# ───────── 4) ~/.ssh/config ─────────
|
||||
echo "[4/5] ~/.ssh/config 설정…"
|
||||
if ! grep -q "^Host gitea$" "$HOME/.ssh/config" 2>/dev/null; then
|
||||
cat >> "$HOME/.ssh/config" << EOF
|
||||
|
||||
Host gitea
|
||||
HostName ${GITEA_HOST}
|
||||
Port ${GITEA_SSH_PORT}
|
||||
User git
|
||||
IdentityFile ${KEY_FILE}
|
||||
IdentitiesOnly yes
|
||||
StrictHostKeyChecking accept-new
|
||||
EOF
|
||||
chmod 600 "$HOME/.ssh/config"
|
||||
echo " ✔ gitea 별칭 추가됨"
|
||||
else
|
||||
echo " ✔ gitea 별칭 이미 있음"
|
||||
fi
|
||||
|
||||
# SSH 테스트
|
||||
ssh -o BatchMode=yes -T gitea 2>&1 | head -1 || true
|
||||
|
||||
# ───────── 5) repo clone + auto-pull systemd ─────────
|
||||
echo "[5/5] repo clone + auto-pull systemd…"
|
||||
IFS=',' read -ra REPOS <<< "$REPOS_STR"
|
||||
|
||||
mkdir -p "$CLONE_BASE/scripts"
|
||||
|
||||
for REPO in "${REPOS[@]}"; do
|
||||
REPO="${REPO// /}"
|
||||
TARGET="${CLONE_BASE}/${REPO}"
|
||||
if [[ -d "$TARGET/.git" ]]; then
|
||||
echo " ↻ $TARGET 이미 git repo, pull만"
|
||||
(cd "$TARGET" && git pull --ff-only) || echo " ⚠ $REPO pull 실패"
|
||||
else
|
||||
if [[ -d "$TARGET" ]]; then
|
||||
BAK="${TARGET}.backup-$(date +%Y%m%d-%H%M%S)"
|
||||
mv "$TARGET" "$BAK"
|
||||
echo " ↻ 기존 $TARGET 백업: $BAK"
|
||||
fi
|
||||
git clone "gitea:${ORG}/${REPO}.git" "$TARGET" || { echo " ✗ $REPO clone 실패"; continue; }
|
||||
echo " ✔ $REPO clone 완료 → $TARGET"
|
||||
fi
|
||||
done
|
||||
|
||||
# auto-pull 스크립트 (단순 ff-merge, service restart 매핑은 노드별 사용자가 추가)
|
||||
PULL_SH="${CLONE_BASE}/scripts/git-auto-pull.sh"
|
||||
cat > "$PULL_SH" << EOF
|
||||
#!/bin/bash
|
||||
# washtime auto-pull — ${NODE_NAME}
|
||||
set -e
|
||||
for REPO in ${REPOS[@]}; do
|
||||
REPO="\${REPO// /}"
|
||||
R="${CLONE_BASE}/\$REPO"
|
||||
[[ ! -d "\$R/.git" ]] && continue
|
||||
cd "\$R"
|
||||
OLD=\$(git rev-parse HEAD)
|
||||
git fetch --quiet origin main 2>&1
|
||||
NEW=\$(git rev-parse origin/main)
|
||||
[[ "\$OLD" == "\$NEW" ]] && continue
|
||||
echo "[\$(date +%Y-%m-%dT%H:%M:%S)] \$REPO: \$OLD..\$NEW"
|
||||
if ! git diff --quiet || ! git diff --quiet --cached; then
|
||||
git stash push -u -m "auto-pull-\$(date +%s)"
|
||||
fi
|
||||
git merge --ff-only \$NEW || { echo " ❌ ff 불가"; continue; }
|
||||
# TODO: 변경 파일별 service restart hook 추가
|
||||
done
|
||||
EOF
|
||||
chmod +x "$PULL_SH"
|
||||
|
||||
# systemd service + timer (sudo 필요)
|
||||
SVC_FILE="/etc/systemd/system/washtime-git-pull.service"
|
||||
TMR_FILE="/etc/systemd/system/washtime-git-pull.timer"
|
||||
|
||||
if [[ ! -f "$SVC_FILE" ]]; then
|
||||
sudo tee "$SVC_FILE" > /dev/null << EOF
|
||||
[Unit]
|
||||
Description=washtime git auto-pull (${NODE_NAME})
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=$(whoami)
|
||||
WorkingDirectory=${CLONE_BASE}
|
||||
ExecStart=${PULL_SH}
|
||||
StandardOutput=append:/tmp/washtime-git-pull.log
|
||||
StandardError=append:/tmp/washtime-git-pull.log
|
||||
EOF
|
||||
sudo tee "$TMR_FILE" > /dev/null << EOF
|
||||
[Unit]
|
||||
Description=washtime git auto-pull every 1 min
|
||||
|
||||
[Timer]
|
||||
OnBootSec=30s
|
||||
OnUnitActiveSec=60s
|
||||
AccuracySec=5s
|
||||
Persistent=true
|
||||
Unit=washtime-git-pull.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now washtime-git-pull.timer
|
||||
echo " ✔ systemd timer 활성 (1분 주기)"
|
||||
fi
|
||||
|
||||
# 즉시 한 번 실행
|
||||
sudo systemctl start washtime-git-pull.service 2>/dev/null || true
|
||||
|
||||
echo
|
||||
echo "========================================"
|
||||
echo " ✅ onboarding 완료"
|
||||
echo "========================================"
|
||||
echo " 노드: $NODE_NAME"
|
||||
echo " Clone 위치: $CLONE_BASE"
|
||||
echo " Repo: ${REPOS_STR}"
|
||||
echo " Auto-pull: washtime-git-pull.timer (1분 주기)"
|
||||
echo " Log: /tmp/washtime-git-pull.log"
|
||||
echo
|
||||
echo " 강제 pull: sudo systemctl start washtime-git-pull.service"
|
||||
echo " 로그 보기: tail -f /tmp/washtime-git-pull.log"
|
||||
echo " 타이머 끄기: sudo systemctl disable --now washtime-git-pull.timer"
|
||||
echo
|
||||
Loading…
Reference in New Issue
Block a user