From a6c63ed7f4d3d2329e09f6cc40a53dcccddded3d Mon Sep 17 00:00:00 2001 From: Alessandro Olivero Date: Tue, 10 Oct 2023 10:55:28 +0200 Subject: [PATCH] fix apis --- .../v1alpha1/gatewayclient_types.go | 2 +- .../v1alpha1/wggatewayclient_types.go | 2 + .../v1alpha1/wggatewayserver_types.go | 21 + .../v1alpha1/zz_generated.deepcopy.go | 56 +- cmd/liqo-controller-manager/main.go | 12 +- .../networking.liqo.io_gatewayclients.yaml | 17 +- .../networking.liqo.io_wggatewayclients.yaml | 1139 +++++++++++++++++ .../networking.liqo.io_wggatewayservers.yaml | 1139 +++++++++++++++++ .../liqo-controller-manager-ClusterRole.yaml | 12 + .../liqo-controller-manager-rbac.yaml | 18 + go.mod | 1 + go.sum | 2 + .../client-operator/client_controller.go | 21 +- .../server-operator/server_controller.go | 21 +- .../external-network/utils/getters.go | 14 +- .../external-network/utils/metrics.go | 157 +++ .../external-network/utils/rbac.go | 81 ++ .../wireguard/wggatewayclient_controller.go | 36 +- .../wireguard/wggatewayserver_controller.go | 31 +- pkg/utils/mapper/mapper.go | 51 +- 20 files changed, 2796 insertions(+), 37 deletions(-) create mode 100644 pkg/liqo-controller-manager/external-network/utils/metrics.go create mode 100644 pkg/liqo-controller-manager/external-network/utils/rbac.go diff --git a/apis/networking/v1alpha1/gatewayclient_types.go b/apis/networking/v1alpha1/gatewayclient_types.go index c25af091b0..ef81430e94 100644 --- a/apis/networking/v1alpha1/gatewayclient_types.go +++ b/apis/networking/v1alpha1/gatewayclient_types.go @@ -42,7 +42,7 @@ type GatewayClientSpec struct { // MTU specifies the MTU of the tunnel. MTU int `json:"mtu,omitempty"` // Endpoint specifies the endpoint of the tunnel. - Endpoint Endpoint `json:"endpoint,omitempty"` + Endpoint EndpointStatus `json:"endpoint,omitempty"` } // GatewayClientStatus defines the observed state of GatewayClient. diff --git a/apis/networking/v1alpha1/wggatewayclient_types.go b/apis/networking/v1alpha1/wggatewayclient_types.go index 371794475a..d0a8f2096e 100644 --- a/apis/networking/v1alpha1/wggatewayclient_types.go +++ b/apis/networking/v1alpha1/wggatewayclient_types.go @@ -39,6 +39,8 @@ var WgGatewayClientGroupVersionResource = GroupVersion.WithResource(WgGatewayCli type WgGatewayClientSpec struct { // Deployment specifies the deployment template for the client. Deployment DeploymentTemplate `json:"deployment"` + // Metrics specifies the metrics configuration for the client. + Metrics *Metrics `json:"metrics,omitempty"` } // WgGatewayClientStatus defines the observed state of WgGatewayClient. diff --git a/apis/networking/v1alpha1/wggatewayserver_types.go b/apis/networking/v1alpha1/wggatewayserver_types.go index 6c21bc148f..88a00c9635 100644 --- a/apis/networking/v1alpha1/wggatewayserver_types.go +++ b/apis/networking/v1alpha1/wggatewayserver_types.go @@ -15,6 +15,7 @@ package v1alpha1 import ( + monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -52,12 +53,32 @@ type DeploymentTemplate struct { Spec appsv1.DeploymentSpec `json:"spec,omitempty"` } +// ServiceMonitorTemplate defines the template of a service monitor. +type ServiceMonitorTemplate struct { + // Metadata of the service monitor. + Metadata metav1.ObjectMeta `json:"metadata,omitempty"` + // Spec of the service monitor. + Spec monitoringv1.ServiceMonitorSpec `json:"spec,omitempty"` +} + +// Metrics defines the metrics configuration. +type Metrics struct { + // Enabled specifies whether the metrics are enabled. + Enabled bool `json:"enabled"` + // Service specifies the service template for the metrics. + Service *ServiceTemplate `json:"service,omitempty"` + // ServiceMonitor specifies the service monitor template for the metrics. + ServiceMonitor *ServiceMonitorTemplate `json:"serviceMonitor,omitempty"` +} + // WgGatewayServerSpec defines the desired state of WgGatewayServer. type WgGatewayServerSpec struct { // Service specifies the service template for the server. Service ServiceTemplate `json:"service"` // Deployment specifies the deployment template for the server. Deployment DeploymentTemplate `json:"deployment"` + // Metrics specifies the metrics configuration for the server. + Metrics *Metrics `json:"metrics,omitempty"` } // WgGatewayServerStatus defines the observed state of WgGatewayServer. diff --git a/apis/networking/v1alpha1/zz_generated.deepcopy.go b/apis/networking/v1alpha1/zz_generated.deepcopy.go index 87c4bb0772..8de45fdc1f 100644 --- a/apis/networking/v1alpha1/zz_generated.deepcopy.go +++ b/apis/networking/v1alpha1/zz_generated.deepcopy.go @@ -468,7 +468,7 @@ func (in *GatewayClient) DeepCopyInto(out *GatewayClient) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status } @@ -526,7 +526,7 @@ func (in *GatewayClientList) DeepCopyObject() runtime.Object { func (in *GatewayClientSpec) DeepCopyInto(out *GatewayClientSpec) { *out = *in out.ClientTemplateRef = in.ClientTemplateRef - out.Endpoint = in.Endpoint + in.Endpoint.DeepCopyInto(&out.Endpoint) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayClientSpec. @@ -652,6 +652,31 @@ func (in *GatewayServerStatus) DeepCopy() *GatewayServerStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Metrics) DeepCopyInto(out *Metrics) { + *out = *in + if in.Service != nil { + in, out := &in.Service, &out.Service + *out = new(ServiceTemplate) + (*in).DeepCopyInto(*out) + } + if in.ServiceMonitor != nil { + in, out := &in.ServiceMonitor, &out.ServiceMonitor + *out = new(ServiceMonitorTemplate) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Metrics. +func (in *Metrics) DeepCopy() *Metrics { + if in == nil { + return nil + } + out := new(Metrics) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PingSpec) DeepCopyInto(out *PingSpec) { *out = *in @@ -751,6 +776,23 @@ func (in *PublicKeySpec) DeepCopy() *PublicKeySpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceMonitorTemplate) DeepCopyInto(out *ServiceMonitorTemplate) { + *out = *in + in.Metadata.DeepCopyInto(&out.Metadata) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceMonitorTemplate. +func (in *ServiceMonitorTemplate) DeepCopy() *ServiceMonitorTemplate { + if in == nil { + return nil + } + out := new(ServiceMonitorTemplate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceTemplate) DeepCopyInto(out *ServiceTemplate) { *out = *in @@ -831,6 +873,11 @@ func (in *WgGatewayClientList) DeepCopyObject() runtime.Object { func (in *WgGatewayClientSpec) DeepCopyInto(out *WgGatewayClientSpec) { *out = *in in.Deployment.DeepCopyInto(&out.Deployment) + if in.Metrics != nil { + in, out := &in.Metrics, &out.Metrics + *out = new(Metrics) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WgGatewayClientSpec. @@ -1002,6 +1049,11 @@ func (in *WgGatewayServerSpec) DeepCopyInto(out *WgGatewayServerSpec) { *out = *in in.Service.DeepCopyInto(&out.Service) in.Deployment.DeepCopyInto(&out.Deployment) + if in.Metrics != nil { + in, out := &in.Metrics, &out.Metrics + *out = new(Metrics) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WgGatewayServerSpec. diff --git a/cmd/liqo-controller-manager/main.go b/cmd/liqo-controller-manager/main.go index 93448c7dbd..7ee2d5f052 100644 --- a/cmd/liqo-controller-manager/main.go +++ b/cmd/liqo-controller-manager/main.go @@ -26,6 +26,7 @@ import ( "sync" "time" + monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" certificates "k8s.io/api/certificates/v1" @@ -109,6 +110,8 @@ var ( func init() { _ = clientgoscheme.AddToScheme(scheme) + _ = monitoringv1.AddToScheme(scheme) + _ = sharingv1alpha1.AddToScheme(scheme) _ = netv1alpha1.AddToScheme(scheme) _ = discoveryv1alpha1.AddToScheme(scheme) @@ -132,6 +135,7 @@ func main() { var ipamClient ipam.IpamClient var gatewayServerResources argsutils.StringList var gatewayClientResources argsutils.StringList + var wgGatewayServerClusterRoleName, wgGatewayClientClusterRoleName string webhookPort := flag.Uint("webhook-port", 9443, "The port the webhook server binds to") metricsAddr := flag.String("metrics-address", ":8080", "The address the metric endpoint binds to") @@ -217,6 +221,10 @@ func main() { // External network parameters flag.Var(&gatewayServerResources, "gateway-server-resources", "The list of resource types that implements the gateway server. They must be in the form //") flag.Var(&gatewayClientResources, "gateway-client-resources", "The list of resource types that implements the gateway client. They must be in the form //") + flag.StringVar(&wgGatewayServerClusterRoleName, "wg-gateway-server-cluster-role-name", "liqo-gateway", + "The name of the cluster role used by the wireguard gateway servers") + flag.StringVar(&wgGatewayClientClusterRoleName, "wg-gateway-client-cluster-role-name", "liqo-gateway", + "The name of the cluster role used by the wireguard gateway clients") liqoerrors.InitFlags(nil) restcfg.InitFlags(nil) @@ -664,13 +672,13 @@ func main() { } wgServerRec := wggatewaycontrollers.NewWgGatewayServerReconciler( - mgr.GetClient(), mgr.GetScheme(), auxmgrExtNetworkPods.GetClient()) + mgr.GetClient(), mgr.GetScheme(), auxmgrExtNetworkPods.GetClient(), wgGatewayServerClusterRoleName) if err = wgServerRec.SetupWithManager(mgr); err != nil { klog.Errorf("Unable to start the WgGatewayServerReconciler", err) os.Exit(1) } - wgClientRec := wggatewaycontrollers.NewWgGatewayClientReconciler(mgr.GetClient(), mgr.GetScheme()) + wgClientRec := wggatewaycontrollers.NewWgGatewayClientReconciler(mgr.GetClient(), mgr.GetScheme(), wgGatewayClientClusterRoleName) if err = wgClientRec.SetupWithManager(mgr); err != nil { klog.Errorf("Unable to start the WgGatewayClientReconciler", err) os.Exit(1) diff --git a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_gatewayclients.yaml b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_gatewayclients.yaml index 7f8593bf38..d77a2846b9 100644 --- a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_gatewayclients.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_gatewayclients.yaml @@ -78,18 +78,21 @@ spec: endpoint: description: Endpoint specifies the endpoint of the tunnel. properties: + addresses: + description: Addresses specifies the addresses of the endpoint. + items: + type: string + type: array port: description: Port specifies the port of the endpoint. format: int32 type: integer - serviceType: - default: ClusterIP - description: ServiceType specifies the type of the service. + protocol: + default: TCP + description: Protocol specifies the protocol of the endpoint. enum: - - ClusterIP - - NodePort - - LoadBalancer - - ExternalName + - TCP + - UDP type: string type: object mtu: diff --git a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayclients.yaml b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayclients.yaml index 880109bd3c..bb80d8a428 100644 --- a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayclients.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayclients.yaml @@ -8585,6 +8585,1145 @@ spec: - template type: object type: object + metrics: + description: Metrics specifies the metrics configuration for the client. + properties: + enabled: + description: Enabled specifies whether the metrics are enabled. + type: boolean + service: + description: Service specifies the service template for the metrics. + properties: + metadata: + description: Metadata of the service. + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: Spec of the service. + properties: + allocateLoadBalancerNodePorts: + description: allocateLoadBalancerNodePorts defines if + NodePorts will be automatically allocated for services + with type LoadBalancer. Default is "true". It may be + set to "false" if the cluster load-balancer does not + rely on NodePorts. If the caller requests specific + NodePorts (by specifying a value), those requests will + be respected, regardless of this field. This field may + only be set for services with type LoadBalancer and + will be cleared if the type is changed to any other + type. + type: boolean + clusterIP: + description: 'clusterIP is the IP address of the service + and is usually assigned randomly. If an address is specified + manually, is in-range (as per system configuration), + and is not in use, it will be allocated to the service; + otherwise creation of the service will fail. This field + may not be changed through updates unless the type field + is also being changed to ExternalName (which requires + this field to be blank) or the type field is being changed + from ExternalName (in which case this field may optionally + be specified, as describe above). Valid values are + "None", empty string (""), or a valid IP address. Setting + this to "None" makes a "headless service" (no virtual + IP), which is useful when direct endpoint connections + are preferred and proxying is not required. Only applies + to types ClusterIP, NodePort, and LoadBalancer. If this + field is specified when creating a Service of type ExternalName, + creation will fail. This field will be wiped when updating + a Service to type ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies' + type: string + clusterIPs: + description: "ClusterIPs is a list of IP addresses assigned + to this service, and are usually assigned randomly. + \ If an address is specified manually, is in-range (as + per system configuration), and is not in use, it will + be allocated to the service; otherwise creation of the + service will fail. This field may not be changed through + updates unless the type field is also being changed + to ExternalName (which requires this field to be empty) + or the type field is being changed from ExternalName + (in which case this field may optionally be specified, + as describe above). Valid values are \"None\", empty + string (\"\"), or a valid IP address. Setting this + to \"None\" makes a \"headless service\" (no virtual + IP), which is useful when direct endpoint connections + are preferred and proxying is not required. Only applies + to types ClusterIP, NodePort, and LoadBalancer. If this + field is specified when creating a Service of type ExternalName, + creation will fail. This field will be wiped when updating + a Service to type ExternalName. If this field is not + specified, it will be initialized from the clusterIP + field. If this field is specified, clients must ensure + that clusterIPs[0] and clusterIP have the same value. + \n This field may hold a maximum of two entries (dual-stack + IPs, in either order). These IPs must correspond to + the values of the ipFamilies field. Both clusterIPs + and ipFamilies are governed by the ipFamilyPolicy field. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies" + items: + type: string + type: array + x-kubernetes-list-type: atomic + externalIPs: + description: externalIPs is a list of IP addresses for + which nodes in the cluster will also accept traffic + for this service. These IPs are not managed by Kubernetes. The + user is responsible for ensuring that traffic arrives + at a node with this IP. A common example is external + load-balancers that are not part of the Kubernetes system. + items: + type: string + type: array + externalName: + description: externalName is the external reference that + discovery mechanisms will return as an alias for this + service (e.g. a DNS CNAME record). No proxying will + be involved. Must be a lowercase RFC-1123 hostname + (https://tools.ietf.org/html/rfc1123) and requires `type` + to be "ExternalName". + type: string + externalTrafficPolicy: + description: externalTrafficPolicy describes how nodes + distribute service traffic they receive on one of the + Service's "externally-facing" addresses (NodePorts, + ExternalIPs, and LoadBalancer IPs). If set to "Local", + the proxy will configure the service in a way that assumes + that external load balancers will take care of balancing + the service traffic between nodes, and so each node + will deliver traffic only to the node-local endpoints + of the service, without masquerading the client source + IP. (Traffic mistakenly sent to a node with no endpoints + will be dropped.) The default value, "Cluster", uses + the standard behavior of routing to all endpoints evenly + (possibly modified by topology and other features). + Note that traffic sent to an External IP or LoadBalancer + IP from within the cluster will always get "Cluster" + semantics, but clients sending to a NodePort from within + the cluster may need to take traffic policy into account + when picking a node. + type: string + healthCheckNodePort: + description: healthCheckNodePort specifies the healthcheck + nodePort for the service. This only applies when type + is set to LoadBalancer and externalTrafficPolicy is + set to Local. If a value is specified, is in-range, + and is not in use, it will be used. If not specified, + a value will be automatically allocated. External systems + (e.g. load-balancers) can use this port to determine + if a given node holds endpoints for this service or + not. If this field is specified when creating a Service + which does not need it, creation will fail. This field + will be wiped when updating a Service to no longer need + it (e.g. changing type). This field cannot be updated + once set. + format: int32 + type: integer + internalTrafficPolicy: + description: InternalTrafficPolicy describes how nodes + distribute service traffic they receive on the ClusterIP. + If set to "Local", the proxy will assume that pods only + want to talk to endpoints of the service on the same + node as the pod, dropping the traffic if there are no + local endpoints. The default value, "Cluster", uses + the standard behavior of routing to all endpoints evenly + (possibly modified by topology and other features). + type: string + ipFamilies: + description: "IPFamilies is a list of IP families (e.g. + IPv4, IPv6) assigned to this service. This field is + usually assigned automatically based on cluster configuration + and the ipFamilyPolicy field. If this field is specified + manually, the requested family is available in the cluster, + and ipFamilyPolicy allows it, it will be used; otherwise + creation of the service will fail. This field is conditionally + mutable: it allows for adding or removing a secondary + IP family, but it does not allow changing the primary + IP family of the Service. Valid values are \"IPv4\" + and \"IPv6\". This field only applies to Services of + types ClusterIP, NodePort, and LoadBalancer, and does + apply to \"headless\" services. This field will be wiped + when updating a Service to type ExternalName. \n This + field may hold a maximum of two entries (dual-stack + families, in either order). These families must correspond + to the values of the clusterIPs field, if specified. + Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy + field." + items: + description: IPFamily represents the IP Family (IPv4 + or IPv6). This type is used to express the family + of an IP expressed by a type (e.g. service.spec.ipFamilies). + type: string + type: array + x-kubernetes-list-type: atomic + ipFamilyPolicy: + description: IPFamilyPolicy represents the dual-stack-ness + requested or required by this Service. If there is no + value provided, then this field will be set to SingleStack. + Services can be "SingleStack" (a single IP family), + "PreferDualStack" (two IP families on dual-stack configured + clusters or a single IP family on single-stack clusters), + or "RequireDualStack" (two IP families on dual-stack + configured clusters, otherwise fail). The ipFamilies + and clusterIPs fields depend on the value of this field. + This field will be wiped when updating a service to + type ExternalName. + type: string + loadBalancerClass: + description: loadBalancerClass is the class of the load + balancer implementation this Service belongs to. If + specified, the value of this field must be a label-style + identifier, with an optional prefix, e.g. "internal-vip" + or "example.com/internal-vip". Unprefixed names are + reserved for end-users. This field can only be set when + the Service type is 'LoadBalancer'. If not set, the + default load balancer implementation is used, today + this is typically done through the cloud provider integration, + but should apply for any default implementation. If + set, it is assumed that a load balancer implementation + is watching for Services with a matching class. Any + default load balancer implementation (e.g. cloud providers) + should ignore Services that set this field. This field + can only be set when creating or updating a Service + to type 'LoadBalancer'. Once set, it can not be changed. + This field will be wiped when a service is updated to + a non 'LoadBalancer' type. + type: string + loadBalancerIP: + description: 'Only applies to Service Type: LoadBalancer. + This feature depends on whether the underlying cloud-provider + supports specifying the loadBalancerIP when a load balancer + is created. This field will be ignored if the cloud-provider + does not support the feature. Deprecated: This field + was under-specified and its meaning varies across implementations. + Using it is non-portable and it may not support dual-stack. + Users are encouraged to use implementation-specific + annotations when available.' + type: string + loadBalancerSourceRanges: + description: 'If specified and supported by the platform, + this will restrict traffic through the cloud-provider + load-balancer will be restricted to the specified client + IPs. This field will be ignored if the cloud-provider + does not support the feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/' + items: + type: string + type: array + ports: + description: 'The list of ports that are exposed by this + service. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies' + items: + description: ServicePort contains information on service's + port. + properties: + appProtocol: + description: "The application protocol for this + port. This is used as a hint for implementations + to offer richer behavior for protocols that they + understand. This field follows standard Kubernetes + label syntax. Valid values are either: \n * Un-prefixed + protocol names - reserved for IANA standard service + names (as per RFC-6335 and https://www.iana.org/assignments/service-names). + \n * Kubernetes-defined prefixed names: * 'kubernetes.io/h2c' + - HTTP/2 over cleartext as described in https://www.rfc-editor.org/rfc/rfc7540 + * 'kubernetes.io/ws' - WebSocket over cleartext + as described in https://www.rfc-editor.org/rfc/rfc6455 + * 'kubernetes.io/wss' - WebSocket over TLS as + described in https://www.rfc-editor.org/rfc/rfc6455 + \n * Other protocols should use implementation-defined + prefixed names such as mycompany.com/my-custom-protocol." + type: string + name: + description: The name of this port within the service. + This must be a DNS_LABEL. All ports within a ServiceSpec + must have unique names. When considering the endpoints + for a Service, this must match the 'name' field + in the EndpointPort. Optional if only one ServicePort + is defined on this service. + type: string + nodePort: + description: 'The port on each node on which this + service is exposed when type is NodePort or LoadBalancer. Usually + assigned by the system. If a value is specified, + in-range, and not in use it will be used, otherwise + the operation will fail. If not specified, a + port will be allocated if this Service requires + one. If this field is specified when creating + a Service which does not need it, creation will + fail. This field will be wiped when updating a + Service to no longer need it (e.g. changing type + from NodePort to ClusterIP). More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport' + format: int32 + type: integer + port: + description: The port that will be exposed by this + service. + format: int32 + type: integer + protocol: + default: TCP + description: The IP protocol for this port. Supports + "TCP", "UDP", and "SCTP". Default is TCP. + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: 'Number or name of the port to access + on the pods targeted by the service. Number must + be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + If this is a string, it will be looked up as a + named port in the target Pod''s container ports. + If this is not specified, the value of the ''port'' + field is used (an identity map). This field is + ignored for services with clusterIP=None, and + should be omitted or set equal to the ''port'' + field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service' + x-kubernetes-int-or-string: true + required: + - port + type: object + type: array + x-kubernetes-list-map-keys: + - port + - protocol + x-kubernetes-list-type: map + publishNotReadyAddresses: + description: publishNotReadyAddresses indicates that any + agent which deals with endpoints for this Service should + disregard any indications of ready/not-ready. The primary + use case for setting this field is for a StatefulSet's + Headless Service to propagate SRV DNS records for its + Pods for the purpose of peer discovery. The Kubernetes + controllers that generate Endpoints and EndpointSlice + resources for Services interpret this to mean that all + endpoints are considered "ready" even if the Pods themselves + are not. Agents which consume only Kubernetes generated + endpoints through the Endpoints or EndpointSlice resources + can safely assume this behavior. + type: boolean + selector: + additionalProperties: + type: string + description: 'Route service traffic to pods with label + keys and values matching this selector. If empty or + not present, the service is assumed to have an external + process managing its endpoints, which Kubernetes will + not modify. Only applies to types ClusterIP, NodePort, + and LoadBalancer. Ignored if type is ExternalName. More + info: https://kubernetes.io/docs/concepts/services-networking/service/' + type: object + x-kubernetes-map-type: atomic + sessionAffinity: + description: 'Supports "ClientIP" and "None". Used to + maintain session affinity. Enable client IP based session + affinity. Must be ClientIP or None. Defaults to None. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies' + type: string + sessionAffinityConfig: + description: sessionAffinityConfig contains the configurations + of session affinity. + properties: + clientIP: + description: clientIP contains the configurations + of Client IP based session affinity. + properties: + timeoutSeconds: + description: timeoutSeconds specifies the seconds + of ClientIP type session sticky time. The value + must be >0 && <=86400(for 1 day) if ServiceAffinity + == "ClientIP". Default value is 10800(for 3 + hours). + format: int32 + type: integer + type: object + type: object + type: + description: 'type determines how the Service is exposed. + Defaults to ClusterIP. Valid options are ExternalName, + ClusterIP, NodePort, and LoadBalancer. "ClusterIP" allocates + a cluster-internal IP address for load-balancing to + endpoints. Endpoints are determined by the selector + or if that is not specified, by manual construction + of an Endpoints object or EndpointSlice objects. If + clusterIP is "None", no virtual IP is allocated and + the endpoints are published as a set of endpoints rather + than a virtual IP. "NodePort" builds on ClusterIP and + allocates a port on every node which routes to the same + endpoints as the clusterIP. "LoadBalancer" builds on + NodePort and creates an external load-balancer (if supported + in the current cloud) which routes to the same endpoints + as the clusterIP. "ExternalName" aliases this service + to the specified externalName. Several other fields + do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types' + type: string + type: object + type: object + serviceMonitor: + description: ServiceMonitor specifies the service monitor template + for the metrics. + properties: + metadata: + description: Metadata of the service monitor. + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: Spec of the service monitor. + properties: + attachMetadata: + description: Attaches node metadata to discovered targets. + Requires Prometheus v2.37.0 and above. + properties: + node: + description: When set to true, Prometheus must have + permissions to get Nodes. + type: boolean + type: object + endpoints: + description: A list of endpoints allowed as part of this + ServiceMonitor. + items: + description: Endpoint defines a scrapeable endpoint + serving Prometheus metrics. + properties: + authorization: + description: Authorization section for this endpoint + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: "Defines the authentication type. + The value is case-insensitive. \n \"Basic\" + is not a supported value. \n Default: \"Bearer\"" + type: string + type: object + basicAuth: + description: 'BasicAuth allow an endpoint to authenticate + over basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints' + properties: + password: + description: The secret in the service monitor + namespace that contains the password for authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: The secret in the service monitor + namespace that contains the username for authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenFile: + description: File to read bearer token for scraping + targets. + type: string + bearerTokenSecret: + description: Secret to mount to read bearer token + for scraping targets. The secret needs to be in + the same namespace as the service monitor and + accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + enableHttp2: + description: Whether to enable HTTP2. + type: boolean + filterRunning: + description: 'Drop pods that are not running. (Failed, + Succeeded). Enabled by default. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase' + type: boolean + followRedirects: + description: FollowRedirects configures whether + scrape requests follow HTTP 3xx redirects. + type: boolean + honorLabels: + description: HonorLabels chooses the metric's labels + on collisions with target labels. + type: boolean + honorTimestamps: + description: HonorTimestamps controls whether Prometheus + respects the timestamps present in scraped data. + type: boolean + interval: + description: Interval at which metrics should be + scraped If not specified Prometheus' global scrape + interval is used. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + metricRelabelings: + description: MetricRelabelConfigs to apply to samples + before ingestion. + items: + description: "RelabelConfig allows dynamic rewriting + of the label set for targets, alerts, scraped + samples and remote write samples. \n More info: + https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config" + properties: + action: + default: replace + description: "Action to perform based on the + regex matching. \n `Uppercase` and `Lowercase` + actions require Prometheus >= v2.36.0. `DropEqual` + and `KeepEqual` actions require Prometheus + >= v2.41.0. \n Default: \"Replace\"" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: "Modulus to take of the hash + of the source label values. \n Only applicable + when the action is `HashMod`." + format: int64 + type: integer + regex: + description: Regular expression against which + the extracted value is matched. + type: string + replacement: + description: "Replacement value against which + a Replace action is performed if the regular + expression matches. \n Regex capture groups + are available." + type: string + separator: + description: Separator is the string between + concatenated SourceLabels. + type: string + sourceLabels: + description: The source labels select values + from existing labels. Their content is concatenated + using the configured Separator and matched + against the configured regular expression. + items: + description: LabelName is a valid Prometheus + label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: "Label to which the resulting + string is written in a replacement. \n It + is mandatory for `Replace`, `HashMod`, `Lowercase`, + `Uppercase`, `KeepEqual` and `DropEqual` + actions. \n Regex capture groups are available." + type: string + type: object + type: array + oauth2: + description: OAuth2 for the URL. Only valid in Prometheus + versions 2.27.0 and newer. + properties: + clientId: + description: The secret or configmap containing + the OAuth2 client id + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: The secret containing the OAuth2 + client secret + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: Parameters to append to the token + URL + type: object + scopes: + description: OAuth2 scopes used for the token + request + items: + type: string + type: array + tokenUrl: + description: The URL to fetch the token from + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + params: + additionalProperties: + items: + type: string + type: array + description: Optional HTTP URL parameters + type: object + path: + description: HTTP path to scrape for metrics. If + empty, Prometheus uses the default value (e.g. + `/metrics`). + type: string + port: + description: Name of the service port this endpoint + refers to. Mutually exclusive with targetPort. + type: string + proxyUrl: + description: ProxyURL eg http://proxyserver:2195 + Directs scrapes to proxy through this endpoint. + type: string + relabelings: + description: 'RelabelConfigs to apply to samples + before scraping. Prometheus Operator automatically + adds relabelings for a few standard Kubernetes + fields. The original scrape job''s name is available + via the `__tmp_prometheus_job_name` label. More + info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config' + items: + description: "RelabelConfig allows dynamic rewriting + of the label set for targets, alerts, scraped + samples and remote write samples. \n More info: + https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config" + properties: + action: + default: replace + description: "Action to perform based on the + regex matching. \n `Uppercase` and `Lowercase` + actions require Prometheus >= v2.36.0. `DropEqual` + and `KeepEqual` actions require Prometheus + >= v2.41.0. \n Default: \"Replace\"" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: "Modulus to take of the hash + of the source label values. \n Only applicable + when the action is `HashMod`." + format: int64 + type: integer + regex: + description: Regular expression against which + the extracted value is matched. + type: string + replacement: + description: "Replacement value against which + a Replace action is performed if the regular + expression matches. \n Regex capture groups + are available." + type: string + separator: + description: Separator is the string between + concatenated SourceLabels. + type: string + sourceLabels: + description: The source labels select values + from existing labels. Their content is concatenated + using the configured Separator and matched + against the configured regular expression. + items: + description: LabelName is a valid Prometheus + label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: "Label to which the resulting + string is written in a replacement. \n It + is mandatory for `Replace`, `HashMod`, `Lowercase`, + `Uppercase`, `KeepEqual` and `DropEqual` + actions. \n Regex capture groups are available." + type: string + type: object + type: array + scheme: + description: HTTP scheme to use for scraping. `http` + and `https` are the expected values unless you + rewrite the `__scheme__` label via relabeling. + If empty, Prometheus uses the default value `http`. + enum: + - http + - https + type: string + scrapeTimeout: + description: Timeout after which the scrape is ended + If not specified, the Prometheus global scrape + timeout is used unless it is less than `Interval` + in which the latter is used. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: Name or number of the target port of + the Pod behind the Service, the port must be specified + with container port property. Mutually exclusive + with port. + x-kubernetes-int-or-string: true + tlsConfig: + description: TLS configuration to use when scraping + the endpoint + properties: + ca: + description: Certificate authority used when + verifying server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + description: Path to the CA cert in the Prometheus + container to use for the targets. + type: string + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + description: Path to the client cert file in + the Prometheus container for the targets. + type: string + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keyFile: + description: Path to the client key file in + the Prometheus container for the targets. + type: string + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for + the targets. + type: string + type: object + type: object + type: array + jobLabel: + description: "JobLabel selects the label from the associated + Kubernetes service which will be used as the `job` label + for all metrics. \n For example: If in `ServiceMonitor.spec.jobLabel: + foo` and in `Service.metadata.labels.foo: bar`, then + the `job=\"bar\"` label is added to all metrics. \n + If the value of this field is empty or if the label + doesn't exist for the given Service, the `job` label + of the metrics defaults to the name of the Kubernetes + Service." + type: string + labelLimit: + description: Per-scrape limit on number of labels that + will be accepted for a sample. Only valid in Prometheus + versions 2.27.0 and newer. + format: int64 + type: integer + labelNameLengthLimit: + description: Per-scrape limit on length of labels name + that will be accepted for a sample. Only valid in Prometheus + versions 2.27.0 and newer. + format: int64 + type: integer + labelValueLengthLimit: + description: Per-scrape limit on length of labels value + that will be accepted for a sample. Only valid in Prometheus + versions 2.27.0 and newer. + format: int64 + type: integer + namespaceSelector: + description: Selector to select which namespaces the Kubernetes + Endpoints objects are discovered from. + properties: + any: + description: Boolean describing whether all namespaces + are selected in contrast to a list restricting them. + type: boolean + matchNames: + description: List of namespace names to select from. + items: + type: string + type: array + type: object + podTargetLabels: + description: PodTargetLabels transfers labels on the Kubernetes + `Pod` onto the created metrics. + items: + type: string + type: array + sampleLimit: + description: SampleLimit defines per-scrape limit on number + of scraped samples that will be accepted. + format: int64 + type: integer + selector: + description: Selector to select Endpoints objects. + 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 + x-kubernetes-map-type: atomic + targetLabels: + description: TargetLabels transfers labels from the Kubernetes + `Service` onto the created metrics. + items: + type: string + type: array + targetLimit: + description: TargetLimit defines a limit on the number + of scraped targets that will be accepted. + format: int64 + type: integer + required: + - endpoints + - selector + type: object + type: object + required: + - enabled + type: object required: - deployment type: object diff --git a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayservers.yaml b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayservers.yaml index 0b41283b36..eff25fa3d2 100644 --- a/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayservers.yaml +++ b/deployments/liqo/charts/liqo-crds/crds/networking.liqo.io_wggatewayservers.yaml @@ -8585,6 +8585,1145 @@ spec: - template type: object type: object + metrics: + description: Metrics specifies the metrics configuration for the server. + properties: + enabled: + description: Enabled specifies whether the metrics are enabled. + type: boolean + service: + description: Service specifies the service template for the metrics. + properties: + metadata: + description: Metadata of the service. + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: Spec of the service. + properties: + allocateLoadBalancerNodePorts: + description: allocateLoadBalancerNodePorts defines if + NodePorts will be automatically allocated for services + with type LoadBalancer. Default is "true". It may be + set to "false" if the cluster load-balancer does not + rely on NodePorts. If the caller requests specific + NodePorts (by specifying a value), those requests will + be respected, regardless of this field. This field may + only be set for services with type LoadBalancer and + will be cleared if the type is changed to any other + type. + type: boolean + clusterIP: + description: 'clusterIP is the IP address of the service + and is usually assigned randomly. If an address is specified + manually, is in-range (as per system configuration), + and is not in use, it will be allocated to the service; + otherwise creation of the service will fail. This field + may not be changed through updates unless the type field + is also being changed to ExternalName (which requires + this field to be blank) or the type field is being changed + from ExternalName (in which case this field may optionally + be specified, as describe above). Valid values are + "None", empty string (""), or a valid IP address. Setting + this to "None" makes a "headless service" (no virtual + IP), which is useful when direct endpoint connections + are preferred and proxying is not required. Only applies + to types ClusterIP, NodePort, and LoadBalancer. If this + field is specified when creating a Service of type ExternalName, + creation will fail. This field will be wiped when updating + a Service to type ExternalName. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies' + type: string + clusterIPs: + description: "ClusterIPs is a list of IP addresses assigned + to this service, and are usually assigned randomly. + \ If an address is specified manually, is in-range (as + per system configuration), and is not in use, it will + be allocated to the service; otherwise creation of the + service will fail. This field may not be changed through + updates unless the type field is also being changed + to ExternalName (which requires this field to be empty) + or the type field is being changed from ExternalName + (in which case this field may optionally be specified, + as describe above). Valid values are \"None\", empty + string (\"\"), or a valid IP address. Setting this + to \"None\" makes a \"headless service\" (no virtual + IP), which is useful when direct endpoint connections + are preferred and proxying is not required. Only applies + to types ClusterIP, NodePort, and LoadBalancer. If this + field is specified when creating a Service of type ExternalName, + creation will fail. This field will be wiped when updating + a Service to type ExternalName. If this field is not + specified, it will be initialized from the clusterIP + field. If this field is specified, clients must ensure + that clusterIPs[0] and clusterIP have the same value. + \n This field may hold a maximum of two entries (dual-stack + IPs, in either order). These IPs must correspond to + the values of the ipFamilies field. Both clusterIPs + and ipFamilies are governed by the ipFamilyPolicy field. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies" + items: + type: string + type: array + x-kubernetes-list-type: atomic + externalIPs: + description: externalIPs is a list of IP addresses for + which nodes in the cluster will also accept traffic + for this service. These IPs are not managed by Kubernetes. The + user is responsible for ensuring that traffic arrives + at a node with this IP. A common example is external + load-balancers that are not part of the Kubernetes system. + items: + type: string + type: array + externalName: + description: externalName is the external reference that + discovery mechanisms will return as an alias for this + service (e.g. a DNS CNAME record). No proxying will + be involved. Must be a lowercase RFC-1123 hostname + (https://tools.ietf.org/html/rfc1123) and requires `type` + to be "ExternalName". + type: string + externalTrafficPolicy: + description: externalTrafficPolicy describes how nodes + distribute service traffic they receive on one of the + Service's "externally-facing" addresses (NodePorts, + ExternalIPs, and LoadBalancer IPs). If set to "Local", + the proxy will configure the service in a way that assumes + that external load balancers will take care of balancing + the service traffic between nodes, and so each node + will deliver traffic only to the node-local endpoints + of the service, without masquerading the client source + IP. (Traffic mistakenly sent to a node with no endpoints + will be dropped.) The default value, "Cluster", uses + the standard behavior of routing to all endpoints evenly + (possibly modified by topology and other features). + Note that traffic sent to an External IP or LoadBalancer + IP from within the cluster will always get "Cluster" + semantics, but clients sending to a NodePort from within + the cluster may need to take traffic policy into account + when picking a node. + type: string + healthCheckNodePort: + description: healthCheckNodePort specifies the healthcheck + nodePort for the service. This only applies when type + is set to LoadBalancer and externalTrafficPolicy is + set to Local. If a value is specified, is in-range, + and is not in use, it will be used. If not specified, + a value will be automatically allocated. External systems + (e.g. load-balancers) can use this port to determine + if a given node holds endpoints for this service or + not. If this field is specified when creating a Service + which does not need it, creation will fail. This field + will be wiped when updating a Service to no longer need + it (e.g. changing type). This field cannot be updated + once set. + format: int32 + type: integer + internalTrafficPolicy: + description: InternalTrafficPolicy describes how nodes + distribute service traffic they receive on the ClusterIP. + If set to "Local", the proxy will assume that pods only + want to talk to endpoints of the service on the same + node as the pod, dropping the traffic if there are no + local endpoints. The default value, "Cluster", uses + the standard behavior of routing to all endpoints evenly + (possibly modified by topology and other features). + type: string + ipFamilies: + description: "IPFamilies is a list of IP families (e.g. + IPv4, IPv6) assigned to this service. This field is + usually assigned automatically based on cluster configuration + and the ipFamilyPolicy field. If this field is specified + manually, the requested family is available in the cluster, + and ipFamilyPolicy allows it, it will be used; otherwise + creation of the service will fail. This field is conditionally + mutable: it allows for adding or removing a secondary + IP family, but it does not allow changing the primary + IP family of the Service. Valid values are \"IPv4\" + and \"IPv6\". This field only applies to Services of + types ClusterIP, NodePort, and LoadBalancer, and does + apply to \"headless\" services. This field will be wiped + when updating a Service to type ExternalName. \n This + field may hold a maximum of two entries (dual-stack + families, in either order). These families must correspond + to the values of the clusterIPs field, if specified. + Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy + field." + items: + description: IPFamily represents the IP Family (IPv4 + or IPv6). This type is used to express the family + of an IP expressed by a type (e.g. service.spec.ipFamilies). + type: string + type: array + x-kubernetes-list-type: atomic + ipFamilyPolicy: + description: IPFamilyPolicy represents the dual-stack-ness + requested or required by this Service. If there is no + value provided, then this field will be set to SingleStack. + Services can be "SingleStack" (a single IP family), + "PreferDualStack" (two IP families on dual-stack configured + clusters or a single IP family on single-stack clusters), + or "RequireDualStack" (two IP families on dual-stack + configured clusters, otherwise fail). The ipFamilies + and clusterIPs fields depend on the value of this field. + This field will be wiped when updating a service to + type ExternalName. + type: string + loadBalancerClass: + description: loadBalancerClass is the class of the load + balancer implementation this Service belongs to. If + specified, the value of this field must be a label-style + identifier, with an optional prefix, e.g. "internal-vip" + or "example.com/internal-vip". Unprefixed names are + reserved for end-users. This field can only be set when + the Service type is 'LoadBalancer'. If not set, the + default load balancer implementation is used, today + this is typically done through the cloud provider integration, + but should apply for any default implementation. If + set, it is assumed that a load balancer implementation + is watching for Services with a matching class. Any + default load balancer implementation (e.g. cloud providers) + should ignore Services that set this field. This field + can only be set when creating or updating a Service + to type 'LoadBalancer'. Once set, it can not be changed. + This field will be wiped when a service is updated to + a non 'LoadBalancer' type. + type: string + loadBalancerIP: + description: 'Only applies to Service Type: LoadBalancer. + This feature depends on whether the underlying cloud-provider + supports specifying the loadBalancerIP when a load balancer + is created. This field will be ignored if the cloud-provider + does not support the feature. Deprecated: This field + was under-specified and its meaning varies across implementations. + Using it is non-portable and it may not support dual-stack. + Users are encouraged to use implementation-specific + annotations when available.' + type: string + loadBalancerSourceRanges: + description: 'If specified and supported by the platform, + this will restrict traffic through the cloud-provider + load-balancer will be restricted to the specified client + IPs. This field will be ignored if the cloud-provider + does not support the feature." More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/' + items: + type: string + type: array + ports: + description: 'The list of ports that are exposed by this + service. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies' + items: + description: ServicePort contains information on service's + port. + properties: + appProtocol: + description: "The application protocol for this + port. This is used as a hint for implementations + to offer richer behavior for protocols that they + understand. This field follows standard Kubernetes + label syntax. Valid values are either: \n * Un-prefixed + protocol names - reserved for IANA standard service + names (as per RFC-6335 and https://www.iana.org/assignments/service-names). + \n * Kubernetes-defined prefixed names: * 'kubernetes.io/h2c' + - HTTP/2 over cleartext as described in https://www.rfc-editor.org/rfc/rfc7540 + * 'kubernetes.io/ws' - WebSocket over cleartext + as described in https://www.rfc-editor.org/rfc/rfc6455 + * 'kubernetes.io/wss' - WebSocket over TLS as + described in https://www.rfc-editor.org/rfc/rfc6455 + \n * Other protocols should use implementation-defined + prefixed names such as mycompany.com/my-custom-protocol." + type: string + name: + description: The name of this port within the service. + This must be a DNS_LABEL. All ports within a ServiceSpec + must have unique names. When considering the endpoints + for a Service, this must match the 'name' field + in the EndpointPort. Optional if only one ServicePort + is defined on this service. + type: string + nodePort: + description: 'The port on each node on which this + service is exposed when type is NodePort or LoadBalancer. Usually + assigned by the system. If a value is specified, + in-range, and not in use it will be used, otherwise + the operation will fail. If not specified, a + port will be allocated if this Service requires + one. If this field is specified when creating + a Service which does not need it, creation will + fail. This field will be wiped when updating a + Service to no longer need it (e.g. changing type + from NodePort to ClusterIP). More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport' + format: int32 + type: integer + port: + description: The port that will be exposed by this + service. + format: int32 + type: integer + protocol: + default: TCP + description: The IP protocol for this port. Supports + "TCP", "UDP", and "SCTP". Default is TCP. + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: 'Number or name of the port to access + on the pods targeted by the service. Number must + be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + If this is a string, it will be looked up as a + named port in the target Pod''s container ports. + If this is not specified, the value of the ''port'' + field is used (an identity map). This field is + ignored for services with clusterIP=None, and + should be omitted or set equal to the ''port'' + field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service' + x-kubernetes-int-or-string: true + required: + - port + type: object + type: array + x-kubernetes-list-map-keys: + - port + - protocol + x-kubernetes-list-type: map + publishNotReadyAddresses: + description: publishNotReadyAddresses indicates that any + agent which deals with endpoints for this Service should + disregard any indications of ready/not-ready. The primary + use case for setting this field is for a StatefulSet's + Headless Service to propagate SRV DNS records for its + Pods for the purpose of peer discovery. The Kubernetes + controllers that generate Endpoints and EndpointSlice + resources for Services interpret this to mean that all + endpoints are considered "ready" even if the Pods themselves + are not. Agents which consume only Kubernetes generated + endpoints through the Endpoints or EndpointSlice resources + can safely assume this behavior. + type: boolean + selector: + additionalProperties: + type: string + description: 'Route service traffic to pods with label + keys and values matching this selector. If empty or + not present, the service is assumed to have an external + process managing its endpoints, which Kubernetes will + not modify. Only applies to types ClusterIP, NodePort, + and LoadBalancer. Ignored if type is ExternalName. More + info: https://kubernetes.io/docs/concepts/services-networking/service/' + type: object + x-kubernetes-map-type: atomic + sessionAffinity: + description: 'Supports "ClientIP" and "None". Used to + maintain session affinity. Enable client IP based session + affinity. Must be ClientIP or None. Defaults to None. + More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies' + type: string + sessionAffinityConfig: + description: sessionAffinityConfig contains the configurations + of session affinity. + properties: + clientIP: + description: clientIP contains the configurations + of Client IP based session affinity. + properties: + timeoutSeconds: + description: timeoutSeconds specifies the seconds + of ClientIP type session sticky time. The value + must be >0 && <=86400(for 1 day) if ServiceAffinity + == "ClientIP". Default value is 10800(for 3 + hours). + format: int32 + type: integer + type: object + type: object + type: + description: 'type determines how the Service is exposed. + Defaults to ClusterIP. Valid options are ExternalName, + ClusterIP, NodePort, and LoadBalancer. "ClusterIP" allocates + a cluster-internal IP address for load-balancing to + endpoints. Endpoints are determined by the selector + or if that is not specified, by manual construction + of an Endpoints object or EndpointSlice objects. If + clusterIP is "None", no virtual IP is allocated and + the endpoints are published as a set of endpoints rather + than a virtual IP. "NodePort" builds on ClusterIP and + allocates a port on every node which routes to the same + endpoints as the clusterIP. "LoadBalancer" builds on + NodePort and creates an external load-balancer (if supported + in the current cloud) which routes to the same endpoints + as the clusterIP. "ExternalName" aliases this service + to the specified externalName. Several other fields + do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types' + type: string + type: object + type: object + serviceMonitor: + description: ServiceMonitor specifies the service monitor template + for the metrics. + properties: + metadata: + description: Metadata of the service monitor. + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: Spec of the service monitor. + properties: + attachMetadata: + description: Attaches node metadata to discovered targets. + Requires Prometheus v2.37.0 and above. + properties: + node: + description: When set to true, Prometheus must have + permissions to get Nodes. + type: boolean + type: object + endpoints: + description: A list of endpoints allowed as part of this + ServiceMonitor. + items: + description: Endpoint defines a scrapeable endpoint + serving Prometheus metrics. + properties: + authorization: + description: Authorization section for this endpoint + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: "Defines the authentication type. + The value is case-insensitive. \n \"Basic\" + is not a supported value. \n Default: \"Bearer\"" + type: string + type: object + basicAuth: + description: 'BasicAuth allow an endpoint to authenticate + over basic authentication More info: https://prometheus.io/docs/operating/configuration/#endpoints' + properties: + password: + description: The secret in the service monitor + namespace that contains the password for authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: The secret in the service monitor + namespace that contains the username for authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenFile: + description: File to read bearer token for scraping + targets. + type: string + bearerTokenSecret: + description: Secret to mount to read bearer token + for scraping targets. The secret needs to be in + the same namespace as the service monitor and + accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + enableHttp2: + description: Whether to enable HTTP2. + type: boolean + filterRunning: + description: 'Drop pods that are not running. (Failed, + Succeeded). Enabled by default. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase' + type: boolean + followRedirects: + description: FollowRedirects configures whether + scrape requests follow HTTP 3xx redirects. + type: boolean + honorLabels: + description: HonorLabels chooses the metric's labels + on collisions with target labels. + type: boolean + honorTimestamps: + description: HonorTimestamps controls whether Prometheus + respects the timestamps present in scraped data. + type: boolean + interval: + description: Interval at which metrics should be + scraped If not specified Prometheus' global scrape + interval is used. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + metricRelabelings: + description: MetricRelabelConfigs to apply to samples + before ingestion. + items: + description: "RelabelConfig allows dynamic rewriting + of the label set for targets, alerts, scraped + samples and remote write samples. \n More info: + https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config" + properties: + action: + default: replace + description: "Action to perform based on the + regex matching. \n `Uppercase` and `Lowercase` + actions require Prometheus >= v2.36.0. `DropEqual` + and `KeepEqual` actions require Prometheus + >= v2.41.0. \n Default: \"Replace\"" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: "Modulus to take of the hash + of the source label values. \n Only applicable + when the action is `HashMod`." + format: int64 + type: integer + regex: + description: Regular expression against which + the extracted value is matched. + type: string + replacement: + description: "Replacement value against which + a Replace action is performed if the regular + expression matches. \n Regex capture groups + are available." + type: string + separator: + description: Separator is the string between + concatenated SourceLabels. + type: string + sourceLabels: + description: The source labels select values + from existing labels. Their content is concatenated + using the configured Separator and matched + against the configured regular expression. + items: + description: LabelName is a valid Prometheus + label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: "Label to which the resulting + string is written in a replacement. \n It + is mandatory for `Replace`, `HashMod`, `Lowercase`, + `Uppercase`, `KeepEqual` and `DropEqual` + actions. \n Regex capture groups are available." + type: string + type: object + type: array + oauth2: + description: OAuth2 for the URL. Only valid in Prometheus + versions 2.27.0 and newer. + properties: + clientId: + description: The secret or configmap containing + the OAuth2 client id + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: The secret containing the OAuth2 + client secret + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: Parameters to append to the token + URL + type: object + scopes: + description: OAuth2 scopes used for the token + request + items: + type: string + type: array + tokenUrl: + description: The URL to fetch the token from + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + params: + additionalProperties: + items: + type: string + type: array + description: Optional HTTP URL parameters + type: object + path: + description: HTTP path to scrape for metrics. If + empty, Prometheus uses the default value (e.g. + `/metrics`). + type: string + port: + description: Name of the service port this endpoint + refers to. Mutually exclusive with targetPort. + type: string + proxyUrl: + description: ProxyURL eg http://proxyserver:2195 + Directs scrapes to proxy through this endpoint. + type: string + relabelings: + description: 'RelabelConfigs to apply to samples + before scraping. Prometheus Operator automatically + adds relabelings for a few standard Kubernetes + fields. The original scrape job''s name is available + via the `__tmp_prometheus_job_name` label. More + info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config' + items: + description: "RelabelConfig allows dynamic rewriting + of the label set for targets, alerts, scraped + samples and remote write samples. \n More info: + https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config" + properties: + action: + default: replace + description: "Action to perform based on the + regex matching. \n `Uppercase` and `Lowercase` + actions require Prometheus >= v2.36.0. `DropEqual` + and `KeepEqual` actions require Prometheus + >= v2.41.0. \n Default: \"Replace\"" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: "Modulus to take of the hash + of the source label values. \n Only applicable + when the action is `HashMod`." + format: int64 + type: integer + regex: + description: Regular expression against which + the extracted value is matched. + type: string + replacement: + description: "Replacement value against which + a Replace action is performed if the regular + expression matches. \n Regex capture groups + are available." + type: string + separator: + description: Separator is the string between + concatenated SourceLabels. + type: string + sourceLabels: + description: The source labels select values + from existing labels. Their content is concatenated + using the configured Separator and matched + against the configured regular expression. + items: + description: LabelName is a valid Prometheus + label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: "Label to which the resulting + string is written in a replacement. \n It + is mandatory for `Replace`, `HashMod`, `Lowercase`, + `Uppercase`, `KeepEqual` and `DropEqual` + actions. \n Regex capture groups are available." + type: string + type: object + type: array + scheme: + description: HTTP scheme to use for scraping. `http` + and `https` are the expected values unless you + rewrite the `__scheme__` label via relabeling. + If empty, Prometheus uses the default value `http`. + enum: + - http + - https + type: string + scrapeTimeout: + description: Timeout after which the scrape is ended + If not specified, the Prometheus global scrape + timeout is used unless it is less than `Interval` + in which the latter is used. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: Name or number of the target port of + the Pod behind the Service, the port must be specified + with container port property. Mutually exclusive + with port. + x-kubernetes-int-or-string: true + tlsConfig: + description: TLS configuration to use when scraping + the endpoint + properties: + ca: + description: Certificate authority used when + verifying server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + description: Path to the CA cert in the Prometheus + container to use for the targets. + type: string + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + description: Path to the client cert file in + the Prometheus container for the targets. + type: string + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keyFile: + description: Path to the client key file in + the Prometheus container for the targets. + type: string + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for + the targets. + type: string + type: object + type: object + type: array + jobLabel: + description: "JobLabel selects the label from the associated + Kubernetes service which will be used as the `job` label + for all metrics. \n For example: If in `ServiceMonitor.spec.jobLabel: + foo` and in `Service.metadata.labels.foo: bar`, then + the `job=\"bar\"` label is added to all metrics. \n + If the value of this field is empty or if the label + doesn't exist for the given Service, the `job` label + of the metrics defaults to the name of the Kubernetes + Service." + type: string + labelLimit: + description: Per-scrape limit on number of labels that + will be accepted for a sample. Only valid in Prometheus + versions 2.27.0 and newer. + format: int64 + type: integer + labelNameLengthLimit: + description: Per-scrape limit on length of labels name + that will be accepted for a sample. Only valid in Prometheus + versions 2.27.0 and newer. + format: int64 + type: integer + labelValueLengthLimit: + description: Per-scrape limit on length of labels value + that will be accepted for a sample. Only valid in Prometheus + versions 2.27.0 and newer. + format: int64 + type: integer + namespaceSelector: + description: Selector to select which namespaces the Kubernetes + Endpoints objects are discovered from. + properties: + any: + description: Boolean describing whether all namespaces + are selected in contrast to a list restricting them. + type: boolean + matchNames: + description: List of namespace names to select from. + items: + type: string + type: array + type: object + podTargetLabels: + description: PodTargetLabels transfers labels on the Kubernetes + `Pod` onto the created metrics. + items: + type: string + type: array + sampleLimit: + description: SampleLimit defines per-scrape limit on number + of scraped samples that will be accepted. + format: int64 + type: integer + selector: + description: Selector to select Endpoints objects. + 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 + x-kubernetes-map-type: atomic + targetLabels: + description: TargetLabels transfers labels from the Kubernetes + `Service` onto the created metrics. + items: + type: string + type: array + targetLimit: + description: TargetLimit defines a limit on the number + of scraped targets that will be accepted. + format: int64 + type: integer + required: + - endpoints + - selector + type: object + type: object + required: + - enabled + type: object service: description: Service specifies the service template for the server. properties: diff --git a/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml b/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml index 46f0071b3a..3f62d6d8eb 100644 --- a/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml +++ b/deployments/liqo/files/liqo-controller-manager-ClusterRole.yaml @@ -347,6 +347,18 @@ rules: - scrape/metrics verbs: - get +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - net.liqo.io resources: diff --git a/deployments/liqo/templates/liqo-controller-manager-rbac.yaml b/deployments/liqo/templates/liqo-controller-manager-rbac.yaml index 1e6a161780..9afca0c3b4 100644 --- a/deployments/liqo/templates/liqo-controller-manager-rbac.yaml +++ b/deployments/liqo/templates/liqo-controller-manager-rbac.yaml @@ -1,5 +1,6 @@ --- {{- $ctrlManagerConfig := (merge (dict "name" "controller-manager" "module" "controller-manager") .) -}} +{{- $gatewayConfig := (merge (dict "name" "gateway" "module" "networking") .) -}} {{- $virtualKubeletConfigLocal := (merge (dict "name" "virtual-kubelet-local" "module" "virtualkubelet") .) -}} {{- $virtualKubeletConfigRemote := (merge (dict "name" "virtual-kubelet-remote" "module" "virtualkubelet") .) -}} @@ -25,6 +26,23 @@ roleRef: kind: ClusterRole name: {{ include "liqo.prefixedName" $ctrlManagerConfig }} --- +# The controller-manager needs to be also granted the wireguard gateway permissions, +# as it needs to create the necessary cluster role binding associated with the wireguard gateway. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "liqo.prefixedName" $ctrlManagerConfig }}-grant-wg-gateway + labels: + {{- include "liqo.labels" $ctrlManagerConfig | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "liqo.prefixedName" $ctrlManagerConfig }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "liqo.prefixedName" $gatewayConfig }} +--- # The controller-manager needs to be also granted the local virtual kubelet permissions, # as it needs to create the necessary cluster role binding associated with the virtual kubelet. apiVersion: rbac.authorization.k8s.io/v1 diff --git a/go.mod b/go.mod index 420d491ec5..63a9a41a55 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/openshift/api v0.0.0-20210521075222-e273a339932a github.com/openshift/client-go v0.0.0-20210521082421-73d9475a9142 github.com/pkg/errors v0.9.1 + github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.67.0 github.com/prometheus/client_golang v1.17.0 github.com/pterm/pterm v0.12.69 github.com/spf13/cobra v1.7.0 diff --git a/go.sum b/go.sum index 0ca751e95a..40816eef7e 100644 --- a/go.sum +++ b/go.sum @@ -702,6 +702,8 @@ github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.67.0 h1:q4oq0KX1vPbvXGUwEXN4D3mFzvQR/WmWK4lfIj0K5oI= +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.67.0/go.mod h1:KZHvrby65G+rA4V/vMTUXDV22TI+GgLIrCigYClpjzk= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= diff --git a/pkg/liqo-controller-manager/external-network/client-operator/client_controller.go b/pkg/liqo-controller-manager/external-network/client-operator/client_controller.go index 1713e12252..0e34b3e102 100644 --- a/pkg/liqo-controller-manager/external-network/client-operator/client_controller.go +++ b/pkg/liqo-controller-manager/external-network/client-operator/client_controller.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" + "github.com/liqotech/liqo/pkg/consts" enutils "github.com/liqotech/liqo/pkg/liqo-controller-manager/external-network/utils" dynamicutils "github.com/liqotech/liqo/pkg/utils/dynamic" ) @@ -44,6 +45,12 @@ type ClientReconciler struct { ClientResources []string } +type templateData struct { + Spec networkingv1alpha1.GatewayClientSpec + GatewayUID string + ClusterID string +} + // NewClientReconciler returns a new ClientReconciler. func NewClientReconciler(cl client.Client, dynClient dynamic.Interface, factory *dynamicutils.RunnableFactory, s *runtime.Scheme, @@ -97,6 +104,14 @@ func (r *ClientReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res // EnsureGatewayClient ensures the GatewayClient is correctly configured. func (r *ClientReconciler) EnsureGatewayClient(ctx context.Context, gwClient *networkingv1alpha1.GatewayClient) error { + if gwClient.Labels == nil { + gwClient.Labels = map[string]string{} + } + remoteClusterID, ok := gwClient.Labels[consts.RemoteClusterID] + if !ok { + return fmt.Errorf("missing label %q on GatewayClient %q", consts.RemoteClusterID, gwClient.Name) + } + templateGV, err := schema.ParseGroupVersion(gwClient.Spec.ClientTemplateRef.APIVersion) if err != nil { return fmt.Errorf("unable to parse the client template group version: %w", err) @@ -162,7 +177,11 @@ func (r *ClientReconciler) EnsureGatewayClient(ctx context.Context, gwClient *ne Controller: pointer.Bool(true), }, }) - spec, err := enutils.RenderTemplate(objectTemplateSpec, gwClient.Spec) + spec, err := enutils.RenderTemplate(objectTemplateSpec, templateData{ + Spec: gwClient.Spec, + GatewayUID: string(gwClient.UID), + ClusterID: remoteClusterID, + }) if err != nil { return fmt.Errorf("unable to render the template: %w", err) } diff --git a/pkg/liqo-controller-manager/external-network/server-operator/server_controller.go b/pkg/liqo-controller-manager/external-network/server-operator/server_controller.go index afc954fe04..cea196bb20 100644 --- a/pkg/liqo-controller-manager/external-network/server-operator/server_controller.go +++ b/pkg/liqo-controller-manager/external-network/server-operator/server_controller.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" + "github.com/liqotech/liqo/pkg/consts" enutils "github.com/liqotech/liqo/pkg/liqo-controller-manager/external-network/utils" dynamicutils "github.com/liqotech/liqo/pkg/utils/dynamic" ) @@ -44,6 +45,12 @@ type ServerReconciler struct { ServerResources []string } +type templateData struct { + Spec networkingv1alpha1.GatewayServerSpec + GatewayUID string + ClusterID string +} + // NewServerReconciler returns a new ServerReconciler. func NewServerReconciler(cl client.Client, dynClient dynamic.Interface, factory *dynamicutils.RunnableFactory, s *runtime.Scheme, @@ -97,6 +104,14 @@ func (r *ServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res // EnsureGatewayServer ensures the GatewayServer is correctly configured. func (r *ServerReconciler) EnsureGatewayServer(ctx context.Context, server *networkingv1alpha1.GatewayServer) error { + if server.Labels == nil { + server.Labels = map[string]string{} + } + remoteClusterID, ok := server.Labels[consts.RemoteClusterID] + if !ok { + return fmt.Errorf("missing label %q on GatewayServer %q", consts.RemoteClusterID, server.Name) + } + templateGV, err := schema.ParseGroupVersion(server.Spec.ServerTemplateRef.APIVersion) if err != nil { return fmt.Errorf("unable to parse the server template group version: %w", err) @@ -162,7 +177,11 @@ func (r *ServerReconciler) EnsureGatewayServer(ctx context.Context, server *netw Controller: pointer.Bool(true), }, }) - spec, err := enutils.RenderTemplate(objectTemplateSpec, server.Spec) + spec, err := enutils.RenderTemplate(objectTemplateSpec, templateData{ + Spec: server.Spec, + GatewayUID: string(server.UID), + ClusterID: remoteClusterID, + }) if err != nil { return fmt.Errorf("unable to render the template: %w", err) } diff --git a/pkg/liqo-controller-manager/external-network/utils/getters.go b/pkg/liqo-controller-manager/external-network/utils/getters.go index a6a952d3a7..1b3a152a1c 100644 --- a/pkg/liqo-controller-manager/external-network/utils/getters.go +++ b/pkg/liqo-controller-manager/external-network/utils/getters.go @@ -28,18 +28,26 @@ import ( func ParseEndpoint(endpoint map[string]interface{}) *networkingv1alpha1.EndpointStatus { res := &networkingv1alpha1.EndpointStatus{} if value, ok := endpoint["addresses"]; ok { - res.Addresses = value.([]string) + res.Addresses = interfaceListToList[string](value.([]interface{})) } if value, ok := endpoint["port"]; ok { - res.Port = value.(int32) + res.Port = int32(value.(int64)) } if value, ok := endpoint["protocol"]; ok { - tmp := value.(corev1.Protocol) + tmp := corev1.Protocol(value.(string)) res.Protocol = &tmp } return res } +func interfaceListToList[T any](list []interface{}) []T { + res := make([]T, len(list)) + for i, v := range list { + res[i] = v.(T) + } + return res +} + // ParseGroupVersionResource parses a GroupVersionResource from a string in the form group/version/resource. func ParseGroupVersionResource(gvr string) (schema.GroupVersionResource, error) { tmp := strings.Split(gvr, "/") diff --git a/pkg/liqo-controller-manager/external-network/utils/metrics.go b/pkg/liqo-controller-manager/external-network/utils/metrics.go new file mode 100644 index 0000000000..0018ba4f42 --- /dev/null +++ b/pkg/liqo-controller-manager/external-network/utils/metrics.go @@ -0,0 +1,157 @@ +// Copyright 2019-2023 The Liqo 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 utils + +import ( + "context" + "errors" + "fmt" + + monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + discovery "k8s.io/client-go/discovery" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" + mapsutil "github.com/liqotech/liqo/pkg/utils/maps" +) + +// EnsureMetrics ensures that the metrics service and service monitor are created or deleted. +func EnsureMetrics(ctx context.Context, + cl client.Client, s *runtime.Scheme, + metrics *networkingv1alpha1.Metrics, owner metav1.Object) error { + if metrics == nil || !metrics.Enabled { + if err := deleteMetricsService(ctx, cl, owner); err != nil { + klog.Errorf("error while deleting service %q: %v", fmt.Sprintf("%s-metrics", owner.GetName()), err) + return err + } + + if err := deleteMetricsServiceMonitor(ctx, cl, owner); err != nil { + klog.Errorf("error while deleting service monitor %q: %v", fmt.Sprintf("%s-metrics", owner.GetName()), err) + return err + } + return nil + } + + if metrics.Service != nil { + if err := createMetricsService(ctx, cl, s, metrics, owner); err != nil { + klog.Errorf("error while creating service %q: %v", fmt.Sprintf("%s-metrics", owner.GetName()), err) + return err + } + } else { + if err := deleteMetricsService(ctx, cl, owner); err != nil { + klog.Errorf("error while deleting service %q: %v", fmt.Sprintf("%s-metrics", owner.GetName()), err) + return err + } + } + + if metrics.ServiceMonitor != nil { + if err := createMetricsServiceMonitor(ctx, cl, s, metrics, owner); err != nil { + klog.Errorf("error while creating service monitor %q: %v", fmt.Sprintf("%s-metrics", owner.GetName()), err) + return err + } + } else { + if err := deleteMetricsServiceMonitor(ctx, cl, owner); err != nil { + klog.Errorf("error while deleting service monitor %q: %v", fmt.Sprintf("%s-metrics", owner.GetName()), err) + return err + } + } + + return nil +} + +// IgnoreAPINotFoundError ignores the error if it is an API not found error (the CRD is not installed). +func IgnoreAPINotFoundError(err error) error { + var dErr *discovery.ErrGroupDiscoveryFailed + if errors.As(err, &dErr) { + return nil + } + var noKindErr *meta.NoKindMatchError + if errors.As(err, &noKindErr) { + return nil + } + return err +} + +func deleteMetricsService(ctx context.Context, + cl client.Client, owner metav1.Object) error { + return client.IgnoreNotFound(cl.Delete(ctx, &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-metrics", owner.GetName()), + Namespace: owner.GetNamespace(), + }, + })) +} + +func deleteMetricsServiceMonitor(ctx context.Context, + cl client.Client, owner metav1.Object) error { + return IgnoreAPINotFoundError(client.IgnoreNotFound(cl.Delete(ctx, &monitoringv1.ServiceMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-metrics", owner.GetName()), + Namespace: owner.GetNamespace(), + }, + }))) +} + +func createMetricsService(ctx context.Context, + cl client.Client, s *runtime.Scheme, + metrics *networkingv1alpha1.Metrics, owner metav1.Object) error { + svc := corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-metrics", owner.GetName()), + Namespace: owner.GetNamespace(), + }, + } + _, err := controllerutil.CreateOrUpdate(ctx, cl, &svc, func() error { + // Forge metadata + mapsutil.SmartMergeLabels(&svc, metrics.Service.Metadata.GetLabels()) + mapsutil.SmartMergeAnnotations(&svc, metrics.Service.Metadata.GetAnnotations()) + + // Forge spec + svc.Spec = metrics.Service.Spec + + // Set owner of the service + return controllerutil.SetControllerReference(owner, &svc, s) + }) + return err +} + +func createMetricsServiceMonitor(ctx context.Context, + cl client.Client, s *runtime.Scheme, + metrics *networkingv1alpha1.Metrics, owner metav1.Object) error { + svcMonitor := monitoringv1.ServiceMonitor{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-metrics", owner.GetName()), + Namespace: owner.GetNamespace(), + }, + } + _, err := controllerutil.CreateOrUpdate(ctx, cl, &svcMonitor, func() error { + // Forge metadata + mapsutil.SmartMergeLabels(&svcMonitor, metrics.ServiceMonitor.Metadata.GetLabels()) + mapsutil.SmartMergeAnnotations(&svcMonitor, metrics.ServiceMonitor.Metadata.GetAnnotations()) + + // Forge spec + svcMonitor.Spec = metrics.ServiceMonitor.Spec + + // Set owner of the service + return controllerutil.SetControllerReference(owner, &svcMonitor, s) + }) + return err +} diff --git a/pkg/liqo-controller-manager/external-network/utils/rbac.go b/pkg/liqo-controller-manager/external-network/utils/rbac.go new file mode 100644 index 0000000000..97af4b5623 --- /dev/null +++ b/pkg/liqo-controller-manager/external-network/utils/rbac.go @@ -0,0 +1,81 @@ +// Copyright 2019-2023 The Liqo 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 utils + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" +) + +// EnsureServiceAccountAndRoleBinding ensures that the service account and the role binding are created or deleted. +func EnsureServiceAccountAndRoleBinding(ctx context.Context, cl client.Client, s *runtime.Scheme, + deploy *networkingv1alpha1.DeploymentTemplate, owner metav1.Object, clusterRoleName string) error { + namespace := owner.GetNamespace() + name := owner.GetName() + + saName := deploy.Spec.Template.Spec.ServiceAccountName + if saName == "" { + saName = "default" + } + + // ensure service account + sa := &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: saName, + Namespace: namespace, + }, + } + if _, err := controllerutil.CreateOrUpdate(ctx, cl, sa, func() error { + return controllerutil.SetControllerReference(owner, sa, s) + }); err != nil { + klog.Errorf("error while creating service account %q: %v", saName, err) + return err + } + + // ensure role binding + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + } + if _, err := controllerutil.CreateOrUpdate(ctx, cl, rb, func() error { + rb.RoleRef = rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: clusterRoleName, + } + rb.Subjects = []rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: saName, + Namespace: namespace, + }} + return controllerutil.SetControllerReference(owner, rb, s) + }); err != nil { + klog.Errorf("error while creating role binding %q: %v", name, err) + return err + } + + return nil +} diff --git a/pkg/liqo-controller-manager/external-network/wireguard/wggatewayclient_controller.go b/pkg/liqo-controller-manager/external-network/wireguard/wggatewayclient_controller.go index 4baeeccb52..ecc6c26cac 100644 --- a/pkg/liqo-controller-manager/external-network/wireguard/wggatewayclient_controller.go +++ b/pkg/liqo-controller-manager/external-network/wireguard/wggatewayclient_controller.go @@ -20,6 +20,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -35,6 +36,7 @@ import ( networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" "github.com/liqotech/liqo/pkg/consts" + enutils "github.com/liqotech/liqo/pkg/liqo-controller-manager/external-network/utils" liqolabels "github.com/liqotech/liqo/pkg/utils/labels" mapsutil "github.com/liqotech/liqo/pkg/utils/maps" ) @@ -42,14 +44,16 @@ import ( // WgGatewayClientReconciler manage WgGatewayClient lifecycle. type WgGatewayClientReconciler struct { client.Client - Scheme *runtime.Scheme + Scheme *runtime.Scheme + clusterRoleName string } // NewWgGatewayClientReconciler returns a new WgGatewayClientReconciler. -func NewWgGatewayClientReconciler(cl client.Client, s *runtime.Scheme) *WgGatewayClientReconciler { +func NewWgGatewayClientReconciler(cl client.Client, s *runtime.Scheme, clusterRoleName string) *WgGatewayClientReconciler { return &WgGatewayClientReconciler{ - Client: cl, - Scheme: s, + Client: cl, + Scheme: s, + clusterRoleName: clusterRoleName, } } @@ -58,6 +62,9 @@ func NewWgGatewayClientReconciler(cl client.Client, s *runtime.Scheme) *WgGatewa // +kubebuilder:rbac:groups=networking.liqo.io,resources=wggatewayclients/status,verbs=get;update;patch // +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;delete;create;update;patch // +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch +// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors,verbs=get;list;watch;delete;create;update;patch +// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;delete;create;update;patch +// +kubectl:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch;delete;create;update;patch // Reconcile manage GatewayClient lifecycle. func (r *WgGatewayClientReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) { @@ -76,6 +83,12 @@ func (r *WgGatewayClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, nil } + // Ensure ServiceAccount and RoleBinding (create or update) + if err = enutils.EnsureServiceAccountAndRoleBinding(ctx, r.Client, r.Scheme, &wgClient.Spec.Deployment, wgClient, + r.clusterRoleName); err != nil { + return ctrl.Result{}, err + } + // Ensure deployment (create or update) deployNsName := types.NamespacedName{Namespace: wgClient.Namespace, Name: wgClient.Name} _, err = r.ensureDeployment(ctx, wgClient, deployNsName) @@ -83,6 +96,14 @@ func (r *WgGatewayClientReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } + // Ensure Metrics (if set) + err = enutils.EnsureMetrics(ctx, + r.Client, r.Scheme, + wgClient.Spec.Metrics, wgClient) + if err != nil { + return ctrl.Result{}, err + } + // Handle status defer func() { newErr := r.Status().Update(ctx, wgClient) @@ -107,6 +128,8 @@ func (r *WgGatewayClientReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&networkingv1alpha1.WgGatewayClient{}). Owns(&appsv1.Deployment{}). + Owns(&corev1.ServiceAccount{}). + Owns(&rbacv1.RoleBinding{}). Watches(&corev1.Secret{}, handler.EnqueueRequestsFromMapFunc(r.secretEnquerer), builder.WithPredicates(r.filterSecretsPredicate())). Complete(r) } @@ -165,6 +188,11 @@ func (r *WgGatewayClientReconciler) mutateFnWgClientDeployment(deployment *appsv // Forge spec deployment.Spec = wgClient.Spec.Deployment.Spec + if deployment.Spec.Template.ObjectMeta.Labels == nil { + deployment.Spec.Template.ObjectMeta.Labels = map[string]string{} + } + deployment.Spec.Template.ObjectMeta.Labels[consts.ExternalNetworkLabel] = consts.ExternalNetworkLabelValue + // Set WireGuard client as owner of the deployment return controllerutil.SetControllerReference(wgClient, deployment, r.Scheme) } diff --git a/pkg/liqo-controller-manager/external-network/wireguard/wggatewayserver_controller.go b/pkg/liqo-controller-manager/external-network/wireguard/wggatewayserver_controller.go index 4839956715..041093225e 100644 --- a/pkg/liqo-controller-manager/external-network/wireguard/wggatewayserver_controller.go +++ b/pkg/liqo-controller-manager/external-network/wireguard/wggatewayserver_controller.go @@ -21,6 +21,7 @@ import ( "golang.org/x/exp/maps" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -38,6 +39,7 @@ import ( networkingv1alpha1 "github.com/liqotech/liqo/apis/networking/v1alpha1" "github.com/liqotech/liqo/pkg/consts" "github.com/liqotech/liqo/pkg/discovery" + enutils "github.com/liqotech/liqo/pkg/liqo-controller-manager/external-network/utils" "github.com/liqotech/liqo/pkg/utils" liqolabels "github.com/liqotech/liqo/pkg/utils/labels" mapsutil "github.com/liqotech/liqo/pkg/utils/maps" @@ -48,14 +50,17 @@ type WgGatewayServerReconciler struct { client.Client Scheme *runtime.Scheme extNetPodsClient client.Client + clusterRoleName string } // NewWgGatewayServerReconciler returns a new WgGatewayServerReconciler. -func NewWgGatewayServerReconciler(cl client.Client, s *runtime.Scheme, extNetPodsClient client.Client) *WgGatewayServerReconciler { +func NewWgGatewayServerReconciler(cl client.Client, s *runtime.Scheme, extNetPodsClient client.Client, + clusterRoleName string) *WgGatewayServerReconciler { return &WgGatewayServerReconciler{ Client: cl, Scheme: s, extNetPodsClient: extNetPodsClient, + clusterRoleName: clusterRoleName, } } @@ -66,6 +71,9 @@ func NewWgGatewayServerReconciler(cl client.Client, s *runtime.Scheme, extNetPod // +kubebuilder:rbac:groups=core,resources=nodes,verbs=get;list;watch // +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;delete;create;update;patch // +kubebuilder:rbac:groups=core,resources=secrets,verbs=get;list;watch +// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors,verbs=get;list;watch;delete;create;update;patch +// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;delete;create;update;patch +// +kubectl:rbac:groups=core,resources=serviceaccounts,verbs=get;list;watch;delete;create;update;patch // Reconcile manage GatewayServer lifecycle. func (r *WgGatewayServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) { @@ -84,6 +92,12 @@ func (r *WgGatewayServerReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, nil } + // Ensure ServiceAccount and RoleBinding (create or update) + if err = enutils.EnsureServiceAccountAndRoleBinding(ctx, r.Client, r.Scheme, &wgServer.Spec.Deployment, wgServer, + r.clusterRoleName); err != nil { + return ctrl.Result{}, err + } + // Ensure deployment (create or update) deployNsName := types.NamespacedName{Namespace: wgServer.Namespace, Name: wgServer.Name} deploy, err := r.ensureDeployment(ctx, wgServer, deployNsName) @@ -98,6 +112,14 @@ func (r *WgGatewayServerReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, err } + // Ensure Metrics (if set) + err = enutils.EnsureMetrics(ctx, + r.Client, r.Scheme, + wgServer.Spec.Metrics, wgServer) + if err != nil { + return ctrl.Result{}, err + } + // Handle status defer func() { newErr := r.Status().Update(ctx, wgServer) @@ -127,6 +149,8 @@ func (r *WgGatewayServerReconciler) SetupWithManager(mgr ctrl.Manager) error { For(&networkingv1alpha1.WgGatewayServer{}). Owns(&appsv1.Deployment{}). Owns(&corev1.Service{}). + Owns(&corev1.ServiceAccount{}). + Owns(&rbacv1.RoleBinding{}). Watches(&corev1.Secret{}, handler.EnqueueRequestsFromMapFunc(r.secretEnquerer), builder.WithPredicates(r.filterSecretsPredicate())). Complete(r) } @@ -204,6 +228,11 @@ func (r *WgGatewayServerReconciler) mutateFnWgServerDeployment(deployment *appsv // Forge spec deployment.Spec = wgServer.Spec.Deployment.Spec + if deployment.Spec.Template.ObjectMeta.Labels == nil { + deployment.Spec.Template.ObjectMeta.Labels = map[string]string{} + } + deployment.Spec.Template.ObjectMeta.Labels[consts.ExternalNetworkLabel] = consts.ExternalNetworkLabelValue + // Set WireGuard server as owner of the deployment return controllerutil.SetControllerReference(wgServer, deployment, r.Scheme) } diff --git a/pkg/utils/mapper/mapper.go b/pkg/utils/mapper/mapper.go index ffe589c1ad..16a4b6dc3f 100644 --- a/pkg/utils/mapper/mapper.go +++ b/pkg/utils/mapper/mapper.go @@ -15,13 +15,16 @@ package mapper import ( + "errors" "net/http" + monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" discoveryv1 "k8s.io/api/discovery/v1" rbacv1 "k8s.io/api/rbac/v1" storagev1 "k8s.io/api/storage/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -57,7 +60,7 @@ func LiqoMapperProvider(scheme *runtime.Scheme, additionalGroupVersions ...schem } for _, gv := range additionalGroupVersions { - if err = addGroup(dClient, gv, mapper); err != nil { + if err = addGroup(dClient, gv, mapper, GroupRequired); err != nil { klog.Error(err) return nil, err } @@ -72,48 +75,66 @@ func addDefaults(dClient *discovery.DiscoveryClient, mapper *meta.DefaultRESTMap var err error // Liqo groups - if err = addGroup(dClient, discoveryv1alpha1.GroupVersion, mapper); err != nil { + if err = addGroup(dClient, discoveryv1alpha1.GroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, netv1alpha1.GroupVersion, mapper); err != nil { + if err = addGroup(dClient, netv1alpha1.GroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, sharingv1alpha1.GroupVersion, mapper); err != nil { + if err = addGroup(dClient, sharingv1alpha1.GroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, virtualKubeletv1alpha1.SchemeGroupVersion, mapper); err != nil { + if err = addGroup(dClient, virtualKubeletv1alpha1.SchemeGroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, offv1alpha1.GroupVersion, mapper); err != nil { + if err = addGroup(dClient, offv1alpha1.GroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, ipamv1alpha1.GroupVersion, mapper); err != nil { + if err = addGroup(dClient, ipamv1alpha1.GroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, networkingv1alpha1.GroupVersion, mapper); err != nil { + if err = addGroup(dClient, networkingv1alpha1.GroupVersion, mapper, GroupRequired); err != nil { return err } // Kubernetes groups - if err = addGroup(dClient, corev1.SchemeGroupVersion, mapper); err != nil { + if err = addGroup(dClient, corev1.SchemeGroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, appsv1.SchemeGroupVersion, mapper); err != nil { + if err = addGroup(dClient, appsv1.SchemeGroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, rbacv1.SchemeGroupVersion, mapper); err != nil { + if err = addGroup(dClient, rbacv1.SchemeGroupVersion, mapper, GroupRequired); err != nil { return err } - if err = addGroup(dClient, discoveryv1.SchemeGroupVersion, mapper); err != nil { + if err = addGroup(dClient, discoveryv1.SchemeGroupVersion, mapper, GroupRequired); err != nil { return err } - return addGroup(dClient, storagev1.SchemeGroupVersion, mapper) + if err = addGroup(dClient, storagev1.SchemeGroupVersion, mapper, GroupRequired); err != nil { + return err + } + + // Prometheus operator group + return addGroup(dClient, monitoringv1.SchemeGroupVersion, mapper, GroupOptional) } +const ( + // GroupRequired is used to specify that a group is required by the mapper. + GroupRequired = true + // GroupOptional is used to specify that a group is optional for the mapper. + GroupOptional = false +) + // add all the resources in the specified groupVersion to the mapper. -func addGroup(dClient *discovery.DiscoveryClient, groupVersion schema.GroupVersion, mapper *meta.DefaultRESTMapper) error { +func addGroup(dClient *discovery.DiscoveryClient, groupVersion schema.GroupVersion, + mapper *meta.DefaultRESTMapper, required bool) error { res, err := dClient.ServerResourcesForGroupVersion(groupVersion.String()) - if err != nil { + var dErr *apierrors.StatusError + switch { + case errors.As(err, &dErr) && !required: + // ignore error, and do not add the group to the mapper, the CRD is not available. + return nil + case err != nil: klog.Error(err) return err }