Skip to content

Commit

Permalink
feat: working dir gets higher precedence while fetching app files
Browse files Browse the repository at this point in the history
  • Loading branch information
nettoclaudio committed Feb 23, 2023
1 parent 578d6b9 commit 8ca79f4
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 28 deletions.
28 changes: 15 additions & 13 deletions pkg/build/buildkit/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,12 @@ func (b *BuildKit) buildFromAppSourceFiles(ctx context.Context, r *pb.BuildReque
return nil, err
}

// NOTE(nettoclaudio): Some platforms doesn't require an user-defined Procfile (e.g. go, java, static, etc).
// NOTE(nettoclaudio): Some platforms don't require an user-defined Procfile (e.g. go, java, static, etc).
// So we need to retrieve the default Procfile from the platform image.
if appFiles.Procfile == "" {
fmt.Fprintln(w, "User-defined Procfile not found, trying to extract it from platform's container image")

tc, err := b.extractTsuruConfigsFromContainerImage(ctx, r.DestinationImages[0])
tc, err := b.extractTsuruConfigsFromContainerImage(ctx, r.DestinationImages[0], build.DefaultTsuruPlatformWorkingDir)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -177,7 +177,7 @@ func (b *BuildKit) buildFromContainerImage(ctx context.Context, r *pb.BuildReque
return nil, err
}

appFiles, err := b.callBuildKitToExtractTsuruConfigs(ctx, tmpDir)
appFiles, err := b.callBuildKitToExtractTsuruConfigs(ctx, tmpDir, imageConfig.WorkingDir)
if err != nil {
return nil, err
}
Expand All @@ -186,17 +186,17 @@ func (b *BuildKit) buildFromContainerImage(ctx context.Context, r *pb.BuildReque
return appFiles, nil
}

func (b *BuildKit) extractTsuruConfigsFromContainerImage(ctx context.Context, image string) (*pb.TsuruConfig, error) {
func (b *BuildKit) extractTsuruConfigsFromContainerImage(ctx context.Context, image, workingDir string) (*pb.TsuruConfig, error) {
tmpDir, cleanFunc, err := generateBuildLocalDir(ctx, b.opts.TempDir, fmt.Sprintf("FROM %s", image), nil, nil, nil)
if err != nil {
return nil, err
}
defer cleanFunc()

return b.callBuildKitToExtractTsuruConfigs(ctx, tmpDir)
return b.callBuildKitToExtractTsuruConfigs(ctx, tmpDir, workingDir)
}

func (b *BuildKit) callBuildKitToExtractTsuruConfigs(ctx context.Context, localContextDir string) (*pb.TsuruConfig, error) {
func (b *BuildKit) callBuildKitToExtractTsuruConfigs(ctx context.Context, localContextDir, workingDir string) (*pb.TsuruConfig, error) {
eg, ctx := errgroup.WithContext(ctx)
pr, pw := io.Pipe() // reader/writer for tar output

Expand Down Expand Up @@ -231,7 +231,7 @@ func (b *BuildKit) callBuildKitToExtractTsuruConfigs(ctx context.Context, localC
var tc *pb.TsuruConfig
eg.Go(func() error {
var err error
tc, err = build.ExtractTsuruAppFilesFromContainerImageTarball(ctx, pr)
tc, err = build.ExtractTsuruAppFilesFromContainerImageTarball(ctx, pr, workingDir)
return err
})

Expand Down Expand Up @@ -387,21 +387,23 @@ func (b *BuildKit) buildFromContainerFile(ctx context.Context, r *pb.BuildReques
return nil, err
}

tc, err := b.extractTsuruConfigsFromContainerImage(ctx, r.DestinationImages[0])
if err != nil {
return nil, err
}

var insecureRegistry bool
if r.PushOptions != nil {
insecureRegistry = r.PushOptions.InsecureRegistry
}

tc.ImageConfig, err = extractContainerImageConfigFromImageManifest(ctx, r.DestinationImages[0], insecureRegistry)
ic, err := extractContainerImageConfigFromImageManifest(ctx, r.DestinationImages[0], insecureRegistry)
if err != nil {
return nil, err
}

tc, err := b.extractTsuruConfigsFromContainerImage(ctx, r.DestinationImages[0], ic.WorkingDir)
if err != nil {
return nil, err
}

tc.ImageConfig = ic

return tc, nil
}

Expand Down
40 changes: 40 additions & 0 deletions pkg/build/buildkit/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,46 @@ CMD ["--port", "8080"]
},
}, appFiles)
})

