Просмотр исходного кода

优化upgrade.service自动升级服务编码,使其支持安装依赖目录,如: lib/、config/等

niujiuru 2 дней назад
Родитель
Сommit
f0244ff21a
1 измененных файлов с 78 добавлено и 14 удалено
  1. 78 14
      upgrade.service/upgrade.go

+ 78 - 14
upgrade.service/upgrade.go

@@ -24,6 +24,7 @@ type serviceUpgradeConfig struct {
 	CheckVerURL string
 	ClonePkgURL string
 	InstallPath string
+	ReplaceDirs []string
 }
 
 var upgradeServices = []serviceUpgradeConfig{
@@ -54,6 +55,7 @@ var upgradeServices = []serviceUpgradeConfig{
 		CheckVerURL: "",
 		ClonePkgURL: "",
 		InstallPath: "/opt/yfkj/camera-capture.service",
+		ReplaceDirs: []string{"lib"},
 	},
 	{ // 5, 应用安装服务
 		Name:        "app-install",
@@ -133,12 +135,12 @@ func (p *program) checkUpgrade() {
 
 		oldVersion, newVersion, upgraded, err := p.upgradeService(service)
 		if err != nil {
-			baseapp.Logger.Errorf("[%s] 服务 yfkj-%s.service 自动升级失败: %v!!", p.name, service.Name, err)
+			baseapp.Logger.Errorf("[%s] yfkj-%s.service 自动升级失败: %v!!", p.name, service.Name, err)
 			continue
 		}
 
 		if upgraded {
-			baseapp.Logger.Infof("[%s] 服务 yfkj-%s.service 自动升级成功: %s -> %s", p.name, service.Name, oldVersion, newVersion)
+			baseapp.Logger.Infof("[%s] yfkj-%s.service 自动升级成功: %s -> %s", p.name, service.Name, oldVersion, newVersion)
 		}
 	}
 }
@@ -239,19 +241,19 @@ func getFtpUpgradeInfo(ctx context.Context, u *servicelib.UpgradeURL, timeout ti
 	info.SHA256 = strings.TrimSpace(info.SHA256)
 
 	if info.Version == "" {
-		return upgradeInfo{}, fmt.Errorf("版本号字段为空")
+		return upgradeInfo{}, fmt.Errorf("版本号为空")
 	}
 
 	if info.SHA256 == "" {
-		return upgradeInfo{}, fmt.Errorf("SHA256字段为空")
+		return upgradeInfo{}, fmt.Errorf("校验值为空")
 	}
 
 	if len(info.SHA256) != 64 {
-		return upgradeInfo{}, fmt.Errorf("SHA256格式错误")
+		return upgradeInfo{}, fmt.Errorf("校验值长度错误")
 	}
 
 	if _, err := hex.DecodeString(info.SHA256); err != nil {
-		return upgradeInfo{}, fmt.Errorf("SHA256格式错误")
+		return upgradeInfo{}, fmt.Errorf("校验值格式错误")
 	}
 
 	return info, nil
@@ -321,18 +323,81 @@ func nextVersionDir(currentDir string) string {
 	}
 }
 
-// 升级包仅包含与服务同名的可执行程序,只解压该程序
+// 升级包默认包含与服务同名的可执行程序,之后再解压
 func installPackage(pkg string, targetDir string, service serviceUpgradeConfig) error {
-	if err := os.MkdirAll(targetDir, 0755); err != nil {
-		return fmt.Errorf("创建版本目录失败: %w", err)
+	tempDir, err := os.MkdirTemp(service.InstallPath, ".upgrade-")
+	if err != nil {
+		return fmt.Errorf("创建临时目录未成功: %w", err)
 	}
+	defer os.RemoveAll(tempDir)
 
-	cmd := exec.Command("tar", "-xzf", pkg, "-C", targetDir, service.Name)
-
+	cmd := exec.Command("tar", "-xzf", pkg, "-C", tempDir)
 	output, err := cmd.CombinedOutput()
 	if err != nil {
-		return fmt.Errorf("安装 %s 失败: %w: %s", service.Name, err,
-			strings.TrimSpace(string(output)))
+		return fmt.Errorf("解压%s升级包未成功: %w: %s", service.Name, err, strings.TrimSpace(string(output)))
+	}
+
+	program := filepath.Join(tempDir, service.Name)
+	if _, err := os.Stat(program); err != nil {
+		return fmt.Errorf("检查%s服务程序失败: %w", service.Name, err)
+	}
+
+	if err := os.MkdirAll(targetDir, 0755); err != nil {
+		return fmt.Errorf("创建%s版本目录失败: %w", service.Name, err)
+	}
+
+	if err := os.Rename(program, filepath.Join(targetDir, service.Name)); err != nil {
+		return fmt.Errorf("安装%s服务程序失败: %w", service.Name, err)
+	}
+
+	if err := replacePackageDirs(tempDir, service.InstallPath, service.ReplaceDirs); err != nil {
+		return fmt.Errorf("安装%s服务目录失败: %w", service.Name, err)
+	}
+
+	return nil
+}
+
+// 替换升级包中的附加目录,可用于升级服务的依赖库等
+func replacePackageDirs(tempDir string, targetBaseDir string, dirs []string) error {
+	for _, name := range dirs {
+		srcDir := filepath.Join(tempDir, name)
+		if _, err := os.Stat(srcDir); err != nil {
+			if os.IsNotExist(err) { //// 如果升级包中没有该目录
+				continue
+			}
+			return fmt.Errorf("检查%s目录失败: %w", name, err)
+		}
+
+		targetDir := filepath.Join(targetBaseDir, name)
+		newDir := filepath.Join(targetBaseDir, "."+name+"-new")
+		oldDir := filepath.Join(targetBaseDir, "."+name+"-old")
+
+		if err := os.RemoveAll(newDir); err != nil {
+			return fmt.Errorf("清理%s目录失败: %w", name, err)
+		}
+
+		if err := os.RemoveAll(oldDir); err != nil {
+			return fmt.Errorf("清理%s目录失败: %w", name, err)
+		}
+
+		if err := os.Rename(srcDir, newDir); err != nil {
+			return fmt.Errorf("移动%s目录失败: %w", name, err)
+		}
+
+		if err := os.Rename(targetDir, oldDir); err != nil && !os.IsNotExist(err) {
+			return fmt.Errorf("备份%s目录失败: %w", name, err)
+		}
+
+		if err := os.Rename(newDir, targetDir); err != nil {
+			if _, statErr := os.Stat(oldDir); statErr == nil {
+				_ = os.Rename(oldDir, targetDir) ///// 还原旧目录
+			}
+			return fmt.Errorf("替换%s目录失败: %w", name, err)
+		}
+
+		if err := os.RemoveAll(oldDir); err != nil {
+			return fmt.Errorf("删除%s目录失败: %w", name, err)
+		}
 	}
 
 	return nil
@@ -366,7 +431,6 @@ func switchServiceVersion(serviceName string, installPath string, targetName str
 
 	if err := exec.Command("systemctl", "start", service).Run(); err != nil {
 		startErr := err
-		_ = os.Remove(tempLink)
 
 		if err := os.Symlink(currentTarget, tempLink); err == nil {
 			if err := os.Rename(tempLink, currentLink); err == nil {