Skip to content

Commit f451a45

Browse files
committed
Escape systemd special chars in —docker-env
1 parent 9b8e3ed commit f451a45

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

pkg/provision/buildroot.go

+17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"path"
2323
"path/filepath"
24+
"strings"
2425
"text/template"
2526
"time"
2627

@@ -47,6 +48,9 @@ type BuildrootProvisioner struct {
4748
provision.SystemdProvisioner
4849
}
4950

51+
// for escaping systemd template specifiers (e.g. '%i'), which are not supported by minikube
52+
var systemdSpecifierEscaper = strings.NewReplacer("%", "%%")
53+
5054
func init() {
5155
provision.Register("Buildroot", &provision.RegisteredProvisioner{
5256
New: NewBuildrootProvisioner,
@@ -64,6 +68,17 @@ func (p *BuildrootProvisioner) String() string {
6468
return "buildroot"
6569
}
6670

71+
// escapeSystemdDirectives escapes special characters in the input variables used to create the
72+
// systemd unit file, which would otherwise be interpreted as systemd directives. An example
73+
// are template specifiers (e.g. '%i') which are predefined variables that get evaluated dynamically
74+
// (see systemd man pages for more info). This is not supported by minikube, thus needs to be escaped.
75+
func escapeSystemdDirectives(engineConfigContext *provision.EngineConfigContext) {
76+
// escape '%' in Environment option so that it does not evaluate into a template specifier
77+
engineConfigContext.EngineOptions.Env = util.ReplaceChars(engineConfigContext.EngineOptions.Env, systemdSpecifierEscaper)
78+
// input might contain whitespaces, wrap it in quotes
79+
engineConfigContext.EngineOptions.Env = util.ConcatStrings(engineConfigContext.EngineOptions.Env, "\"", "\"")
80+
}
81+
6782
// GenerateDockerOptions generates the *provision.DockerOptions for this provisioner
6883
func (p *BuildrootProvisioner) GenerateDockerOptions(dockerPort int) (*provision.DockerOptions, error) {
6984
var engineCfg bytes.Buffer
@@ -127,6 +142,8 @@ WantedBy=multi-user.target
127142
EngineOptions: p.EngineOptions,
128143
}
129144

145+
escapeSystemdDirectives(&engineConfigContext)
146+
130147
if err := t.Execute(&engineCfg, engineConfigContext); err != nil {
131148
return nil, err
132149
}

pkg/util/utils.go

+23
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,26 @@ func TeePrefix(prefix string, r io.Reader, w io.Writer, logger func(format strin
250250
}
251251
return nil
252252
}
253+
254+
// ReplaceChars returns a copy of the src slice with each string modified by the replacer
255+
func ReplaceChars(src []string, replacer *strings.Replacer) []string {
256+
ret := make([]string, len(src))
257+
for i, s := range src {
258+
ret[i] = replacer.Replace(s)
259+
}
260+
return ret
261+
}
262+
263+
// ConcatStrings concatenates each string in the src slice with prefix and postfix and returns a new slice
264+
func ConcatStrings(src []string, prefix string, postfix string) []string {
265+
var buf bytes.Buffer
266+
ret := make([]string, len(src))
267+
for i, s := range src {
268+
buf.WriteString(prefix)
269+
buf.WriteString(s)
270+
buf.WriteString(postfix)
271+
ret[i] = buf.String()
272+
buf.Reset()
273+
}
274+
return ret
275+
}

pkg/util/utils_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,43 @@ func TestTeePrefix(t *testing.T) {
197197
t.Errorf("log=%q, want: %q", gotLog, wantLog)
198198
}
199199
}
200+
201+
func TestReplaceChars(t *testing.T) {
202+
testData := []struct {
203+
src []string
204+
replacer *strings.Replacer
205+
expectedRes []string
206+
}{
207+
{[]string{"abc%def", "%Y%"}, strings.NewReplacer("%", "X"), []string{"abcXdef", "XYX"}},
208+
}
209+
210+
for _, tt := range testData {
211+
res := ReplaceChars(tt.src, tt.replacer)
212+
for i, val := range res {
213+
if val != tt.expectedRes[i] {
214+
t.Fatalf("Expected '%s' but got '%s'", tt.expectedRes, res)
215+
}
216+
}
217+
}
218+
}
219+
220+
func TestConcatStrings(t *testing.T) {
221+
testData := []struct {
222+
src []string
223+
prefix string
224+
postfix string
225+
expectedRes []string
226+
}{
227+
{[]string{"abc", ""}, "xx", "yy", []string{"xxabcyy", "xxyy"}},
228+
{[]string{"abc", ""}, "", "", []string{"abc", ""}},
229+
}
230+
231+
for _, tt := range testData {
232+
res := ConcatStrings(tt.src, tt.prefix, tt.postfix)
233+
for i, val := range res {
234+
if val != tt.expectedRes[i] {
235+
t.Fatalf("Expected '%s' but got '%s'", tt.expectedRes, res)
236+
}
237+
}
238+
}
239+
}

0 commit comments

Comments
 (0)