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

backup: init migrate webhook #412

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions pkg/webhooks/migrate_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package webhooks

import (
"context"
"fmt"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook"

"kurator.dev/kurator/pkg/apis/backups/v1alpha1"
)

var _ webhook.CustomValidator = &MigrateWebhook{}

type MigrateWebhook struct {
Client client.Reader
}

func (wh *MigrateWebhook) SetupWebhookWithManager(mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(&v1alpha1.Migrate{}).
WithValidator(wh).
Complete()
}

func (wh *MigrateWebhook) ValidateCreate(ctx context.Context, obj runtime.Object) error {
in, ok := obj.(*v1alpha1.Migrate)
if !ok {
return apierrors.NewBadRequest(fmt.Sprintf("expected a Migrate but got a %T", obj))
}

return wh.validate(in)
}

func (wh *MigrateWebhook) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error {
in, ok := newObj.(*v1alpha1.Migrate)
if !ok {
return apierrors.NewBadRequest(fmt.Sprintf("expected a Migrate but got a %T", newObj))
}

return wh.validate(in)
}

func (wh *MigrateWebhook) ValidateDelete(ctx context.Context, obj runtime.Object) error {
return nil
}

func (wh *MigrateWebhook) validate(in *v1alpha1.Migrate) error {
var allErrs field.ErrorList

// Ensure that SourceCluster points to only ONE cluster.
// Because the current migration only supports migrating from one SourceCluster to one or more TargetCluster.
if len(in.Spec.SourceCluster.Clusters) != 1 {
allErrs = append(allErrs, field.Invalid(field.NewPath("sourceCluster"), len(in.Spec.SourceCluster.Clusters), "must have exactly one source cluster"))
}
// Validate referenced clusters in SourceCluster
allErrs = append(allErrs, validateDestinationClusters(in.Spec.SourceCluster.Clusters)...)

Check failure on line 61 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: validateDestinationClusters

Check failure on line 61 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: validateDestinationClusters

Check failure on line 61 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: validateDestinationClusters

Check failure on line 61 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Compile

undefined: validateDestinationClusters

Check failure on line 61 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Unit test

undefined: validateDestinationClusters

sourceCluster := in.Spec.SourceCluster.Clusters[0]

// If the 'clusters' field is not specified, it defaults to encompassing all clusters; hence, there's no need to validate the count of TargetClusters.

// Validate referenced clusters in TargetClusters
allErrs = append(allErrs, validateDestinationClusters(in.Spec.TargetClusters.Clusters)...)

Check failure on line 68 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: validateDestinationClusters

Check failure on line 68 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: validateDestinationClusters

Check failure on line 68 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Compile

undefined: validateDestinationClusters

Check failure on line 68 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Unit test

undefined: validateDestinationClusters

// Ensure target cluster not be the same as source cluster
for _, targetCluster := range in.Spec.TargetClusters.Clusters {
if targetCluster.Name == sourceCluster.Name && targetCluster.Kind == sourceCluster.Kind {
allErrs = append(allErrs, field.Invalid(field.NewPath("targetCluster"), targetCluster.Name, "target cluster cannot be the same as source cluster"))
}
}

// Validate Policy
if in.Spec.Policy != nil {
// Validate Resource Filter
allErrs = append(allErrs, validateResourceFilter(in.Spec.Policy.ResourceFilter)...)

Check failure on line 80 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: validateResourceFilter) (typecheck)

Check failure on line 80 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Lint

undefined: validateResourceFilter) (typecheck)

Check failure on line 80 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Compile

undefined: validateResourceFilter

Check failure on line 80 in pkg/webhooks/migrate_webhook.go

View workflow job for this annotation

GitHub Actions / Unit test

undefined: validateResourceFilter
}

if len(allErrs) > 0 {
return apierrors.NewInvalid(v1alpha1.SchemeGroupVersion.WithKind("Migrate").GroupKind(), in.Name, allErrs)
}

return nil
}
68 changes: 68 additions & 0 deletions pkg/webhooks/migrate_webhook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
Copyright Kurator 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 webhooks

import (
"io/fs"
"os"
"path"
"path/filepath"
"testing"

. "github.com/onsi/gomega"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/yaml"

"kurator.dev/kurator/pkg/apis/backups/v1alpha1"
)

func TestInvalidMigrateValidation(t *testing.T) {
r := path.Join("testdata", "migrate")
caseNames := make([]string, 0)
err := filepath.WalkDir(r, func(path string, d fs.DirEntry, err error) error {
if d.IsDir() {
return nil
}
caseNames = append(caseNames, path)
return nil
})
assert.NoError(t, err)

wh := &MigrateWebhook{}
for _, tt := range caseNames {
t.Run(tt, func(t *testing.T) {
g := NewWithT(t)
c, err := readMigrate(tt)
g.Expect(err).NotTo(HaveOccurred())

err = wh.validate(c)
g.Expect(err).To(HaveOccurred())
t.Logf("%v", err)
})
}
}

func readMigrate(filename string) (*v1alpha1.Migrate, error) {
b, err := os.ReadFile(filename)
if err != nil {
return nil, err
}

c := &v1alpha1.Migrate{}
if err := yaml.Unmarshal(b, c); err != nil {
return nil, err
}

return c, nil
}
18 changes: 18 additions & 0 deletions pkg/webhooks/testdata/migrate/multi-source-cluster.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: kurator.dev/v1alpha1
kind: Migrate
metadata:
name: multi-source-cluster
namespace: default
spec:
sourceCluster:
fleet: quickstart
clusters:
- name: source-cluster-1
kind: Cluster
- name: source-cluster-2
kind: Cluster
targetCluster:
fleet: quickstart
clusters:
- name: target-cluster-1
kind: Cluster
16 changes: 16 additions & 0 deletions pkg/webhooks/testdata/migrate/source-same-with-target.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: kurator.dev/v1alpha1
kind: Migrate
metadata:
name: source-same-with-target
namespace: default
spec:
sourceCluster:
fleet: quickstart
clusters:
- name: same-cluster
kind: Cluster
targetCluster:
fleet: quickstart
clusters:
- name: same-cluster
kind: Cluster
Loading