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

TEP-0075: Implement object var replacement on task&taskrun level #4904

Merged
merged 1 commit into from
Jul 4, 2022
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
29 changes: 21 additions & 8 deletions pkg/reconciler/taskrun/resources/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,29 +49,42 @@ func ApplyParameters(spec *v1beta1.TaskSpec, tr *v1beta1.TaskRun, defaults ...v1
"inputs.params.%s",
}

// reference pattern for object individual keys params.<object_param_name>.<key_name>
objectIndividualVariablePattern := "params.%s.%s"

// Set all the default stringReplacements
chuangw6 marked this conversation as resolved.
Show resolved Hide resolved
for _, p := range defaults {
if p.Default != nil {
if p.Default.Type == v1beta1.ParamTypeString {
switch p.Default.Type {
case v1beta1.ParamTypeArray:
for _, pattern := range patterns {
stringReplacements[fmt.Sprintf(pattern, p.Name)] = p.Default.StringVal
arrayReplacements[fmt.Sprintf(pattern, p.Name)] = p.Default.ArrayVal
}
} else {
case v1beta1.ParamTypeObject:
for k, v := range p.Default.ObjectVal {
stringReplacements[fmt.Sprintf(objectIndividualVariablePattern, p.Name, k)] = v
}
default:
for _, pattern := range patterns {
arrayReplacements[fmt.Sprintf(pattern, p.Name)] = p.Default.ArrayVal
stringReplacements[fmt.Sprintf(pattern, p.Name)] = p.Default.StringVal
}
}
}
}
// Set and overwrite params with the ones from the TaskRun
for _, p := range tr.Spec.Params {
if p.Value.Type == v1beta1.ParamTypeString {
switch p.Value.Type {
case v1beta1.ParamTypeArray:
for _, pattern := range patterns {
stringReplacements[fmt.Sprintf(pattern, p.Name)] = p.Value.StringVal
arrayReplacements[fmt.Sprintf(pattern, p.Name)] = p.Value.ArrayVal
}
} else {
case v1beta1.ParamTypeObject:
for k, v := range p.Value.ObjectVal {
stringReplacements[fmt.Sprintf(objectIndividualVariablePattern, p.Name, k)] = v
}
default:
for _, pattern := range patterns {
arrayReplacements[fmt.Sprintf(pattern, p.Name)] = p.Value.ArrayVal
stringReplacements[fmt.Sprintf(pattern, p.Name)] = p.Value.StringVal
}
}
}
Expand Down
265 changes: 265 additions & 0 deletions pkg/reconciler/taskrun/resources/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,128 @@ var (
},
}

// a taskspec for testing object var in all places i.e. Sidecars, StepTemplate, Steps and Volumns
objectParamTaskSpec = &v1beta1.TaskSpec{
Sidecars: []v1beta1.Sidecar{{
Name: "foo",
Image: `$(params.myObject.key1)`,
Env: []corev1.EnvVar{{
Name: "foo",
Value: "$(params.myObject.key2)",
}},
}},
StepTemplate: &v1beta1.StepTemplate{
Image: "$(params.myObject.key1)",
Env: []corev1.EnvVar{{
Name: "template-var",
Value: `$(params.myObject.key2)`,
}},
},
Steps: []v1beta1.Step{{
Name: "foo",
Image: "$(params.myObject.key1)",
WorkingDir: "path/to/$(params.myObject.key2)",
Args: []string{"first $(params.myObject.key1)", "second $(params.myObject.key2)"},
VolumeMounts: []corev1.VolumeMount{{
Name: "$(params.myObject.key1)",
MountPath: "path/to/$(params.myObject.key2)",
SubPath: "sub/$(params.myObject.key2)/path",
}},
Env: []corev1.EnvVar{{
Name: "foo",
Value: "value-$(params.myObject.key1)",
}, {
Name: "bar",
ValueFrom: &corev1.EnvVarSource{
ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
LocalObjectReference: corev1.LocalObjectReference{Name: "config-$(params.myObject.key1)"},
Key: "config-key-$(params.myObject.key2)",
},
},
}, {
Name: "baz",
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{Name: "secret-$(params.myObject.key1)"},
Key: "secret-key-$(params.myObject.key2)",
},
},
}},
EnvFrom: []corev1.EnvFromSource{{
Prefix: "prefix-0-$(params.myObject.key1)",
ConfigMapRef: &corev1.ConfigMapEnvSource{
LocalObjectReference: corev1.LocalObjectReference{Name: "config-$(params.myObject.key1)"},
},
}, {
Prefix: "prefix-1-$(params.myObject.key1)",
SecretRef: &corev1.SecretEnvSource{
LocalObjectReference: corev1.LocalObjectReference{Name: "secret-$(params.myObject.key1)"},
},
}},
}},
Volumes: []corev1.Volume{{
Name: "$(params.myObject.key1)",
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: "$(params.myObject.key1)",
},
Items: []corev1.KeyToPath{{
Key: "$(params.myObject.key1)",
Path: "$(params.myObject.key2)",
}},
},
Secret: &corev1.SecretVolumeSource{
SecretName: "$(params.myObject.key1)",
Items: []corev1.KeyToPath{{
Key: "$(params.myObject.key1)",
Path: "$(params.myObject.key2)",
}},
},
},
}, {
Name: "some-pvc",
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: "$(params.myObject.key1)",
},
},
}, {
Name: "some-projected-volumes",
VolumeSource: corev1.VolumeSource{
Projected: &corev1.ProjectedVolumeSource{
Sources: []corev1.VolumeProjection{{
ConfigMap: &corev1.ConfigMapProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "$(params.myObject.key1)",
},
},
Secret: &corev1.SecretProjection{
LocalObjectReference: corev1.LocalObjectReference{
Name: "$(params.myObject.key1)",
},
},
ServiceAccountToken: &corev1.ServiceAccountTokenProjection{
Audience: "$(params.myObject.key2)",
},
}},
},
},
}, {
Name: "some-csi",
VolumeSource: corev1.VolumeSource{
CSI: &corev1.CSIVolumeSource{
VolumeAttributes: map[string]string{
"secretProviderClass": "$(params.myObject.key1)",
},
NodePublishSecretRef: &corev1.LocalObjectReference{
Name: "$(params.myObject.key1)",
},
},
},
}},
}

