safesight/edge/scripts/init-device.sh
tian 29d9ef5d0d refactor: 项目结构梳理 - 设备端/管理端对称布局
仓库结构:
  edge/     设备端(原根目录设备端代码整体移入)
  control/  管理端(清理后)
  docs/     文档(PRD 移入 design/)
  README.md 根导航(新增)

清理:
- control/.brainstorm 临时草稿删除
- control 根级重复文档(API表/PRD_04)并入 docs/design/
- control/plan.md -> docs/implementation/control-plan.md
- control/safesightd-linux-arm64 二进制取消版本控制(.gitignore)
- edge/transform 模型转换产物归入 models/,onnx/pt 大源文件取消跟踪(.gitignore)
- Readme.md(PRD) -> docs/design/PRD_Product_v1.2.md(避开 README 大小写冲突)

更新:
- 根 README.md 导航、docs/README.md 文档索引
- deployment.md/检查表路径加 edge/ 前缀
- .gitignore 重写(edge/control 分区规则)
2026-08-02 11:39:54 +08:00

244 lines
10 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# =============================================================================
# init-device.sh — 批量烧录后的单台设备初始化
# -----------------------------------------------------------------------------
# 在每台烧录好产品镜像的盒子上运行root。完成
# 1. 设置主机名
# 2. 设置静态 IPnetplan
# 3. 验证设备身份唯一machine-id / SSH 密钥 / device_id
# 4. 验证 safesight 服务正常
# 5. 启用断电保护 overlayroot出厂镜像故意未启用统一在此启用
# 6. 重启
#
# 用法:
# sudo ./init-device.sh --hostname safesight-01 \
# --ip 10.0.0.83/24 --gw 10.0.0.1 --dns 10.0.0.1
# 可选:
# --token <后台管理统一主钥匙> 轮换 agent token默认沿用镜像内主钥匙
# --hls-ram HLS 分片放内存(减小 SD 写入)
# --dhcp 保持 DHCP默认会写静态 IP
# --no-overlay 不启用断电保护(仅初始化)
# =============================================================================
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
ok() { echo -e "${GREEN}${NC} $*"; }
warn() { echo -e "${YELLOW}${NC} $*"; }
die() { echo -e "${RED}${NC} $*" >&2; exit 1; }
# ---------------------------------------------------------------------------
# 参数
# ---------------------------------------------------------------------------
HOSTNAME="" IP_CIDR="" GW="" DNS="" TOKEN="" HLS_RAM=0 USE_DHCP=0 NO_OVERLAY=0
usage() {
echo "用法: sudo $0 --hostname <名> --ip <IP/掩码> --gw <网关> --dns <DNS> [选项]"
echo ""
echo "必选:"
echo " --hostname <名称> 如 safesight-01"
echo " --ip <IP/掩码> 如 10.0.0.83/24"
echo " --gw <网关> 如 10.0.0.1"
echo " --dns <DNS> 如 10.0.0.1"
echo "可选:"
echo " --token <主钥匙> 轮换后台管理统一主钥匙"
echo " --hls-ram HLS 分片放内存"
echo " --dhcp 保持 DHCP不写静态 IP"
echo " --no-overlay 不启用断电保护"
exit 1
}
while [ $# -gt 0 ]; do
case "$1" in
--hostname) HOSTNAME="$2"; shift 2 ;;
--ip) IP_CIDR="$2"; shift 2 ;;
--gw) GW="$2"; shift 2 ;;
--dns) DNS="$2"; shift 2 ;;
--token) TOKEN="$2"; shift 2 ;;
--hls-ram) HLS_RAM=1; shift ;;
--dhcp) USE_DHCP=1; shift ;;
--no-overlay) NO_OVERLAY=1; shift ;;
*) warn "未知参数: $1"; shift ;;
esac
done
[ "$(id -u)" -eq 0 ] || die "请使用 sudo 运行"
if [ "$USE_DHCP" = "0" ]; then
[ -n "$HOSTNAME" ] || die "缺少 --hostname"
[ -n "$IP_CIDR" ] || die "缺少 --ip"
[ -n "$GW" ] || die "缺少 --gw"
[ -n "$DNS" ] || die "缺少 --dns"
fi
OVERLAY_SCRIPT="/opt/safesight-edge-server/scripts/setup-overlayroot.sh"
[ -x "$OVERLAY_SCRIPT" ] || OVERLAY_SCRIPT="$(cd "$(dirname "$0")" && pwd)/setup-overlayroot.sh"
# ---------------------------------------------------------------------------
# 1. 主机名
# ---------------------------------------------------------------------------
if [ -n "$HOSTNAME" ]; then
info "设置主机名: $HOSTNAME"
hostnamectl set-hostname "$HOSTNAME"
sed -i "/^127.0.1.1/d" /etc/hosts
echo "127.0.1.1 $HOSTNAME" >> /etc/hosts
ok "主机名已设置"
fi
# ---------------------------------------------------------------------------
# 2. 静态 IPnetplan
# ---------------------------------------------------------------------------
NETPLAN_DIR="/etc/netplan"
if [ "$USE_DHCP" = "0" ]; then
# 检测默认网卡(优先有默认路由的网卡,其次第一个非 lo 网卡)
IFACE="$(ip route show default 2>/dev/null | awk '/default/{print $5; exit}')"
[ -n "$IFACE" ] || IFACE="$(ls /sys/class/net | grep -v '^lo$' | head -1)"
[ -n "$IFACE" ] || die "未检测到网卡"
info "配置静态 IP: $IFACE $IP_CIDR (gw=$GW dns=$DNS)"
mkdir -p "$NETPLAN_DIR"
# 备份现有配置
cp -a "$NETPLAN_DIR"/01-*.yaml "$NETPLAN_DIR/backup-"$(date +%s)".yaml" 2>/dev/null || true
rm -f "$NETPLAN_DIR"/01-*.yaml 2>/dev/null || true
cat > "$NETPLAN_DIR/01-safesight-static.yaml" << EOF
network:
version: 2
ethernets:
$IFACE:
dhcp4: no
addresses:
- $IP_CIDR
routes:
- to: default
via: $GW
nameservers:
addresses:
- $DNS
EOF
netplan apply 2>/dev/null || warn "netplan apply 失败(重启后生效)"
ok "静态 IP 已配置: $IP_CIDR"
else
info "保持 DHCP"
fi
# ---------------------------------------------------------------------------
# 3. 设备身份验证(出厂镜像已清空,首次启动应已自动重建)
# ---------------------------------------------------------------------------
info "验证设备身份 ..."
[ -s /etc/machine-id ] || { systemd-machine-id-setup 2>/dev/null || warn "machine-id 缺失(重启后自动生成)"; }
[ -s /etc/machine-id ] && ok "machine-id: $(cat /etc/machine-id)"
if ls /etc/ssh/ssh_host_*_key >/dev/null 2>&1; then
ok "SSH 主机密钥已生成"
else
ssh-keygen -A 2>/dev/null || true
ok "SSH 主机密钥已生成ssh-keygen -A"
fi
# ---------------------------------------------------------------------------
# 4. agent token可选轮换
# ---------------------------------------------------------------------------
if [ -n "$TOKEN" ]; then
info "轮换 agent 主钥匙 ..."
printf '%s\n' "$TOKEN" > /opt/safesight-edge-agent/agent.token
chmod 600 /opt/safesight-edge-agent/agent.token
# 更新 agent 配置中的 token
if [ -f /opt/safesight-edge-agent/agent.config.json ]; then
sed -i "s/\"token\": \"[^\"]*\"/\"token\": \"$TOKEN\"/" /opt/safesight-edge-agent/agent.config.json
fi
ok "agent token 已更新"
fi
# ---------------------------------------------------------------------------
# 4.5 /data 分区自动扩容(小镜像烧到 64G 产品卡后,把 /data 扩到整卡剩余)
# ---------------------------------------------------------------------------
grow_data_partition() {
info "扩容 /data 分区到 SD 卡剩余空间 ..."
DATA_PART="$(findmnt -no SOURCE /data 2>/dev/null || true)"
[ -n "$DATA_PART" ] || { warn "/data 未挂载,跳过扩容"; return; }
DISK=""; PARTNUM=""
case "$DATA_PART" in
/dev/mmcblk*) DISK="${DATA_PART%p*}"; PARTNUM="${DATA_PART##*p}" ;;
/dev/nvme*) DISK="${DATA_PART%p*}"; PARTNUM="${DATA_PART##*p}" ;;
/dev/sd*) DISK="${DATA_PART%[0-9]*}"; PARTNUM="${DATA_PART##*[a-z]}" ;;
esac
[ -n "$DISK" ] || { warn "无法识别 /data 所在磁盘,跳过扩容"; return; }
# 需要 growpartcloud-guest-utils 提供)
if ! command -v growpart >/dev/null 2>&1; then
info "安装 growpart ..."
apt-get install -y cloud-guest-utils 2>/dev/null || warn "growpart 安装失败,跳过扩容"
fi
command -v growpart >/dev/null 2>&1 || return
# 停服务并卸载 /data 后扩容(避免分区忙)
systemctl stop safesight-edge-server safesight-edge-agent 2>/dev/null || true
umount /data 2>/dev/null || true
growpart "$DISK" "$PARTNUM" 2>/dev/null || warn "growpart 无变化(可能已扩满)"
resize2fs "$DATA_PART" 2>/dev/null || warn "resize2fs 失败"
mount /data 2>/dev/null || mount -a 2>/dev/null || true
systemctl start safesight-edge-server safesight-edge-agent 2>/dev/null || true
ok "/data 扩容完成: $(df -h /data 2>/dev/null | awk 'NR==2{print "总"$2" 可用"$4}')64G 产品卡自动占满剩余空间)"
}
# ---------------------------------------------------------------------------
# 5. 验证 safesight 服务
# ---------------------------------------------------------------------------
info "验证服务 ..."
systemctl start safesight-edge-server safesight-edge-agent 2>/dev/null || true
sleep 3
for s in safesight-edge-server safesight-edge-agent; do
if systemctl is-active --quiet "$s" 2>/dev/null; then
ok "$s 运行中"
else
warn "$s 未运行(可稍后 systemctl status $s 排查)"
fi
done
if [ -f /var/lib/safesight-edge-agent/device_id ]; then
ok "device_id: $(cat /var/lib/safesight-edge-agent/device_id)"
else
info "device_id 由 agent 首次运行时生成(读取 machine-id"
fi
# ---------------------------------------------------------------------------
# 4.5 /data 分区自动扩容(小镜像烧到 64G 产品卡后,把 /data 扩到整卡剩余)
# ---------------------------------------------------------------------------
grow_data_partition
# ---------------------------------------------------------------------------
# 6. 启用断电保护
# ---------------------------------------------------------------------------
if [ "$NO_OVERLAY" = "1" ]; then
warn "跳过断电保护启用(--no-overlay"
else
info "启用断电保护overlayroot + /data..."
EXTRA=""
[ "$HLS_RAM" = "1" ] && EXTRA="--hls-ram"
if [ -x "$OVERLAY_SCRIPT" ]; then
bash "$OVERLAY_SCRIPT" install --yes $EXTRA || die "断电保护启用失败"
else
die "未找到 setup-overlayroot.sh$OVERLAY_SCRIPT),请先完成部署"
fi
ok "断电保护已配置,重启后生效"
fi
# ---------------------------------------------------------------------------
# 7. 完成
# ---------------------------------------------------------------------------
echo ""
echo -e "${GREEN}════════════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN} 初始化完成!${NC}"
echo -e "${GREEN}════════════════════════════════════════════════════════════════${NC}"
echo ""
echo " IP: ${IP_CIDR:-DHCP}"
echo " 主机名: ${HOSTNAME:-未设置}"
echo " 管理界面: http://${IP_CIDR%/*}:9100"
echo ""
echo "请重启使全部配置生效:"
echo " sudo reboot"
echo ""
echo "重启后建议:"
echo " sudo $OVERLAY_SCRIPT verify # 断电保护验证"
echo " 在管理端发现该设备 → 设置别名 → 下发配置"