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

api: define API for MultiClusterService #4290

Merged
merged 1 commit into from
Nov 24, 2023
Merged
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
18 changes: 17 additions & 1 deletion api/openapi-spec/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -21169,10 +21169,26 @@
}
},
"range": {
"description": "Range specifies the ranges where the referencing service should be exposed. Only valid and optional in case of Types contains CrossCluster. If not set and Types contains CrossCluster, all clusters will be selected, that means the referencing service will be exposed across all registered clusters.",
"description": "Range specifies the ranges where the referencing service should be exposed. Only valid and optional in case of Types contains CrossCluster. If not set and Types contains CrossCluster, all clusters will be selected, that means the referencing service will be exposed across all registered clusters. Deprecated: in favor of ServiceProvisionClusters/ServiceConsumptionClusters.",
"default": {},
"$ref": "#/definitions/com.github.karmada-io.karmada.pkg.apis.networking.v1alpha1.ExposureRange"
},
"serviceConsumptionClusters": {
"description": "ServiceConsumptionClusters specifies the clusters where the service will be exposed, for clients. If leave it empty, the service will be exposed to all clusters.",
"type": "array",
"items": {
"type": "string",
"default": ""
}
},
"serviceProvisionClusters": {
"description": "ServiceProvisionClusters specifies the clusters which will provision the service backend. If leave it empty, we will collect the backend endpoints from all clusters and sync them to the ServiceConsumptionClusters.",
"type": "array",
"items": {
"type": "string",
"default": ""
}
},
"types": {
"description": "Types specifies how to expose the service referencing by this MultiClusterService.",
"type": "array",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,32 @@ spec:
type: object
type: array
range:
description: Range specifies the ranges where the referencing service
description: 'Range specifies the ranges where the referencing service
should be exposed. Only valid and optional in case of Types contains
CrossCluster. If not set and Types contains CrossCluster, all clusters
will be selected, that means the referencing service will be exposed
across all registered clusters.
across all registered clusters. Deprecated: in favor of ServiceProvisionClusters/ServiceConsumptionClusters.'
properties:
clusterNames:
description: ClusterNames is the list of clusters to be selected.
items:
type: string
type: array
type: object
serviceConsumptionClusters:
description: ServiceConsumptionClusters specifies the clusters where
the service will be exposed, for clients. If leave it empty, the
service will be exposed to all clusters.
items:
type: string
type: array
serviceProvisionClusters:
description: ServiceProvisionClusters specifies the clusters which
will provision the service backend. If leave it empty, we will collect
the backend endpoints from all clusters and sync them to the ServiceConsumptionClusters.
items:
type: string
type: array
types:
description: Types specifies how to expose the service referencing
by this MultiClusterService.
Expand Down
12 changes: 12 additions & 0 deletions pkg/apis/networking/v1alpha1/service_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,20 @@ type MultiClusterServiceSpec struct {
// If not set and Types contains CrossCluster, all clusters will
// be selected, that means the referencing service will be exposed
// across all registered clusters.
// Deprecated: in favor of ServiceProvisionClusters/ServiceConsumptionClusters.
// +optional
Range ExposureRange `json:"range,omitempty"`
jwcesign marked this conversation as resolved.
Show resolved Hide resolved

// ServiceProvisionClusters specifies the clusters which will provision the service backend.
// If leave it empty, we will collect the backend endpoints from all clusters and sync
// them to the ServiceConsumptionClusters.
// +optional
ServiceProvisionClusters []string `json:"serviceProvisionClusters,omitempty"`

// ServiceConsumptionClusters specifies the clusters where the service will be exposed, for clients.
// If leave it empty, the service will be exposed to all clusters.
// +optional
ServiceConsumptionClusters []string `json:"serviceConsumptionClusters,omitempty"`
}

// ExposureType describes how to expose the service.
Expand Down
10 changes: 10 additions & 0 deletions pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 31 additions & 1 deletion pkg/generated/openapi/zz_generated.openapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions pkg/webhook/multiclusterservice/validating.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,19 @@ func (v *ValidatingAdmission) validateMultiClusterServiceSpec(mcs *networkingv1a
exposureType := mcs.Spec.Types[i]
allErrs = append(allErrs, v.validateExposureType(&exposureType, typePath)...)
}
clusterNamesPath := specPath.Child("range").Child("clusterNames")
for i := range mcs.Spec.Range.ClusterNames {
clusterNamesPath := specPath.Child("range").Child("serviceProvisionClusters")
for i := range mcs.Spec.ServiceProvisionClusters {
clusterNamePath := clusterNamesPath.Index(i)
clusterName := mcs.Spec.Range.ClusterNames[i]
clusterName := mcs.Spec.ServiceProvisionClusters[i]
if errMegs := clustervalidation.ValidateClusterName(clusterName); len(errMegs) > 0 {
allErrs = append(allErrs, field.Invalid(clusterNamePath, clusterName, strings.Join(errMegs, ",")))
}
}

clusterNamesPath = specPath.Child("range").Child("serviceConsumptionClusters")
for i := range mcs.Spec.ServiceConsumptionClusters {
clusterNamePath := clusterNamesPath.Index(i)
clusterName := mcs.Spec.ServiceConsumptionClusters[i]
if errMegs := clustervalidation.ValidateClusterName(clusterName); len(errMegs) > 0 {
allErrs = append(allErrs, field.Invalid(clusterNamePath, clusterName, strings.Join(errMegs, ",")))
}
Expand Down
27 changes: 11 additions & 16 deletions pkg/webhook/multiclusterservice/validating_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,8 @@ func TestValidateMultiClusterServiceSpec(t *testing.T) {
networkingv1alpha1.ExposureTypeLoadBalancer,
networkingv1alpha1.ExposureTypeCrossCluster,
},
Range: networkingv1alpha1.ExposureRange{
ClusterNames: []string{"member1", "member2"},
},
ServiceProvisionClusters: []string{"member1", "member2"},
ServiceConsumptionClusters: []string{"member1", "member2"},
},
},
expectedErr: field.ErrorList{},
Expand All @@ -78,9 +77,8 @@ func TestValidateMultiClusterServiceSpec(t *testing.T) {
networkingv1alpha1.ExposureTypeLoadBalancer,
networkingv1alpha1.ExposureTypeLoadBalancer,
},
Range: networkingv1alpha1.ExposureRange{
ClusterNames: []string{"member1"},
},
ServiceProvisionClusters: []string{"member1", "member2"},
ServiceConsumptionClusters: []string{"member1", "member2"},
},
},
expectedErr: field.ErrorList{field.Duplicate(specFld.Child("ports").Index(1).Child("name"), "foo")},
Expand All @@ -98,9 +96,8 @@ func TestValidateMultiClusterServiceSpec(t *testing.T) {
Types: []networkingv1alpha1.ExposureType{
networkingv1alpha1.ExposureTypeLoadBalancer,
},
Range: networkingv1alpha1.ExposureRange{
ClusterNames: []string{"member1"},
},
ServiceProvisionClusters: []string{"member1", "member2"},
ServiceConsumptionClusters: []string{"member1", "member2"},
},
},
expectedErr: field.ErrorList{field.Invalid(specFld.Child("ports").Index(0).Child("port"), int32(163121), validation.InclusiveRangeError(1, 65535))},
Expand All @@ -118,9 +115,8 @@ func TestValidateMultiClusterServiceSpec(t *testing.T) {
Types: []networkingv1alpha1.ExposureType{
"",
},
Range: networkingv1alpha1.ExposureRange{
ClusterNames: []string{"member1"},
},
ServiceProvisionClusters: []string{"member1", "member2"},
ServiceConsumptionClusters: []string{"member1", "member2"},
},
},
expectedErr: field.ErrorList{field.Invalid(specFld.Child("types").Index(0), networkingv1alpha1.ExposureType(""), "ExposureType Error")},
Expand All @@ -138,12 +134,11 @@ func TestValidateMultiClusterServiceSpec(t *testing.T) {
Types: []networkingv1alpha1.ExposureType{
networkingv1alpha1.ExposureTypeCrossCluster,
},
Range: networkingv1alpha1.ExposureRange{
ClusterNames: []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
},
ServiceProvisionClusters: []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"},
ServiceConsumptionClusters: []string{},
},
},
expectedErr: field.ErrorList{field.Invalid(specFld.Child("range").Child("clusterNames").Index(0), "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "must be no more than 48 characters")},
expectedErr: field.ErrorList{field.Invalid(specFld.Child("range").Child("serviceProvisionClusters").Index(0), "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "must be no more than 48 characters")},
},
}
for _, tt := range tests {
Expand Down
Loading