mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 10:00:06 +00:00
* feat: implement output resource existence validation in component, trait, and policy definitions Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add validation tests for ComponentDefinition and TraitDefinition outputs - Implement tests for ComponentDefinition with non-existent CRDs in outputs, ensuring they are rejected. - Add tests for valid outputs in ComponentDefinition, confirming acceptance. - Include tests for mixed valid and non-K8s outputs in ComponentDefinition, verifying they pass validation. - Test handling of empty outputs in ComponentDefinition, ensuring they are accepted. - Introduce tests for invalid apiVersion formats in ComponentDefinition, confirming rejection. - Add tests for TraitDefinition with mixed valid and invalid outputs, ensuring proper rejection. - Create YAML manifests for valid and invalid ComponentDefinitions and TraitDefinitions to support e2e tests. - Ensure comprehensive coverage of edge cases in output validation logic. Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> fix: handle errors in resource validation for component, trait, and policy definitions Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> fix: improve error handling in Go module tidy and resource validation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add webhook debugging setup and validation tests for ComponentDefinition and TraitDefinition Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add VS Code launch configuration for debugging webhook validation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> refactor: streamline error handling in Go module tidy and remove obsolete test manifests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add mock context support for CUE template compilation Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: enhance validation for WorkflowStepDefinition resources and improve output resource checks Signed-off-by: viskumar <viskumar@guidewire.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: implement resource validation for CUE templates and add unit tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: enhance logging and validation for component, policy, and trait definitions Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: improve error handling and logging in validation handlers for component, policy, trait, and workflow step definitions Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Remove testUnknownResource folder from repository Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: implement structured logging for validation handlers and remove deprecated request_logger Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: enhance structured logging and error handling in admission validation handlers Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: improve logging messages in validating handlers for better clarity Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: refactor logging field definitions for consistency and improve error handling in resource validation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> chore: add license header to invalid_resource_check.go and invalid_resource_check_test.go Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: enhance validation tests for WorkflowStepDefinition and improve error messages Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add e2e-test-local target for k3d cluster setup and webhook validation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add webhook configuration for workflow step definitions with validation rules Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: update e2e-test-local configuration and improve Ingress API version compatibility Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add installation of FluxCD CRDs in pre-hook to prevent webhook validation errors Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add ValidateResourcesExist feature gate and enhance resource validation in webhook handlers Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: enhance resource validation in e2e tests and improve addon definition checks Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: enhance addon definition detection by using owner references for validation Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: add ValidateResourcesExist feature gate and implement webhook validation for resource existence Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: update Ingress API version to v1 and adjust service references in tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> chore: remove webhook test commands and related YAML files from makefiles and tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> chore: remove architecture section from webhook debugging guide Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> feat: update webhook setup script with k3d host gateway IP note and improve cluster creation logic Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Fix: Correct path in Ingress resource definition in template tests Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> * Chore: add empty line to re-trigger failing workflow Signed-off-by: Vaibhav Agrawal <vaibhav.agrawal0096@gmail.com> * Chore: remove space to re-trigger workflow Signed-off-by: Chaitanya Reddy Onteddu <co@guidewire.com> --------- Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com> Signed-off-by: Vaibhav Agrawal <vaibhav.agrawal0096@gmail.com> Signed-off-by: Chaitanya Reddy Onteddu <co@guidewire.com> Co-authored-by: Chaitanya Reddy Onteddu <chaitanyareddy0702@gmail.com> Co-authored-by: Amit Singh <amisingh@guidewire.com>
388 lines
10 KiB
Go
388 lines
10 KiB
Go
/*
|
|
Copyright 2021 The KubeVela Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package appfile
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"cuelang.org/go/cue/cuecontext"
|
|
"github.com/crossplane/crossplane-runtime/pkg/test"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/stretchr/testify/assert"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
ktypes "k8s.io/apimachinery/pkg/types"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
|
"github.com/oam-dev/kubevela/apis/types"
|
|
oamutil "github.com/oam-dev/kubevela/pkg/oam/util"
|
|
)
|
|
|
|
func TestLoadComponentTemplate(t *testing.T) {
|
|
cueTemplate := `
|
|
context: {
|
|
name: "test"
|
|
}
|
|
output: {
|
|
apiVersion: "apps/v1"
|
|
kind: "Deployment"
|
|
spec: {
|
|
selector: matchLabels: {
|
|
"app.oam.dev/component": context.name
|
|
}
|
|
|
|
template: {
|
|
metadata: labels: {
|
|
"app.oam.dev/component": context.name
|
|
}
|
|
|
|
spec: {
|
|
containers: [{
|
|
name: context.name
|
|
image: parameter.image
|
|
|
|
if parameter["cmd"] != _|_ {
|
|
command: parameter.cmd
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
|
|
selector:
|
|
matchLabels:
|
|
"app.oam.dev/component": context.name
|
|
}
|
|
}
|
|
|
|
parameter: {
|
|
// +usage=Which image would you like to use for your service
|
|
// +short=i
|
|
image: string
|
|
|
|
cmd?: [...string]
|
|
}
|
|
`
|
|
|
|
var componentDefintion = `
|
|
apiVersion: core.oam.dev/v1beta1
|
|
kind: ComponentDefinition
|
|
metadata:
|
|
name: worker
|
|
namespace: default
|
|
annotations:
|
|
definition.oam.dev/description: "Long-running scalable backend worker without network endpoint"
|
|
spec:
|
|
workload:
|
|
definition:
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
extension:
|
|
template: |
|
|
` + cueTemplate
|
|
|
|
// Create mock client
|
|
tclient := test.MockClient{
|
|
MockGet: func(ctx context.Context, key ktypes.NamespacedName, obj client.Object) error {
|
|
switch o := obj.(type) {
|
|
case *v1beta1.ComponentDefinition:
|
|
cd, err := oamutil.UnMarshalStringToComponentDefinition(componentDefintion)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*o = *cd
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
var annotations = make(map[string]string)
|
|
temp, err := LoadTemplate(context.TODO(), &tclient, "worker", types.TypeComponentDefinition, annotations)
|
|
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
inst := cuecontext.New().CompileString(temp.TemplateStr)
|
|
instDest := cuecontext.New().CompileString(cueTemplate)
|
|
s1, _ := inst.Value().String()
|
|
s2, _ := instDest.Value().String()
|
|
if s1 != s2 {
|
|
t.Errorf("parsered template is not correct")
|
|
}
|
|
}
|
|
|
|
func TestLoadTraitTemplate(t *testing.T) {
|
|
cueTemplate := `
|
|
parameter: {
|
|
domain: string
|
|
http: [string]: int
|
|
}
|
|
context: {
|
|
name: "test"
|
|
}
|
|
// trait template can have multiple outputs in one trait
|
|
outputs: service: {
|
|
apiVersion: "v1"
|
|
kind: "Service"
|
|
metadata:
|
|
name: context.name
|
|
spec: {
|
|
selector:
|
|
"app.oam.dev/component": context.name
|
|
ports: [
|
|
for k, v in parameter.http {
|
|
port: v
|
|
targetPort: v
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
outputs: ingress: {
|
|
apiVersion: "networking.k8s.io/v1"
|
|
kind: "Ingress"
|
|
metadata:
|
|
name: context.name
|
|
spec: {
|
|
rules: [{
|
|
host: parameter.domain
|
|
http: {
|
|
paths: [
|
|
for k, v in parameter.http {
|
|
path: k
|
|
pathType: "Prefix"
|
|
backend: {
|
|
service: {
|
|
name: context.name
|
|
port: {
|
|
number: v
|
|
}
|
|
}
|
|
}
|
|
},
|
|
]
|
|
}
|
|
}]
|
|
}
|
|
}
|
|
`
|
|
|
|
var traitDefintion = `
|
|
apiVersion: core.oam.dev/v1beta1
|
|
kind: TraitDefinition
|
|
metadata:
|
|
annotations:
|
|
definition.oam.dev/description: "Configures K8s ingress and service to enable web traffic for your service.
|
|
Please use route trait in cap center for advanced usage."
|
|
name: ingress
|
|
namespace: default
|
|
spec:
|
|
status:
|
|
customStatus: |-
|
|
if len(context.outputs.ingress.status.loadBalancer.ingress) > 0 {
|
|
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + context.outputs.ingress.status.loadBalancer.ingress[0].ip
|
|
}
|
|
if len(context.outputs.ingress.status.loadBalancer.ingress) == 0 {
|
|
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
|
|
}
|
|
healthPolicy: |
|
|
isHealth: len(context.outputs.service.spec.clusterIP) > 0
|
|
appliesToWorkloads:
|
|
- deployments.apps
|
|
schematic:
|
|
cue:
|
|
template: |
|
|
` + cueTemplate
|
|
|
|
// Create mock client
|
|
tclient := test.MockClient{
|
|
MockGet: func(ctx context.Context, key ktypes.NamespacedName, obj client.Object) error {
|
|
switch o := obj.(type) {
|
|
case *v1beta1.TraitDefinition:
|
|
wd, err := oamutil.UnMarshalStringToTraitDefinition(traitDefintion)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*o = *wd
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
var annotations = make(map[string]string)
|
|
temp, err := LoadTemplate(context.TODO(), &tclient, "ingress", types.TypeTrait, annotations)
|
|
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
inst := cuecontext.New().CompileString(temp.TemplateStr)
|
|
instDest := cuecontext.New().CompileString(cueTemplate)
|
|
s1, _ := inst.Value().String()
|
|
s2, _ := instDest.Value().String()
|
|
if s1 != s2 {
|
|
t.Errorf("parsered template is not correct")
|
|
}
|
|
}
|
|
|
|
func TestLoadSchematicToTemplate(t *testing.T) {
|
|
testCases := map[string]struct {
|
|
schematic *common.Schematic
|
|
status *common.Status
|
|
ext *runtime.RawExtension
|
|
want *Template
|
|
}{
|
|
"only tmp": {
|
|
schematic: &common.Schematic{CUE: &common.CUE{Template: "t1"}},
|
|
want: &Template{
|
|
TemplateStr: "t1",
|
|
CapabilityCategory: types.CUECategory,
|
|
},
|
|
},
|
|
"no tmp,but has extension": {
|
|
ext: &runtime.RawExtension{Raw: []byte(`{"template":"t1"}`)},
|
|
want: &Template{
|
|
TemplateStr: "t1",
|
|
CapabilityCategory: types.CUECategory,
|
|
},
|
|
},
|
|
"no tmp,but has extension without temp": {
|
|
ext: &runtime.RawExtension{Raw: []byte(`{"template":{"t1":"t2"}}`)},
|
|
want: &Template{
|
|
TemplateStr: "",
|
|
CapabilityCategory: types.CUECategory,
|
|
},
|
|
},
|
|
"tmp with status": {
|
|
schematic: &common.Schematic{CUE: &common.CUE{Template: "t1"}},
|
|
status: &common.Status{
|
|
CustomStatus: "s1",
|
|
HealthPolicy: "h1",
|
|
},
|
|
want: &Template{
|
|
TemplateStr: "t1",
|
|
CustomStatus: "s1",
|
|
Health: "h1",
|
|
CapabilityCategory: types.CUECategory,
|
|
},
|
|
},
|
|
"no tmp only status": {
|
|
status: &common.Status{
|
|
CustomStatus: "s1",
|
|
HealthPolicy: "h1",
|
|
},
|
|
want: &Template{
|
|
CustomStatus: "s1",
|
|
Health: "h1",
|
|
},
|
|
},
|
|
"terraform schematic": {
|
|
schematic: &common.Schematic{Terraform: &common.Terraform{}},
|
|
want: &Template{
|
|
CapabilityCategory: types.TerraformCategory,
|
|
Terraform: &common.Terraform{},
|
|
},
|
|
},
|
|
}
|
|
for reason, casei := range testCases {
|
|
gtmp := &Template{}
|
|
err := loadSchematicToTemplate(gtmp, casei.status, casei.schematic, casei.ext)
|
|
assert.NoError(t, err, reason)
|
|
assert.Equal(t, casei.want, gtmp, reason)
|
|
}
|
|
}
|
|
|
|
func TestDryRunTemplateLoader(t *testing.T) {
|
|
compDefStr := `
|
|
apiVersion: core.oam.dev/v1beta1
|
|
kind: ComponentDefinition
|
|
metadata:
|
|
name: myworker
|
|
spec:
|
|
status:
|
|
customStatus: testCustomStatus
|
|
healthPolicy: testHealthPolicy
|
|
workload:
|
|
definition:
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
schematic:
|
|
cue:
|
|
template: testCUE `
|
|
|
|
traitDefStr := `
|
|
apiVersion: core.oam.dev/v1beta1
|
|
kind: TraitDefinition
|
|
metadata:
|
|
name: myingress
|
|
spec:
|
|
status:
|
|
customStatus: testCustomStatus
|
|
healthPolicy: testHealthPolicy
|
|
appliesToWorkloads:
|
|
- deployments.apps
|
|
schematic:
|
|
cue:
|
|
template: testCUE `
|
|
|
|
compDef, _ := oamutil.UnMarshalStringToComponentDefinition(compDefStr)
|
|
traitDef, _ := oamutil.UnMarshalStringToTraitDefinition(traitDefStr)
|
|
unstrctCompDef, _ := oamutil.Object2Unstructured(compDef)
|
|
unstrctTraitDef, _ := oamutil.Object2Unstructured(traitDef)
|
|
|
|
expectedCompTmpl := &Template{
|
|
TemplateStr: "testCUE",
|
|
Health: "testHealthPolicy",
|
|
CustomStatus: "testCustomStatus",
|
|
CapabilityCategory: types.CUECategory,
|
|
Reference: common.WorkloadTypeDescriptor{
|
|
Definition: common.WorkloadGVK{
|
|
APIVersion: "apps/v1",
|
|
Kind: "Deployment",
|
|
},
|
|
},
|
|
ComponentDefinition: compDef,
|
|
}
|
|
|
|
expectedTraitTmpl := &Template{
|
|
TemplateStr: "testCUE",
|
|
Health: "testHealthPolicy",
|
|
CustomStatus: "testCustomStatus",
|
|
CapabilityCategory: types.CUECategory,
|
|
TraitDefinition: traitDef,
|
|
}
|
|
|
|
var annotations = make(map[string]string)
|
|
dryRunLoadTemplate := DryRunTemplateLoader([]*unstructured.Unstructured{unstrctCompDef, unstrctTraitDef})
|
|
compTmpl, err := dryRunLoadTemplate(nil, nil, "myworker", types.TypeComponentDefinition, annotations)
|
|
if err != nil {
|
|
t.Error("failed load template of component defintion", err)
|
|
}
|
|
if diff := cmp.Diff(expectedCompTmpl, compTmpl); diff != "" {
|
|
t.Fatal("failed load template of component defintion", diff)
|
|
}
|
|
|
|
traitTmpl, err := dryRunLoadTemplate(nil, nil, "myingress", types.TypeTrait, annotations)
|
|
if err != nil {
|
|
t.Error("failed load template of component defintion", err)
|
|
}
|
|
if diff := cmp.Diff(expectedTraitTmpl, traitTmpl); diff != "" {
|
|
t.Fatal("failed load template of trait definition ", diff)
|
|
}
|
|
}
|