diff --git a/pkg/ippoolmanager/ippool_validate.go b/pkg/ippoolmanager/ippool_validate.go index 92b4af0933..f59201db0b 100644 --- a/pkg/ippoolmanager/ippool_validate.go +++ b/pkg/ippoolmanager/ippool_validate.go @@ -8,6 +8,7 @@ import ( "fmt" "strconv" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/utils/strings/slices" @@ -197,8 +198,10 @@ func (iw *IPPoolWebhook) validateIPPoolCIDR(ctx context.Context, ipPool *spiderp for _, pool := range ipPoolList.Items { if *pool.Spec.IPVersion == *ipPool.Spec.IPVersion { + // since we met already exist IPPool resource, we just return the error to avoid the following taxing operations. + // the user can also use k8s 'errors.IsAlreadyExists' to get the right error type assertion. if pool.Name == ipPool.Name { - return field.InternalError(subnetField, fmt.Errorf("IPPool %s already exists", ipPool.Name)) + return field.InternalError(subnetField, fmt.Errorf("IPPool %s %s", ipPool.Name, metav1.StatusReasonAlreadyExists)) } if pool.Spec.Subnet == ipPool.Spec.Subnet { diff --git a/pkg/ippoolmanager/ippool_webhook.go b/pkg/ippoolmanager/ippool_webhook.go index ef962b06f0..28ea7a2f70 100644 --- a/pkg/ippoolmanager/ippool_webhook.go +++ b/pkg/ippoolmanager/ippool_webhook.go @@ -6,9 +6,11 @@ package ippoolmanager import ( "context" "errors" + "strings" "go.uber.org/zap" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ctrl "sigs.k8s.io/controller-runtime" @@ -77,12 +79,20 @@ func (iw *IPPoolWebhook) ValidateCreate(ctx context.Context, obj runtime.Object) logger.Sugar().Debugf("Request IPPool: %+v", *ipPool) if errs := iw.validateCreateIPPoolWhileEnableSpiderSubnet(logutils.IntoContext(ctx, logger), ipPool); len(errs) != 0 { - logger.Sugar().Errorf("Failed to create IPPool: %v", errs.ToAggregate().Error()) - return nil, apierrors.NewInvalid( - schema.GroupKind{Group: constant.SpiderpoolAPIGroup, Kind: constant.KindSpiderIPPool}, - ipPool.Name, - errs, - ) + aggregatedErr := errs.ToAggregate() + logger.Sugar().Errorf("Failed to create IPPool: %s", aggregatedErr) + // the user will receive the following errors rather than K8S API server specific typed errors. + // Refer to https://github.com/spidernet-io/spiderpool/issues/3321 + switch { + case strings.Contains(aggregatedErr.Error(), string(metav1.StatusReasonAlreadyExists)): + return nil, apierrors.NewAlreadyExists(spiderpoolv2beta1.Resource(constant.KindSpiderIPPool), ipPool.Name) + default: + return nil, apierrors.NewInvalid( + schema.GroupKind{Group: constant.SpiderpoolAPIGroup, Kind: constant.KindSpiderIPPool}, + ipPool.Name, + errs, + ) + } } return nil, nil diff --git a/pkg/ippoolmanager/ippool_webhook_test.go b/pkg/ippoolmanager/ippool_webhook_test.go index aea62c319b..e10fa9518d 100644 --- a/pkg/ippoolmanager/ippool_webhook_test.go +++ b/pkg/ippoolmanager/ippool_webhook_test.go @@ -682,7 +682,7 @@ var _ = Describe("IPPoolWebhook", Label("ippool_webhook_test"), func() { Expect(err).NotTo(HaveOccurred()) warns, err := ipPoolWebhook.ValidateCreate(ctx, ipPoolT) - Expect(apierrors.IsInvalid(err)).To(BeTrue()) + Expect(apierrors.IsAlreadyExists(err)).To(BeTrue()) Expect(warns).To(BeNil()) }) diff --git a/pkg/subnetmanager/subnet_validate.go b/pkg/subnetmanager/subnet_validate.go index 84effa05c1..0ed8897240 100644 --- a/pkg/subnetmanager/subnet_validate.go +++ b/pkg/subnetmanager/subnet_validate.go @@ -8,14 +8,14 @@ import ( "fmt" "strconv" - "k8s.io/apimachinery/pkg/util/validation/field" - "github.com/spidernet-io/spiderpool/pkg/constant" spiderpoolip "github.com/spidernet-io/spiderpool/pkg/ip" "github.com/spidernet-io/spiderpool/pkg/ippoolmanager" spiderpoolv2beta1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v2beta1" "github.com/spidernet-io/spiderpool/pkg/types" "github.com/spidernet-io/spiderpool/pkg/utils/convert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" ) var ( @@ -192,8 +192,10 @@ func (sw *SubnetWebhook) validateSubnetCIDR(ctx context.Context, subnet *spiderp for _, s := range subnetList.Items { if *s.Spec.IPVersion == *subnet.Spec.IPVersion { + // since we met already exist Subnet resource, we just return the error to avoid the following taxing operations. + // the user can also use k8s 'errors.IsAlreadyExists' to get the right error type assertion. if s.Name == subnet.Name { - return field.InternalError(subnetField, fmt.Errorf("subnet %s already exists", subnet.Name)) + return field.InternalError(subnetField, fmt.Errorf("subnet %s %s", subnet.Name, metav1.StatusReasonAlreadyExists)) } overlap, err := spiderpoolip.IsCIDROverlap(*subnet.Spec.IPVersion, subnet.Spec.Subnet, s.Spec.Subnet) diff --git a/pkg/subnetmanager/subnet_webhook.go b/pkg/subnetmanager/subnet_webhook.go index 6870e6d391..b7dafcb42e 100644 --- a/pkg/subnetmanager/subnet_webhook.go +++ b/pkg/subnetmanager/subnet_webhook.go @@ -6,9 +6,11 @@ package subnetmanager import ( "context" "errors" + "strings" "go.uber.org/zap" apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ctrl "sigs.k8s.io/controller-runtime" @@ -76,12 +78,20 @@ func (sw *SubnetWebhook) ValidateCreate(ctx context.Context, obj runtime.Object) logger.Sugar().Debugf("Request Subnet: %+v", *subnet) if errs := sw.validateCreateSubnet(logutils.IntoContext(ctx, logger), subnet); len(errs) != 0 { - logger.Sugar().Errorf("Failed to create Subnet: %v", errs.ToAggregate().Error()) - return nil, apierrors.NewInvalid( - schema.GroupKind{Group: constant.SpiderpoolAPIGroup, Kind: constant.KindSpiderSubnet}, - subnet.Name, - errs, - ) + aggregatedErr := errs.ToAggregate() + logger.Sugar().Errorf("Failed to create Subnet: %s", aggregatedErr) + // the user will receive the following errors rather than K8S API server specific typed errors. + // Refer to https://github.com/spidernet-io/spiderpool/issues/3321 + switch { + case strings.Contains(aggregatedErr.Error(), string(metav1.StatusReasonAlreadyExists)): + return nil, apierrors.NewAlreadyExists(spiderpoolv2beta1.Resource(constant.KindSpiderSubnet), subnet.Name) + default: + return nil, apierrors.NewInvalid( + schema.GroupKind{Group: constant.SpiderpoolAPIGroup, Kind: constant.KindSpiderSubnet}, + subnet.Name, + errs, + ) + } } return nil, nil diff --git a/pkg/subnetmanager/subnet_webhook_test.go b/pkg/subnetmanager/subnet_webhook_test.go index 55de118c74..15e27d6222 100644 --- a/pkg/subnetmanager/subnet_webhook_test.go +++ b/pkg/subnetmanager/subnet_webhook_test.go @@ -478,7 +478,7 @@ var _ = Describe("SubnetWebhook", Label("subnet_webhook_test"), func() { Expect(err).NotTo(HaveOccurred()) warns, err := subnetWebhook.ValidateCreate(ctx, subnetT) - Expect(apierrors.IsInvalid(err)).To(BeTrue()) + Expect(apierrors.IsAlreadyExists(err)).To(BeTrue()) Expect(warns).To(BeNil()) })