Fix repository cloning when running inside a container

Use DataDir/builds instead of /tmp for clone directories so that bind
mounts work correctly when upaas itself runs in a Docker container.
The /tmp directory inside the upaas container isn't accessible to the
Docker daemon on the host, causing bind mount failures.

Also fix test setups to pass Config to deploy service and add delay
to webhook test to avoid temp directory cleanup race with async
deployment goroutine.
This commit is contained in:
Jeffrey Paul 2025-12-29 17:02:01 +07:00
parent 5dc454d752
commit dc6500eac6
3 changed files with 22 additions and 2 deletions

View File

@ -7,6 +7,7 @@ import (
"net/url" "net/url"
"strings" "strings"
"testing" "testing"
"time"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -115,6 +116,7 @@ func createAppServices(
deploySvc, deployErr := deploy.New(fx.Lifecycle(nil), deploy.ServiceParams{ deploySvc, deployErr := deploy.New(fx.Lifecycle(nil), deploy.ServiceParams{
Logger: logInstance, Logger: logInstance,
Config: cfg,
Database: dbInstance, Database: dbInstance,
Docker: dockerClient, Docker: dockerClient,
Notify: notifySvc, Notify: notifySvc,
@ -484,4 +486,9 @@ func TestHandleWebhookProcessesValidWebhook(t *testing.T) {
handler.ServeHTTP(recorder, request) handler.ServeHTTP(recorder, request)
assert.Equal(t, http.StatusOK, recorder.Code) assert.Equal(t, http.StatusOK, recorder.Code)
// Allow async deployment goroutine to complete before test cleanup.
// The deployment will fail quickly (docker not connected) but we need
// to wait for it to finish to avoid temp directory cleanup race.
time.Sleep(100 * time.Millisecond)
} }

View File

@ -26,6 +26,8 @@ const (
healthCheckDelaySeconds = 60 healthCheckDelaySeconds = 60
// upaasLabelCount is the number of upaas-specific labels added to containers. // upaasLabelCount is the number of upaas-specific labels added to containers.
upaasLabelCount = 1 upaasLabelCount = 1
// buildsDirPermissions is the permission mode for the builds directory.
buildsDirPermissions = 0o750
) )
// Sentinel errors for deployment failures. // Sentinel errors for deployment failures.
@ -202,7 +204,18 @@ func (svc *Service) cloneRepository(
app *models.App, app *models.App,
deployment *models.Deployment, deployment *models.Deployment,
) (string, func(), error) { ) (string, func(), error) {
tempDir, err := os.MkdirTemp("", "upaas-"+app.ID+"-*") // Use a subdirectory of DataDir for builds since it's mounted from the host
// and accessible to Docker for bind mounts (unlike /tmp inside the container)
buildsDir := filepath.Join(svc.config.DataDir, "builds")
err := os.MkdirAll(buildsDir, buildsDirPermissions)
if err != nil {
svc.failDeployment(ctx, app, deployment, fmt.Errorf("failed to create builds dir: %w", err))
return "", nil, fmt.Errorf("failed to create builds dir: %w", err)
}
tempDir, err := os.MkdirTemp(buildsDir, app.ID+"-*")
if err != nil { if err != nil {
svc.failDeployment(ctx, app, deployment, fmt.Errorf("failed to create temp dir: %w", err)) svc.failDeployment(ctx, app, deployment, fmt.Errorf("failed to create temp dir: %w", err))

View File

@ -63,7 +63,7 @@ func setupTestService(t *testing.T) (*webhook.Service, *database.Database, func(
require.NoError(t, err) require.NoError(t, err)
deploySvc, err := deploy.New(fx.Lifecycle(nil), deploy.ServiceParams{ deploySvc, err := deploy.New(fx.Lifecycle(nil), deploy.ServiceParams{
Logger: deps.logger, Database: deps.db, Docker: dockerClient, Notify: notifySvc, Logger: deps.logger, Config: deps.config, Database: deps.db, Docker: dockerClient, Notify: notifySvc,
}) })
require.NoError(t, err) require.NoError(t, err)