Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 0 additions & 53 deletions cli/src/internal/gateway/docker_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package gateway

import (
"errors"
"fmt"
"os"
"os/exec"
Expand Down Expand Up @@ -70,14 +69,6 @@ func BuildGatewayImages(config DockerBuildConfig) error {
}
}

if err := ensureBuildLockInControllerContext(config.TempDir); err != nil {
return err
}

if err := ensurePythonExecutorInRuntimeContext(config.TempDir); err != nil {
return err
}

fmt.Println(" ✓ Gateway-builder completed")

// Step 2: Build the two images
Expand Down Expand Up @@ -105,50 +96,6 @@ func BuildGatewayImages(config DockerBuildConfig) error {
return nil
}

func ensureBuildLockInControllerContext(tempDir string) error {
buildManifestSrc := filepath.Join(tempDir, "build-manifest.yaml")
if _, err := os.Stat(buildManifestSrc); err != nil {
return fmt.Errorf("build-manifest.yaml not found in gateway-builder output: %w", err)
}

buildManifestDst := filepath.Join(tempDir, "output", "gateway-controller", "build-manifest.yaml")
if _, err := os.Stat(buildManifestDst); err == nil {
return nil
} else if !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("failed to access gateway-controller build-manifest.yaml: %w", err)
}

if err := utils.CopyFile(buildManifestSrc, buildManifestDst); err != nil {
return fmt.Errorf("failed to copy build-manifest.yaml into gateway-controller build context: %w", err)
}

return nil
}

// ensurePythonExecutorInRuntimeContext stages the python-executor directory
// produced by gateway-builder into the gateway-runtime Docker build context
// so the Dockerfile's `COPY python-executor/ ...` can resolve it.
func ensurePythonExecutorInRuntimeContext(tempDir string) error {
pythonExecutorSrc := filepath.Join(tempDir, "output", "python-executor")
if _, err := os.Stat(pythonExecutorSrc); err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil
}
return fmt.Errorf("failed to access python-executor output: %w", err)
}

pythonExecutorDst := filepath.Join(tempDir, "output", "gateway-runtime", "python-executor")
if err := os.RemoveAll(pythonExecutorDst); err != nil {
return fmt.Errorf("failed to clear existing python-executor in gateway-runtime build context: %w", err)
}

if err := utils.CopyDir(pythonExecutorSrc, pythonExecutorDst); err != nil {
return fmt.Errorf("failed to copy python-executor into gateway-runtime build context: %w", err)
}

return nil
}

// runGatewayBuilder runs the gateway-builder container
func runGatewayBuilder(config DockerBuildConfig, logFile *os.File) error {
args := []string{"run", "--rm", "-v", config.TempDir + ":/workspace", config.GatewayBuilder,
Expand Down
14 changes: 14 additions & 0 deletions gateway/gateway-builder/cmd/builder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,20 @@ func main() {
errors.FatalError(errors.NewDockerError("Dockerfile generation failed", err))
}

// Stage python-executor into the gateway-runtime build context so that the
// Dockerfile's `COPY python-executor/ ...` directive resolves correctly when the
// CLI later runs `docker build` on the output directory. Doing this here (inside
// the container) avoids a host-side file operation on root-owned output files,
// which fails with permission denied when using a rootful Docker daemon on Linux.
pythonExecutorSrc := filepath.Join(*outputDir, "python-executor")
if _, statErr := os.Stat(pythonExecutorSrc); statErr == nil {
pythonExecutorDst := filepath.Join(*outputDir, "gateway-runtime", "python-executor")
if err := fsutil.CopyDir(pythonExecutorSrc, pythonExecutorDst); err != nil {
errors.FatalError(errors.NewGenerationError("failed to stage python-executor into gateway-runtime build context", err))
}
slog.Info("Staged python-executor into gateway-runtime build context", "dst", pythonExecutorDst)
}

// Phase 6: Build Info Generation
slog.Info("Starting Phase 6: Build Info Generation", "phase", "build-info")

Expand Down
22 changes: 22 additions & 0 deletions gateway/gateway-builder/pkg/fsutil/path_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"
)

// ValidatePathExists checks if a file or directory exists and is accessible.
Expand Down Expand Up @@ -52,6 +53,27 @@ func ValidatePathExists(path string, pathType string) error {
return fmt.Errorf("failed to access %s: %s: %w", pathType, path, err)
}

// CopyDir recursively copies src into dst, preserving file modes.
func CopyDir(src, dst string) error {
return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
rel, err := filepath.Rel(src, path)
if err != nil {
return err
}
target := filepath.Join(dst, rel)
if info.IsDir() {
return os.MkdirAll(target, info.Mode())
}
if !info.Mode().IsRegular() {
return nil
}
return CopyFile(path, target)
})
}

// CopyFile copies a file from src to dst
func CopyFile(src, dst string) error {
sourceFile, err := os.Open(src)
Expand Down
Loading