Skip to content

Commit 7a2075b

Browse files
Add topologySpreadConstraints configuration.
1 parent 409e4c7 commit 7a2075b

File tree

5 files changed

+227
-84
lines changed

5 files changed

+227
-84
lines changed

pkg/apis/acid.zalan.do/v1/crds.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,9 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
13031303
"enable_sidecars": {
13041304
Type: "boolean",
13051305
},
1306+
"enable_topology_spread_constraints": {
1307+
Type: "boolean",
1308+
},
13061309
"ignored_annotations": {
13071310
Type: "array",
13081311
Items: &apiextv1.JSONSchemaPropsOrArray{
@@ -1508,6 +1511,74 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
15081511
},
15091512
},
15101513
},
1514+
"topology_spread_constraints": {
1515+
Type: "array",
1516+
Nullable: true,
1517+
Items: &apiextv1.JSONSchemaPropsOrArray{
1518+
Schema: &apiextv1.JSONSchemaProps{
1519+
Type: "object",
1520+
Required: []string{"max_skew", "topology_key", "when_unsatisfiable"},
1521+
Properties: map[string]apiextv1.JSONSchemaProps{
1522+
"max_skew": {
1523+
Type: "integer",
1524+
Format: "int32",
1525+
},
1526+
"topology_key": {
1527+
Type: "string",
1528+
},
1529+
"when_unsatisfiable": {
1530+
Type: "string",
1531+
Enum: []apiextv1.JSON{
1532+
{
1533+
Raw: []byte(`"DoNotSchedule"`),
1534+
},
1535+
{
1536+
Raw: []byte(`"ScheduleAnyway"`),
1537+
},
1538+
},
1539+
},
1540+
"min_domains": {
1541+
Type: "integer",
1542+
Nullable: true,
1543+
Format: "int32",
1544+
},
1545+
"node_affinity_policy": {
1546+
Type: "string",
1547+
Nullable: true,
1548+
Enum: []apiextv1.JSON{
1549+
{
1550+
Raw: []byte(`"Ignore"`),
1551+
},
1552+
{
1553+
Raw: []byte(`"Honor"`),
1554+
},
1555+
},
1556+
},
1557+
"node_taints_policy": {
1558+
Type: "string",
1559+
Nullable: true,
1560+
Enum: []apiextv1.JSON{
1561+
{
1562+
Raw: []byte(`"Ignore"`),
1563+
},
1564+
{
1565+
Raw: []byte(`"Honor"`),
1566+
},
1567+
},
1568+
},
1569+
"match_label_keys": {
1570+
Type: "array",
1571+
Nullable: true,
1572+
Items: &apiextv1.JSONSchemaPropsOrArray{
1573+
Schema: &apiextv1.JSONSchemaProps{
1574+
Type: "string",
1575+
},
1576+
},
1577+
},
1578+
},
1579+
},
1580+
},
1581+
},
15111582
"watched_namespace": {
15121583
Type: "string",
15131584
},

