sync to github

This commit is contained in:
Alexander Renz 2024-12-02 11:11:56 +01:00
parent 330956ebc7
commit 4cfc5591f6

View File

@ -16,6 +16,7 @@ import (
"net/http"
"net/url"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
@ -97,6 +98,15 @@ type FileConfig struct {
FileRevision int `mapstructure:"FileRevision"`
}
// Configuration structure for ISO settings
type ISOConfig struct {
Enabled bool `mapstructure:"enabled"`
Size string `mapstructure:"size"`
MountPoint string `mapstructure:"mountpoint"`
Charset string `mapstructure:"charset"` // Add this line
}
// Add ISO configuration to the main configuration structure
type Config struct {
Server ServerConfig `mapstructure:"server"`
Timeouts TimeoutConfig `mapstructure:"timeouts"`
@ -107,6 +117,7 @@ type Config struct {
Redis RedisConfig `mapstructure:"redis"`
Workers WorkersConfig `mapstructure:"workers"`
File FileConfig `mapstructure:"file"`
ISO ISOConfig `mapstructure:"iso"`
}
// UploadTask represents a file upload task
@ -180,6 +191,14 @@ func main() {
}
log.Info("Configuration loaded successfully.")
// Verify and create ISO container if it doesn't exist
if conf.ISO.Enabled {
err = verifyAndCreateISOContainer()
if err != nil {
log.Fatalf("ISO container verification failed: %v", err)
}
}
// Initialize file info cache
fileInfoCache = cache.New(5*time.Minute, 10*time.Minute)
@ -338,6 +357,31 @@ func main() {
log.Fatalf("Server failed: %v", err)
}
}
// Example files to include in the ISO container
files := []string{"file1.txt", "file2.txt"}
isoPath := "/path/to/container.iso"
// Create ISO container
err = CreateISOContainer(files, isoPath, conf.ISO.Size, conf.ISO.Charset)
if err != nil {
fmt.Printf("Failed to create ISO container: %v\n", err)
return
}
// Mount ISO container
err = MountISOContainer(isoPath, conf.ISO.MountPoint)
if err != nil {
fmt.Printf("Failed to mount ISO container: %v\n", err)
return
}
// Unmount ISO container (example)
err = UnmountISOContainer(conf.ISO.MountPoint)
if err != nil {
fmt.Printf("Failed to unmount ISO container: %v\n", err)
return
}
}
// Function to load configuration using Viper
@ -427,6 +471,12 @@ func setDefaults() {
// Deduplication defaults
viper.SetDefault("deduplication.Enabled", true)
// ISO defaults
viper.SetDefault("iso.Enabled", true)
viper.SetDefault("iso.Size", "1GB")
viper.SetDefault("iso.MountPoint", "/mnt/iso")
viper.SetDefault("iso.Charset", "utf-8") // Add this line
}
// Validate configuration fields
@ -462,6 +512,19 @@ func validateConfig(conf *Config) error {
}
}
// Validate ISO configuration
if conf.ISO.Enabled {
if conf.ISO.Size == "" {
return fmt.Errorf("ISO size must be set")
}
if conf.ISO.MountPoint == "" {
return fmt.Errorf("ISO mount point must be set")
}
if conf.ISO.Charset == "" {
return fmt.Errorf("ISO charset must be set")
}
}
// Add more validations as needed
return nil
@ -765,6 +828,17 @@ func processUpload(task UploadTask) error {
log.Infof("Deduplication handled successfully for file: %s", absFilename)
}
// Handle ISO container if enabled
if conf.ISO.Enabled {
err = handleISOContainer(absFilename)
if err != nil {
log.WithError(err).Error("ISO container handling failed")
uploadErrorsTotal.Inc()
return err
}
log.Infof("ISO container handled successfully for file: %s", absFilename)
}
log.WithFields(logrus.Fields{
"file": absFilename,
}).Info("File uploaded and processed successfully")
@ -774,7 +848,7 @@ func processUpload(task UploadTask) error {
return nil
}
// uploadWorker processes upload tasks from the uploadQueue
// Improved uploadWorker function with better concurrency handling
func uploadWorker(ctx context.Context, workerID int) {
log.Infof("Upload worker %d started.", workerID)
defer log.Infof("Upload worker %d stopped.", workerID)
@ -801,7 +875,7 @@ func uploadWorker(ctx context.Context, workerID int) {
}
}
// Initialize upload worker pool
// Improved initializeUploadWorkerPool function
func initializeUploadWorkerPool(ctx context.Context) {
for i := 0; i < conf.Workers.NumWorkers; i++ {
go uploadWorker(ctx, i)
@ -1156,19 +1230,17 @@ func handleDownload(w http.ResponseWriter, r *http.Request, absFilename, fileSto
}
}
// Create the file for upload with buffered Writer
// Improved createFile function with proper resource management
func createFile(tempFilename string, r *http.Request) error {
absDirectory := filepath.Dir(tempFilename)
err := os.MkdirAll(absDirectory, os.ModePerm)
if err != nil {
log.WithError(err).Errorf("Failed to create directory %s", absDirectory)
return fmt.Errorf("failed to create directory %s: %w", absDirectory, err)
return err
}
// Open the file for writing
targetFile, err := os.OpenFile(tempFilename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
log.WithError(err).Errorf("Failed to create file %s", tempFilename)
return fmt.Errorf("failed to create file %s: %w", tempFilename, err)
}
defer targetFile.Close()
@ -1185,7 +1257,6 @@ func createFile(tempFilename string, r *http.Request) error {
totalBytes += int64(n)
_, writeErr := writer.Write(buffer[:n])
if writeErr != nil {
log.WithError(writeErr).Errorf("Failed to write to file %s", tempFilename)
return fmt.Errorf("failed to write to file %s: %w", tempFilename, writeErr)
}
}
@ -1193,14 +1264,12 @@ func createFile(tempFilename string, r *http.Request) error {
if readErr == io.EOF {
break
}
log.WithError(readErr).Error("Failed to read request body")
return fmt.Errorf("failed to read request body: %w", readErr)
}
}
err = writer.Flush()
if err != nil {
log.WithError(err).Errorf("Failed to flush buffer to file %s", tempFilename)
return fmt.Errorf("failed to flush buffer to file %s: %w", tempFilename, err)
}
@ -1595,7 +1664,7 @@ func MonitorRedisHealth(ctx context.Context, client *redis.Client, checkInterval
}
redisConnected = false
} else {
if (!redisConnected) {
if !redisConnected {
log.Info("Redis reconnected successfully")
}
redisConnected = true
@ -1738,7 +1807,7 @@ func computeFileHash(filePath string) (string, error) {
return hex.EncodeToString(hasher.Sum(nil)), nil
}
// handleMultipartUpload handles multipart file uploads
// handleMultipartUpload handles multipart uploads
func handleMultipartUpload(w http.ResponseWriter, r *http.Request, absFilename string) error {
err := r.ParseMultipartForm(32 << 20) // 32MB is the default used by FormFile
if err != nil {
@ -1978,3 +2047,137 @@ func checkFreeSpaceWithRetry(path string, retries int, delay time.Duration) erro
}
return fmt.Errorf("checkFreeSpace: insufficient free space after %d attempts", retries)
}
// CreateISOContainer creates an ISO container with the specified size
func CreateISOContainer(files []string, isoPath string, size string, charset string) error {
args := []string{"-o", isoPath, "-V", "ISO_CONTAINER", "-J", "-R", "-input-charset", charset}
args = append(args, files...)
cmd := exec.Command("genisoimage", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
// Improved logging and error handling
func MountISOContainer(isoPath string, mountPoint string) error {
// Ensure the mount point directory exists
if err := os.MkdirAll(mountPoint, os.ModePerm); err != nil {
return fmt.Errorf("failed to create mount point directory: %w", err)
}
var output []byte
var err error
for i := 0; i < 3; i++ {
cmd := exec.Command("mount", "-o", "loop,ro", isoPath, mountPoint)
output, err = cmd.CombinedOutput()
if err == nil {
log.Infof("ISO container mounted successfully at %s", mountPoint)
return nil
}
log.Warnf("Failed to mount ISO container (attempt %d/3): %v, output: %s", i+1, err, string(output))
time.Sleep(2 * time.Second)
}
return fmt.Errorf("failed to mount ISO container: %w, output: %s", err, string(output))
}
// UnmountISOContainer unmounts the ISO container from the specified mount point
func UnmountISOContainer(mountPoint string) error {
cmd := exec.Command("umount", mountPoint)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func handleISOContainer(absFilename string) error {
isoPath := filepath.Join(conf.ISO.MountPoint, "container.iso")
// Create ISO container
err := CreateISOContainer([]string{absFilename}, isoPath, conf.ISO.Size, conf.ISO.Charset)
if err != nil {
return fmt.Errorf("failed to create ISO container: %w", err)
}
// Ensure the mount point directory exists
if err := os.MkdirAll(conf.ISO.MountPoint, os.ModePerm); err != nil {
return fmt.Errorf("failed to create mount point directory: %w", err)
}
// Mount ISO container
err = MountISOContainer(isoPath, conf.ISO.MountPoint)
if err != nil {
return fmt.Errorf("failed to mount ISO container: %w", err)
}
// Unmount ISO container (example)
err = UnmountISOContainer(conf.ISO.MountPoint)
if err != nil {
return fmt.Errorf("failed to unmount ISO container: %w", err)
}
return nil
}
// Verify and create ISO container if it doesn't exist
func verifyAndCreateISOContainer() error {
isoPath := filepath.Join(conf.ISO.MountPoint, "container.iso")
// Check if ISO file exists
if exists, _ := fileExists(isoPath); !exists {
log.Infof("ISO container does not exist. Creating new ISO container at %s", isoPath)
// Example files to include in the ISO container
files := []string{conf.Server.StoragePath}
// Create ISO container
err := CreateISOContainer(files, isoPath, conf.ISO.Size, conf.ISO.Charset)
if err != nil {
return fmt.Errorf("failed to create ISO container: %w", err)
}
log.Infof("ISO container created successfully at %s", isoPath)
}
// Verify ISO file consistency
err := verifyISOFile(isoPath)
if err != nil {
// Handle corrupted ISO file
files := []string{conf.Server.StoragePath}
err = handleCorruptedISOFile(isoPath, files, conf.ISO.Size, conf.ISO.Charset)
if err != nil {
return fmt.Errorf("failed to handle corrupted ISO file: %w", err)
}
}
// Ensure the mount point directory exists
if err := os.MkdirAll(conf.ISO.MountPoint, os.ModePerm); err != nil {
return fmt.Errorf("failed to create mount point directory: %w", err)
}
// Mount ISO container
err = MountISOContainer(isoPath, conf.ISO.MountPoint)
if err != nil {
return fmt.Errorf("failed to mount ISO container: %w", err)
}
log.Infof("ISO container mounted successfully at %s", conf.ISO.MountPoint)
return nil
}
// Verify ISO file consistency using a checksum
func verifyISOFile(isoPath string) error {
cmd := exec.Command("isoinfo", "-i", isoPath, "-d")
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to verify ISO file: %w, output: %s", err, string(output))
}
return nil
}
// Handle corrupted ISO file by recreating it
func handleCorruptedISOFile(isoPath string, files []string, size string, charset string) error {
log.Warnf("ISO file %s is corrupted. Recreating it.", isoPath)
err := CreateISOContainer(files, isoPath, size, charset)
if err != nil {
return fmt.Errorf("failed to recreate ISO container: %w", err)
}
return nil
}