From ea84f27acdcd52d6ea7c98736d812bdc52b4bb87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8F=A9=E8=BD=A9?= Date: Fri, 28 Jul 2023 16:22:38 +0800 Subject: [PATCH] add new gateway version --- .../crds/raven.openyurt.io_gateways.yaml | 195 ++++++++++++++++ .../yurt-manager-auto-generated.yaml | 12 +- pkg/apis/addtoscheme_raven_v1beta1.go | 26 +++ .../apps/v1alpha1/zz_generated.deepcopy.go | 2 +- .../apps/v1beta1/zz_generated.deepcopy.go | 2 +- pkg/apis/raven/v1alpha1/gateway_conversion.go | 94 +++++++- .../raven/v1alpha1/zz_generated.deepcopy.go | 2 +- pkg/apis/raven/v1beta1/default.go | 43 ++++ pkg/apis/raven/v1beta1/gateway_conversion.go | 48 ++++ pkg/apis/raven/v1beta1/gateway_types.go | 139 +++++++++++ pkg/apis/raven/v1beta1/groupversion_info.go | 44 ++++ .../raven/v1beta1/zz_generated.deepcopy.go | 220 ++++++++++++++++++ pkg/controller/raven/common.go | 2 +- .../gateway/v1alpha1/gateway_default.go | 4 +- .../gateway/v1alpha1/gateway_handler.go | 3 - .../gateway/v1beta1/gateway_default.go | 39 ++++ .../gateway/v1beta1/gateway_handler.go | 56 +++++ .../gateway/v1beta1/gateway_validation.go | 128 ++++++++++ pkg/webhook/server.go | 4 +- 19 files changed, 1038 insertions(+), 25 deletions(-) create mode 100644 pkg/apis/addtoscheme_raven_v1beta1.go create mode 100644 pkg/apis/raven/v1beta1/default.go create mode 100644 pkg/apis/raven/v1beta1/gateway_conversion.go create mode 100644 pkg/apis/raven/v1beta1/gateway_types.go create mode 100644 pkg/apis/raven/v1beta1/groupversion_info.go create mode 100644 pkg/apis/raven/v1beta1/zz_generated.deepcopy.go create mode 100644 pkg/webhook/gateway/v1beta1/gateway_default.go create mode 100644 pkg/webhook/gateway/v1beta1/gateway_handler.go create mode 100644 pkg/webhook/gateway/v1beta1/gateway_validation.go diff --git a/charts/yurt-manager/crds/raven.openyurt.io_gateways.yaml b/charts/yurt-manager/crds/raven.openyurt.io_gateways.yaml index 0924060e97d..1fbbefafb3f 100644 --- a/charts/yurt-manager/crds/raven.openyurt.io_gateways.yaml +++ b/charts/yurt-manager/crds/raven.openyurt.io_gateways.yaml @@ -159,6 +159,201 @@ spec: type: object type: object served: true + storage: false + subresources: + status: {} + - name: v1beta1 + schema: + openAPIV3Schema: + description: Gateway is the Schema for the gateways API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: GatewaySpec defines the desired state of Gateway + properties: + endpoints: + description: Endpoints are a list of available Endpoint. + items: + description: Endpoint stores all essential data for establishing + the VPN tunnel and Proxy + properties: + config: + additionalProperties: + type: string + description: Config is a map to record config for the raven + agent of node + type: object + nodeName: + description: NodeName is the Node hosting this endpoint. + type: string + port: + description: Port is the exposed port of the node + type: integer + publicIP: + description: PublicIP is the exposed IP of the node + type: string + type: + description: Type is the service type of the node, proxy or + tunnel + type: string + underNAT: + description: UnderNAT indicates whether node is under NAT + type: boolean + required: + - nodeName + - type + type: object + type: array + exposeType: + description: ExposeType determines how the Gateway is exposed. + type: string + nodeSelector: + description: NodeSelector is a label query over nodes that managed + by the gateway. The nodes in the same gateway should share same + layer 3 network. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + proxyConfig: + description: ProxyConfig determine the l7 proxy configuration + properties: + Replicas: + description: Replicas is the number of gateway active endpoints + that enabled proxy + type: integer + proxyHTTPPort: + description: ProxyHTTPPort is the proxy http port of the cross-domain + request + type: string + proxyHTTPSPort: + description: ProxyHTTPSPort is the proxy https port of the cross-domain + request + type: string + required: + - Replicas + type: object + tunnelConfig: + description: TunnelConfig determine the l3 tunnel configuration + properties: + Replicas: + description: Replicas is the number of gateway active endpoints + that enabled tunnel + type: integer + required: + - Replicas + type: object + type: object + status: + description: GatewayStatus defines the observed state of Gateway + properties: + activeEndpoints: + description: ActiveEndpoints is the reference of the active endpoint. + items: + description: Endpoint stores all essential data for establishing + the VPN tunnel and Proxy + properties: + config: + additionalProperties: + type: string + description: Config is a map to record config for the raven + agent of node + type: object + nodeName: + description: NodeName is the Node hosting this endpoint. + type: string + port: + description: Port is the exposed port of the node + type: integer + publicIP: + description: PublicIP is the exposed IP of the node + type: string + type: + description: Type is the service type of the node, proxy or + tunnel + type: string + underNAT: + description: UnderNAT indicates whether node is under NAT + type: boolean + required: + - nodeName + - type + type: object + type: array + nodes: + description: Nodes contains all information of nodes managed by Gateway. + items: + description: NodeInfo stores information of node managed by Gateway. + properties: + nodeName: + description: NodeName is the Node host name. + type: string + privateIP: + description: PrivateIP is the node private ip address + type: string + subnets: + description: Subnets is the pod ip range of the node + items: + type: string + type: array + required: + - nodeName + - privateIP + - subnets + type: object + type: array + type: object + type: object + served: true storage: true subresources: status: {} diff --git a/charts/yurt-manager/templates/yurt-manager-auto-generated.yaml b/charts/yurt-manager/templates/yurt-manager-auto-generated.yaml index 3dda7a3d1b4..ec0a756f28a 100644 --- a/charts/yurt-manager/templates/yurt-manager-auto-generated.yaml +++ b/charts/yurt-manager/templates/yurt-manager-auto-generated.yaml @@ -444,14 +444,14 @@ webhooks: service: name: yurt-manager-webhook-service namespace: {{ .Release.Namespace }} - path: /mutate-raven-openyurt-io-v1alpha1-gateway + path: /mutate-raven-openyurt-io-v1beta1-gateway failurePolicy: Fail - name: mutate.raven.v1alpha1.gateway.openyurt.io + name: mutate.gateway.v1beta1.raven.openyurt.io rules: - apiGroups: - raven.openyurt.io apiVersions: - - v1alpha1 + - v1beta1 operations: - CREATE - UPDATE @@ -574,14 +574,14 @@ webhooks: service: name: yurt-manager-webhook-service namespace: {{ .Release.Namespace }} - path: /validate-raven-openyurt-io-v1alpha1-gateway + path: /validate-raven-openyurt-io-v1beta1-gateway failurePolicy: Fail - name: validate.raven.v1alpha1.gateway.openyurt.io + name: validate.gateway.v1beta1.raven.openyurt.io rules: - apiGroups: - raven.openyurt.io apiVersions: - - v1alpha1 + - v1beta1 operations: - CREATE - UPDATE diff --git a/pkg/apis/addtoscheme_raven_v1beta1.go b/pkg/apis/addtoscheme_raven_v1beta1.go new file mode 100644 index 00000000000..f5f8a575d08 --- /dev/null +++ b/pkg/apis/addtoscheme_raven_v1beta1.go @@ -0,0 +1,26 @@ +/* +Copyright 2023 The OpenYurt 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 apis + +import ( + version "github.com/openyurtio/openyurt/pkg/apis/raven/v1beta1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, version.SchemeBuilder.AddToScheme) +} diff --git a/pkg/apis/apps/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/apps/v1alpha1/zz_generated.deepcopy.go index a1352c1b16f..f732bdcaa9b 100644 --- a/pkg/apis/apps/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/apps/v1alpha1/zz_generated.deepcopy.go @@ -23,7 +23,7 @@ package v1alpha1 import ( corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) diff --git a/pkg/apis/apps/v1beta1/zz_generated.deepcopy.go b/pkg/apis/apps/v1beta1/zz_generated.deepcopy.go index a62c4266aa2..ebb32758258 100644 --- a/pkg/apis/apps/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/apps/v1beta1/zz_generated.deepcopy.go @@ -23,7 +23,7 @@ package v1beta1 import ( corev1 "k8s.io/api/core/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/pkg/apis/raven/v1alpha1/gateway_conversion.go b/pkg/apis/raven/v1alpha1/gateway_conversion.go index ebcce13d9dc..6192bfc4a21 100644 --- a/pkg/apis/raven/v1alpha1/gateway_conversion.go +++ b/pkg/apis/raven/v1alpha1/gateway_conversion.go @@ -16,6 +16,13 @@ limitations under the License. package v1alpha1 +import ( + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/conversion" + + "github.com/openyurtio/openyurt/pkg/apis/raven/v1beta1" +) + /* Implementing the hub method is pretty easy -- we just have to add an empty method called Hub() to serve as a @@ -31,15 +38,86 @@ method called Hub() to serve as a // NOTE !!!!!!! @kadisi // If this version is not storageversion, you need to implement the ConvertTo and ConvertFrom methods -// need import "sigs.k8s.io/controller-runtime/pkg/conversion" -//func (src *Gateway) ConvertTo(dstRaw conversion.Hub) error { -// return nil -//} +func (src *Gateway) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*v1beta1.Gateway) + dst.ObjectMeta = src.ObjectMeta + if src.Spec.NodeSelector != nil { + dst.Spec.NodeSelector = src.Spec.NodeSelector + } + dst.Spec.ExposeType = string(src.Spec.ExposeType) + dst.Spec.TunnelConfig.Replicas = 1 + dst.Spec.ProxyConfig.Replicas = 1 + for _, eps := range src.Spec.Endpoints { + dst.Spec.Endpoints = append(dst.Spec.Endpoints, v1beta1.Endpoint{ + NodeName: eps.NodeName, + PublicIP: eps.PublicIP, + UnderNAT: eps.UnderNAT, + Config: eps.Config, + Type: v1beta1.Tunnel, + Port: v1beta1.DefaultTunnelServerExposedPort, + }) + } + for _, node := range src.Status.Nodes { + dst.Status.Nodes = append(dst.Status.Nodes, v1beta1.NodeInfo{ + NodeName: node.NodeName, + PrivateIP: node.PrivateIP, + Subnets: node.Subnets, + }) + } + if src.Status.ActiveEndpoint != nil { + dst.Status.ActiveEndpoints = []*v1beta1.Endpoint{ + { + NodeName: src.Status.ActiveEndpoint.NodeName, + PublicIP: src.Status.ActiveEndpoint.PublicIP, + UnderNAT: src.Status.ActiveEndpoint.UnderNAT, + Config: src.Status.ActiveEndpoint.Config, + Type: v1beta1.Tunnel, + Port: v1beta1.DefaultTunnelServerExposedPort, + }, + } + } + + klog.Infof("convert from v1alpha1 to v1beta1 for %s", dst.Name) + return nil +} // NOTE !!!!!!! @kadisi // If this version is not storageversion, you need to implement the ConvertTo and ConvertFrom methods -// need import "sigs.k8s.io/controller-runtime/pkg/conversion" -//func (dst *Gateway) ConvertFrom(srcRaw conversion.Hub) error { -// return nil -//} +func (dst *Gateway) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*v1beta1.Gateway) + dst.ObjectMeta = src.ObjectMeta + dst.Spec.NodeSelector = src.Spec.NodeSelector + dst.Spec.ExposeType = ExposeType(src.Spec.ExposeType) + for _, eps := range src.Spec.Endpoints { + dst.Spec.Endpoints = append(dst.Spec.Endpoints, Endpoint{ + NodeName: eps.NodeName, + PublicIP: eps.PublicIP, + UnderNAT: eps.UnderNAT, + Config: eps.Config, + }) + } + for _, node := range src.Status.Nodes { + dst.Status.Nodes = append(dst.Status.Nodes, NodeInfo{ + NodeName: node.NodeName, + PrivateIP: node.PrivateIP, + Subnets: node.Subnets, + }) + } + if src.Status.ActiveEndpoints == nil { + klog.Infof("convert from v1beta1 to v1alpha1 for %s", dst.Name) + return nil + } + if len(src.Status.ActiveEndpoints) < 1 { + dst.Status.ActiveEndpoint = nil + } else { + dst.Status.ActiveEndpoint = &Endpoint{ + NodeName: src.Status.ActiveEndpoints[0].NodeName, + PublicIP: src.Status.ActiveEndpoints[0].PublicIP, + UnderNAT: src.Status.ActiveEndpoints[0].UnderNAT, + Config: src.Status.ActiveEndpoints[0].Config, + } + } + klog.Infof("convert from v1beta1 to v1alpha1 for %s", dst.Name) + return nil +} diff --git a/pkg/apis/raven/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/raven/v1alpha1/zz_generated.deepcopy.go index d2d42342df3..c736ea956f0 100644 --- a/pkg/apis/raven/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/raven/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ limitations under the License. package v1alpha1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/pkg/apis/raven/v1beta1/default.go b/pkg/apis/raven/v1beta1/default.go new file mode 100644 index 00000000000..cbbea9a915f --- /dev/null +++ b/pkg/apis/raven/v1beta1/default.go @@ -0,0 +1,43 @@ +/* +Copyright 2023 The OpenYurt 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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/openyurtio/openyurt/pkg/apis/raven" +) + +// SetDefaultsGateway set default values for Gateway. +func SetDefaultsGateway(obj *Gateway) { + // Set default value for Gateway + obj.Spec.NodeSelector = &metav1.LabelSelector{ + MatchLabels: map[string]string{ + raven.LabelCurrentGateway: obj.Name, + }, + } + for idx, val := range obj.Spec.Endpoints { + if val.Port == 0 { + switch val.Type { + case Proxy: + obj.Spec.Endpoints[idx].Port = DefaultProxyServerExposedPort + case Tunnel: + obj.Spec.Endpoints[idx].Port = DefaultTunnelServerExposedPort + } + } + } +} diff --git a/pkg/apis/raven/v1beta1/gateway_conversion.go b/pkg/apis/raven/v1beta1/gateway_conversion.go new file mode 100644 index 00000000000..4a87604e040 --- /dev/null +++ b/pkg/apis/raven/v1beta1/gateway_conversion.go @@ -0,0 +1,48 @@ +/* +Copyright 2023 The OpenYurt 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 v1beta1 + +/* +Implementing the hub method is pretty easy -- we just have to add an empty +method called Hub() to serve as a +[marker](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/conversion?tab=doc#Hub). +*/ + +// NOTE !!!!!! @kadisi +// If this version is storageversion, you only need to uncommand this method + +// Hub marks this type as a conversion hub. +//func (*Gateway) Hub() {} + +// NOTE !!!!!!! @kadisi +// If this version is not storageversion, you need to implement the ConvertTo and ConvertFrom methods + +// need import "sigs.k8s.io/controller-runtime/pkg/conversion" +//func (src *Gateway) ConvertTo(dstRaw conversion.Hub) error { +// return nil +//} + +// NOTE !!!!!!! @kadisi +// If this version is not storageversion, you need to implement the ConvertTo and ConvertFrom methods + +// need import "sigs.k8s.io/controller-runtime/pkg/conversion" +//func (dst *Gateway) ConvertFrom(srcRaw conversion.Hub) error { +// return nil +//} + +// Hub marks this type as a conversion hub. +func (*Gateway) Hub() {} diff --git a/pkg/apis/raven/v1beta1/gateway_types.go b/pkg/apis/raven/v1beta1/gateway_types.go new file mode 100644 index 00000000000..a8d433c0a46 --- /dev/null +++ b/pkg/apis/raven/v1beta1/gateway_types.go @@ -0,0 +1,139 @@ +/* +Copyright 2023 The OpenYurt 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 v1beta1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// Event reason. +const ( + // EventActiveEndpointElected is the event indicating a new active endpoint is elected. + EventActiveEndpointElected = "ActiveEndpointElected" + // EventActiveEndpointLost is the event indicating the active endpoint is lost. + EventActiveEndpointLost = "ActiveEndpointLost" +) + +const ( + ExposeTypePublicIP = "PublicIP" + ExposeTypeLoadBalancer = "LoadBalancer" +) + +const ( + Proxy = "proxy" + Tunnel = "tunnel" + + DefaultProxyServerSecurePort = 10263 + DefaultProxyServerInsecurePort = 10264 + DefaultProxyServerExposedPort = 10262 + DefaultTunnelServerExposedPort = 4500 +) + +// ProxyConfiguration is the configuration for raven l7 proxy +type ProxyConfiguration struct { + // Replicas is the number of gateway active endpoints that enabled proxy + Replicas int `json:"Replicas"` + // ProxyHTTPPort is the proxy http port of the cross-domain request + ProxyHTTPPort string `json:"proxyHTTPPort,omitempty"` + // ProxyHTTPSPort is the proxy https port of the cross-domain request + ProxyHTTPSPort string `json:"proxyHTTPSPort,omitempty"` +} + +// TunnelConfiguration is the configuration for raven l3 tunnel +type TunnelConfiguration struct { + // Replicas is the number of gateway active endpoints that enabled tunnel + Replicas int `json:"Replicas"` +} + +// GatewaySpec defines the desired state of Gateway +type GatewaySpec struct { + // NodeSelector is a label query over nodes that managed by the gateway. + // The nodes in the same gateway should share same layer 3 network. + NodeSelector *metav1.LabelSelector `json:"nodeSelector,omitempty"` + // ProxyConfig determine the l7 proxy configuration + ProxyConfig ProxyConfiguration `json:"proxyConfig,omitempty"` + // TunnelConfig determine the l3 tunnel configuration + TunnelConfig TunnelConfiguration `json:"tunnelConfig,omitempty"` + // Endpoints are a list of available Endpoint. + Endpoints []Endpoint `json:"endpoints,omitempty"` + // ExposeType determines how the Gateway is exposed. + ExposeType string `json:"exposeType,omitempty"` +} + +// Endpoint stores all essential data for establishing the VPN tunnel and Proxy +type Endpoint struct { + // NodeName is the Node hosting this endpoint. + NodeName string `json:"nodeName"` + // Type is the service type of the node, proxy or tunnel + Type string `json:"type"` + // Port is the exposed port of the node + Port int `json:"port,omitempty"` + // UnderNAT indicates whether node is under NAT + UnderNAT bool `json:"underNAT,omitempty"` + // PublicIP is the exposed IP of the node + PublicIP string `json:"publicIP,omitempty"` + // Config is a map to record config for the raven agent of node + Config map[string]string `json:"config,omitempty"` +} + +// NodeInfo stores information of node managed by Gateway. +type NodeInfo struct { + // NodeName is the Node host name. + NodeName string `json:"nodeName"` + // PrivateIP is the node private ip address + PrivateIP string `json:"privateIP"` + // Subnets is the pod ip range of the node + Subnets []string `json:"subnets"` +} + +// GatewayStatus defines the observed state of Gateway +type GatewayStatus struct { + // Nodes contains all information of nodes managed by Gateway. + Nodes []NodeInfo `json:"nodes,omitempty"` + // ActiveEndpoints is the reference of the active endpoint. + ActiveEndpoints []*Endpoint `json:"activeEndpoints,omitempty"` +} + +// +genclient +// +k8s:openapi-gen=true +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster,path=gateways,shortName=gw,categories=all +// +kubebuilder:storageversion + +// Gateway is the Schema for the gateways API +type Gateway struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec GatewaySpec `json:"spec,omitempty"` + Status GatewayStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// GatewayList contains a list of Gateway +type GatewayList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Gateway `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Gateway{}, &GatewayList{}) +} diff --git a/pkg/apis/raven/v1beta1/groupversion_info.go b/pkg/apis/raven/v1beta1/groupversion_info.go new file mode 100644 index 00000000000..e35d10626d0 --- /dev/null +++ b/pkg/apis/raven/v1beta1/groupversion_info.go @@ -0,0 +1,44 @@ +/* +Copyright 2023 The OpenYurt 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 v1beta1 + +// Package v1beta1 contains API Schema definitions for the raven v1beta1API group +// +kubebuilder:object:generate=true +// +groupName=raven.openyurt.io + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "raven.openyurt.io", Version: "v1beta1"} + + SchemeGroupVersion = GroupVersion + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource is required by pkg/client/listers/... +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/pkg/apis/raven/v1beta1/zz_generated.deepcopy.go b/pkg/apis/raven/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..99e1cbb33f2 --- /dev/null +++ b/pkg/apis/raven/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,220 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 2023 The OpenYurt 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. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Endpoint) DeepCopyInto(out *Endpoint) { + *out = *in + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint. +func (in *Endpoint) DeepCopy() *Endpoint { + if in == nil { + return nil + } + out := new(Endpoint) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Gateway) DeepCopyInto(out *Gateway) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Gateway. +func (in *Gateway) DeepCopy() *Gateway { + if in == nil { + return nil + } + out := new(Gateway) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Gateway) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayList) DeepCopyInto(out *GatewayList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Gateway, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayList. +func (in *GatewayList) DeepCopy() *GatewayList { + if in == nil { + return nil + } + out := new(GatewayList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GatewayList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewaySpec) DeepCopyInto(out *GatewaySpec) { + *out = *in + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + out.ProxyConfig = in.ProxyConfig + out.TunnelConfig = in.TunnelConfig + if in.Endpoints != nil { + in, out := &in.Endpoints, &out.Endpoints + *out = make([]Endpoint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewaySpec. +func (in *GatewaySpec) DeepCopy() *GatewaySpec { + if in == nil { + return nil + } + out := new(GatewaySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayStatus) DeepCopyInto(out *GatewayStatus) { + *out = *in + if in.Nodes != nil { + in, out := &in.Nodes, &out.Nodes + *out = make([]NodeInfo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ActiveEndpoints != nil { + in, out := &in.ActiveEndpoints, &out.ActiveEndpoints + *out = make([]*Endpoint, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Endpoint) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayStatus. +func (in *GatewayStatus) DeepCopy() *GatewayStatus { + if in == nil { + return nil + } + out := new(GatewayStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NodeInfo) DeepCopyInto(out *NodeInfo) { + *out = *in + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeInfo. +func (in *NodeInfo) DeepCopy() *NodeInfo { + if in == nil { + return nil + } + out := new(NodeInfo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ProxyConfiguration) DeepCopyInto(out *ProxyConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfiguration. +func (in *ProxyConfiguration) DeepCopy() *ProxyConfiguration { + if in == nil { + return nil + } + out := new(ProxyConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TunnelConfiguration) DeepCopyInto(out *TunnelConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TunnelConfiguration. +func (in *TunnelConfiguration) DeepCopy() *TunnelConfiguration { + if in == nil { + return nil + } + out := new(TunnelConfiguration) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/controller/raven/common.go b/pkg/controller/raven/common.go index e1af9b1184d..f9325510320 100644 --- a/pkg/controller/raven/common.go +++ b/pkg/controller/raven/common.go @@ -21,5 +21,5 @@ var ( ) const ( - ControllerName = "ravenl3" + ControllerName = "gateway" ) diff --git a/pkg/webhook/gateway/v1alpha1/gateway_default.go b/pkg/webhook/gateway/v1alpha1/gateway_default.go index d7766e1e856..8a55524a79f 100644 --- a/pkg/webhook/gateway/v1alpha1/gateway_default.go +++ b/pkg/webhook/gateway/v1alpha1/gateway_default.go @@ -28,12 +28,12 @@ import ( // Default satisfies the defaulting webhook interface. func (webhook *GatewayHandler) Default(ctx context.Context, obj runtime.Object) error { - np, ok := obj.(*v1alpha1.Gateway) + gw, ok := obj.(*v1alpha1.Gateway) if !ok { return apierrors.NewBadRequest(fmt.Sprintf("expected a Gateway but got a %T", obj)) } - v1alpha1.SetDefaultsGateway(np) + v1alpha1.SetDefaultsGateway(gw) return nil } diff --git a/pkg/webhook/gateway/v1alpha1/gateway_handler.go b/pkg/webhook/gateway/v1alpha1/gateway_handler.go index 61cecb7c0e3..97573b424a4 100644 --- a/pkg/webhook/gateway/v1alpha1/gateway_handler.go +++ b/pkg/webhook/gateway/v1alpha1/gateway_handler.go @@ -44,9 +44,6 @@ func (webhook *GatewayHandler) SetupWebhookWithManager(mgr ctrl.Manager) (string Complete() } -// +kubebuilder:webhook:path=/validate-raven-openyurt-io-v1alpha1-gateway,mutating=false,failurePolicy=fail,sideEffects=None,admissionReviewVersions=v1;v1beta1,groups=raven.openyurt.io,resources=gateways,verbs=create;update,versions=v1alpha1,name=validate.raven.v1alpha1.gateway.openyurt.io -// +kubebuilder:webhook:path=/mutate-raven-openyurt-io-v1alpha1-gateway,mutating=true,failurePolicy=fail,sideEffects=None,admissionReviewVersions=v1;v1beta1,groups=raven.openyurt.io,resources=gateways,verbs=create;update,versions=v1alpha1,name=mutate.raven.v1alpha1.gateway.openyurt.io - // Cluster implements a validating and defaulting webhook for Cluster. type GatewayHandler struct { Client client.Client diff --git a/pkg/webhook/gateway/v1beta1/gateway_default.go b/pkg/webhook/gateway/v1beta1/gateway_default.go new file mode 100644 index 00000000000..c966416956c --- /dev/null +++ b/pkg/webhook/gateway/v1beta1/gateway_default.go @@ -0,0 +1,39 @@ +/* +Copyright 2023 The OpenYurt 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 v1beta1 + +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/openyurtio/openyurt/pkg/apis/raven/v1beta1" +) + +// Default satisfies the defaulting webhook interface. +func (webhook *GatewayHandler) Default(ctx context.Context, obj runtime.Object) error { + gw, ok := obj.(*v1beta1.Gateway) + if !ok { + return apierrors.NewBadRequest(fmt.Sprintf("expected a Gateway but got a %T", obj)) + } + + v1beta1.SetDefaultsGateway(gw) + + return nil +} diff --git a/pkg/webhook/gateway/v1beta1/gateway_handler.go b/pkg/webhook/gateway/v1beta1/gateway_handler.go new file mode 100644 index 00000000000..1cd33b5540a --- /dev/null +++ b/pkg/webhook/gateway/v1beta1/gateway_handler.go @@ -0,0 +1,56 @@ +/* +Copyright 2023 The OpenYurt 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 v1beta1 + +import ( + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/openyurtio/openyurt/pkg/apis/raven/v1beta1" + "github.com/openyurtio/openyurt/pkg/webhook/util" +) + +// SetupWebhookWithManager sets up Cluster webhooks. mutate path, validatepath, error +func (webhook *GatewayHandler) SetupWebhookWithManager(mgr ctrl.Manager) (string, string, error) { + // init + webhook.Client = mgr.GetClient() + + gvk, err := apiutil.GVKForObject(&v1beta1.Gateway{}, mgr.GetScheme()) + if err != nil { + return "", "", err + } + return util.GenerateMutatePath(gvk), + util.GenerateValidatePath(gvk), + ctrl.NewWebhookManagedBy(mgr). + For(&v1beta1.Gateway{}). + WithDefaulter(webhook). + WithValidator(webhook). + Complete() +} + +// +kubebuilder:webhook:path=/validate-raven-openyurt-io-v1beta1-gateway,mutating=false,failurePolicy=fail,sideEffects=None,admissionReviewVersions=v1;v1beta1,groups=raven.openyurt.io,resources=gateways,verbs=create;update,versions=v1beta1,name=validate.gateway.v1beta1.raven.openyurt.io +// +kubebuilder:webhook:path=/mutate-raven-openyurt-io-v1beta1-gateway,mutating=true,failurePolicy=fail,sideEffects=None,admissionReviewVersions=v1;v1beta1,groups=raven.openyurt.io,resources=gateways,verbs=create;update,versions=v1beta1,name=mutate.gateway.v1beta1.raven.openyurt.io + +// Cluster implements a validating and defaulting webhook for Cluster. +type GatewayHandler struct { + Client client.Client +} + +var _ webhook.CustomDefaulter = &GatewayHandler{} +var _ webhook.CustomValidator = &GatewayHandler{} diff --git a/pkg/webhook/gateway/v1beta1/gateway_validation.go b/pkg/webhook/gateway/v1beta1/gateway_validation.go new file mode 100644 index 00000000000..6c9008cb53c --- /dev/null +++ b/pkg/webhook/gateway/v1beta1/gateway_validation.go @@ -0,0 +1,128 @@ +/* +Copyright 2023 The OpenYurt 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 v1beta1 + +import ( + "context" + "fmt" + "net" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/klog/v2" + + "github.com/openyurtio/openyurt/pkg/apis/raven/v1beta1" +) + +// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type. +func (webhook *GatewayHandler) ValidateCreate(ctx context.Context, obj runtime.Object) error { + gw, ok := obj.(*v1beta1.Gateway) + if !ok { + return apierrors.NewBadRequest(fmt.Sprintf("expected a Gateway but got a %T", obj)) + } + + return validate(gw) +} + +// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type. +func (webhook *GatewayHandler) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error { + newGw, ok := newObj.(*v1beta1.Gateway) + if !ok { + return apierrors.NewBadRequest(fmt.Sprintf("expected a Gateway but got a %T", newObj)) + } + oldGw, ok := oldObj.(*v1beta1.Gateway) + if !ok { + return apierrors.NewBadRequest(fmt.Sprintf("expected a Gateway} but got a %T", oldObj)) + } + + if newGw.GetName() != oldGw.GetName() { + return apierrors.NewBadRequest(fmt.Sprintf("gateway name can not change")) + } + if err := validate(newGw); err != nil { + return err + } + + return nil +} + +// ValidateDelete implements webhook.CustomValidator so a webhook will be registered for the type. +func (webhook *GatewayHandler) ValidateDelete(_ context.Context, obj runtime.Object) error { + return nil +} + +func validate(g *v1beta1.Gateway) error { + var errList field.ErrorList + + if g.Spec.ExposeType != "" { + if g.Spec.ExposeType != v1beta1.ExposeTypeLoadBalancer && g.Spec.ExposeType != v1beta1.ExposeTypePublicIP { + fldPath := field.NewPath("spec").Child("exposeType") + errList = append(errList, field.Invalid(fldPath, g.Spec.ExposeType, "the 'exposeType' field is irregularity")) + } + if g.Spec.ExposeType == v1beta1.ExposeTypeLoadBalancer || g.Spec.ExposeType == v1beta1.ExposeTypePublicIP { + for i, ep := range g.Spec.Endpoints { + if ep.UnderNAT { + fldPath := field.NewPath("spec").Child(fmt.Sprintf("endpoints[%d]", i)).Child("underNAT") + errList = append(errList, field.Invalid(fldPath, ep.UnderNAT, fmt.Sprintf("the 'underNAT' field for exposed gateway %s/%s must be false", g.Namespace, g.Name))) + } + } + } + } + + if len(g.Spec.Endpoints) != 0 { + underNAT := g.Spec.Endpoints[0].UnderNAT + for i, ep := range g.Spec.Endpoints { + if ep.UnderNAT != underNAT { + fldPath := field.NewPath("spec").Child(fmt.Sprintf("endpoints[%d]", i)).Child("underNAT") + errList = append(errList, field.Invalid(fldPath, ep.UnderNAT, "the 'underNAT' field in endpoints must be the same")) + } + if ep.PublicIP != "" { + if err := validateIP(ep.PublicIP); err != nil { + fldPath := field.NewPath("spec").Child(fmt.Sprintf("endpoints[%d]", i)).Child("publicIP") + errList = append(errList, field.Invalid(fldPath, ep.PublicIP, "the 'publicIP' field must be a validate IP address")) + } + } + if ep.Type != v1beta1.Tunnel && ep.Type != v1beta1.Proxy { + fldPath := field.NewPath("spec").Child(fmt.Sprintf("endpoints[%d]", i)).Child("type") + errList = append(errList, field.Invalid(fldPath, ep.Type, fmt.Sprintf("the 'type' field must be set %s or %s ", v1beta1.Tunnel, v1beta1.Proxy))) + } + if len(ep.NodeName) == 0 { + fldPath := field.NewPath("spec").Child(fmt.Sprintf("endpoints[%d]", i)).Child("nodeName") + errList = append(errList, field.Invalid(fldPath, ep.NodeName, "the 'nodeName' field must not be empty")) + } + } + } + + if errList != nil { + return apierrors.NewInvalid( + schema.GroupKind{Group: v1beta1.SchemeGroupVersion.Group, Kind: g.Kind}, + g.Name, errList) + } + + klog.Infof("Validate Gateway %s successfully ...", klog.KObj(g)) + + return nil +} + +func validateIP(ip string) error { + s := net.ParseIP(ip) + if s.To4() != nil || s.To16() != nil { + return nil + } + return fmt.Errorf("invalid ip address: %s", ip) +} diff --git a/pkg/webhook/server.go b/pkg/webhook/server.go index c22ffe2ef49..60278a30a2d 100644 --- a/pkg/webhook/server.go +++ b/pkg/webhook/server.go @@ -33,7 +33,7 @@ import ( "github.com/openyurtio/openyurt/pkg/controller/yurtappdaemon" "github.com/openyurtio/openyurt/pkg/controller/yurtappset" "github.com/openyurtio/openyurt/pkg/controller/yurtstaticset" - v1alpha1gateway "github.com/openyurtio/openyurt/pkg/webhook/gateway/v1alpha1" + v1beta1gateway "github.com/openyurtio/openyurt/pkg/webhook/gateway/v1beta1" v1node "github.com/openyurtio/openyurt/pkg/webhook/node/v1" v1alpha1nodepool "github.com/openyurtio/openyurt/pkg/webhook/nodepool/v1alpha1" v1beta1nodepool "github.com/openyurtio/openyurt/pkg/webhook/nodepool/v1beta1" @@ -73,7 +73,7 @@ func addControllerWebhook(name string, handler SetupWebhookWithManager) { } func init() { - addControllerWebhook(raven.ControllerName, &v1alpha1gateway.GatewayHandler{}) + addControllerWebhook(raven.ControllerName, &v1beta1gateway.GatewayHandler{}) addControllerWebhook(nodepool.ControllerName, &v1alpha1nodepool.NodePoolHandler{}) addControllerWebhook(nodepool.ControllerName, &v1beta1nodepool.NodePoolHandler{}) addControllerWebhook(yurtstaticset.ControllerName, &v1alpha1yurtstaticset.YurtStaticSetHandler{})