check thirdparty resources
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
This commit is contained in:
parent
0e10088974
commit
62723e9a49
|
@ -0,0 +1,6 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-acj-nginx.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-acj-nginx.yaml
|
||||
operation: InterpretDependency
|
|
@ -0,0 +1,18 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-bcj-nginx.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-bcj-nginx.yaml
|
||||
operation: InterpretDependency
|
||||
- observedInputPath: testdata/observed-bcj-nginx.yaml
|
||||
operation: InterpretReplica
|
||||
- desiredInputPath: testdata/desired-bcj-nginx.yaml
|
||||
observedInputPath: testdata/observed-bcj-nginx.yaml
|
||||
operation: Retain
|
||||
- observedInputPath: testdata/observed-bcj-nginx.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-bcj-nginx.yaml
|
||||
operation: InterpretStatus
|
||||
- observedInputPath: testdata/observed-bcj-nginx.yaml
|
||||
operation: ReviseReplica
|
||||
desiredReplicas: 1
|
|
@ -0,0 +1,15 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-cloneset-nginx.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-cloneset-nginx.yaml
|
||||
operation: InterpretDependency
|
||||
- observedInputPath: testdata/observed-cloneset-nginx.yaml
|
||||
operation: InterpretReplica
|
||||
- observedInputPath: testdata/observed-cloneset-nginx.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-cloneset-nginx.yaml
|
||||
operation: InterpretStatus
|
||||
- observedInputPath: testdata/observed-cloneset-nginx.yaml
|
||||
operation: ReviseReplica
|
||||
desiredReplicas: 1
|
|
@ -0,0 +1,10 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-daemonset-nginx.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-daemonset-nginx.yaml
|
||||
operation: InterpretDependency
|
||||
- observedInputPath: testdata/observed-daemonset-nginx.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-daemonset-nginx.yaml
|
||||
operation: InterpretStatus
|
|
@ -0,0 +1,15 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-statefulset-nginx.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-statefulset-nginx.yaml
|
||||
operation: InterpretDependency
|
||||
- observedInputPath: testdata/observed-statefulset-nginx.yaml
|
||||
operation: InterpretReplica
|
||||
- observedInputPath: testdata/observed-statefulset-nginx.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-statefulset-nginx.yaml
|
||||
operation: InterpretStatus
|
||||
- observedInputPath: testdata/observed-statefulset-nginx.yaml
|
||||
operation: ReviseReplica
|
||||
desiredReplicas: 1
|
|
@ -0,0 +1,13 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-helmrelease.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-helmrelease.yaml
|
||||
operation: InterpretDependency
|
||||
- desiredInputPath: testdata/desired-helmrelease.yaml
|
||||
observedInputPath: testdata/observed-helmrelease.yaml
|
||||
operation: Retain
|
||||
- observedInputPath: testdata/observed-helmrelease.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-helmrelease.yaml
|
||||
operation: InterpretStatus
|
|
@ -0,0 +1,14 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-kustomization.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-kustomization.yaml
|
||||
operation: InterpretDependency
|
||||
- desiredInputPath: testdata/desired-kustomization.yaml
|
||||
observedInputPath: testdata/observed-kustomization.yaml
|
||||
operation: Retain
|
||||
- observedInputPath: testdata/observed-kustomization.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-kustomization.yaml
|
||||
operation: InterpretStatus
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-gitrepository.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-gitrepository.yaml
|
||||
operation: InterpretDependency
|
||||
- desiredInputPath: testdata/desired-gitrepository.yaml
|
||||
observedInputPath: testdata/observed-gitrepository.yaml
|
||||
operation: Retain
|
||||
- observedInputPath: testdata/observed-gitrepository.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-gitrepository.yaml
|
||||
operation: InterpretStatus
|
|
@ -0,0 +1,13 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-bucket.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-bucket.yaml
|
||||
operation: InterpretDependency
|
||||
- desiredInputPath: testdata/desired-bucket.yaml
|
||||
observedInputPath: testdata/observed-bucket.yaml
|
||||
operation: Retain
|
||||
- observedInputPath: testdata/observed-bucket.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-bucket.yaml
|
||||
operation: InterpretStatus
|
|
@ -0,0 +1,13 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-helmchart.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-helmchart.yaml
|
||||
operation: InterpretDependency
|
||||
- desiredInputPath: testdata/desired-helmchart.yaml
|
||||
observedInputPath: testdata/observed-helmchart.yaml
|
||||
operation: Retain
|
||||
- observedInputPath: testdata/observed-helmchart.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-helmchart.yaml
|
||||
operation: InterpretStatus
|
|
@ -0,0 +1,13 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-helmrepository.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-helmrepository.yaml
|
||||
operation: InterpretDependency
|
||||
- desiredInputPath: testdata/desired-helmrepository.yaml
|
||||
observedInputPath: testdata/observed-helmrepository.yaml
|
||||
operation: Retain
|
||||
- observedInputPath: testdata/observed-helmrepository.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-helmrepository.yaml
|
||||
operation: InterpretStatus
|
|
@ -0,0 +1,14 @@
|
|||
tests:
|
||||
- desiredInputPath: testdata/desired-ocirepository.yaml
|
||||
statusInputPath: testdata/status-file.yaml
|
||||
operation: AggregateStatus
|
||||
- desiredInputPath: testdata/desired-ocirepository.yaml
|
||||
operation: InterpretDependency
|
||||
- desiredInputPath: testdata/desired-ocirepository.yaml
|
||||
observedInputPath: testdata/observed-ocirepository.yaml
|
||||
operation: Retain
|
||||
- observedInputPath: testdata/observed-ocirepository.yaml
|
||||
operation: InterpretHealth
|
||||
- observedInputPath: testdata/observed-ocirepository.yaml
|
||||
operation: InterpretStatus
|
||||
|
|
@ -7,6 +7,8 @@ spec:
|
|||
interval: 5m
|
||||
ref:
|
||||
branch: master
|
||||
url: oci://ghcr.io/stefanprodan/podinfo-deploy
|
||||
ref:
|
||||
semver: "6.2.x"
|
||||
url: oci://ghcr.io/stefanprodan/podinfo-deploy
|
||||
secretRef:
|
||||
name: fake-secret
|
||||
serviceAccountName: fake-serviceaccount
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
package thirdparty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
|
||||
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
|
||||
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
|
||||
"github.com/karmada-io/karmada/pkg/resourceinterpreter/customized/declarative"
|
||||
"github.com/karmada-io/karmada/pkg/resourceinterpreter/customized/declarative/luavm"
|
||||
"github.com/karmada-io/karmada/pkg/util/interpreter"
|
||||
)
|
||||
|
||||
var rules interpreter.Rules = interpreter.AllResourceInterpreterCustomizationRules
|
||||
|
||||
func checkScript(script string) error {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
|
||||
defer cancel()
|
||||
l, err := luavm.NewWithContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.Close()
|
||||
_, err = l.LoadString(script)
|
||||
return err
|
||||
}
|
||||
|
||||
func getObj(t *testing.T, path string) *unstructured.Unstructured {
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
jsonData, err := yaml.ToJSON(data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
obj := make(map[string]interface{})
|
||||
err = json.Unmarshal(jsonData, &obj)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return &unstructured.Unstructured{Object: obj}
|
||||
}
|
||||
|
||||
func getAggregatedStatusItems(t *testing.T, path string) []workv1alpha2.AggregatedStatusItem {
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var statusItems []workv1alpha2.AggregatedStatusItem
|
||||
decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(data), 4096)
|
||||
for {
|
||||
statusItem := &workv1alpha2.AggregatedStatusItem{}
|
||||
err = decoder.Decode(statusItem)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
statusItems = append(statusItems, *statusItem)
|
||||
}
|
||||
if err != io.EOF {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return statusItems
|
||||
}
|
||||
|
||||
type TestStructure struct {
|
||||
Tests []IndividualTest `yaml:"tests"`
|
||||
}
|
||||
|
||||
type IndividualTest struct {
|
||||
DesiredInputPath string `yaml:"desiredInputPath,omitempty"`
|
||||
ObservedInputPath string `yaml:"observedInputPath,omitempty"`
|
||||
StatusInputPath string `yaml:"statusInputPath,omitempty"`
|
||||
DesiredReplica int64 `yaml:"desiredReplicas,omitempty"`
|
||||
Operation string `yaml:"operation"`
|
||||
}
|
||||
|
||||
func checkInterpretationRule(t *testing.T, path string, configs []*configv1alpha1.ResourceInterpreterCustomization) {
|
||||
ipt := declarative.NewConfigurableInterpreter(nil)
|
||||
ipt.LoadConfig(configs)
|
||||
|
||||
dir := filepath.Dir(path)
|
||||
yamlBytes, err := os.ReadFile(dir + string(os.PathSeparator) + "customizations_tests.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var resourceTest TestStructure
|
||||
err = yaml.Unmarshal(yamlBytes, &resourceTest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, customization := range configs {
|
||||
for _, input := range resourceTest.Tests {
|
||||
rule := rules.GetByOperation(input.Operation)
|
||||
if rule == nil {
|
||||
t.Fatalf("operation %s is not supported. Use one of: %s", input.Operation, strings.Join(rules.Names(), ", "))
|
||||
}
|
||||
err = checkScript(rule.GetScript(customization))
|
||||
if err != nil {
|
||||
t.Fatalf("checking %s of %s, expected nil, but got: %v", rule.Name(), customization.Name, err)
|
||||
}
|
||||
args := interpreter.RuleArgs{Replica: input.DesiredReplica}
|
||||
if input.DesiredInputPath != "" {
|
||||
args.Desired = getObj(t, dir+"/"+strings.TrimPrefix(input.DesiredInputPath, "/"))
|
||||
}
|
||||
if input.ObservedInputPath != "" {
|
||||
args.Observed = getObj(t, dir+"/"+strings.TrimPrefix(input.ObservedInputPath, "/"))
|
||||
}
|
||||
if input.StatusInputPath != "" {
|
||||
args.Status = getAggregatedStatusItems(t, dir+"/"+strings.TrimPrefix(input.StatusInputPath, "/"))
|
||||
}
|
||||
if result := rule.Run(ipt, args); result.Err != nil {
|
||||
t.Fatalf("execute %s %s error: %v\n", customization.Name, rule.Name(), result.Err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestThirdPartyCustomizationsFile(t *testing.T) {
|
||||
err := filepath.Walk("resourcecustomizations", func(path string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
// cannot happen
|
||||
return err
|
||||
}
|
||||
if f.IsDir() {
|
||||
return nil
|
||||
}
|
||||
if strings.Contains(path, "testdata") {
|
||||
return nil
|
||||
}
|
||||
if filepath.Base(path) != configurableInterpreterFile {
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
// cannot happen
|
||||
return err
|
||||
}
|
||||
var configs []*configv1alpha1.ResourceInterpreterCustomization
|
||||
decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(data), 4096)
|
||||
for {
|
||||
config := &configv1alpha1.ResourceInterpreterCustomization{}
|
||||
err = decoder.Decode(config)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
dirSplit := strings.Split(path, string(os.PathSeparator))
|
||||
if len(dirSplit) != 5 {
|
||||
return fmt.Errorf("the directory format is incorrect. Dir: %s", path)
|
||||
}
|
||||
if config.Spec.Target.APIVersion != fmt.Sprintf("%s/%s", dirSplit[1], dirSplit[2]) {
|
||||
return fmt.Errorf("Target.APIVersion does not match directory format. Target.APIVersion: %s, Dir: %s", config.Spec.Target.APIVersion, path)
|
||||
}
|
||||
if config.Spec.Target.Kind != dirSplit[3] {
|
||||
return fmt.Errorf("Target.Kind does not match directory format. Target.Kind: %s, Dir: %s", config.Spec.Target.Kind, path)
|
||||
}
|
||||
configs = append(configs, config)
|
||||
}
|
||||
if err != io.EOF {
|
||||
return err
|
||||
}
|
||||
checkInterpretationRule(t, path, configs)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected nil, but got: %v", err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue