feat: prevent updates to mcs.types or when multiple types are involved.

Signed-off-by: jwcesign <jwcesign@gmail.com>
This commit is contained in:
jwcesign 2023-12-19 18:39:01 +08:00
parent 33c98a4e44
commit dc4338398a
2 changed files with 51 additions and 1 deletions

View File

@ -19,6 +19,7 @@ package multiclusterservice
import (
"context"
"net/http"
"reflect"
"strings"
admissionv1 "k8s.io/api/admission/v1"
@ -73,11 +74,21 @@ func (v *ValidatingAdmission) Handle(ctx context.Context, req admission.Request)
func (v *ValidatingAdmission) validateMCSUpdate(oldMcs, newMcs *networkingv1alpha1.MultiClusterService) field.ErrorList {
allErrs := apimachineryvalidation.ValidateObjectMetaUpdate(&newMcs.ObjectMeta, &oldMcs.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, v.validateMCSTypesUpdate(oldMcs, newMcs)...)
allErrs = append(allErrs, v.validateMCS(newMcs)...)
allErrs = append(allErrs, lifted.ValidateLoadBalancerStatus(&newMcs.Status.LoadBalancer, field.NewPath("status", "loadBalancer"))...)
return allErrs
}
func (v *ValidatingAdmission) validateMCSTypesUpdate(oldMcs, newMcs *networkingv1alpha1.MultiClusterService) field.ErrorList {
allErrs := field.ErrorList{}
if !reflect.DeepEqual(oldMcs.Spec.Types, newMcs.Spec.Types) {
typePath := field.NewPath("spec").Child("types")
allErrs = append(allErrs, field.Invalid(typePath, oldMcs.Spec.Types, "MultiClusterService types are immutable"))
}
return allErrs
}
func (v *ValidatingAdmission) validateMCS(mcs *networkingv1alpha1.MultiClusterService) field.ErrorList {
allErrs := apimachineryvalidation.ValidateObjectMeta(&mcs.ObjectMeta, true,
apimachineryvalidation.NameIsDNS1035Label, field.NewPath("metadata"))
@ -97,12 +108,19 @@ func (v *ValidatingAdmission) validateMultiClusterServiceSpec(mcs *networkingv1a
port := mcs.Spec.Ports[i]
allErrs = append(allErrs, v.validateExposurePort(&port, allPortNames, portPath)...)
}
typesSet := sets.Set[string]{}
typesPath := specPath.Child("types")
for i := range mcs.Spec.Types {
typePath := typesPath.Index(i)
exposureType := mcs.Spec.Types[i]
typesSet.Insert(string(exposureType))
allErrs = append(allErrs, v.validateExposureType(&exposureType, typePath)...)
}
if len(typesSet) > 1 {
allErrs = append(allErrs, field.Invalid(typesPath, mcs.Spec.Types, "MultiClusterService types should not contain more than one type"))
}
clusterNamesPath := specPath.Child("range").Child("providerClusters")
for i := range mcs.Spec.ProviderClusters {
clusterNamePath := clusterNamesPath.Index(i)

View File

@ -51,7 +51,6 @@ func TestValidateMultiClusterServiceSpec(t *testing.T) {
},
Types: []networkingv1alpha1.ExposureType{
networkingv1alpha1.ExposureTypeLoadBalancer,
networkingv1alpha1.ExposureTypeCrossCluster,
},
ProviderClusters: []networkingv1alpha1.ClusterSelector{
{Name: "member1"},
@ -65,6 +64,39 @@ func TestValidateMultiClusterServiceSpec(t *testing.T) {
},
expectedErr: field.ErrorList{},
},
{
name: "multiple exposure type mcs",
mcs: &networkingv1alpha1.MultiClusterService{
Spec: networkingv1alpha1.MultiClusterServiceSpec{
Ports: []networkingv1alpha1.ExposurePort{
{
Name: "foo",
Port: 16312,
},
{
Name: "bar",
Port: 16313,
},
},
Types: []networkingv1alpha1.ExposureType{
networkingv1alpha1.ExposureTypeLoadBalancer,
networkingv1alpha1.ExposureTypeCrossCluster,
},
ProviderClusters: []networkingv1alpha1.ClusterSelector{
{Name: "member1"},
{Name: "member2"},
},
ConsumerClusters: []networkingv1alpha1.ClusterSelector{
{Name: "member1"},
{Name: "member2"},
},
},
},
expectedErr: field.ErrorList{field.Invalid(specFld.Child("types"), []networkingv1alpha1.ExposureType{
networkingv1alpha1.ExposureTypeLoadBalancer,
networkingv1alpha1.ExposureTypeCrossCluster,
}, "MultiClusterService types should not contain more than one type")},
},
{
name: "duplicated svc name",
mcs: &networkingv1alpha1.MultiClusterService{