
#!/bin/bash
# 描述：批量推送本地所有镜像到Harbor仓库
# 作者：运维工程师
# 使用方式：修改下方HARBOR配置后直接运行

### 配置区（根据实际情况修改） ###
HARBOR_URL="192.168.31.248:7443"    # Harbor地址
PROJECT_NAME="library"          # Harbor项目名称
MAX_RETRY=2                        # 单镜像推送失败重试次数
CONCURRENT_PUSH=3                  # 并行推送数（根据机器性能调整）

### 脚本核心逻辑（无需修改） ###
FAILED_LOG="failed_images.log"
TMP_IMAGE_LIST="/tmp/image_list.txt"

# 登录Harbor（安全提示：建议使用凭证文件而非明文密码）
echo "请登录Harbor仓库 $HARBOR_URL："
docker login $HARBOR_URL || {
  echo "Harbor登录失败！脚本终止。"
  exit 1
}

# 生成镜像列表（排除Harbor自身镜像）
docker images --format "{{.Repository}}:{{.Tag}}" | 
  grep -vE "^$HARBOR_URL|^<none>|^REPOSITORY" > $TMP_IMAGE_LIST

TOTAL_IMAGES=$(wc -l < $TMP_IMAGE_LIST)
CURRENT=1

echo "===== 开始推送镜像（共 $TOTAL_IMAGES 个） ====="

# 定义推送函数
push_image() {
  local src_image=$1
  local retry=0
  
  # 转换镜像名称规则：
  # docker.io/library/nginx:alpine → harbor.example.com/my-project/nginx:alpine
  # quay.io/coreos/kube-rbac:latest → harbor.example.com/my-project/coreos/kube-rbac:latest
  local harbor_image=$(echo $src_image | sed \
    -e "s|^docker.io/||" \
    -e "s|^library/||" \
    -e "s|^|$HARBOR_URL/$PROJECT_NAME/|")

  # 显示进度
  echo "[$CURRENT/$TOTAL_IMAGES] 正在推送: $src_image → $harbor_image"

  # 重试逻辑
  while [ $retry -le $MAX_RETRY ]; do
    docker tag "$src_image" "$harbor_image"
    if docker push "$harbor_image" > /dev/null 2>&1; then
      docker rmi "$harbor_image"  # 清理临时tag
      return 0
    else
      ((retry++))
      echo "推送失败（尝试 $retry/$((MAX_RETRY+1))）: $harbor_image"
      sleep 2
    fi
  done

  echo "$src_image → $harbor_image" >> $FAILED_LOG
  return 1
}

# 并行推送控制
export -f push_image
export HARBOR_URL PROJECT_NAME MAX_RETRY FAILED_LOG CURRENT TOTAL_IMAGES

cat $TMP_IMAGE_LIST | xargs -P $CONCURRENT_PUSH -I {} bash -c 'push_image "$@"' _ {}

# 结果统计
SUCCESS_COUNT=$(($TOTAL_IMAGES - $(wc -l < $FAILED_LOG 2>/dev/null || echo 0)))
echo "===== 推送完成 ====="
echo "成功: $SUCCESS_COUNT"
echo "失败: $(wc -l < $FAILED_LOG 2>/dev/null || echo 0)"
[[ -s $FAILED_LOG ]] && echo "失败列表详见: $FAILED_LOG"

# 清理临时文件
rm $TMP_IMAGE_LIST