Skip to content

Commit

Permalink
feature: kubefile CMD support ENV variable format (#3921) (#3942)
Browse files Browse the repository at this point in the history
Co-authored-by: Zihan Li <eden.zh.li@outlook.com>
  • Loading branch information
sealos-ci-robot and LZiHaN committed Sep 17, 2023
1 parent 7f2af2f commit 4b5f3fe
Show file tree
Hide file tree
Showing 2 changed files with 252 additions and 8 deletions.
40 changes: 32 additions & 8 deletions fork/golang/expansion/expand.go
Expand Up @@ -2,17 +2,20 @@ package expansion

import (
"bytes"
"unicode"
)

const (
operator = '$'
referenceOpener = '('
referenceCloser = ')'
operator = '$'
referenceCurlyOpener = '{'
referenceCurlyCloser = '}'
referenceParenOpener = '('
referenceParenCloser = ')'
)

// syntaxWrap returns the input string wrapped by the expansion syntax.
func syntaxWrap(input string) string {
return string(operator) + string(referenceOpener) + input + string(referenceCloser)
return string(operator) + string(referenceParenOpener) + input + string(referenceParenCloser)
}

// MappingFuncFor returns a mapping function for use with Expand that
Expand Down Expand Up @@ -83,20 +86,41 @@ func tryReadVariableName(input string) (string, bool, int) {
case operator:
// Escaped operator; return it.
return input[0:1], false, 1
case referenceOpener:
case referenceParenOpener:
// Scan to expression closer
for i := 1; i < len(input); i++ {
if input[i] == referenceCloser {
if input[i] == referenceParenCloser {
return input[1:i], true, i + 1
}
}

// Incomplete reference; return it.
return string(operator) + string(referenceOpener), false, 1
return string(operator) + string(referenceParenOpener), false, 1
case referenceCurlyOpener:
// Scan to expression closer
for i := 1; i < len(input); i++ {
if input[i] == referenceCurlyCloser {
return input[1:i], true, i + 1
}
}

// Incomplete reference; return it.
return string(operator) + string(referenceParenOpener), false, 1
default:
// Not the beginning of an expression, ie, an operator
// that doesn't begin an expression. Return the operator
// and the first rune in the string.
return (string(operator) + string(input[0])), false, 1
var variableName string
var i int
for i = 0; i < len(input); i++ {
if !unicode.IsLetter(rune(input[i])) && !unicode.IsDigit(rune(input[i])) && input[i] != '_' {
break
}
variableName += string(input[i])
}
if len(variableName) > 0 {
return variableName, true, i
}
return string(operator) + string(input[0]), false, 1
}
}
220 changes: 220 additions & 0 deletions pkg/guest/guest_test.go
Expand Up @@ -135,3 +135,223 @@ func TestDefault_getGuestCmd(t *testing.T) {
})
}
}

func TestDefault_getGuestCmd_dollarBraceVariable(t *testing.T) {
shell := func(cName, containerName, cmd string) string {
return fmt.Sprintf(constants.CdAndExecCmd, constants.GetAppWorkDir(cName, containerName), cmd)
}
type fields struct {
}
type args struct {
envs map[string]string
cluster *v2.Cluster
mounts []v2.MountImage
}
tests := []struct {
name string
fields fields
args args
want []string
}{
{
name: "default",
fields: fields{},
args: args{
envs: map[string]string{},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: nil}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=${IFACE} bash ovn-install.sh"},
Entrypoint: nil,
Env: map[string]string{"IFACE": "cccc"},
},
},
},
want: []string{shell("", "", "IFACE=cccc bash ovn-install.sh")},
},