pkg/apis/acid.zalan.do/v1/operator_configuration_type.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,18 +91,20 @@ type KubernetesMetaConfiguration struct {
9191
NodeReadinessLabelMerge string `json:"node_readiness_label_merge,omitempty"`
9292
CustomPodAnnotations map[string]string `json:"custom_pod_annotations,omitempty"`
9393
// TODO: use a proper toleration structure?
94-
PodToleration map[string]string `json:"toleration,omitempty"`
95-
PodEnvironmentConfigMap spec.NamespacedName `json:"pod_environment_configmap,omitempty"`
96-
PodEnvironmentSecret string `json:"pod_environment_secret,omitempty"`
97-
PodPriorityClassName string `json:"pod_priority_class_name,omitempty"`
98-
MasterPodMoveTimeout Duration `json:"master_pod_move_timeout,omitempty"`
99-
EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity,omitempty"`
100-
PodAntiAffinityPreferredDuringScheduling bool `json:"pod_antiaffinity_preferred_during_scheduling,omitempty"`
101-
PodAntiAffinityTopologyKey string `json:"pod_antiaffinity_topology_key,omitempty"`
102-
PodManagementPolicy string `json:"pod_management_policy,omitempty"`
103-
PersistentVolumeClaimRetentionPolicy map[string]string `json:"persistent_volume_claim_retention_policy,omitempty"`
104-
EnableReadinessProbe bool `json:"enable_readiness_probe,omitempty"`
105-
EnableCrossNamespaceSecret bool `json:"enable_cross_namespace_secret,omitempty"`
94+
PodToleration map[string]string `json:"toleration,omitempty"`
95+
PodEnvironmentConfigMap spec.NamespacedName `json:"pod_environment_configmap,omitempty"`
96+
PodEnvironmentSecret string `json:"pod_environment_secret,omitempty"`
97+
PodPriorityClassName string `json:"pod_priority_class_name,omitempty"`
98+
MasterPodMoveTimeout Duration `json:"master_pod_move_timeout,omitempty"`
99+
EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity,omitempty"`
100+
PodAntiAffinityPreferredDuringScheduling bool `json:"pod_antiaffinity_preferred_during_scheduling,omitempty"`
101+
PodAntiAffinityTopologyKey string `json:"pod_antiaffinity_topology_key,omitempty"`
102+
PodManagementPolicy string `json:"pod_management_policy,omitempty"`
103+
PersistentVolumeClaimRetentionPolicy map[string]string `json:"persistent_volume_claim_retention_policy,omitempty"`
104+
EnableReadinessProbe bool `json:"enable_readiness_probe,omitempty"`
105+
EnableCrossNamespaceSecret bool `json:"enable_cross_namespace_secret,omitempty"`
106+
EnableTopologySpreadConstraints bool `json:"enable_topology_spread_constraints,omitempty"`
107+
TopologySpreadConstraints []*config.TopologySpreadConstraint `json:"topology_spread_constraints,omitempty"`
106108
}
107109

108110
// PostgresPodResourcesDefaults defines the spec of default resources

pkg/cluster/k8sres.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,36 @@ func generatePodAntiAffinity(podAffinityTerm v1.PodAffinityTerm, preferredDuring
572572
return podAntiAffinity
573573
}
574574

