From eca30f65144e8aa71167e21d22499194f0c3aa4f Mon Sep 17 00:00:00 2001 From: tcas Date: Mon, 4 Aug 2025 15:07:29 +0200 Subject: [PATCH] Support custom list of services to be added to /etc/hosts in cluster DNS operator - RFE-4145 --- .../generated_openapi/zz_generated.openapi.go | 56 ++++++++++++++++++- openapi/openapi.json | 33 +++++++++++ operator/v1/types_dns.go | 37 ++++++++++++ .../0000_70_dns_00_dnses.crd.yaml | 49 ++++++++++++++++ operator/v1/zz_generated.deepcopy.go | 21 +++++++ .../AAA_ungated.yaml | 49 ++++++++++++++++ .../v1/zz_generated.swagger_doc_generated.go | 11 ++++ 7 files changed, 255 insertions(+), 1 deletion(-) diff --git a/openapi/generated_openapi/zz_generated.openapi.go b/openapi/generated_openapi/zz_generated.openapi.go index 2d6aa95a925..61d64b25576 100644 --- a/openapi/generated_openapi/zz_generated.openapi.go +++ b/openapi/generated_openapi/zz_generated.openapi.go @@ -974,6 +974,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/openshift/api/operator/v1.DNSCache": schema_openshift_api_operator_v1_DNSCache(ref), "github.com/openshift/api/operator/v1.DNSList": schema_openshift_api_operator_v1_DNSList(ref), "github.com/openshift/api/operator/v1.DNSNodePlacement": schema_openshift_api_operator_v1_DNSNodePlacement(ref), + "github.com/openshift/api/operator/v1.DNSNodeService": schema_openshift_api_operator_v1_DNSNodeService(ref), "github.com/openshift/api/operator/v1.DNSOverTLSConfig": schema_openshift_api_operator_v1_DNSOverTLSConfig(ref), "github.com/openshift/api/operator/v1.DNSSpec": schema_openshift_api_operator_v1_DNSSpec(ref), "github.com/openshift/api/operator/v1.DNSStatus": schema_openshift_api_operator_v1_DNSStatus(ref), @@ -49600,6 +49601,36 @@ func schema_openshift_api_operator_v1_DNSNodePlacement(ref common.ReferenceCallb } } +func schema_openshift_api_operator_v1_DNSNodeService(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DNSNodeService represents a Kubernetes service by name and namespace for node services.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the service. The name should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, and should start with an alphabetic character and end with an alphanumeric character.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "namespace": { + SchemaProps: spec.SchemaProps{ + Description: "namespace is the namespace of the service. The namespace should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, and should start and end with an alphanumeric character.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name", "namespace"}, + }, + }, + } +} + func schema_openshift_api_operator_v1_DNSOverTLSConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -49680,6 +49711,29 @@ func schema_openshift_api_operator_v1_DNSSpec(ref common.ReferenceCallback) comm Format: "", }, }, + "nodeServices": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "name", + "namespace", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "nodeServices specifies a list of service objects for which host level resolvable entries should be added. Services in this list will be added to /etc/hosts on each node in the cluster by the node resolver. When not specified, only the default image registry service is resolvable. Services in this list will be added in addition to the default \"image-registry.openshift-image-registry.svc\" service. The default image registry service cannot be removed. For each service reference, entries will be created using the format \"..svc\" and an alias with the CLUSTER_DOMAIN suffix of cluster.local will also be added.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/openshift/api/operator/v1.DNSNodeService"), + }, + }, + }, + }, + }, "logLevel": { SchemaProps: spec.SchemaProps{ Description: "logLevel describes the desired logging verbosity for CoreDNS. Any one of the following values may be specified: * Normal logs errors from upstream resolvers. * Debug logs errors, NXDOMAIN responses, and NODATA responses. * Trace logs errors and all responses.\n Setting logLevel: Trace will produce extremely verbose logs.\nValid values are: \"Normal\", \"Debug\", \"Trace\". Defaults to \"Normal\".", @@ -49698,7 +49752,7 @@ func schema_openshift_api_operator_v1_DNSSpec(ref common.ReferenceCallback) comm }, }, Dependencies: []string{ - "github.com/openshift/api/operator/v1.DNSCache", "github.com/openshift/api/operator/v1.DNSNodePlacement", "github.com/openshift/api/operator/v1.Server", "github.com/openshift/api/operator/v1.UpstreamResolvers"}, + "github.com/openshift/api/operator/v1.DNSCache", "github.com/openshift/api/operator/v1.DNSNodePlacement", "github.com/openshift/api/operator/v1.DNSNodeService", "github.com/openshift/api/operator/v1.Server", "github.com/openshift/api/operator/v1.UpstreamResolvers"}, } } diff --git a/openapi/openapi.json b/openapi/openapi.json index c227dd53de7..b8487d3fef7 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -28801,6 +28801,26 @@ } } }, + "com.github.openshift.api.operator.v1.DNSNodeService": { + "description": "DNSNodeService represents a Kubernetes service by name and namespace for node services.", + "type": "object", + "required": [ + "name", + "namespace" + ], + "properties": { + "name": { + "description": "name is the name of the service. The name should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, and should start with an alphabetic character and end with an alphanumeric character.", + "type": "string", + "default": "" + }, + "namespace": { + "description": "namespace is the namespace of the service. The namespace should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, and should start and end with an alphanumeric character.", + "type": "string", + "default": "" + } + } + }, "com.github.openshift.api.operator.v1.DNSOverTLSConfig": { "description": "DNSOverTLSConfig describes optional DNSTransportConfig fields that should be captured.", "type": "object", @@ -28842,6 +28862,19 @@ "default": {}, "$ref": "#/definitions/com.github.openshift.api.operator.v1.DNSNodePlacement" }, + "nodeServices": { + "description": "nodeServices specifies a list of service objects for which host level resolvable entries should be added. Services in this list will be added to /etc/hosts on each node in the cluster by the node resolver. When not specified, only the default image registry service is resolvable. Services in this list will be added in addition to the default \"image-registry.openshift-image-registry.svc\" service. The default image registry service cannot be removed. For each service reference, entries will be created using the format \"..svc\" and an alias with the CLUSTER_DOMAIN suffix of cluster.local will also be added.", + "type": "array", + "items": { + "default": {}, + "$ref": "#/definitions/com.github.openshift.api.operator.v1.DNSNodeService" + }, + "x-kubernetes-list-map-keys": [ + "name", + "namespace" + ], + "x-kubernetes-list-type": "map" + }, "operatorLogLevel": { "description": "operatorLogLevel controls the logging level of the DNS Operator. Valid values are: \"Normal\", \"Debug\", \"Trace\". Defaults to \"Normal\". setting operatorLogLevel: Trace will produce extremely verbose logs.", "type": "string" diff --git a/operator/v1/types_dns.go b/operator/v1/types_dns.go index 25880478684..111034cf565 100644 --- a/operator/v1/types_dns.go +++ b/operator/v1/types_dns.go @@ -95,6 +95,22 @@ type DNSSpec struct { // +kubebuilder:default=Normal OperatorLogLevel DNSLogLevel `json:"operatorLogLevel,omitempty"` + // nodeServices specifies a list of service objects for which host level resolvable entries should be added. + // Services in this list will be added to /etc/hosts on each node in the cluster by the node resolver. + // When not specified, only the default image registry service is resolvable. + // Services in this list will be added in addition to the default "image-registry.openshift-image-registry.svc" service. + // The default image registry service cannot be removed. + // For each service reference, entries will be created using the format "..svc" + // and an alias with the CLUSTER_DOMAIN suffix of cluster.local will also be added. + // + // +optional + // +kubebuilder:validation:MaxItems=20 + // +kubebuilder:validation:MinItems=1 + // +listType=map + // +listMapKey=name + // +listMapKey=namespace + NodeServices []DNSNodeService `json:"nodeServices,omitempty"` + // logLevel describes the desired logging verbosity for CoreDNS. // Any one of the following values may be specified: // * Normal logs errors from upstream resolvers. @@ -163,6 +179,27 @@ var ( DNSLogLevelTrace DNSLogLevel = "Trace" ) +// DNSNodeService represents a Kubernetes service by name and namespace for node services. +type DNSNodeService struct { + // name is the name of the service. + // The name should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, + // and should start with an alphabetic character and end with an alphanumeric character. + // +required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:XValidation:rule=`!format.dns1035Label().validate(self).hasValue()`,message="a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character" + Name string `json:"name"` + + // namespace is the namespace of the service. + // The namespace should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, + // and should start and end with an alphanumeric character. + // +required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=63 + // +kubebuilder:validation:XValidation:rule=`!format.dns1123Label().validate(self).hasValue()`,message="the value must consist of only lowercase alphanumeric characters and hyphens" + Namespace string `json:"namespace"` +} + // Server defines the schema for a server that runs per instance of CoreDNS. type Server struct { // name is required and specifies a unique name for the server. Name must comply diff --git a/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml b/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml index 946f6aaade2..cc99d267178 100644 --- a/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml +++ b/operator/v1/zz_generated.crd-manifests/0000_70_dns_00_dnses.crd.yaml @@ -191,6 +191,55 @@ spec: type: object type: array type: object + nodeServices: + description: |- + nodeServices specifies a list of service objects for which host level resolvable entries should be added. + Services in this list will be added to /etc/hosts on each node in the cluster by the node resolver. + When not specified, only the default image registry service is resolvable. + Services in this list will be added in addition to the default "image-registry.openshift-image-registry.svc" service. + The default image registry service cannot be removed. + For each service reference, entries will be created using the format "..svc" + and an alias with the CLUSTER_DOMAIN suffix of cluster.local will also be added. + items: + description: DNSNodeService represents a Kubernetes service by name + and namespace for node services. + properties: + name: + description: |- + name is the name of the service. + The name should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, + and should start with an alphabetic character and end with an alphanumeric character. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: a DNS-1035 label must consist of lower case alphanumeric + characters or '-', start with an alphabetic character, and + end with an alphanumeric character + rule: '!format.dns1035Label().validate(self).hasValue()' + namespace: + description: |- + namespace is the namespace of the service. + The namespace should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, + and should start and end with an alphanumeric character. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: the value must consist of only lowercase alphanumeric + characters and hyphens + rule: '!format.dns1123Label().validate(self).hasValue()' + required: + - name + - namespace + type: object + maxItems: 20 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + - namespace + x-kubernetes-list-type: map operatorLogLevel: default: Normal description: |- diff --git a/operator/v1/zz_generated.deepcopy.go b/operator/v1/zz_generated.deepcopy.go index d8f3cbc2f49..237f66af5c0 100644 --- a/operator/v1/zz_generated.deepcopy.go +++ b/operator/v1/zz_generated.deepcopy.go @@ -1206,6 +1206,22 @@ func (in *DNSNodePlacement) DeepCopy() *DNSNodePlacement { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DNSNodeService) DeepCopyInto(out *DNSNodeService) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSNodeService. +func (in *DNSNodeService) DeepCopy() *DNSNodeService { + if in == nil { + return nil + } + out := new(DNSNodeService) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DNSOverTLSConfig) DeepCopyInto(out *DNSOverTLSConfig) { *out = *in @@ -1235,6 +1251,11 @@ func (in *DNSSpec) DeepCopyInto(out *DNSSpec) { } in.UpstreamResolvers.DeepCopyInto(&out.UpstreamResolvers) in.NodePlacement.DeepCopyInto(&out.NodePlacement) + if in.NodeServices != nil { + in, out := &in.NodeServices, &out.NodeServices + *out = make([]DNSNodeService, len(*in)) + copy(*out, *in) + } out.Cache = in.Cache return } diff --git a/operator/v1/zz_generated.featuregated-crd-manifests/dnses.operator.openshift.io/AAA_ungated.yaml b/operator/v1/zz_generated.featuregated-crd-manifests/dnses.operator.openshift.io/AAA_ungated.yaml index 32f00a1494c..cb76146bd9f 100644 --- a/operator/v1/zz_generated.featuregated-crd-manifests/dnses.operator.openshift.io/AAA_ungated.yaml +++ b/operator/v1/zz_generated.featuregated-crd-manifests/dnses.operator.openshift.io/AAA_ungated.yaml @@ -192,6 +192,55 @@ spec: type: object type: array type: object + nodeServices: + description: |- + nodeServices specifies a list of service objects for which host level resolvable entries should be added. + Services in this list will be added to /etc/hosts on each node in the cluster by the node resolver. + When not specified, only the default image registry service is resolvable. + Services in this list will be added in addition to the default "image-registry.openshift-image-registry.svc" service. + The default image registry service cannot be removed. + For each service reference, entries will be created using the format "..svc" + and an alias with the CLUSTER_DOMAIN suffix of cluster.local will also be added. + items: + description: DNSNodeService represents a Kubernetes service by name + and namespace for node services. + properties: + name: + description: |- + name is the name of the service. + The name should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, + and should start with an alphabetic character and end with an alphanumeric character. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: a DNS-1035 label must consist of lower case alphanumeric + characters or '-', start with an alphabetic character, and + end with an alphanumeric character + rule: '!format.dns1035Label().validate(self).hasValue()' + namespace: + description: |- + namespace is the namespace of the service. + The namespace should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, + and should start and end with an alphanumeric character. + maxLength: 63 + minLength: 1 + type: string + x-kubernetes-validations: + - message: the value must consist of only lowercase alphanumeric + characters and hyphens + rule: '!format.dns1123Label().validate(self).hasValue()' + required: + - name + - namespace + type: object + maxItems: 20 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + - namespace + x-kubernetes-list-type: map operatorLogLevel: default: Normal description: |- diff --git a/operator/v1/zz_generated.swagger_doc_generated.go b/operator/v1/zz_generated.swagger_doc_generated.go index 582f9686ffd..514fb3612ed 100644 --- a/operator/v1/zz_generated.swagger_doc_generated.go +++ b/operator/v1/zz_generated.swagger_doc_generated.go @@ -685,6 +685,16 @@ func (DNSNodePlacement) SwaggerDoc() map[string]string { return map_DNSNodePlacement } +var map_DNSNodeService = map[string]string{ + "": "DNSNodeService represents a Kubernetes service by name and namespace for node services.", + "name": "name is the name of the service. The name should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, and should start with an alphabetic character and end with an alphanumeric character.", + "namespace": "namespace is the namespace of the service. The namespace should consist of at most 63 characters, and of only lowercase alphanumeric characters and hyphens, and should start and end with an alphanumeric character.", +} + +func (DNSNodeService) SwaggerDoc() map[string]string { + return map_DNSNodeService +} + var map_DNSOverTLSConfig = map[string]string{ "": "DNSOverTLSConfig describes optional DNSTransportConfig fields that should be captured.", "serverName": "serverName is the upstream server to connect to when forwarding DNS queries. This is required when Transport is set to \"TLS\". ServerName will be validated against the DNS naming conventions in RFC 1123 and should match the TLS certificate installed in the upstream resolver(s).", @@ -702,6 +712,7 @@ var map_DNSSpec = map[string]string{ "nodePlacement": "nodePlacement provides explicit control over the scheduling of DNS pods.\n\nGenerally, it is useful to run a DNS pod on every node so that DNS queries are always handled by a local DNS pod instead of going over the network to a DNS pod on another node. However, security policies may require restricting the placement of DNS pods to specific nodes. For example, if a security policy prohibits pods on arbitrary nodes from communicating with the API, a node selector can be specified to restrict DNS pods to nodes that are permitted to communicate with the API. Conversely, if running DNS pods on nodes with a particular taint is desired, a toleration can be specified for that taint.\n\nIf unset, defaults are used. See nodePlacement for more details.", "managementState": "managementState indicates whether the DNS operator should manage cluster DNS", "operatorLogLevel": "operatorLogLevel controls the logging level of the DNS Operator. Valid values are: \"Normal\", \"Debug\", \"Trace\". Defaults to \"Normal\". setting operatorLogLevel: Trace will produce extremely verbose logs.", + "nodeServices": "nodeServices specifies a list of service objects for which host level resolvable entries should be added. Services in this list will be added to /etc/hosts on each node in the cluster by the node resolver. When not specified, only the default image registry service is resolvable. Services in this list will be added in addition to the default \"image-registry.openshift-image-registry.svc\" service. The default image registry service cannot be removed. For each service reference, entries will be created using the format \"..svc\" and an alias with the CLUSTER_DOMAIN suffix of cluster.local will also be added.", "logLevel": "logLevel describes the desired logging verbosity for CoreDNS. Any one of the following values may be specified: * Normal logs errors from upstream resolvers. * Debug logs errors, NXDOMAIN responses, and NODATA responses. * Trace logs errors and all responses.\n Setting logLevel: Trace will produce extremely verbose logs.\nValid values are: \"Normal\", \"Debug\", \"Trace\". Defaults to \"Normal\".", "cache": "cache describes the caching configuration that applies to all server blocks listed in the Corefile. This field allows a cluster admin to optionally configure: * positiveTTL which is a duration for which positive responses should be cached. * negativeTTL which is a duration for which negative responses should be cached. If this is not configured, OpenShift will configure positive and negative caching with a default value that is subject to change. At the time of writing, the default positiveTTL is 900 seconds and the default negativeTTL is 30 seconds or as noted in the respective Corefile for your version of OpenShift.", }