{
name: "default-env",
fields: fields{},
args: args{
envs: map[string]string{},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: nil}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=\"${IFACE}\" bash ovn-install.sh"},
Entrypoint: nil,
Env: map[string]string{"IFACE": "eth.*|en.*"},
},
},
},
want: []string{shell("", "", "IFACE=\"eth.*|en.*\" bash ovn-install.sh")},
},
{
name: "default-env-override",
fields: fields{},
args: args{
envs: map[string]string{"IFACE": "default"},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: nil}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=\"${IFACE}\" bash ovn-install.sh"},
Entrypoint: nil,
Env: map[string]string{"IFACE": "eth.*|en.*"},
},
},
},
want: []string{shell("", "", "IFACE=\"default\" bash ovn-install.sh")},
},
{
name: "default-cmd-override",
fields: fields{},
args: args{
envs: map[string]string{"IFACE": "default"},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: []string{"IFACE=\"${IFACE}\" sh ovn-install.sh"}}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=\"${IFACE}\" bash ovn-install.sh"},
Entrypoint: nil,
Env: map[string]string{"IFACE": "eth.*|en.*"},
},
},
},
want: []string{shell("", "", "IFACE=\"default\" sh ovn-install.sh")},
},
{
name: "default-entrypoint-cmd-override",
fields: fields{},
args: args{
envs: map[string]string{"IFACE": "default"},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: []string{"IFACE=\"${IFACE}\" sh ovn-install.sh"}}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=\"${IFACE}\" bash ovn-install.sh"},
Entrypoint: []string{"AA=${IFACE}"},
Env: map[string]string{"IFACE": "eth.*|en.*"},
},
},
},
want: []string{shell("", "", "AA=default"), shell("", "", "IFACE=\"default\" sh ovn-install.sh")},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for i := range tt.args.mounts {
if got := formalizeImageCommands(tt.args.cluster, i, tt.args.mounts[i], tt.args.envs); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getGuestCmd() = %v, want %v", got, tt.want)
}
}
})
}
}

func TestDefault_getGuestCmd_dollarVariable(t *testing.T) {
shell := func(cName, containerName, cmd string) string {
return fmt.Sprintf(constants.CdAndExecCmd, constants.GetAppWorkDir(cName, containerName), cmd)
}
type fields struct {
}
type args struct {
envs map[string]string
cluster *v2.Cluster
mounts []v2.MountImage
}
tests := []struct {
name string
fields fields
args args
want []string
}{
{
name: "default",
fields: fields{},
args: args{
envs: map[string]string{},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: nil}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=$IFACE bash ovn-install.sh"},
Entrypoint: nil,
Env: map[string]string{"IFACE": "cccc"},
},
},
},
want: []string{shell("", "", "IFACE=cccc bash ovn-install.sh")},
},

{
name: "default-env",
fields: fields{},
args: args{
envs: map[string]string{},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: nil}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=\"$IFACE\" bash ovn-install.sh"},
Entrypoint: nil,
Env: map[string]string{"IFACE": "eth.*|en.*"},
},
},
},
want: []string{shell("", "", "IFACE=\"eth.*|en.*\" bash ovn-install.sh")},
},
{
name: "default-env-override",
fields: fields{},
args: args{
envs: map[string]string{"IFACE": "default"},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: nil}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=\"$IFACE\" bash ovn-install.sh"},
Entrypoint: nil,
Env: map[string]string{"IFACE": "eth.*|en.*"},
},
},
},
want: []string{shell("", "", "IFACE=\"default\" bash ovn-install.sh")},
},
{
name: "default-cmd-override",
fields: fields{},
args: args{
envs: map[string]string{"IFACE": "default"},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: []string{"IFACE=\"$IFACE\" sh ovn-install.sh"}}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=\"$IFACE\" bash ovn-install.sh"},
Entrypoint: nil,
Env: map[string]string{"IFACE": "eth.*|en.*"},
},
},
},
want: []string{shell("", "", "IFACE=\"default\" sh ovn-install.sh")},
},
{
name: "default-entrypoint-cmd-override",
fields: fields{},
args: args{
envs: map[string]string{"IFACE": "default"},
cluster: &v2.Cluster{Spec: v2.ClusterSpec{Command: []string{"IFACE=\"$IFACE\" sh ovn-install.sh"}}},
mounts: []v2.MountImage{
{
Cmd: []string{"IFACE=\"$IFACE\" bash ovn-install.sh"},
Entrypoint: []string{"AA=$IFACE"},
Env: map[string]string{"IFACE": "eth.*|en.*"},
},
},
},
want: []string{shell("", "", "AA=default"), shell("", "", "IFACE=\"default\" sh ovn-install.sh")},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for i := range tt.args.mounts {
if got := formalizeImageCommands(tt.args.cluster, i, tt.args.mounts[i], tt.args.envs); !reflect.DeepEqual(got, tt.want) {
t.Errorf("getGuestCmd() = %v, want %v", got, tt.want)
}
}
})
}
}

0 comments on commit 4b5f3fe

Please sign in to comment.