diff --git a/pkg/reconciler/taskrun/resources/apply.go b/pkg/reconciler/taskrun/resources/apply.go index c038fbc3915..597d827f22e 100644 --- a/pkg/reconciler/taskrun/resources/apply.go +++ b/pkg/reconciler/taskrun/resources/apply.go @@ -49,29 +49,42 @@ func ApplyParameters(spec *v1beta1.TaskSpec, tr *v1beta1.TaskRun, defaults ...v1 "inputs.params.%s", } + // reference pattern for object individual keys params.. + objectIndividualVariablePattern := "params.%s.%s" + // Set all the default stringReplacements 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 } } } diff --git a/pkg/reconciler/taskrun/resources/apply_test.go b/pkg/reconciler/taskrun/resources/apply_test.go index d7e3636e752..2f8cf80249b 100644 --- a/pkg/reconciler/taskrun/resources/apply_test.go +++ b/pkg/reconciler/taskrun/resources/apply_test.go @@ -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", @@ -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", @@ -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{{ @@ -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{{ @@ -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, } @@ -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{ @@ -575,6 +774,72 @@ func TestApplyParameters(t *testing.T) { } } +func TestApplyObjectParameters(t *testing.T) { + // 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