Skip to content

Commit 43956db

Browse files
committed
Change workdir for gomplate (#3684)
Workaround to run gomplate from a non-root directory in distroless images, because gomplate tries to access CWD on start. See: hairyhenderson/gomplate#2202 Signed-off-by: m.nabokikh <maksim.nabokikh@flant.com>
1 parent 54fb570 commit 43956db

File tree

2 files changed

+62
-63
lines changed

2 files changed

+62
-63
lines changed

cmd/docker-entrypoint/main.go

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,13 @@ func main() {
2222
os.Exit(1)
2323
}
2424

25-
if err := run(args, realExec, realWhich); err != nil {
25+
if err := run(args, realExec, realWhich, realGomplate); err != nil {
2626
fmt.Println("error:", err.Error())
2727
os.Exit(1)
2828
}
2929
}
3030

31-
func realExec(fork bool, args ...string) error {
32-
if fork {
33-
if output, err := exec.Command(args[0], args[1:]...).CombinedOutput(); err != nil {
34-
return fmt.Errorf("cannot fork/exec command %s: %w (output: %q)", args, err, string(output))
35-
}
36-
return nil
37-
}
38-
31+
func realExec(args ...string) error {
3932
argv0, err := exec.LookPath(args[0])
4033
if err != nil {
4134
return fmt.Errorf("cannot lookup path for command %s: %w", args[0], err)
@@ -56,34 +49,49 @@ func realWhich(path string) string {
5649
return fullPath
5750
}
5851

59-
func run(args []string, execFunc func(bool, ...string) error, whichFunc func(string) string) error {
52+
func realGomplate(path string) (string, error) {
53+
tmpFile, err := os.CreateTemp("/tmp", "dex.config.yaml-*")
54+
if err != nil {
55+
return "", fmt.Errorf("cannot create temp file: %w", err)
56+
}
57+
58+
cmd := exec.Command("gomplate", "-f", path, "-o", tmpFile.Name())
59+
// TODO(nabokihms): Workaround to run gomplate from a non-root directory in distroless images
60+
// gomplate tries to access CWD on start, see: https://github.com/hairyhenderson/gomplate/pull/2202
61+
cmd.Dir = "/etc/dex"
62+
63+
output, err := cmd.CombinedOutput()
64+
if err != nil {
65+
return "", fmt.Errorf("error executing gomplate: %w, (output: %q)", err, string(output))
66+
}
67+
68+
return tmpFile.Name(), nil
69+
}
70+
71+
func run(args []string, execFunc func(...string) error, whichFunc func(string) string, gomplateFunc func(string) (string, error)) error {
6072
if args[0] != "dex" && args[0] != whichFunc("dex") {
61-
return execFunc(false, args...)
73+
return execFunc(args...)
6274
}
6375

6476
if args[1] != "serve" {
65-
return execFunc(false, args...)
77+
return execFunc(args...)
6678
}
6779

6880
newArgs := []string{}
6981
for _, tplCandidate := range args {
7082
if hasSuffixes(tplCandidate, ".tpl", ".tmpl", ".yaml") {
71-
tmpFile, err := os.CreateTemp("/tmp", "dex.config.yaml-*")
83+
fileName, err := gomplateFunc(tplCandidate)
7284
if err != nil {
73-
return fmt.Errorf("cannot create temp file: %w", err)
74-
}
75-
76-
if err := execFunc(true, "gomplate", "-f", tplCandidate, "-o", tmpFile.Name()); err != nil {
7785
return err
7886
}
7987

80-
newArgs = append(newArgs, tmpFile.Name())
88+
newArgs = append(newArgs, fileName)
8189
} else {
8290
newArgs = append(newArgs, tplCandidate)
8391
}
8492
}
8593

86-
return execFunc(false, newArgs...)
94+
return execFunc(newArgs...)
8795
}
8896

8997
func hasSuffixes(s string, suffixes ...string) bool {

cmd/docker-entrypoint/main_test.go

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
)
77

88
type execArgs struct {
9-
fork bool
9+
gomplate bool
1010
argPrefixes []string
1111
}
1212

@@ -16,98 +16,89 @@ func TestRun(t *testing.T) {
1616
args []string
1717
execReturns error
1818
whichReturns string
19-
wantExecArgs []execArgs
19+
wantExecArgs execArgs
2020
wantErr error
2121
}{
2222
{
2323
name: "executable not dex",
2424
args: []string{"tuna", "fish"},
25-
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"tuna", "fish"}}},
25+
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"tuna", "fish"}},
2626
},
2727
{
2828
name: "executable is full path to dex",
2929
args: []string{"/usr/local/bin/dex", "marshmallow", "zelda"},
3030
whichReturns: "/usr/local/bin/dex",
31-
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"/usr/local/bin/dex", "marshmallow", "zelda"}}},
31+
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"/usr/local/bin/dex", "marshmallow", "zelda"}},
3232
},
3333
{
3434
name: "command is not serve",
3535
args: []string{"dex", "marshmallow", "zelda"},
36-
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "marshmallow", "zelda"}}},
36+
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "marshmallow", "zelda"}},
3737
},
3838
{
3939
name: "no templates",
4040
args: []string{"dex", "serve", "config.yaml.not-a-template"},
41-
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}}},
41+
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}},
4242
},
4343
{
4444
name: "no templates",
4545
args: []string{"dex", "serve", "config.yaml.not-a-template"},
46-
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}}},
46+
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}},
4747
},
4848
{
49-
name: ".tpl template",
50-
args: []string{"dex", "serve", "config.tpl"},
51-
wantExecArgs: []execArgs{
52-
{fork: true, argPrefixes: []string{"gomplate", "-f", "config.tpl", "-o", "/tmp/dex.config.yaml-"}},
53-
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
54-
},
49+
name: ".tpl template",
50+
args: []string{"dex", "serve", "config.tpl"},
51+
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
5552
},
5653
{
57-
name: ".tmpl template",
58-
args: []string{"dex", "serve", "config.tmpl"},
59-
wantExecArgs: []execArgs{
60-
{fork: true, argPrefixes: []string{"gomplate", "-f", "config.tmpl", "-o", "/tmp/dex.config.yaml-"}},
61-
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
62-
},
54+
name: ".tmpl template",
55+
args: []string{"dex", "serve", "config.tmpl"},
56+
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
6357
},
6458
{
65-
name: ".yaml template",
66-
args: []string{"dex", "serve", "some/path/config.yaml"},
67-
wantExecArgs: []execArgs{
68-
{fork: true, argPrefixes: []string{"gomplate", "-f", "some/path/config.yaml", "-o", "/tmp/dex.config.yaml-"}},
69-
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
70-
},
59+
name: ".yaml template",
60+
args: []string{"dex", "serve", "some/path/config.yaml"},
61+
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
7162
},
7263
}
7364
for _, test := range tests {
7465
t.Run(test.name, func(t *testing.T) {
75-
var gotExecForks []bool
76-
var gotExecArgs [][]string
77-
fakeExec := func(fork bool, args ...string) error {
78-
gotExecForks = append(gotExecForks, fork)
79-
gotExecArgs = append(gotExecArgs, args)
66+
var gotExecArgs []string
67+
var runsGomplate bool
68+
69+
fakeExec := func(args ...string) error {
70+
gotExecArgs = append(args, gotExecArgs...)
8071
return test.execReturns
8172
}
8273

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

85-
gotErr := run(test.args, fakeExec, fakeWhich)
76+
fakeGomplate := func(file string) (string, error) {
77+
runsGomplate = true
78+
return "/tmp/dex.config.yaml-", nil
79+
}
80+
81+
gotErr := run(test.args, fakeExec, fakeWhich, fakeGomplate)
8682
if (test.wantErr == nil) != (gotErr == nil) {
8783
t.Errorf("wanted error %s, got %s", test.wantErr, gotErr)
8884
}
89-
if !execArgsMatch(test.wantExecArgs, gotExecForks, gotExecArgs) {
90-
t.Errorf("wanted exec args %+v, got %+v %+v", test.wantExecArgs, gotExecForks, gotExecArgs)
85+
86+
if !execArgsMatch(test.wantExecArgs, runsGomplate, gotExecArgs) {
87+
t.Errorf("wanted exec args %+v (running gomplate: %+v), got %+v (running gomplate: %+v)",
88+
test.wantExecArgs.argPrefixes, test.wantExecArgs.gomplate, gotExecArgs, runsGomplate)
9189
}
9290
})
9391
}
9492
}
9593

96-
func execArgsMatch(wantExecArgs []execArgs, gotForks []bool, gotExecArgs [][]string) bool {
97-
if len(wantExecArgs) != len(gotForks) {
94+
func execArgsMatch(wantExecArgs execArgs, gomplate bool, gotExecArgs []string) bool {
95+
if wantExecArgs.gomplate != gomplate {
9896
return false
9997
}
100-
101-
for i := range wantExecArgs {
102-
if wantExecArgs[i].fork != gotForks[i] {
98+
for i := range wantExecArgs.argPrefixes {
99+
if !strings.HasPrefix(gotExecArgs[i], wantExecArgs.argPrefixes[i]) {
103100
return false
104101
}
105-
for j := range wantExecArgs[i].argPrefixes {
106-
if !strings.HasPrefix(gotExecArgs[i][j], wantExecArgs[i].argPrefixes[j]) {
107-
return false
108-
}
109-
}
110102
}
111-
112103
return true
113104
}

0 commit comments

Comments
 (0)