From ef110e36e6f704b457cf67e1c43f32b5127c9a00 Mon Sep 17 00:00:00 2001 From: Andrii Dema Date: Fri, 1 Sep 2023 13:45:40 +0300 Subject: [PATCH] K8SPSMDB-227: Add `topologySpreadConstraints` (#1280) * K8SPSMDB-227: Add `topologySpreadConstraints` https://jira.percona.com/browse/K8SPSMDB-227 * fix tests * fix defaults * fix `upgrade-consistency` test * update `cr.yaml` * Revert "fix tests" This reverts commit 6796ce71e62001b334a934a0fee795a25c9f4f1b. * don't add topologySpreadConstraints by default * fix `TestSetSafeDefault` --------- Co-authored-by: Inel Pandzic --- ...mdb.percona.com_perconaservermongodbs.yaml | 364 ++++++++++++++++++ deploy/bundle.yaml | 364 ++++++++++++++++++ deploy/cr.yaml | 21 + deploy/crd.yaml | 364 ++++++++++++++++++ deploy/cw-bundle.yaml | 364 ++++++++++++++++++ e2e-tests/version-service/conf/crd.yaml | 364 ++++++++++++++++++ pkg/apis/psmdb/v1/psmdb_defaults.go | 29 +- pkg/apis/psmdb/v1/psmdb_defaults_test.go | 5 +- pkg/apis/psmdb/v1/psmdb_types.go | 21 +- pkg/apis/psmdb/v1/zz_generated.deepcopy.go | 7 + pkg/psmdb/mongos.go | 1 + pkg/psmdb/statefulset.go | 16 + 12 files changed, 1903 insertions(+), 17 deletions(-) diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml index 4326fb3cdf..245754a991 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml @@ -2767,6 +2767,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -5202,6 +5254,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -7076,6 +7180,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -9541,6 +9697,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -11976,6 +12184,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -13850,6 +14110,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -16247,6 +16559,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array type: object required: - enabled diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index b6e06cb1e0..8aa6a00a17 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -3370,6 +3370,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -5805,6 +5857,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -7679,6 +7783,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -10144,6 +10300,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -12579,6 +12787,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -14453,6 +14713,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -16850,6 +17162,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array type: object required: - enabled diff --git a/deploy/cr.yaml b/deploy/cr.yaml index 989a58505a..16b26d7dcc 100644 --- a/deploy/cr.yaml +++ b/deploy/cr.yaml @@ -49,6 +49,13 @@ spec: - name: rs0 size: 3 # terminationGracePeriodSeconds: 300 +# topologySpreadConstraints: +# - labelSelector: +# matchLabels: +# app.kubernetes.io/name: percona-server-mongodb +# maxSkew: 1 +# topologyKey: kubernetes.io/hostname +# whenUnsatisfiable: DoNotSchedule # externalNodes: # - host: 34.124.76.90 # - host: 34.124.76.91 @@ -310,6 +317,13 @@ spec: configsvrReplSet: size: 3 # terminationGracePeriodSeconds: 300 +# topologySpreadConstraints: +# - labelSelector: +# matchLabels: +# app.kubernetes.io/name: percona-server-mongodb +# maxSkew: 1 +# topologyKey: kubernetes.io/hostname +# whenUnsatisfiable: DoNotSchedule # externalNodes: # - host: 34.124.76.93 # - host: 34.124.76.94 @@ -407,6 +421,13 @@ spec: mongos: size: 3 # terminationGracePeriodSeconds: 300 +# topologySpreadConstraints: +# - labelSelector: +# matchLabels: +# app.kubernetes.io/name: percona-server-mongodb +# maxSkew: 1 +# topologyKey: kubernetes.io/hostname +# whenUnsatisfiable: DoNotSchedule # # for more configuration fields refer to https://docs.mongodb.com/manual/reference/configuration-options/ # configuration: | # systemLog: diff --git a/deploy/crd.yaml b/deploy/crd.yaml index 5dd7521cc3..3696ca1321 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -3370,6 +3370,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -5805,6 +5857,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -7679,6 +7783,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -10144,6 +10300,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -12579,6 +12787,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -14453,6 +14713,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -16850,6 +17162,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array type: object required: - enabled diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index 5093f0c474..faafa2a175 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -3370,6 +3370,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -5805,6 +5857,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -7679,6 +7783,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -10144,6 +10300,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -12579,6 +12787,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -14453,6 +14713,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -16850,6 +17162,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array type: object required: - enabled diff --git a/e2e-tests/version-service/conf/crd.yaml b/e2e-tests/version-service/conf/crd.yaml index 5dd7521cc3..3696ca1321 100644 --- a/e2e-tests/version-service/conf/crd.yaml +++ b/e2e-tests/version-service/conf/crd.yaml @@ -3370,6 +3370,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -5805,6 +5857,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -7679,6 +7783,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -10144,6 +10300,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array required: - enabled - size @@ -12579,6 +12787,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -14453,6 +14713,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array volumeSpec: properties: emptyDir: @@ -16850,6 +17162,58 @@ spec: type: string type: object type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array type: object required: - enabled diff --git a/pkg/apis/psmdb/v1/psmdb_defaults.go b/pkg/apis/psmdb/v1/psmdb_defaults.go index 7c24cd11e7..96248dfb08 100644 --- a/pkg/apis/psmdb/v1/psmdb_defaults.go +++ b/pkg/apis/psmdb/v1/psmdb_defaults.go @@ -273,7 +273,7 @@ func (cr *PerconaServerMongoDB) CheckNSetDefaults(platform version.Platform, log cr.Spec.Sharding.Mongos.ReadinessProbe.FailureThreshold = 3 } - cr.Spec.Sharding.Mongos.reconcileOpts() + cr.Spec.Sharding.Mongos.reconcileOpts(cr) if err := cr.Spec.Sharding.Mongos.Configuration.SetDefaults(); err != nil { return errors.Wrap(err, "failed to set configuration defaults") @@ -558,10 +558,10 @@ func (rs *ReplsetSpec) SetDefaults(platform version.Platform, cr *PerconaServerM rs.Expose.ExposeType = corev1.ServiceTypeClusterIP } - rs.MultiAZ.reconcileOpts() + rs.MultiAZ.reconcileOpts(cr) if rs.Arbiter.Enabled { - rs.Arbiter.MultiAZ.reconcileOpts() + rs.Arbiter.MultiAZ.reconcileOpts(cr) } if !cr.Spec.UnsafeConf && cr.DeletionTimestamp == nil { @@ -694,7 +694,7 @@ func (nv *NonVotingSpec) SetDefaults(cr *PerconaServerMongoDB, rs *ReplsetSpec) nv.ServiceAccountName = WorkloadSA } - nv.MultiAZ.reconcileOpts() + nv.MultiAZ.reconcileOpts(cr) if nv.ContainerSecurityContext == nil { nv.ContainerSecurityContext = rs.ContainerSecurityContext @@ -741,8 +741,9 @@ func (rs *ReplsetSpec) setSafeDefaults(log logr.Logger) { } } -func (m *MultiAZ) reconcileOpts() { +func (m *MultiAZ) reconcileOpts(cr *PerconaServerMongoDB) { m.reconcileAffinityOpts() + m.reconcileTopologySpreadConstraints(cr) if m.PodDisruptionBudget == nil { defaultMaxUnavailable := intstr.FromInt(1) @@ -786,6 +787,24 @@ func (m *MultiAZ) reconcileAffinityOpts() { } } +func (m *MultiAZ) reconcileTopologySpreadConstraints(cr *PerconaServerMongoDB) { + if cr.CompareVersion("1.15.0") < 0 { + return + } + + for i := range m.TopologySpreadConstraints { + if m.TopologySpreadConstraints[i].MaxSkew == 0 { + m.TopologySpreadConstraints[i].MaxSkew = 1 + } + if m.TopologySpreadConstraints[i].TopologyKey == "" { + m.TopologySpreadConstraints[i].TopologyKey = defaultAffinityTopologyKey + } + if m.TopologySpreadConstraints[i].WhenUnsatisfiable == "" { + m.TopologySpreadConstraints[i].WhenUnsatisfiable = corev1.DoNotSchedule + } + } +} + func (v *VolumeSpec) reconcileOpts() error { if v.EmptyDir == nil && v.HostPath == nil && v.PersistentVolumeClaim.PersistentVolumeClaimSpec == nil { v.PersistentVolumeClaim.PersistentVolumeClaimSpec = &corev1.PersistentVolumeClaimSpec{} diff --git a/pkg/apis/psmdb/v1/psmdb_defaults_test.go b/pkg/apis/psmdb/v1/psmdb_defaults_test.go index f00524d2fa..2f350a326c 100644 --- a/pkg/apis/psmdb/v1/psmdb_defaults_test.go +++ b/pkg/apis/psmdb/v1/psmdb_defaults_test.go @@ -226,8 +226,9 @@ func TestSetSafeDefault(t *testing.T) { cr := &api.PerconaServerMongoDB{ ObjectMeta: metav1.ObjectMeta{Name: "psmdb-mock", Namespace: "psmdb"}, Spec: api.PerconaServerMongoDBSpec{ - Replsets: []*api.ReplsetSpec{{Name: "rs0", Size: 3}, {Name: "rs1", Size: 3}}, - Sharding: api.Sharding{Enabled: true, Mongos: &api.MongosSpec{Size: 3}}, + CRVersion: version.Version, + Replsets: []*api.ReplsetSpec{{Name: "rs0", Size: 3}, {Name: "rs1", Size: 3}}, + Sharding: api.Sharding{Enabled: true, Mongos: &api.MongosSpec{Size: 3}}, }, } diff --git a/pkg/apis/psmdb/v1/psmdb_types.go b/pkg/apis/psmdb/v1/psmdb_types.go index fd17cbae62..4618b9bed7 100644 --- a/pkg/apis/psmdb/v1/psmdb_types.go +++ b/pkg/apis/psmdb/v1/psmdb_types.go @@ -287,16 +287,17 @@ func (spec *PMMSpec) ShouldUseAPIKeyAuth(secret *corev1.Secret) bool { } type MultiAZ struct { - Affinity *PodAffinity `json:"affinity,omitempty"` - NodeSelector map[string]string `json:"nodeSelector,omitempty"` - Tolerations []corev1.Toleration `json:"tolerations,omitempty"` - PriorityClassName string `json:"priorityClassName,omitempty"` - ServiceAccountName string `json:"serviceAccountName,omitempty"` - Annotations map[string]string `json:"annotations,omitempty"` - Labels map[string]string `json:"labels,omitempty"` - PodDisruptionBudget *PodDisruptionBudgetSpec `json:"podDisruptionBudget,omitempty"` - TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` - RuntimeClassName *string `json:"runtimeClassName,omitempty"` + Affinity *PodAffinity `json:"affinity,omitempty"` + TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"` + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + PriorityClassName string `json:"priorityClassName,omitempty"` + ServiceAccountName string `json:"serviceAccountName,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + PodDisruptionBudget *PodDisruptionBudgetSpec `json:"podDisruptionBudget,omitempty"` + TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` + RuntimeClassName *string `json:"runtimeClassName,omitempty"` Resources corev1.ResourceRequirements `json:"resources,omitempty"` diff --git a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go index 77e5a78484..e7bff35d0a 100644 --- a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go +++ b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go @@ -520,6 +520,13 @@ func (in *MultiAZ) DeepCopyInto(out *MultiAZ) { *out = new(PodAffinity) (*in).DeepCopyInto(*out) } + if in.TopologySpreadConstraints != nil { + in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints + *out = make([]corev1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.NodeSelector != nil { in, out := &in.NodeSelector, &out.NodeSelector *out = make(map[string]string, len(*in)) diff --git a/pkg/psmdb/mongos.go b/pkg/psmdb/mongos.go index 801573c49c..4054a84920 100644 --- a/pkg/psmdb/mongos.go +++ b/pkg/psmdb/mongos.go @@ -125,6 +125,7 @@ func MongosTemplateSpec(cr *api.PerconaServerMongoDB, initImage string, log logr HostAliases: cr.Spec.Sharding.Mongos.HostAliases, SecurityContext: cr.Spec.Sharding.Mongos.PodSecurityContext, Affinity: PodAffinity(cr, cr.Spec.Sharding.Mongos.MultiAZ.Affinity, ls), + TopologySpreadConstraints: PodTopologySpreadConstraints(cr, cr.Spec.Sharding.Mongos.MultiAZ.TopologySpreadConstraints, ls), NodeSelector: cr.Spec.Sharding.Mongos.MultiAZ.NodeSelector, Tolerations: cr.Spec.Sharding.Mongos.MultiAZ.Tolerations, TerminationGracePeriodSeconds: cr.Spec.Sharding.Mongos.MultiAZ.TerminationGracePeriodSeconds, diff --git a/pkg/psmdb/statefulset.go b/pkg/psmdb/statefulset.go index 566321c3be..46e40d0dca 100644 --- a/pkg/psmdb/statefulset.go +++ b/pkg/psmdb/statefulset.go @@ -144,6 +144,7 @@ func StatefulSpec(ctx context.Context, cr *api.PerconaServerMongoDB, replset *ap HostAliases: replset.HostAliases, SecurityContext: podSecurityContext, Affinity: PodAffinity(cr, multiAZ.Affinity, customLabels), + TopologySpreadConstraints: PodTopologySpreadConstraints(cr, multiAZ.TopologySpreadConstraints, customLabels), NodeSelector: multiAZ.NodeSelector, Tolerations: multiAZ.Tolerations, TerminationGracePeriodSeconds: multiAZ.TerminationGracePeriodSeconds, @@ -228,6 +229,21 @@ func PodAffinity(cr *api.PerconaServerMongoDB, af *api.PodAffinity, labels map[s return nil } +func PodTopologySpreadConstraints(cr *api.PerconaServerMongoDB, tscs []corev1.TopologySpreadConstraint, ls map[string]string) []corev1.TopologySpreadConstraint { + result := make([]corev1.TopologySpreadConstraint, 0, len(tscs)) + + for _, tsc := range tscs { + if tsc.LabelSelector == nil && tsc.MatchLabelKeys == nil { + tsc.LabelSelector = &metav1.LabelSelector{ + MatchLabels: ls, + } + } + + result = append(result, tsc) + } + return result +} + func isEncryptionEnabled(cr *api.PerconaServerMongoDB, replset *api.ReplsetSpec) (bool, error) { enabled, err := replset.Configuration.IsEncryptionEnabled() if err != nil {