t.Run("using a different working directory, should get Procfile and Tsuru YAML from that", func(t *testing.T) {
destImage := baseRegistry(t, "my-app", "")

dockerfile := `FROM busybox
RUN set -xef \
&& mkdir -p /var/my-app \
&& echo "web: /path/to/server.sh --port 8888" > /var/my-app/Procfile \
&& echo -e "healthcheck:\n path: /healthz\n" > /var/my-app/tsuru.yaml
WORKDIR /var/my-app
EXPOSE 8888/tcp
`

req := &pb.BuildRequest{
Kind: pb.BuildKind_BUILD_KIND_APP_BUILD_WITH_CONTAINER_FILE,
App: &pb.TsuruApp{
Name: "my-app",
},
DestinationImages: []string{destImage},
Containerfile: string(dockerfile),
PushOptions: &pb.PushOptions{
InsecureRegistry: registryHTTP,
},
}

appFiles, err := NewBuildKit(bc, BuildKitOptions{TempDir: t.TempDir()}).Build(context.TODO(), req, os.Stdout)
require.NoError(t, err)
assert.Equal(t, &pb.TsuruConfig{
Procfile: "web: /path/to/server.sh --port 8888\n",
TsuruYaml: "healthcheck:\n path: /healthz\n\n",
ImageConfig: &pb.ContainerImageConfig{
Cmd: []string{"sh"},
ExposedPorts: []string{"8888/tcp"},
WorkingDir: "/var/my-app",
},
}, appFiles)
})
}

