Skip to content

Commit

Permalink
feat(operator): adapt TaskDefinition validation webhook to consider p…
Browse files Browse the repository at this point in the history
…ython and deno runtime (keptn#1534)

Signed-off-by: RealAnna <[email protected]>
Co-authored-by: RealAnna <[email protected]>
  • Loading branch information
2 people authored and StackScribe committed Jun 22, 2023
1 parent c229e80 commit 911f85f
Show file tree
Hide file tree
Showing 15 changed files with 381 additions and 30 deletions.
27 changes: 22 additions & 5 deletions operator/apis/lifecycle/v1alpha3/keptntaskdefinition_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,39 @@ func (r *KeptnTaskDefinition) validateKeptnTaskDefinition() error {
allErrs)
}
func (r *KeptnTaskDefinition) validateFields() *field.Error {

if r.Spec.Function == nil && r.Spec.Container == nil {
count := countSpec(r)
if count == 0 {
return field.Invalid(
field.NewPath("spec"),
r.Spec,
errors.New("Forbidden! Either Function or Container field must be defined").Error(),
errors.New("Forbidden! Either Function, Container, Python, or Deno field must be defined").Error(),
)
}

if r.Spec.Function != nil && r.Spec.Container != nil {
if count > 1 {
return field.Invalid(
field.NewPath("spec"),
r.Spec,
errors.New("Forbidden! Both Function and Container fields cannot be defined simultaneously").Error(),
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)
}

return nil
}

func countSpec(r *KeptnTaskDefinition) int {
count := 0
if r.Spec.Function != nil {
count++
}
if r.Spec.Container != nil {
count++
}
if r.Spec.Python != nil {
count++
}
if r.Spec.Deno != nil {
count++
}
return count
}
210 changes: 205 additions & 5 deletions operator/apis/lifecycle/v1alpha3/keptntaskdefinition_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,31 @@ func TestKeptnTaskDefinition_ValidateFields(t *testing.T) {
Container: &ContainerSpec{},
}

specWithFunctionAndPython := KeptnTaskDefinitionSpec{
Function: &RuntimeSpec{},
Python: &RuntimeSpec{},
}

specWithFunctionAndDeno := KeptnTaskDefinitionSpec{
Function: &RuntimeSpec{},
Deno: &RuntimeSpec{},
}

specWithContainerAndPython := KeptnTaskDefinitionSpec{
Container: &ContainerSpec{},
Python: &RuntimeSpec{},
}

specWithContainerAndDeno := KeptnTaskDefinitionSpec{
Container: &ContainerSpec{},
Deno: &RuntimeSpec{},
}

specWithPythonAndDeno := KeptnTaskDefinitionSpec{
Python: &RuntimeSpec{},
Deno: &RuntimeSpec{},
}

emptySpec := KeptnTaskDefinitionSpec{}

tests := []struct {
Expand All @@ -29,15 +54,15 @@ func TestKeptnTaskDefinition_ValidateFields(t *testing.T) {
oldSpec runtime.Object
}{
{
name: "with-no-function-or-container",
name: "with-no-function-or-container-or-python-or-deno",
spec: emptySpec,
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"with-no-function-or-container",
"with-no-function-or-container-or-python-or-deno",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
emptySpec,
errors.New("Forbidden! Either Function or Container field must be defined").Error(),
errors.New("Forbidden! Either Function, Container, Python, or Deno field must be defined").Error(),
)},
),
verb: "create",
Expand All @@ -52,7 +77,7 @@ func TestKeptnTaskDefinition_ValidateFields(t *testing.T) {
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithFunctionAndContainer,
errors.New("Forbidden! Both Function and Container fields cannot be defined simultaneously").Error(),
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
},
Expand All @@ -70,6 +95,21 @@ func TestKeptnTaskDefinition_ValidateFields(t *testing.T) {
},
verb: "create",
},
{
name: "with-python-only",
spec: KeptnTaskDefinitionSpec{
Python: &RuntimeSpec{},
},
verb: "create",
},
{
name: "with-deno-only",
spec: KeptnTaskDefinitionSpec{
Deno: &RuntimeSpec{},
},
verb: "create",
},

{
name: "update-with-both-function-and-container",
spec: specWithFunctionAndContainer,
Expand All @@ -79,14 +119,174 @@ func TestKeptnTaskDefinition_ValidateFields(t *testing.T) {
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithFunctionAndContainer,
errors.New("Forbidden! Both Function and Container fields cannot be defined simultaneously").Error(),
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
oldSpec: &KeptnTaskDefinition{
Spec: KeptnTaskDefinitionSpec{},
},
verb: "update",
},

{
name: "with-both-function-and-python",
spec: specWithFunctionAndPython,
verb: "create",
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"with-both-function-and-python",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithFunctionAndPython,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
},
{
name: "update-with-both-function-and-python",
spec: specWithFunctionAndPython,
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"update-with-both-function-and-python",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithFunctionAndPython,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
oldSpec: &KeptnTaskDefinition{
Spec: KeptnTaskDefinitionSpec{},
},
verb: "update",
},

{
name: "with-both-function-and-deno",
spec: specWithFunctionAndDeno,
verb: "create",
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"with-both-function-and-deno",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithFunctionAndDeno,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
},
{
name: "update-with-both-function-and-deno",
spec: specWithFunctionAndDeno,
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"update-with-both-function-and-deno",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithFunctionAndDeno,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
oldSpec: &KeptnTaskDefinition{
Spec: KeptnTaskDefinitionSpec{},
},
verb: "update",
},

{
name: "with-both-container-and-python",
spec: specWithContainerAndPython,
verb: "create",
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"with-both-container-and-python",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithContainerAndPython,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
},
{
name: "update-with-both-container-and-python",
spec: specWithContainerAndPython,
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"update-with-both-container-and-python",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithContainerAndPython,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
oldSpec: &KeptnTaskDefinition{
Spec: KeptnTaskDefinitionSpec{},
},
verb: "update",
},

{
name: "with-both-container-and-deno",
spec: specWithContainerAndDeno,
verb: "create",
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"with-both-container-and-deno",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithContainerAndDeno,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
},
{
name: "update-with-both-container-and-deno",
spec: specWithContainerAndDeno,
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"update-with-both-container-and-deno",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithContainerAndDeno,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
oldSpec: &KeptnTaskDefinition{
Spec: KeptnTaskDefinitionSpec{},
},
verb: "update",
},
{
name: "with-both-python-and-deno",
spec: specWithPythonAndDeno,
verb: "create",
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"with-both-python-and-deno",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithPythonAndDeno,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
},
{
name: "update-with-both-python-and-deno",
spec: specWithPythonAndDeno,
want: apierrors.NewInvalid(
schema.GroupKind{Group: "lifecycle.keptn.sh", Kind: "KeptnTaskDefinition"},
"update-with-both-python-and-deno",
[]*field.Error{field.Invalid(
field.NewPath("spec"),
specWithPythonAndDeno,
errors.New("Forbidden! Only one of Function, Container, Python, or Deno field can be defined").Error(),
)},
),
oldSpec: &KeptnTaskDefinition{
Spec: KeptnTaskDefinitionSpec{},
},
verb: "update",
},

{
name: "delete",
verb: "delete",
Expand Down
19 changes: 17 additions & 2 deletions test/integration/validate-taskdefinition/00-teststep-install.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
- goodtaskdefinition.yaml
- td_good_container.yaml
- td_good_function.yaml
- td_good_python.yaml
- td_good_deno.yaml
commands:
- command: kubectl apply -f badtaskdefinition.yaml
- command: kubectl apply -f td_bad_empty.yaml
ignoreFailure: true # we must install ignoring the validating webhook error to proceed with the test
- command: kubectl apply -f td_bad_container_function.yaml
ignoreFailure: true # we must install ignoring the validating webhook error to proceed with the test
- command: kubectl apply -f td_bad_container_python.yaml
ignoreFailure: true # we must install ignoring the validating webhook error to proceed with the test
- command: kubectl apply -f td_bad_container_deno.yaml
ignoreFailure: true # we must install ignoring the validating webhook error to proceed with the test
- command: kubectl apply -f td_bad_function_python.yaml
ignoreFailure: true # we must install ignoring the validating webhook error to proceed with the test
- command: kubectl apply -f td_bad_function_deno.yaml
ignoreFailure: true # we must install ignoring the validating webhook error to proceed with the test
- command: kubectl apply -f td_bad_python_deno.yaml
ignoreFailure: true # we must install ignoring the validating webhook error to proceed with the test
13 changes: 11 additions & 2 deletions test/integration/validate-taskdefinition/01-teststep-assert.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
error: # this checks that kubectl get resource fails, AKA bad CRD not added
- badtaskdefinition.yaml
- td_bad_empty.yaml
- td_bad_container_function.yaml
- td_bad_container_python.yaml
- td_bad_container_deno.yaml
- td_bad_function_python.yaml
- td_bad_function_deno.yaml
- td_bad_python_deno.yaml
assert: # this checks that kubectl get resource succeeds
- goodtaskdefinition.yaml
- td_good_container.yaml
- td_good_function.yaml
- td_good_python.yaml
- td_good_deno.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
name: badtaskdefinition1
name: badtaskdefinition4
spec:
container:
name: keptntaskdefinition
Expand All @@ -18,10 +18,7 @@ spec:
volumeMounts:
- mountPath: /cache
name: logger
---
# This TaskDefinition will not be accepted by the validation webhook as it doesn't contain either containerSpec or functionSpec
apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
name: badtaskdefinition2
spec:
deno:
inline:
code: |
console.log('hello');
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# This TaskDefinition will not be accepted by the validation webhook as it contains both containerSpec and functionSpec
apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
name: goodtaskdefinition1
name: badtaskdefinition1
spec:
container:
name: keptntaskdefinition1
name: keptntaskdefinition
image: busybox:1.36.0
resources:
limits:
Expand All @@ -17,12 +18,6 @@ spec:
volumeMounts:
- mountPath: /cache
name: logger
---
apiVersion: lifecycle.keptn.sh/v1alpha3
kind: KeptnTaskDefinition
metadata:
name: goodtaskdefinition2
spec:
function:
inline:
code: |
Expand Down
Loading

0 comments on commit 911f85f

Please sign in to comment.