gcsTaskSpec = &v1beta1.TaskSpec{
Steps: []v1beta1.Step{{
Name: "foobar",
Expand Down Expand Up @@ -261,6 +383,18 @@ var (
}},
}

arrayAndObjectParamTaskSpec = &v1beta1.TaskSpec{
Steps: []v1beta1.Step{{
Name: "simple-image",
Image: "some-image",
}, {
Name: "image-with-c-specified",
Image: "some-other-image",
Command: []string{"echo"},
Args: []string{"$(params.myObject.key1)", "$(params.myObject.key2)", "$(params.array-param)", "last"},
}},
}

multipleArrayParamsTaskSpec = &v1beta1.TaskSpec{
Steps: []v1beta1.Step{{
Name: "simple-image",
Expand All @@ -285,6 +419,18 @@ var (
}},
}

multipleArrayAndObjectParamsTaskSpec = &v1beta1.TaskSpec{
Steps: []v1beta1.Step{{
Name: "simple-image",
Image: "image-$(params.myObject.key1)",
}, {
Name: "image-with-c-specified",
Image: "some-other-image",
Command: []string{"cmd", "$(params.array-param1)"},
Args: []string{"$(params.array-param2)", "second", "$(params.array-param1)", "$(params.myObject.key2)", "last"},
}},
}

arrayTaskRun0Elements = &v1beta1.TaskRun{
Spec: v1beta1.TaskRunSpec{
Params: []v1beta1.Param{{
Expand Down Expand Up @@ -339,6 +485,21 @@ var (
},
}

arrayTaskRunWith1ObjectParam = &v1beta1.TaskRun{
Spec: v1beta1.TaskRunSpec{
Params: []v1beta1.Param{{
Name: "array-param",
Value: *v1beta1.NewArrayOrString("middlefirst", "middlesecond"),
}, {
Name: "myObject",
Value: *v1beta1.NewObject(map[string]string{
"key1": "object value1",
"key2": "object value2",
}),
}},
},
}

arrayTaskRunMultipleArraysAndStrings = &v1beta1.TaskRun{
Spec: v1beta1.TaskRunSpec{
Params: []v1beta1.Param{{
Expand All @@ -357,6 +518,24 @@ var (
},
}

arrayTaskRunMultipleArraysAndObject = &v1beta1.TaskRun{
Spec: v1beta1.TaskRunSpec{
Params: []v1beta1.Param{{
Name: "array-param1",
Value: *v1beta1.NewArrayOrString("1-param1", "2-param1", "3-param1", "4-param1"),
}, {
Name: "array-param2",
Value: *v1beta1.NewArrayOrString("1-param2", "2-param2", "3-param3"),
}, {
Name: "myObject",
Value: *v1beta1.NewObject(map[string]string{
"key1": "value1",
"key2": "value2",
}),
}},
},
}

inputs = map[string]v1beta1.PipelineResourceInterface{
"workspace": gitResource,
}
Expand Down Expand Up @@ -482,6 +661,26 @@ func TestApplyArrayParameters(t *testing.T) {
spec.Steps[1].Command = []string{"cmd", "1-param1", "2-param1", "3-param1", "4-param1"}
spec.Steps[1].Args = []string{"1-param2", "2-param2", "2-param3", "second", "1-param1", "2-param1", "3-param1", "4-param1", "foo", "last"}
}),
}, {
name: "array and object parameter",
args: args{
ts: arrayAndObjectParamTaskSpec,
tr: arrayTaskRunWith1ObjectParam,
},
want: applyMutation(arrayAndObjectParamTaskSpec, func(spec *v1beta1.TaskSpec) {
spec.Steps[1].Args = []string{"object value1", "object value2", "middlefirst", "middlesecond", "last"}
}),
}, {
name: "several arrays and objects",
args: args{
ts: multipleArrayAndObjectParamsTaskSpec,
tr: arrayTaskRunMultipleArraysAndObject,
},
want: applyMutation(multipleArrayAndObjectParamsTaskSpec, func(spec *v1beta1.TaskSpec) {
spec.Steps[0].Image = "image-value1"
spec.Steps[1].Command = []string{"cmd", "1-param1", "2-param1", "3-param1", "4-param1"}
spec.Steps[1].Args = []string{"1-param2", "2-param2", "3-param3", "second", "1-param1", "2-param1", "3-param1", "4-param1", "value2", "last"}
}),
}, {
name: "default array parameter",
args: args{
Expand Down Expand Up @@ -575,6 +774,72 @@ func TestApplyParameters(t *testing.T) {
}
}

func TestApplyObjectParameters(t *testing.T) {
chuangw6 marked this conversation as resolved.
Show resolved Hide resolved
// define the taskrun to test values provided by taskrun can overwrite the values provided in spec's default
tr := &v1beta1.TaskRun{
Spec: v1beta1.TaskRunSpec{
Params: []v1beta1.Param{{
Name: "myObject",
Value: *v1beta1.NewObject(map[string]string{
"key1": "taskrun-value-for-key1",
"key2": "taskrun-value-for-key2",
}),
}},
},
}
dp := []v1beta1.ParamSpec{{
Name: "myObject",
Default: v1beta1.NewObject(map[string]string{
"key1": "default-value-for-key1",
"key2": "default-value-for-key2",
}),
}}

want := applyMutation(objectParamTaskSpec, func(spec *v1beta1.TaskSpec) {
spec.Sidecars[0].Image = "taskrun-value-for-key1"
spec.Sidecars[0].Env[0].Value = "taskrun-value-for-key2"

spec.StepTemplate.Image = "taskrun-value-for-key1"
spec.StepTemplate.Env[0].Value = "taskrun-value-for-key2"

spec.Steps[0].Image = "taskrun-value-for-key1"
spec.Steps[0].WorkingDir = "path/to/taskrun-value-for-key2"
spec.Steps[0].Args = []string{"first taskrun-value-for-key1", "second taskrun-value-for-key2"}

spec.Steps[0].VolumeMounts[0].Name = "taskrun-value-for-key1"
spec.Steps[0].VolumeMounts[0].SubPath = "sub/taskrun-value-for-key2/path"
spec.Steps[0].VolumeMounts[0].MountPath = "path/to/taskrun-value-for-key2"

spec.Steps[0].Env[0].Value = "value-taskrun-value-for-key1"
spec.Steps[0].Env[1].ValueFrom.ConfigMapKeyRef.LocalObjectReference.Name = "config-taskrun-value-for-key1"
spec.Steps[0].Env[1].ValueFrom.ConfigMapKeyRef.Key = "config-key-taskrun-value-for-key2"
spec.Steps[0].Env[2].ValueFrom.SecretKeyRef.LocalObjectReference.Name = "secret-taskrun-value-for-key1"
spec.Steps[0].Env[2].ValueFrom.SecretKeyRef.Key = "secret-key-taskrun-value-for-key2"
spec.Steps[0].EnvFrom[0].Prefix = "prefix-0-taskrun-value-for-key1"
spec.Steps[0].EnvFrom[0].ConfigMapRef.LocalObjectReference.Name = "config-taskrun-value-for-key1"
spec.Steps[0].EnvFrom[1].Prefix = "prefix-1-taskrun-value-for-key1"
spec.Steps[0].EnvFrom[1].SecretRef.LocalObjectReference.Name = "secret-taskrun-value-for-key1"

spec.Volumes[0].Name = "taskrun-value-for-key1"
spec.Volumes[0].VolumeSource.ConfigMap.LocalObjectReference.Name = "taskrun-value-for-key1"
spec.Volumes[0].VolumeSource.ConfigMap.Items[0].Key = "taskrun-value-for-key1"
spec.Volumes[0].VolumeSource.ConfigMap.Items[0].Path = "taskrun-value-for-key2"
spec.Volumes[0].VolumeSource.Secret.SecretName = "taskrun-value-for-key1"
spec.Volumes[0].VolumeSource.Secret.Items[0].Key = "taskrun-value-for-key1"
spec.Volumes[0].VolumeSource.Secret.Items[0].Path = "taskrun-value-for-key2"
spec.Volumes[1].VolumeSource.PersistentVolumeClaim.ClaimName = "taskrun-value-for-key1"
spec.Volumes[2].VolumeSource.Projected.Sources[0].ConfigMap.Name = "taskrun-value-for-key1"
spec.Volumes[2].VolumeSource.Projected.Sources[0].Secret.Name = "taskrun-value-for-key1"
spec.Volumes[2].VolumeSource.Projected.Sources[0].ServiceAccountToken.Audience = "taskrun-value-for-key2"
spec.Volumes[3].VolumeSource.CSI.VolumeAttributes["secretProviderClass"] = "taskrun-value-for-key1"
spec.Volumes[3].VolumeSource.CSI.NodePublishSecretRef.Name = "taskrun-value-for-key1"
})
got := resources.ApplyParameters(objectParamTaskSpec, tr, dp...)
if d := cmp.Diff(want, got); d != "" {
t.Errorf("ApplyParameters() got diff %s", diff.PrintWantGot(d))
}
}

func TestApplyResources(t *testing.T) {
tests := []struct {
name string
Expand Down