Enhance logging and context handling in job management. Introduce a logger initialization with configurable parameters in the manager and runner commands. Update job context handling to use tar files instead of tar.gz, and implement ETag generation for improved caching. Refactor API endpoints to support new context file structure and enhance error handling in job submissions. Add support for unhide objects and auto-execution options in job creation requests.
This commit is contained in:
@@ -3,9 +3,9 @@ package storage
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -31,6 +31,7 @@ func (s *Storage) init() error {
|
||||
s.basePath,
|
||||
s.uploadsPath(),
|
||||
s.outputsPath(),
|
||||
s.tempPath(),
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
@@ -42,6 +43,28 @@ func (s *Storage) init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// tempPath returns the path for temporary files
|
||||
func (s *Storage) tempPath() string {
|
||||
return filepath.Join(s.basePath, "temp")
|
||||
}
|
||||
|
||||
// BasePath returns the storage base path (for cleanup tasks)
|
||||
func (s *Storage) BasePath() string {
|
||||
return s.basePath
|
||||
}
|
||||
|
||||
// TempDir creates a temporary directory under the storage base path
|
||||
// Returns the path to the temporary directory
|
||||
func (s *Storage) TempDir(pattern string) (string, error) {
|
||||
// Ensure temp directory exists
|
||||
if err := os.MkdirAll(s.tempPath(), 0755); err != nil {
|
||||
return "", fmt.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
|
||||
// Create temp directory under storage base path
|
||||
return os.MkdirTemp(s.tempPath(), pattern)
|
||||
}
|
||||
|
||||
// uploadsPath returns the path for uploads
|
||||
func (s *Storage) uploadsPath() string {
|
||||
return filepath.Join(s.basePath, "uploads")
|
||||
@@ -142,6 +165,13 @@ func (s *Storage) GetFileSize(filePath string) (int64, error) {
|
||||
// ExtractZip extracts a ZIP file to the destination directory
|
||||
// Returns a list of all extracted file paths
|
||||
func (s *Storage) ExtractZip(zipPath, destDir string) ([]string, error) {
|
||||
log.Printf("Extracting ZIP archive: %s -> %s", zipPath, destDir)
|
||||
|
||||
// Ensure destination directory exists
|
||||
if err := os.MkdirAll(destDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create destination directory: %w", err)
|
||||
}
|
||||
|
||||
r, err := zip.OpenReader(zipPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open ZIP file: %w", err)
|
||||
@@ -149,12 +179,20 @@ func (s *Storage) ExtractZip(zipPath, destDir string) ([]string, error) {
|
||||
defer r.Close()
|
||||
|
||||
var extractedFiles []string
|
||||
fileCount := 0
|
||||
dirCount := 0
|
||||
|
||||
log.Printf("ZIP contains %d entries", len(r.File))
|
||||
|
||||
for _, f := range r.File {
|
||||
// Sanitize file path to prevent directory traversal
|
||||
destPath := filepath.Join(destDir, f.Name)
|
||||
if !strings.HasPrefix(destPath, filepath.Clean(destDir)+string(os.PathSeparator)) {
|
||||
return nil, fmt.Errorf("invalid file path in ZIP: %s", f.Name)
|
||||
|
||||
cleanDestPath := filepath.Clean(destPath)
|
||||
cleanDestDir := filepath.Clean(destDir)
|
||||
if !strings.HasPrefix(cleanDestPath, cleanDestDir+string(os.PathSeparator)) && cleanDestPath != cleanDestDir {
|
||||
log.Printf("ERROR: Invalid file path in ZIP - target: %s, destDir: %s", cleanDestPath, cleanDestDir)
|
||||
return nil, fmt.Errorf("invalid file path in ZIP: %s (target: %s, destDir: %s)", f.Name, cleanDestPath, cleanDestDir)
|
||||
}
|
||||
|
||||
// Create directory structure
|
||||
@@ -162,6 +200,7 @@ func (s *Storage) ExtractZip(zipPath, destDir string) ([]string, error) {
|
||||
if err := os.MkdirAll(destPath, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create directory: %w", err)
|
||||
}
|
||||
dirCount++
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -191,8 +230,10 @@ func (s *Storage) ExtractZip(zipPath, destDir string) ([]string, error) {
|
||||
}
|
||||
|
||||
extractedFiles = append(extractedFiles, destPath)
|
||||
fileCount++
|
||||
}
|
||||
|
||||
log.Printf("ZIP extraction complete: %d files, %d directories extracted to %s", fileCount, dirCount, destDir)
|
||||
return extractedFiles, nil
|
||||
}
|
||||
|
||||
@@ -261,15 +302,15 @@ func isBlenderSaveFile(filename string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CreateJobContext creates a tar.gz archive containing all job input files
|
||||
// CreateJobContext creates a tar archive containing all job input files
|
||||
// Filters out Blender save files (.blend1, .blend2, etc.)
|
||||
// Uses temporary directories and streaming to handle large files efficiently
|
||||
func (s *Storage) CreateJobContext(jobID int64) (string, error) {
|
||||
jobPath := s.JobPath(jobID)
|
||||
contextPath := filepath.Join(jobPath, "context.tar.gz")
|
||||
contextPath := filepath.Join(jobPath, "context.tar")
|
||||
|
||||
// Create temporary directory for staging
|
||||
tmpDir, err := os.MkdirTemp("", "fuego-context-*")
|
||||
tmpDir, err := os.MkdirTemp("", "jiggablend-context-*")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temporary directory: %w", err)
|
||||
}
|
||||
@@ -320,17 +361,14 @@ func (s *Storage) CreateJobContext(jobID int64) (string, error) {
|
||||
return "", fmt.Errorf("no files found to include in context")
|
||||
}
|
||||
|
||||
// Create the tar.gz file using streaming
|
||||
// Create the tar file using streaming
|
||||
contextFile, err := os.Create(contextPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create context file: %w", err)
|
||||
}
|
||||
defer contextFile.Close()
|
||||
|
||||
gzWriter := gzip.NewWriter(contextFile)
|
||||
defer gzWriter.Close()
|
||||
|
||||
tarWriter := tar.NewWriter(gzWriter)
|
||||
tarWriter := tar.NewWriter(contextFile)
|
||||
defer tarWriter.Close()
|
||||
|
||||
// Add each file to the tar archive
|
||||
@@ -383,9 +421,6 @@ func (s *Storage) CreateJobContext(jobID int64) (string, error) {
|
||||
if err := tarWriter.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close tar writer: %w", err)
|
||||
}
|
||||
if err := gzWriter.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close gzip writer: %w", err)
|
||||
}
|
||||
if err := contextFile.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close context file: %w", err)
|
||||
}
|
||||
@@ -393,12 +428,12 @@ func (s *Storage) CreateJobContext(jobID int64) (string, error) {
|
||||
return contextPath, nil
|
||||
}
|
||||
|
||||
// CreateJobContextFromDir creates a context archive (tar.gz) from files in a source directory
|
||||
// CreateJobContextFromDir creates a context archive (tar) from files in a source directory
|
||||
// This is used during upload to immediately create the context archive as the primary artifact
|
||||
// excludeFiles is a set of relative paths (from sourceDir) to exclude from the context
|
||||
func (s *Storage) CreateJobContextFromDir(sourceDir string, jobID int64, excludeFiles ...string) (string, error) {
|
||||
jobPath := s.JobPath(jobID)
|
||||
contextPath := filepath.Join(jobPath, "context.tar.gz")
|
||||
contextPath := filepath.Join(jobPath, "context.tar")
|
||||
|
||||
// Ensure job directory exists
|
||||
if err := os.MkdirAll(jobPath, 0755); err != nil {
|
||||
@@ -498,17 +533,14 @@ func (s *Storage) CreateJobContextFromDir(sourceDir string, jobID int64, exclude
|
||||
return "", fmt.Errorf("multiple .blend files found at root level in context archive (found %d, expected 1)", blendFilesAtRoot)
|
||||
}
|
||||
|
||||
// Create the tar.gz file using streaming
|
||||
// Create the tar file using streaming
|
||||
contextFile, err := os.Create(contextPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create context file: %w", err)
|
||||
}
|
||||
defer contextFile.Close()
|
||||
|
||||
gzWriter := gzip.NewWriter(contextFile)
|
||||
defer gzWriter.Close()
|
||||
|
||||
tarWriter := tar.NewWriter(gzWriter)
|
||||
tarWriter := tar.NewWriter(contextFile)
|
||||
defer tarWriter.Close()
|
||||
|
||||
// Add each file to the tar archive
|
||||
@@ -560,9 +592,6 @@ func (s *Storage) CreateJobContextFromDir(sourceDir string, jobID int64, exclude
|
||||
if err := tarWriter.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close tar writer: %w", err)
|
||||
}
|
||||
if err := gzWriter.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close gzip writer: %w", err)
|
||||
}
|
||||
if err := contextFile.Close(); err != nil {
|
||||
return "", fmt.Errorf("failed to close context file: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user