Skip to content

Commit

Permalink
Escape systemd special chars in —docker-env
Browse files Browse the repository at this point in the history
  • Loading branch information
11janci committed Mar 29, 2019
1 parent 786eb65 commit e3cd272
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 0 deletions.
17 changes: 17 additions & 0 deletions pkg/provision/buildroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"path"
"path/filepath"
"strings"
"text/template"
"time"

Expand All @@ -47,6 +48,9 @@ type BuildrootProvisioner struct {
provision.SystemdProvisioner
}

// for escaping systemd template specifiers (e.g. '%i'), which are not supported by minikube
var systemdSpecifierEscaper = strings.NewReplacer("%", "%%")

func init() {
provision.Register("Buildroot", &provision.RegisteredProvisioner{
New: NewBuildrootProvisioner,
Expand All @@ -64,6 +68,17 @@ func (p *BuildrootProvisioner) String() string {
return "buildroot"
}

// escapeSystemdDirectives escapes special characters in the input variables used to create the
// systemd unit file, which would otherwise be interpreted as systemd directives. An example
// are template specifiers (e.g. '%i') which are predefined variables that get evaluated dynamically
// (see systemd man pages for more info). This is not supported by minikube, thus needs to be escaped.
func escapeSystemdDirectives(engineConfigContext *provision.EngineConfigContext) {
// escape '%' in Environment option so that it does not evaluate into a template specifier
engineConfigContext.EngineOptions.Env = util.ReplaceChars(engineConfigContext.EngineOptions.Env, systemdSpecifierEscaper)
// input might contain whitespaces, wrap it in quotes
engineConfigContext.EngineOptions.Env = util.ConcatStrings(engineConfigContext.EngineOptions.Env, "\"", "\"")
}

// GenerateDockerOptions generates the *provision.DockerOptions for this provisioner
func (p *BuildrootProvisioner) GenerateDockerOptions(dockerPort int) (*provision.DockerOptions, error) {
var engineCfg bytes.Buffer
Expand Down Expand Up @@ -127,6 +142,8 @@ WantedBy=multi-user.target
EngineOptions: p.EngineOptions,
}

escapeSystemdDirectives(&engineConfigContext)

if err := t.Execute(&engineCfg, engineConfigContext); err != nil {
return nil, err
}
Expand Down
23 changes: 23 additions & 0 deletions pkg/util/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,26 @@ func TeePrefix(prefix string, r io.Reader, w io.Writer, logger func(format strin
}
return nil
}

// ReplaceChars returns a copy of the src slice with each string modified by the replacer
func ReplaceChars(src []string, replacer *strings.Replacer) []string {
ret := make([]string, len(src))
for i, s := range src {
ret[i] = replacer.Replace(s)
}
return ret
}

// ConcatStrings concatenates each string in the src slice with prefix and postfix and returns a new slice
func ConcatStrings(src []string, prefix string, postfix string) []string {
var buf bytes.Buffer
ret := make([]string, len(src))
for i, s := range src {
buf.WriteString(prefix)
buf.WriteString(s)
buf.WriteString(postfix)
ret[i] = buf.String()
buf.Reset()
}
return ret
}
40 changes: 40 additions & 0 deletions pkg/util/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,43 @@ func TestTeePrefix(t *testing.T) {
t.Errorf("log=%q, want: %q", gotLog, wantLog)
}
}

func TestReplaceChars(t *testing.T) {
testData := []struct {
src []string
replacer *strings.Replacer
expectedRes []string
}{
{[]string{"abc%def", "%Y%"}, strings.NewReplacer("%", "X"), []string{"abcXdef", "XYX"}},
}

for _, tt := range testData {
res := ReplaceChars(tt.src, tt.replacer)
for i, val := range res {
if val != tt.expectedRes[i] {
t.Fatalf("Expected '%s' but got '%s'", tt.expectedRes, res)
}
}
}
}

func TestConcatStrings(t *testing.T) {
testData := []struct {
src []string
prefix string
postfix string
expectedRes []string
}{
{[]string{"abc", ""}, "xx", "yy", []string{"xxabcyy", "xxyy"}},
{[]string{"abc", ""}, "", "", []string{"abc", ""}},
}

for _, tt := range testData {
res := ConcatStrings(tt.src, tt.prefix, tt.postfix)
for i, val := range res {
if val != tt.expectedRes[i] {
t.Fatalf("Expected '%s' but got '%s'", tt.expectedRes, res)
}
}
}
}

0 comments on commit e3cd272

Please sign in to comment.