Add checksum verification and retry logic- Add SHA256 checksum verification for downloaded images- Add qemu-img check verification before and after operations- Add retry logic (3 attempts) for download, upload, and commands- Verify image integrity after customization- Verify uploaded image on Proxmox host before import- Auto-remove corrupted images and retry download

This commit is contained in:
2025-11-14 21:14:39 +07:00
parent 8d057bfd94
commit aea1b31115
3 changed files with 163 additions and 35 deletions

View File

@@ -82,11 +82,44 @@ func createProxmoxVM(config *Config) error {
remotePath := fmt.Sprintf("/tmp/%s", imageName)
fmt.Println("Uploading image to Proxmox host...")
cmd := scpCmd(config.ImageURL, remotePath)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("failed to upload image: %w", err)
maxRetries := 3
var uploadErr error
for attempt := 1; attempt <= maxRetries; attempt++ {
if attempt > 1 {
fmt.Printf("Retry upload attempt %d/%d...\n", attempt, maxRetries)
}
cmd := scpCmd(config.ImageURL, remotePath)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
uploadErr = cmd.Run()
if uploadErr == nil {
fmt.Println("Upload completed! Verifying uploaded image...")
verifyCmd := sshCmd("qemu-img", "check", remotePath)
var verifyOut bytes.Buffer
verifyCmd.Stdout = &verifyOut
verifyCmd.Stderr = &verifyOut
if err := verifyCmd.Run(); err != nil {
fmt.Printf("Remote image verification failed: %s\n", verifyOut.String())
if attempt < maxRetries {
fmt.Println("Re-uploading...")
sshCmd("rm", "-f", remotePath).Run()
continue
}
return fmt.Errorf("uploaded image verification failed after %d attempts", maxRetries)
}
fmt.Println("Remote image verification passed!")
break
}
if attempt == maxRetries {
return fmt.Errorf("failed to upload image after %d attempts: %w", maxRetries, uploadErr)
}
fmt.Printf("Upload failed: %v\n", uploadErr)
}
fmt.Println("Creating VM and converting to template...")
@@ -119,20 +152,35 @@ func createProxmoxVM(config *Config) error {
for _, cmdArgs := range commands {
fmt.Printf("Running: %s\n", strings.Join(cmdArgs, " "))
cmd := sshCmd(cmdArgs...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
var cmdErr error
for attempt := 1; attempt <= maxRetries; attempt++ {
if attempt > 1 {
fmt.Printf("Retry command attempt %d/%d...\n", attempt, maxRetries)
}
cmd := sshCmd(cmdArgs...)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmdErr = cmd.Run()
if cmdErr == nil {
if stdout.Len() > 0 {
fmt.Println(stdout.String())
}
break
}
if err := cmd.Run(); err != nil {
fmt.Println(stdout.String())
fmt.Println(stderr.String())
return fmt.Errorf("failed to execute command '%s': %w", strings.Join(cmdArgs, " "), err)
}
if stdout.Len() > 0 {
fmt.Println(stdout.String())
if attempt == maxRetries {
return fmt.Errorf("failed to execute command '%s' after %d attempts: %w", strings.Join(cmdArgs, " "), maxRetries, cmdErr)
}
fmt.Printf("Command failed: %v\n", cmdErr)
}
}