Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change workdir for gomplate #3684

Merged
merged 1 commit into from
Aug 7, 2024
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
46 changes: 27 additions & 19 deletions cmd/docker-entrypoint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,13 @@ func main() {
os.Exit(1)
}

if err := run(args, realExec, realWhich); err != nil {
if err := run(args, realExec, realWhich, realGomplate); err != nil {
fmt.Println("error:", err.Error())
os.Exit(1)
}
}

func realExec(fork bool, args ...string) error {
if fork {
if output, err := exec.Command(args[0], args[1:]...).CombinedOutput(); err != nil {
return fmt.Errorf("cannot fork/exec command %s: %w (output: %q)", args, err, string(output))
}
return nil
}

func realExec(args ...string) error {
argv0, err := exec.LookPath(args[0])
if err != nil {
return fmt.Errorf("cannot lookup path for command %s: %w", args[0], err)
Expand All @@ -56,34 +49,49 @@ func realWhich(path string) string {
return fullPath
}

func run(args []string, execFunc func(bool, ...string) error, whichFunc func(string) string) error {
func realGomplate(path string) (string, error) {
tmpFile, err := os.CreateTemp("/tmp", "dex.config.yaml-*")
if err != nil {
return "", fmt.Errorf("cannot create temp file: %w", err)
}

cmd := exec.Command("gomplate", "-f", path, "-o", tmpFile.Name())
// TODO(nabokihms): Workaround to run gomplate from a non-root directory in distroless images
// gomplate tries to access CWD on start, see: https://github.com/hairyhenderson/gomplate/pull/2202
cmd.Dir = "/etc/dex"

output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("error executing gomplate: %w, (output: %q)", err, string(output))
}

return tmpFile.Name(), nil
}

func run(args []string, execFunc func(...string) error, whichFunc func(string) string, gomplateFunc func(string) (string, error)) error {
if args[0] != "dex" && args[0] != whichFunc("dex") {
return execFunc(false, args...)
return execFunc(args...)
}

if args[1] != "serve" {
return execFunc(false, args...)
return execFunc(args...)
}

newArgs := []string{}
for _, tplCandidate := range args {
if hasSuffixes(tplCandidate, ".tpl", ".tmpl", ".yaml") {
tmpFile, err := os.CreateTemp("/tmp", "dex.config.yaml-*")
fileName, err := gomplateFunc(tplCandidate)
if err != nil {
return fmt.Errorf("cannot create temp file: %w", err)
}

if err := execFunc(true, "gomplate", "-f", tplCandidate, "-o", tmpFile.Name()); err != nil {
return err
}

newArgs = append(newArgs, tmpFile.Name())
newArgs = append(newArgs, fileName)
} else {
newArgs = append(newArgs, tplCandidate)
}
}

return execFunc(false, newArgs...)
return execFunc(newArgs...)
}

func hasSuffixes(s string, suffixes ...string) bool {
Expand Down
79 changes: 35 additions & 44 deletions cmd/docker-entrypoint/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

type execArgs struct {
fork bool
gomplate bool
argPrefixes []string
}

Expand All @@ -16,98 +16,89 @@ func TestRun(t *testing.T) {
args []string
execReturns error
whichReturns string
wantExecArgs []execArgs
wantExecArgs execArgs
wantErr error
}{
{
name: "executable not dex",
args: []string{"tuna", "fish"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"tuna", "fish"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"tuna", "fish"}},
},
{
name: "executable is full path to dex",
args: []string{"/usr/local/bin/dex", "marshmallow", "zelda"},
whichReturns: "/usr/local/bin/dex",
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"/usr/local/bin/dex", "marshmallow", "zelda"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"/usr/local/bin/dex", "marshmallow", "zelda"}},
},
{
name: "command is not serve",
args: []string{"dex", "marshmallow", "zelda"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "marshmallow", "zelda"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "marshmallow", "zelda"}},
},
{
name: "no templates",
args: []string{"dex", "serve", "config.yaml.not-a-template"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}},
},
{
name: "no templates",
args: []string{"dex", "serve", "config.yaml.not-a-template"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}},
},
{
name: ".tpl template",
args: []string{"dex", "serve", "config.tpl"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "config.tpl", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
name: ".tpl template",
args: []string{"dex", "serve", "config.tpl"},
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
{
name: ".tmpl template",
args: []string{"dex", "serve", "config.tmpl"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "config.tmpl", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
name: ".tmpl template",
args: []string{"dex", "serve", "config.tmpl"},
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
{
name: ".yaml template",
args: []string{"dex", "serve", "some/path/config.yaml"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "some/path/config.yaml", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
name: ".yaml template",
args: []string{"dex", "serve", "some/path/config.yaml"},
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var gotExecForks []bool
var gotExecArgs [][]string
fakeExec := func(fork bool, args ...string) error {
gotExecForks = append(gotExecForks, fork)
gotExecArgs = append(gotExecArgs, args)
var gotExecArgs []string
var runsGomplate bool

fakeExec := func(args ...string) error {
gotExecArgs = append(args, gotExecArgs...)
return test.execReturns
}

fakeWhich := func(_ string) string { return test.whichReturns }

gotErr := run(test.args, fakeExec, fakeWhich)
fakeGomplate := func(file string) (string, error) {
runsGomplate = true
return "/tmp/dex.config.yaml-", nil
}

gotErr := run(test.args, fakeExec, fakeWhich, fakeGomplate)
if (test.wantErr == nil) != (gotErr == nil) {
t.Errorf("wanted error %s, got %s", test.wantErr, gotErr)
}
if !execArgsMatch(test.wantExecArgs, gotExecForks, gotExecArgs) {
t.Errorf("wanted exec args %+v, got %+v %+v", test.wantExecArgs, gotExecForks, gotExecArgs)

if !execArgsMatch(test.wantExecArgs, runsGomplate, gotExecArgs) {
t.Errorf("wanted exec args %+v (running gomplate: %+v), got %+v (running gomplate: %+v)",
test.wantExecArgs.argPrefixes, test.wantExecArgs.gomplate, gotExecArgs, runsGomplate)
}
})
}
}

func execArgsMatch(wantExecArgs []execArgs, gotForks []bool, gotExecArgs [][]string) bool {
if len(wantExecArgs) != len(gotForks) {
func execArgsMatch(wantExecArgs execArgs, gomplate bool, gotExecArgs []string) bool {
if wantExecArgs.gomplate != gomplate {
return false
}

for i := range wantExecArgs {
if wantExecArgs[i].fork != gotForks[i] {
for i := range wantExecArgs.argPrefixes {
if !strings.HasPrefix(gotExecArgs[i], wantExecArgs.argPrefixes[i]) {
return false
}
for j := range wantExecArgs[i].argPrefixes {
if !strings.HasPrefix(gotExecArgs[i][j], wantExecArgs[i].argPrefixes[j]) {
return false
}
}
}

return true
}