575+
func generateTopologySpreadConstraints(labels labels.Set, topologySpreadConstraintObjs []*config.TopologySpreadConstraint) []v1.TopologySpreadConstraint {
576+
var topologySpreadConstraints []v1.TopologySpreadConstraint
577+
var nodeAffinityPolicy *v1.NodeInclusionPolicy
578+
var nodeTaintsPolicy *v1.NodeInclusionPolicy
579+
for _, topologySpreadConstraintObj := range topologySpreadConstraintObjs {
580+
if topologySpreadConstraintObj.NodeAffinityPolicy != nil {
581+
nodeAffinityPolicy = (*v1.NodeInclusionPolicy)(topologySpreadConstraintObj.NodeAffinityPolicy)
582+
}
583+
if topologySpreadConstraintObj.NodeTaintsPolicy != nil {
584+
nodeTaintsPolicy = (*v1.NodeInclusionPolicy)(topologySpreadConstraintObj.NodeTaintsPolicy)
585+
}
586+
topologySpreadConstraint := v1.TopologySpreadConstraint{
587+
MaxSkew: topologySpreadConstraintObj.MaxSkew,
588+
TopologyKey: topologySpreadConstraintObj.TopologyKey,
589+
WhenUnsatisfiable: v1.UnsatisfiableConstraintAction(topologySpreadConstraintObj.WhenUnsatisfiable),
590+
LabelSelector: &metav1.LabelSelector{
591+
MatchLabels: labels,
592+
},
593+
MinDomains: topologySpreadConstraintObj.MinDomains,
594+
NodeAffinityPolicy: nodeAffinityPolicy,
595+
NodeTaintsPolicy: nodeTaintsPolicy,
596+
MatchLabelKeys: topologySpreadConstraintObj.MatchLabelKeys,
597+
}
598+
topologySpreadConstraints = append(topologySpreadConstraints, topologySpreadConstraint)
599+
nodeAffinityPolicy = nil
600+
nodeTaintsPolicy = nil
601+
}
602+
return topologySpreadConstraints
603+
}
604+
575605
func tolerations(tolerationsSpec *[]v1.Toleration, podToleration map[string]string) []v1.Toleration {
576606
// allow to override tolerations by postgresql manifest
577607
if len(*tolerationsSpec) > 0 {
@@ -788,6 +818,8 @@ func (c *Cluster) generatePodTemplate(
788818
additionalSecretMount string,
789819
additionalSecretMountPath string,
790820
additionalVolumes []acidv1.AdditionalVolume,
821+
topologySpreadConstraint bool,
822+
topologySpreadConstraintsArr []*config.TopologySpreadConstraint,
791823
) (*v1.PodTemplateSpec, error) {
792824

793825
terminateGracePeriodSeconds := terminateGracePeriod
@@ -836,6 +868,10 @@ func (c *Cluster) generatePodTemplate(
836868
podSpec.Affinity = nodeAffinity
837869
}
838870

871+
if topologySpreadConstraint && len(topologySpreadConstraintsArr) > 0 {
872+
podSpec.TopologySpreadConstraints = generateTopologySpreadConstraints(labels, topologySpreadConstraintsArr)
873+
}
874+
839875
if priorityClassName != "" {
840876
podSpec.PriorityClassName = priorityClassName
841877
}
@@ -1412,7 +1448,9 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef
14121448
c.OpConfig.PodAntiAffinityPreferredDuringScheduling,
14131449
c.OpConfig.AdditionalSecretMount,
14141450
c.OpConfig.AdditionalSecretMountPath,
1415-
additionalVolumes)
1451+
additionalVolumes,
1452+
c.OpConfig.EnableTopologySpreadConstraints,
1453+
c.OpConfig.TopologySpreadConstraints)
14161454

14171455
if err != nil {
14181456
return nil, fmt.Errorf("could not generate pod template: %v", err)
@@ -2233,7 +2271,9 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1.CronJob, error) {
22332271
false,
22342272
c.OpConfig.AdditionalSecretMount,
22352273
c.OpConfig.AdditionalSecretMountPath,
2236-
[]acidv1.AdditionalVolume{}); err != nil {
2274+
[]acidv1.AdditionalVolume{},
2275+
false,
2276+
[]*config.TopologySpreadConstraint{}); err != nil {
22372277
return nil, fmt.Errorf("could not generate pod template for logical backup pod: %v", err)
22382278
}
22392279

pkg/controller/operator_config.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,5 +282,23 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
282282
fromCRD.ConnectionPooler.MaxDBConnections,
283283
k8sutil.Int32ToPointer(constants.ConnectionPoolerMaxDBConnections))
284284

285+
result.EnableTopologySpreadConstraints = fromCRD.Kubernetes.EnableTopologySpreadConstraints
286+
if fromCRD.Kubernetes.TopologySpreadConstraints != nil {
287+
result.TopologySpreadConstraints = []*config.TopologySpreadConstraint{}
288+
for _, topologySpreadConstraint := range fromCRD.Kubernetes.TopologySpreadConstraints {
289+
result.TopologySpreadConstraints = append(
290+
result.TopologySpreadConstraints,
291+
&config.TopologySpreadConstraint{
292+
MaxSkew: topologySpreadConstraint.MaxSkew,
293+
TopologyKey: topologySpreadConstraint.TopologyKey,
294+
WhenUnsatisfiable: topologySpreadConstraint.WhenUnsatisfiable,
295+
MinDomains: topologySpreadConstraint.MinDomains,
296+
NodeAffinityPolicy: topologySpreadConstraint.NodeAffinityPolicy,
297+
NodeTaintsPolicy: topologySpreadConstraint.NodeTaintsPolicy,
298+
MatchLabelKeys: topologySpreadConstraint.MatchLabelKeys,
299+
})
300+
}
301+
}
302+
285303
return result
286304
}

0 commit comments

Comments
 (0)