func compressGZIP(t *testing.T, path string) []byte {
Expand Down
35 changes: 25 additions & 10 deletions pkg/build/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,18 @@ func IsTsuruYaml(filename string) bool {

type TsuruYamlCandidates map[string]string

func (c TsuruYamlCandidates) String() string {
for _, dir := range TsuruConfigDirs {
func (c TsuruYamlCandidates) Pick(workingDir string) string {
dirs := make([]string, 0, (len(TsuruConfigDirs) + 1))

if workingDir != "" {
dirs = append(dirs, workingDir) // added first to get higher precedence
}

dirs = append(dirs, TsuruConfigDirs...)

for _, dir := range dirs {
for _, baseName := range TsuruYamlNames {
filename := filepath.Join(dir, baseName)

if s, found := c[filename]; found {
return s
}
Expand All @@ -65,8 +72,16 @@ func IsProcfile(filename string) bool {

type ProcfileCandidates map[string]string

func (c ProcfileCandidates) String() string {
for _, dir := range TsuruConfigDirs {
func (c ProcfileCandidates) Pick(workingDir string) string {
dirs := make([]string, 0, (len(TsuruConfigDirs) + 1))

if workingDir != "" {
dirs = append(dirs, workingDir) // added first to get higher precedence
}

dirs = append(dirs, TsuruConfigDirs...)

for _, dir := range dirs {
filename := filepath.Join(dir, ProcfileName)
if s, found := c[filename]; found {
return s
Expand Down Expand Up @@ -118,12 +133,12 @@ func ExtractTsuruAppFilesFromAppSourceContext(ctx context.Context, r io.Reader)
}

return &pb.TsuruConfig{
Procfile: procfile.String(),
TsuruYaml: tsuruYaml.String(),
Procfile: procfile.Pick(DefaultTsuruPlatformWorkingDir),
TsuruYaml: tsuruYaml.Pick(DefaultTsuruPlatformWorkingDir),
}, nil
}

func ExtractTsuruAppFilesFromContainerImageTarball(ctx context.Context, r io.Reader) (*pb.TsuruConfig, error) {
func ExtractTsuruAppFilesFromContainerImageTarball(ctx context.Context, r io.Reader, workingDir string) (*pb.TsuruConfig, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
Expand Down Expand Up @@ -158,8 +173,8 @@ func ExtractTsuruAppFilesFromContainerImageTarball(ctx context.Context, r io.Rea
}

return &pb.TsuruConfig{
Procfile: procfile.String(),
TsuruYaml: tsuruYaml.String(),
Procfile: procfile.Pick(workingDir),
TsuruYaml: tsuruYaml.Pick(workingDir),
}, nil
}

Expand Down
54 changes: 49 additions & 5 deletions pkg/build/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,12 @@ func TestIsTsuruYaml(t *testing.T) {
}
}

func TestTsuruYamlCandidates_String(t *testing.T) {
func TestTsuruYamlCandidates_Pick(t *testing.T) {
t.Parallel()

cases := []struct {
candidates TsuruYamlCandidates
workingDir string
expected string
}{
{},
Expand Down Expand Up @@ -112,20 +113,41 @@ func TestTsuruYamlCandidates_String(t *testing.T) {
},
expected: "# Tsuru YAML from tsuru.yaml",
},
{
workingDir: "/var/www/html",
candidates: TsuruYamlCandidates{
"/var/www/html/tsuru.yaml": "# Tsuru YAML from tsuru.yaml",
"/home/application/current/tsuru.yaml": "--------------------",
"/app/user/tsuru.yaml": "--------------------",
"/tsuru.yaml": "--------------------",
},
expected: "# Tsuru YAML from tsuru.yaml",
},
{
workingDir: "/not/found",
candidates: TsuruYamlCandidates{
"/var/www/html/tsuru.yaml": "--------------------",
"/home/application/current/tsuru.yaml": "# Tsuru YAML from tsuru.yaml",
"/app/user/tsuru.yaml": "--------------------",
"/tsuru.yaml": "--------------------",
},
expected: "# Tsuru YAML from tsuru.yaml",
},
}

for _, tt := range cases {
t.Run("", func(t *testing.T) {
assert.Equal(t, tt.expected, tt.candidates.String())
assert.Equal(t, tt.expected, tt.candidates.Pick(tt.workingDir))
})
}
}

func TestProcfileCandidates_String(t *testing.T) {
func TestProcfileCandidates_Pick(t *testing.T) {
t.Parallel()

cases := []struct {
candidates ProcfileCandidates
workingDir string
expected string
}{
{},
Expand Down Expand Up @@ -158,10 +180,32 @@ func TestProcfileCandidates_String(t *testing.T) {
"/home/application/current/demo/Procfile": "--------------------",
},
},
{
workingDir: "/var/www/html",
candidates: ProcfileCandidates{
"/var/www/html/Procfile": "web: ./path/to/server.sh --port ${PORT}",
"/home/application/current/Procfile": "--------------------",
"/app/user/Procfile": "--------------------",
"/Procfile": "--------------------",
},
expected: "web: ./path/to/server.sh --port ${PORT}",
},
{
workingDir: "/not/found",
candidates: ProcfileCandidates{
"/var/www/html/Procfile": "--------------------",
"/home/application/current/Procfile": "web: ./path/to/server.sh --port ${PORT}",
"/app/user/Procfile": "--------------------",
"/Procfile": "--------------------",
},
expected: "web: ./path/to/server.sh --port ${PORT}",
},
}

for _, tt := range cases {
assert.Equal(t, tt.expected, tt.candidates.String())
t.Run("", func(t *testing.T) {
assert.Equal(t, tt.expected, tt.candidates.Pick(tt.workingDir))
})
}
}

Expand Down Expand Up @@ -266,7 +310,7 @@ func TestExtractTsuruAppFilesFromContainerImageTarball(t *testing.T) {
for _, tt := range cases {
t.Run("", func(t *testing.T) {
require.NotNil(t, tt.file)
tsuruFiles, err := ExtractTsuruAppFilesFromContainerImageTarball(context.TODO(), tt.file(t))
tsuruFiles, err := ExtractTsuruAppFilesFromContainerImageTarball(context.TODO(), tt.file(t), "")
if err != nil {
require.EqualError(t, err, tt.expectedError)
return
Expand Down

0 comments on commit 8ca79f4

Please sign in to comment.