diff --git a/api/v1alpha1/service_types.go b/api/v1alpha1/service_types.go index 7eb2b35f..981cce60 100644 --- a/api/v1alpha1/service_types.go +++ b/api/v1alpha1/service_types.go @@ -22,6 +22,7 @@ type GRPCService struct { TLSConfiguration *TLSConfiguration `json:"tls,omitempty"` ExternalHost string `json:"externalHost,omitempty"` // TODO implementation + IPDiscovery *IPDiscovery `json:"ipDiscovery,omitempty"` } type InterconnectService struct { @@ -41,3 +42,9 @@ type DatastreamsService struct { TLSConfiguration *TLSConfiguration `json:"tls,omitempty"` } + +type IPDiscovery struct { + Enabled bool `json:"enabled"` + TargetNameOverride string `json:"targetNameOverride,omitempty"` + IPFamily corev1.IPFamily `json:"ipFamily,omitempty"` +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 61a3689f..fd2ad4a1 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -680,6 +680,11 @@ func (in *GRPCService) DeepCopyInto(out *GRPCService) { *out = new(TLSConfiguration) (*in).DeepCopyInto(*out) } + if in.IPDiscovery != nil { + in, out := &in.IPDiscovery, &out.IPDiscovery + *out = new(IPDiscovery) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GRPCService. @@ -692,6 +697,21 @@ func (in *GRPCService) DeepCopy() *GRPCService { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *IPDiscovery) DeepCopyInto(out *IPDiscovery) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPDiscovery. +func (in *IPDiscovery) DeepCopy() *IPDiscovery { + if in == nil { + return nil + } + out := new(IPDiscovery) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InterconnectService) DeepCopyInto(out *InterconnectService) { *out = *in diff --git a/deploy/ydb-operator/Chart.yaml b/deploy/ydb-operator/Chart.yaml index 1213173b..75e65550 100644 --- a/deploy/ydb-operator/Chart.yaml +++ b/deploy/ydb-operator/Chart.yaml @@ -15,10 +15,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.5.28 +version: 0.5.29 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.5.28" +appVersion: "0.5.29" diff --git a/deploy/ydb-operator/crds/database.yaml b/deploy/ydb-operator/crds/database.yaml index e0b1976e..1bee889b 100644 --- a/deploy/ydb-operator/crds/database.yaml +++ b/deploy/ydb-operator/crds/database.yaml @@ -886,24 +886,6 @@ spec: properties: enabled: type: boolean - iam_service_account_key: - description: SecretKeySelector selects a key of a 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 required: - enabled type: object @@ -1208,7 +1190,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1304,7 +1288,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1417,7 +1403,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1619,7 +1607,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1716,7 +1706,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2000,7 +1991,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -3204,7 +3197,7 @@ spec: in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field - is immutable." + is immutable. It can only be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -3280,7 +3273,7 @@ spec: in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field - is immutable." + is immutable. It can only be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -3614,7 +3607,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be + set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -3811,6 +3805,20 @@ spec: type: object externalHost: type: string + ipDiscovery: + properties: + enabled: + type: boolean + ipFamily: + 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 + targetNameOverride: + type: string + required: + - enabled + type: object ipFamilies: items: description: IPFamily represents the IP Family (IPv4 or @@ -4072,7 +4080,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be + set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -4925,7 +4934,8 @@ spec: defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. + It can only be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. diff --git a/deploy/ydb-operator/crds/databasenodeset.yaml b/deploy/ydb-operator/crds/databasenodeset.yaml index bbbc2cf7..74aebcac 100644 --- a/deploy/ydb-operator/crds/databasenodeset.yaml +++ b/deploy/ydb-operator/crds/databasenodeset.yaml @@ -901,24 +901,6 @@ spec: properties: enabled: type: boolean - iam_service_account_key: - description: SecretKeySelector selects a key of a 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 required: - enabled type: object @@ -1223,7 +1205,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1319,7 +1303,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1432,7 +1418,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1634,7 +1622,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1731,7 +1721,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2015,7 +2006,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -2319,7 +2312,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be + set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2516,6 +2510,20 @@ spec: type: object externalHost: type: string + ipDiscovery: + properties: + enabled: + type: boolean + ipFamily: + 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 + targetNameOverride: + type: string + required: + - enabled + type: object ipFamilies: items: description: IPFamily represents the IP Family (IPv4 or @@ -2777,7 +2785,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be + set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -3630,7 +3639,8 @@ spec: defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. + It can only be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. diff --git a/deploy/ydb-operator/crds/remotedatabasenodeset.yaml b/deploy/ydb-operator/crds/remotedatabasenodeset.yaml index 706fa1ef..bc84fb0f 100644 --- a/deploy/ydb-operator/crds/remotedatabasenodeset.yaml +++ b/deploy/ydb-operator/crds/remotedatabasenodeset.yaml @@ -902,24 +902,6 @@ spec: properties: enabled: type: boolean - iam_service_account_key: - description: SecretKeySelector selects a key of a 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 required: - enabled type: object @@ -1224,7 +1206,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1320,7 +1304,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1433,7 +1419,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1635,7 +1623,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1732,7 +1722,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2016,7 +2007,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -2320,7 +2313,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be + set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2517,6 +2511,20 @@ spec: type: object externalHost: type: string + ipDiscovery: + properties: + enabled: + type: boolean + ipFamily: + 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 + targetNameOverride: + type: string + required: + - enabled + type: object ipFamilies: items: description: IPFamily represents the IP Family (IPv4 or @@ -2778,7 +2786,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be + set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -3631,7 +3640,8 @@ spec: defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. + It can only be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. diff --git a/deploy/ydb-operator/crds/remotestoragenodeset.yaml b/deploy/ydb-operator/crds/remotestoragenodeset.yaml index e8053cc3..f514a2ac 100644 --- a/deploy/ydb-operator/crds/remotestoragenodeset.yaml +++ b/deploy/ydb-operator/crds/remotestoragenodeset.yaml @@ -986,7 +986,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -1373,7 +1374,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1469,7 +1472,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1582,7 +1587,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1784,7 +1791,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1881,7 +1890,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2165,7 +2175,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -2459,7 +2471,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be set + for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2527,6 +2540,20 @@ spec: type: object externalHost: type: string + ipDiscovery: + properties: + enabled: + type: boolean + ipFamily: + 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 + targetNameOverride: + type: string + required: + - enabled + type: object ipFamilies: items: description: IPFamily represents the IP Family (IPv4 or @@ -3565,7 +3592,8 @@ spec: defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. + It can only be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. diff --git a/deploy/ydb-operator/crds/storage.yaml b/deploy/ydb-operator/crds/storage.yaml index a7dc0b0c..9d0a1805 100644 --- a/deploy/ydb-operator/crds/storage.yaml +++ b/deploy/ydb-operator/crds/storage.yaml @@ -985,7 +985,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -1372,7 +1373,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1468,7 +1471,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1581,7 +1586,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1783,7 +1790,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1880,7 +1889,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2164,7 +2174,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -3253,7 +3265,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be + set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -4405,7 +4418,8 @@ spec: defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - \n This field is immutable." + \n This field is immutable. It can only be set for + containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. @@ -4553,7 +4567,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -4960,7 +4975,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be set + for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -5028,6 +5044,20 @@ spec: type: object externalHost: type: string + ipDiscovery: + properties: + enabled: + type: boolean + ipFamily: + 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 + targetNameOverride: + type: string + required: + - enabled + type: object ipFamilies: items: description: IPFamily represents the IP Family (IPv4 or @@ -6052,7 +6082,8 @@ spec: defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. + It can only be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. diff --git a/deploy/ydb-operator/crds/storagenodeset.yaml b/deploy/ydb-operator/crds/storagenodeset.yaml index 0c797170..870a29d2 100644 --- a/deploy/ydb-operator/crds/storagenodeset.yaml +++ b/deploy/ydb-operator/crds/storagenodeset.yaml @@ -985,7 +985,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -1372,7 +1373,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1468,7 +1471,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1581,7 +1586,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1783,7 +1790,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -1880,7 +1889,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only + be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2164,7 +2174,9 @@ spec: to be used in HTTP probes properties: name: - description: The header field name + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. type: string value: description: The header field value @@ -2458,7 +2470,8 @@ spec: description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. It can only be set + for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. properties: @@ -2526,6 +2539,20 @@ spec: type: object externalHost: type: string + ipDiscovery: + properties: + enabled: + type: boolean + ipFamily: + 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 + targetNameOverride: + type: string + required: + - enabled + type: object ipFamilies: items: description: IPFamily represents the IP Family (IPv4 or @@ -3564,7 +3591,8 @@ spec: defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable." + feature gate. \n This field is immutable. + It can only be set for containers." items: description: ResourceClaim references one entry in PodSpec.ResourceClaims. diff --git a/internal/controllers/database/controller_test.go b/internal/controllers/database/controller_test.go index 15333aec..747d070c 100644 --- a/internal/controllers/database/controller_test.go +++ b/internal/controllers/database/controller_test.go @@ -17,6 +17,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" "sigs.k8s.io/controller-runtime/pkg/manager" "github.com/ydb-platform/ydb-kubernetes-operator/api/v1alpha1" @@ -30,12 +31,13 @@ import ( var ( k8sClient client.Client ctx context.Context + env *envtest.Environment ) func TestAPIs(t *testing.T) { RegisterFailHandler(Fail) - test.SetupK8STestManager(&ctx, &k8sClient, func(mgr *manager.Manager) []test.Reconciler { + env = test.SetupK8STestManager(&ctx, &k8sClient, func(mgr *manager.Manager) []test.Reconciler { return []test.Reconciler{ &storage.Reconciler{ Client: k8sClient, @@ -94,6 +96,7 @@ var _ = Describe("Database controller medium tests", func() { AfterEach(func() { Expect(k8sClient.Delete(ctx, &storageSample)).Should(Succeed()) Expect(k8sClient.Delete(ctx, &namespace)).Should(Succeed()) + test.DeleteAllObjects(env, k8sClient, &namespace) }) It("Checking field propagation to objects", func() { @@ -217,4 +220,88 @@ var _ = Describe("Database controller medium tests", func() { return reflect.DeepEqual(encryptionData, encryptionSecret.Data) }, test.Timeout, test.Interval).Should(BeTrue()) }) + + It("Check iPDiscovery flag works", func() { + getDBSts := func(generation int64) appsv1.StatefulSet { + sts := appsv1.StatefulSet{} + + Eventually( + func() error { + objectKey := types.NamespacedName{ + Name: testobjects.DatabaseName, + Namespace: testobjects.YdbNamespace, + } + err := k8sClient.Get(ctx, objectKey, &sts) + if err != nil { + return err + } + + if sts.Generation <= generation { + return fmt.Errorf("sts is too old (generation=%d)", sts.Generation) + } + return nil + }, + ).WithTimeout(test.Timeout).WithPolling(test.Interval).Should(Succeed()) + + return sts + } + getDB := func() v1alpha1.Database { + found := v1alpha1.Database{} + Eventually(func() error { + return k8sClient.Get(ctx, + types.NamespacedName{ + Name: testobjects.DatabaseName, + Namespace: testobjects.YdbNamespace, + }, + &found, + ) + }, test.Timeout, test.Interval).Should(Succeed()) + return found + } + + By("Create test database") + db := *testobjects.DefaultDatabase() + Expect(k8sClient.Create(ctx, &db)).Should(Succeed()) + + By("Check container args") + sts := getDBSts(0) + args := sts.Spec.Template.Spec.Containers[0].Args + + Expect(args).To(ContainElements([]string{"--grpc-public-host"})) + Expect(args).ToNot(ContainElements([]string{"--grpc-public-address-v6", "--grpc-public-address-v4", "--grpc-public-target-name-override"})) + + By("Enabling ip discovery using ipv6") + db = getDB() + db.Spec.Service.GRPC.IPDiscovery = &v1alpha1.IPDiscovery{ + Enabled: true, + IPFamily: corev1.IPv6Protocol, + } + + Expect(k8sClient.Update(ctx, &db)).Should(Succeed()) + + By("Check container args") + sts = getDBSts(sts.Generation) + args = sts.Spec.Template.Spec.Containers[0].Args + + Expect(args).To(ContainElements([]string{"--grpc-public-address-v6"})) + Expect(args).ToNot(ContainElements([]string{"--grpc-public-target-name-override"})) + + db = getDB() + + By("Enabling ip discovery using ipv4 and target name override") + db.Spec.Service.GRPC.IPDiscovery = &v1alpha1.IPDiscovery{ + Enabled: true, + IPFamily: corev1.IPv4Protocol, + TargetNameOverride: "a.b.c.d", + } + + Expect(k8sClient.Update(ctx, &db)).Should(Succeed()) + + By("Check container args") + + sts = getDBSts(sts.Generation) + args = sts.Spec.Template.Spec.Containers[0].Args + + Expect(args).To(ContainElements([]string{"--grpc-public-address-v4", "--grpc-public-target-name-override"})) + }) }) diff --git a/internal/controllers/remotedatabasenodeset/controller_test.go b/internal/controllers/remotedatabasenodeset/controller_test.go index c401b4f9..25252795 100644 --- a/internal/controllers/remotedatabasenodeset/controller_test.go +++ b/internal/controllers/remotedatabasenodeset/controller_test.go @@ -14,10 +14,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes" "k8s.io/kubectl/pkg/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" @@ -349,8 +346,8 @@ var _ = Describe("RemoteDatabaseNodeSet controller tests", func() { AfterEach(func() { Expect(localClient.Delete(ctx, databaseSample)).Should(Succeed()) Expect(localClient.Delete(ctx, storageSample)).Should(Succeed()) - deleteAll(localEnv, localClient, &localNamespace) - deleteAll(remoteEnv, remoteClient, &localNamespace) + test.DeleteAllObjects(localEnv, localClient, &localNamespace) + test.DeleteAllObjects(remoteEnv, remoteClient, &localNamespace) }) When("Created RemoteDatabaseNodeSet in k8s-mgmt-cluster", func() { @@ -892,108 +889,3 @@ var _ = Describe("RemoteDatabaseNodeSet controller tests", func() { }) }) }) - -func deleteAll(env *envtest.Environment, k8sClient client.Client, objs ...client.Object) { - for _, obj := range objs { - ctx := context.Background() - clientGo, err := kubernetes.NewForConfig(env.Config) - Expect(err).ShouldNot(HaveOccurred()) - Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, obj))).Should(Succeed()) - - //nolint:nestif - if ns, ok := obj.(*corev1.Namespace); ok { - // Normally the kube-controller-manager would handle finalization - // and garbage collection of namespaces, but with envtest, we aren't - // running a kube-controller-manager. Instead we're gonna approximate - // (poorly) the kube-controller-manager by explicitly deleting some - // resources within the namespace and then removing the `kubernetes` - // finalizer from the namespace resource so it can finish deleting. - // Note that any resources within the namespace that we don't - // successfully delete could reappear if the namespace is ever - // recreated with the same name. - - // Look up all namespaced resources under the discovery API - _, apiResources, err := clientGo.Discovery().ServerGroupsAndResources() - Expect(err).ShouldNot(HaveOccurred()) - namespacedGVKs := make(map[string]schema.GroupVersionKind) - for _, apiResourceList := range apiResources { - defaultGV, err := schema.ParseGroupVersion(apiResourceList.GroupVersion) - Expect(err).ShouldNot(HaveOccurred()) - for _, r := range apiResourceList.APIResources { - if !r.Namespaced || strings.Contains(r.Name, "/") { - // skip non-namespaced and subresources - continue - } - gvk := schema.GroupVersionKind{ - Group: defaultGV.Group, - Version: defaultGV.Version, - Kind: r.Kind, - } - if r.Group != "" { - gvk.Group = r.Group - } - if r.Version != "" { - gvk.Version = r.Version - } - namespacedGVKs[gvk.String()] = gvk - } - } - - // Delete all namespaced resources in this namespace - for _, gvk := range namespacedGVKs { - var u unstructured.Unstructured - u.SetGroupVersionKind(gvk) - err := k8sClient.DeleteAllOf(ctx, &u, client.InNamespace(ns.Name)) - Expect(client.IgnoreNotFound(ignoreMethodNotAllowed(err))).ShouldNot(HaveOccurred()) - } - - // Delete all Services in this namespace - serviceList := corev1.ServiceList{} - err = k8sClient.List(ctx, &serviceList, client.InNamespace(ns.Name)) - Expect(err).ShouldNot(HaveOccurred()) - for idx := range serviceList.Items { - policy := metav1.DeletePropagationForeground - err = k8sClient.Delete(ctx, &serviceList.Items[idx], &client.DeleteOptions{PropagationPolicy: &policy}) - Expect(err).ShouldNot(HaveOccurred()) - } - - Eventually(func() error { - key := client.ObjectKeyFromObject(ns) - if err := k8sClient.Get(ctx, key, ns); err != nil { - return client.IgnoreNotFound(err) - } - // remove `kubernetes` finalizer - const kubernetes = "kubernetes" - finalizers := []corev1.FinalizerName{} - for _, f := range ns.Spec.Finalizers { - if f != kubernetes { - finalizers = append(finalizers, f) - } - } - ns.Spec.Finalizers = finalizers - - // We have to use the k8s.io/client-go library here to expose - // ability to patch the /finalize subresource on the namespace - _, err = clientGo.CoreV1().Namespaces().Finalize(ctx, ns, metav1.UpdateOptions{}) - return err - }, test.Timeout, test.Interval).Should(Succeed()) - } - - Eventually(func() metav1.StatusReason { - key := client.ObjectKeyFromObject(obj) - if err := k8sClient.Get(ctx, key, obj); err != nil { - return apierrors.ReasonForError(err) - } - return "" - }, test.Timeout, test.Interval).Should(Equal(metav1.StatusReasonNotFound)) - } -} - -func ignoreMethodNotAllowed(err error) error { - if err != nil { - if apierrors.ReasonForError(err) == metav1.StatusReasonMethodNotAllowed { - return nil - } - } - return err -} diff --git a/internal/controllers/remotestoragenodeset/controller_test.go b/internal/controllers/remotestoragenodeset/controller_test.go index e1195aff..0c5666c6 100644 --- a/internal/controllers/remotestoragenodeset/controller_test.go +++ b/internal/controllers/remotestoragenodeset/controller_test.go @@ -5,7 +5,6 @@ import ( "fmt" "path/filepath" "reflect" - "strings" "testing" . "github.com/onsi/ginkgo/v2" @@ -14,10 +13,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes" "k8s.io/kubectl/pkg/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" @@ -280,8 +276,8 @@ var _ = Describe("RemoteStorageNodeSet controller tests", func() { AfterEach(func() { Expect(localClient.Delete(ctx, storageSample)).Should(Succeed()) - deleteAll(localEnv, localClient, &localNamespace) - deleteAll(remoteEnv, remoteClient, &localNamespace) + test.DeleteAllObjects(localEnv, localClient, &localNamespace) + test.DeleteAllObjects(remoteEnv, remoteClient, &localNamespace) }) When("Created RemoteStorageNodeSet in k8s-mgmt-cluster", func() { @@ -635,108 +631,3 @@ var _ = Describe("RemoteStorageNodeSet controller tests", func() { }) }) }) - -func deleteAll(env *envtest.Environment, k8sClient client.Client, objs ...client.Object) { - for _, obj := range objs { - ctx := context.Background() - clientGo, err := kubernetes.NewForConfig(env.Config) - Expect(err).ShouldNot(HaveOccurred()) - Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, obj))).Should(Succeed()) - - //nolint:nestif - if ns, ok := obj.(*corev1.Namespace); ok { - // Normally the kube-controller-manager would handle finalization - // and garbage collection of namespaces, but with envtest, we aren't - // running a kube-controller-manager. Instead we're gonna approximate - // (poorly) the kube-controller-manager by explicitly deleting some - // resources within the namespace and then removing the `kubernetes` - // finalizer from the namespace resource so it can finish deleting. - // Note that any resources within the namespace that we don't - // successfully delete could reappear if the namespace is ever - // recreated with the same name. - - // Look up all namespaced resources under the discovery API - _, apiResources, err := clientGo.Discovery().ServerGroupsAndResources() - Expect(err).ShouldNot(HaveOccurred()) - namespacedGVKs := make(map[string]schema.GroupVersionKind) - for _, apiResourceList := range apiResources { - defaultGV, err := schema.ParseGroupVersion(apiResourceList.GroupVersion) - Expect(err).ShouldNot(HaveOccurred()) - for _, r := range apiResourceList.APIResources { - if !r.Namespaced || strings.Contains(r.Name, "/") { - // skip non-namespaced and subresources - continue - } - gvk := schema.GroupVersionKind{ - Group: defaultGV.Group, - Version: defaultGV.Version, - Kind: r.Kind, - } - if r.Group != "" { - gvk.Group = r.Group - } - if r.Version != "" { - gvk.Version = r.Version - } - namespacedGVKs[gvk.String()] = gvk - } - } - - // Delete all namespaced resources in this namespace - for _, gvk := range namespacedGVKs { - var u unstructured.Unstructured - u.SetGroupVersionKind(gvk) - err := k8sClient.DeleteAllOf(ctx, &u, client.InNamespace(ns.Name)) - Expect(client.IgnoreNotFound(ignoreMethodNotAllowed(err))).ShouldNot(HaveOccurred()) - } - - // Delete all Services in this namespace - serviceList := corev1.ServiceList{} - err = k8sClient.List(ctx, &serviceList, client.InNamespace(ns.Name)) - Expect(err).ShouldNot(HaveOccurred()) - for idx := range serviceList.Items { - policy := metav1.DeletePropagationForeground - err = k8sClient.Delete(ctx, &serviceList.Items[idx], &client.DeleteOptions{PropagationPolicy: &policy}) - Expect(err).ShouldNot(HaveOccurred()) - } - - Eventually(func() error { - key := client.ObjectKeyFromObject(ns) - if err := k8sClient.Get(ctx, key, ns); err != nil { - return client.IgnoreNotFound(err) - } - // remove `kubernetes` finalizer - const kubernetes = "kubernetes" - finalizers := []corev1.FinalizerName{} - for _, f := range ns.Spec.Finalizers { - if f != kubernetes { - finalizers = append(finalizers, f) - } - } - ns.Spec.Finalizers = finalizers - - // We have to use the k8s.io/client-go library here to expose - // ability to patch the /finalize subresource on the namespace - _, err = clientGo.CoreV1().Namespaces().Finalize(ctx, ns, metav1.UpdateOptions{}) - return err - }, test.Timeout, test.Interval).Should(Succeed()) - } - - Eventually(func() metav1.StatusReason { - key := client.ObjectKeyFromObject(obj) - if err := k8sClient.Get(ctx, key, obj); err != nil { - return apierrors.ReasonForError(err) - } - return "" - }, test.Timeout, test.Interval).Should(Equal(metav1.StatusReasonNotFound)) - } -} - -func ignoreMethodNotAllowed(err error) error { - if err != nil { - if apierrors.ReasonForError(err) == metav1.StatusReasonMethodNotAllowed { - return nil - } - } - return err -} diff --git a/internal/resources/database_statefulset.go b/internal/resources/database_statefulset.go index 6c4e3fe4..5d9c63c9 100644 --- a/internal/resources/database_statefulset.go +++ b/internal/resources/database_statefulset.go @@ -75,15 +75,26 @@ func (b *DatabaseStatefulSetBuilder) Build(obj client.Object) error { func (b *DatabaseStatefulSetBuilder) buildEnv() []corev1.EnvVar { var envVars []corev1.EnvVar - envVars = append(envVars, corev1.EnvVar{ - Name: "NODE_NAME", // for `--grpc-public-host` flag - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - APIVersion: "v1", - FieldPath: "metadata.name", + envVars = append(envVars, + corev1.EnvVar{ + Name: "NODE_NAME", // for `--grpc-public-host` flag + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "metadata.name", + }, }, }, - }) + corev1.EnvVar{ + Name: "POD_IP", // for `--grpc-public-address-` flag + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "status.podIP", + }, + }, + }, + ) return envVars } @@ -623,12 +634,37 @@ func (b *DatabaseStatefulSetBuilder) buildContainerArgs() ([]string, []string) { publicHostOption := "--grpc-public-host" publicHost := fmt.Sprintf(api.InterconnectServiceFQDNFormat, b.Database.Name, b.GetNamespace()) // FIXME .svc.cluster.local + if b.Spec.Service.GRPC.ExternalHost != "" { publicHost = b.Spec.Service.GRPC.ExternalHost } if value, ok := b.ObjectMeta.Annotations[api.AnnotationGRPCPublicHost]; ok { publicHost = value } + + if b.Spec.Service.GRPC.IPDiscovery != nil && b.Spec.Service.GRPC.IPDiscovery.Enabled { + targetNameOverride := b.Spec.Service.GRPC.IPDiscovery.TargetNameOverride + ipFamilyArg := "--grpc-public-address-v4" + + if b.Spec.Service.GRPC.IPDiscovery.IPFamily == corev1.IPv6Protocol { + ipFamilyArg = "--grpc-public-address-v6" + } + + args = append( + args, + + ipFamilyArg, + "$(POD_IP)", + ) + if targetNameOverride != "" { + args = append( + args, + "--grpc-public-target-name-override", + fmt.Sprintf("%s.%s", "$(NODE_NAME)", targetNameOverride), + ) + } + } + publicPortOption := "--grpc-public-port" publicPort := api.GRPCPort diff --git a/internal/test/k8s_helpers.go b/internal/test/k8s_helpers.go index a574dd9e..b135bd05 100644 --- a/internal/test/k8s_helpers.go +++ b/internal/test/k8s_helpers.go @@ -4,11 +4,18 @@ import ( "context" "path/filepath" "runtime" + "strings" "time" . "github.com/onsi/ginkgo/v2" //nolint:revive,stylecheck . "github.com/onsi/gomega" //nolint:revive,stylecheck monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes" "k8s.io/kubectl/pkg/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -29,7 +36,112 @@ type Reconciler interface { SetupWithManager(manager ctrl.Manager) error } -func SetupK8STestManager(testCtx *context.Context, k8sClient *client.Client, controllers func(mgr *manager.Manager) []Reconciler) { +func DeleteAllObjects(env *envtest.Environment, k8sClient client.Client, objs ...client.Object) { + for _, obj := range objs { + ctx := context.Background() + clientGo, err := kubernetes.NewForConfig(env.Config) + Expect(err).ShouldNot(HaveOccurred()) + Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, obj))).Should(Succeed()) + + //nolint:nestif + if ns, ok := obj.(*corev1.Namespace); ok { + // Normally the kube-controller-manager would handle finalization + // and garbage collection of namespaces, but with envtest, we aren't + // running a kube-controller-manager. Instead we're gonna approximate + // (poorly) the kube-controller-manager by explicitly deleting some + // resources within the namespace and then removing the `kubernetes` + // finalizer from the namespace resource so it can finish deleting. + // Note that any resources within the namespace that we don't + // successfully delete could reappear if the namespace is ever + // recreated with the same name. + + // Look up all namespaced resources under the discovery API + _, apiResources, err := clientGo.Discovery().ServerGroupsAndResources() + Expect(err).ShouldNot(HaveOccurred()) + namespacedGVKs := make(map[string]schema.GroupVersionKind) + for _, apiResourceList := range apiResources { + defaultGV, err := schema.ParseGroupVersion(apiResourceList.GroupVersion) + Expect(err).ShouldNot(HaveOccurred()) + for _, r := range apiResourceList.APIResources { + if !r.Namespaced || strings.Contains(r.Name, "/") { + // skip non-namespaced and subresources + continue + } + gvk := schema.GroupVersionKind{ + Group: defaultGV.Group, + Version: defaultGV.Version, + Kind: r.Kind, + } + if r.Group != "" { + gvk.Group = r.Group + } + if r.Version != "" { + gvk.Version = r.Version + } + namespacedGVKs[gvk.String()] = gvk + } + } + + // Delete all namespaced resources in this namespace + for _, gvk := range namespacedGVKs { + var u unstructured.Unstructured + u.SetGroupVersionKind(gvk) + err := k8sClient.DeleteAllOf(ctx, &u, client.InNamespace(ns.Name)) + Expect(client.IgnoreNotFound(ignoreMethodNotAllowed(err))).ShouldNot(HaveOccurred()) + } + + // Delete all Services in this namespace + serviceList := corev1.ServiceList{} + err = k8sClient.List(ctx, &serviceList, client.InNamespace(ns.Name)) + Expect(err).ShouldNot(HaveOccurred()) + for idx := range serviceList.Items { + policy := metav1.DeletePropagationForeground + err = k8sClient.Delete(ctx, &serviceList.Items[idx], &client.DeleteOptions{PropagationPolicy: &policy}) + Expect(err).ShouldNot(HaveOccurred()) + } + + Eventually(func() error { + key := client.ObjectKeyFromObject(ns) + if err := k8sClient.Get(ctx, key, ns); err != nil { + return client.IgnoreNotFound(err) + } + // remove `kubernetes` finalizer + const kubernetes = "kubernetes" + finalizers := []corev1.FinalizerName{} + for _, f := range ns.Spec.Finalizers { + if f != kubernetes { + finalizers = append(finalizers, f) + } + } + ns.Spec.Finalizers = finalizers + + // We have to use the k8s.io/client-go library here to expose + // ability to patch the /finalize subresource on the namespace + _, err = clientGo.CoreV1().Namespaces().Finalize(ctx, ns, metav1.UpdateOptions{}) + return err + }, Timeout, Interval).Should(Succeed()) + } + + Eventually(func() metav1.StatusReason { + key := client.ObjectKeyFromObject(obj) + if err := k8sClient.Get(ctx, key, obj); err != nil { + return apierrors.ReasonForError(err) + } + return "" + }, Timeout, Interval).Should(Equal(metav1.StatusReasonNotFound)) + } +} + +func ignoreMethodNotAllowed(err error) error { + if err != nil { + if apierrors.ReasonForError(err) == metav1.StatusReasonMethodNotAllowed { + return nil + } + } + return err +} + +func SetupK8STestManager(testCtx *context.Context, k8sClient *client.Client, controllers func(mgr *manager.Manager) []Reconciler) *envtest.Environment { ctx, cancel := context.WithCancel(context.TODO()) *testCtx = ctx @@ -83,4 +195,6 @@ func SetupK8STestManager(testCtx *context.Context, k8sClient *client.Client, con err := testEnv.Stop() Expect(err).NotTo(HaveOccurred()) }) + + return testEnv }