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

feat(operator): adapt TaskDefinition validation webhook to consider python and deno runtime #1534

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
geoffrey1330 marked this conversation as resolved.
Show resolved Hide resolved
if r.Spec.Function != nil {
geoffrey1330 marked this conversation as resolved.
Show resolved Hide resolved
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
geoffrey1330 marked this conversation as resolved.
Show resolved Hide resolved
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
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