add config option to change affinity merge behavior
This commit is contained in:
		
							parent
							
								
									92db09182e
								
							
						
					
					
						commit
						596ad5375d
					
				|  | @ -230,6 +230,11 @@ spec: | ||||||
|                     type: object |                     type: object | ||||||
|                     additionalProperties: |                     additionalProperties: | ||||||
|                       type: string |                       type: string | ||||||
|  |                   node_readiness_label_merge: | ||||||
|  |                     type: string | ||||||
|  |                     enum: | ||||||
|  |                       - "AND" | ||||||
|  |                       - "OR" | ||||||
|                   oauth_token_secret_name: |                   oauth_token_secret_name: | ||||||
|                     type: string |                     type: string | ||||||
|                     default: "postgresql-operator" |                     default: "postgresql-operator" | ||||||
|  |  | ||||||
|  | @ -130,6 +130,9 @@ configKubernetes: | ||||||
|   # node_readiness_label: |   # node_readiness_label: | ||||||
|   #   status: ready |   #   status: ready | ||||||
| 
 | 
 | ||||||
|  |   # defines how nodeAffinity from manifest should be merged with node_readiness_label | ||||||
|  |   # node_readiness_label_merge: "OR" | ||||||
|  | 
 | ||||||
|   # namespaced name of the secret containing the OAuth2 token to pass to the teams API |   # namespaced name of the secret containing the OAuth2 token to pass to the teams API | ||||||
|   # oauth_token_secret_name: postgresql-operator |   # oauth_token_secret_name: postgresql-operator | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -370,7 +370,10 @@ configuration: | ||||||
| The operator will create a `nodeAffinity` on the pods. This makes the | The operator will create a `nodeAffinity` on the pods. This makes the | ||||||
| `node_readiness_label` option the global configuration for defining node | `node_readiness_label` option the global configuration for defining node | ||||||
| affinities for all Postgres clusters. You can have both, cluster-specific and | affinities for all Postgres clusters. You can have both, cluster-specific and | ||||||
| global affinity, defined and they will get merged on the pods (AND condition). | global affinity, defined and they will get merged on the pods. If | ||||||
|  | `node_readiness_label_merge` is configured to `"AND"` the node readiness | ||||||
|  | affinity will end up under the same `matchExpressions` section(s) from the | ||||||
|  | manifest affinity. | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
|   affinity: |   affinity: | ||||||
|  | @ -390,8 +393,8 @@ global affinity, defined and they will get merged on the pods (AND condition). | ||||||
|             ... |             ... | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| If multiple `matchExpressions` are defined in the manifest (OR condition) the | If `node_readiness_label_merge` is set to `"OR"` (default) the readiness label | ||||||
| readiness label configuration will be appended with its own expressions block: | affinty will be appended with its own expressions block: | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
|   affinity: |   affinity: | ||||||
|  |  | ||||||
|  | @ -342,9 +342,14 @@ configuration they are grouped under the `kubernetes` key. | ||||||
|   a set of labels that a running and active node should possess to be |   a set of labels that a running and active node should possess to be | ||||||
|   considered `ready`. When the set is not empty, the operator assigns the |   considered `ready`. When the set is not empty, the operator assigns the | ||||||
|   `nodeAffinity` clause to the Postgres pods to be scheduled only on `ready` |   `nodeAffinity` clause to the Postgres pods to be scheduled only on `ready` | ||||||
|   nodes. If a `nodeAffinity` is also specified in the postgres cluster |   nodes. The default is empty. | ||||||
|   manifest both affinities will get merged on the pods. See  [user docs](../user.md#use-taints-tolerations-and-node-affinity-for-dedicated-postgresql-nodes) | 
 | ||||||
|   for more details. The default is empty. | * **node_readiness_label_merge** | ||||||
|  |   If a `nodeAffinity` is also specified in the postgres cluster manifest | ||||||
|  |   it will get merged with the `node_readiness_label` affinity on the pods. | ||||||
|  |   The merge strategy can be configured - it can either be "AND" or "OR". | ||||||
|  |   See [user docs](../user.md#use-taints-tolerations-and-node-affinity-for-dedicated-postgresql-nodes) | ||||||
|  |   for more details. Default is "OR". | ||||||
| 
 | 
 | ||||||
| * **toleration** | * **toleration** | ||||||
|   a dictionary that should contain `key`, `operator`, `value` and |   a dictionary that should contain `key`, `operator`, `value` and | ||||||
|  |  | ||||||
|  | @ -1010,6 +1010,7 @@ class EndToEndTestCase(unittest.TestCase): | ||||||
|             patch_readiness_label_config = { |             patch_readiness_label_config = { | ||||||
|                 "data": { |                 "data": { | ||||||
|                     "node_readiness_label": readiness_label + ':' + readiness_value, |                     "node_readiness_label": readiness_label + ':' + readiness_value, | ||||||
|  |                     "node_readiness_label_merge": "AND", | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             k8s.update_config(patch_readiness_label_config, "setting readiness label") |             k8s.update_config(patch_readiness_label_config, "setting readiness label") | ||||||
|  |  | ||||||
|  | @ -85,7 +85,8 @@ data: | ||||||
|   # min_cpu_limit: 250m |   # min_cpu_limit: 250m | ||||||
|   # min_memory_limit: 250Mi |   # min_memory_limit: 250Mi | ||||||
|   # minimal_major_version: "9.6" |   # minimal_major_version: "9.6" | ||||||
|   # node_readiness_label: "" |   # node_readiness_label: "status:ready" | ||||||
|  |   # node_readiness_label_merge: "OR" | ||||||
|   # oauth_token_secret_name: postgresql-operator |   # oauth_token_secret_name: postgresql-operator | ||||||
|   # pam_configuration: | |   # pam_configuration: | | ||||||
|   #  https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees |   #  https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees | ||||||
|  |  | ||||||
|  | @ -225,6 +225,11 @@ spec: | ||||||
|                     type: object |                     type: object | ||||||
|                     additionalProperties: |                     additionalProperties: | ||||||
|                       type: string |                       type: string | ||||||
|  |                   node_readiness_label_merge: | ||||||
|  |                     type: string | ||||||
|  |                     enum: | ||||||
|  |                       - "AND" | ||||||
|  |                       - "OR" | ||||||
|                   oauth_token_secret_name: |                   oauth_token_secret_name: | ||||||
|                     type: string |                     type: string | ||||||
|                     default: "postgresql-operator" |                     default: "postgresql-operator" | ||||||
|  |  | ||||||
|  | @ -69,6 +69,7 @@ configuration: | ||||||
|     master_pod_move_timeout: 20m |     master_pod_move_timeout: 20m | ||||||
|     # node_readiness_label: |     # node_readiness_label: | ||||||
|     #   status: ready |     #   status: ready | ||||||
|  |     # node_readiness_label_merge: "OR" | ||||||
|     oauth_token_secret_name: postgresql-operator |     oauth_token_secret_name: postgresql-operator | ||||||
|     pdb_name_format: "postgres-{cluster}-pdb" |     pdb_name_format: "postgres-{cluster}-pdb" | ||||||
|     pod_antiaffinity_topology_key: "kubernetes.io/hostname" |     pod_antiaffinity_topology_key: "kubernetes.io/hostname" | ||||||
|  |  | ||||||
|  | @ -1164,6 +1164,17 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{ | ||||||
| 									}, | 									}, | ||||||
| 								}, | 								}, | ||||||
| 							}, | 							}, | ||||||
|  | 							"node_readiness_label_merge": { | ||||||
|  | 								Type: "string", | ||||||
|  | 								Enum: []apiextv1.JSON{ | ||||||
|  | 									{ | ||||||
|  | 										Raw: []byte(`"AND"`), | ||||||
|  | 									}, | ||||||
|  | 									{ | ||||||
|  | 										Raw: []byte(`"OR"`), | ||||||
|  | 									}, | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
| 							"oauth_token_secret_name": { | 							"oauth_token_secret_name": { | ||||||
| 								Type: "string", | 								Type: "string", | ||||||
| 							}, | 							}, | ||||||
|  |  | ||||||
|  | @ -82,6 +82,7 @@ type KubernetesMetaConfiguration struct { | ||||||
| 	DeleteAnnotationDateKey                string                       `json:"delete_annotation_date_key,omitempty"` | 	DeleteAnnotationDateKey                string                       `json:"delete_annotation_date_key,omitempty"` | ||||||
| 	DeleteAnnotationNameKey                string                       `json:"delete_annotation_name_key,omitempty"` | 	DeleteAnnotationNameKey                string                       `json:"delete_annotation_name_key,omitempty"` | ||||||
| 	NodeReadinessLabel                     map[string]string            `json:"node_readiness_label,omitempty"` | 	NodeReadinessLabel                     map[string]string            `json:"node_readiness_label,omitempty"` | ||||||
|  | 	NodeReadinessLabelMerge                string                       `json:"node_readiness_label_merge,omitempty"` | ||||||
| 	CustomPodAnnotations                   map[string]string            `json:"custom_pod_annotations,omitempty"` | 	CustomPodAnnotations                   map[string]string            `json:"custom_pod_annotations,omitempty"` | ||||||
| 	// TODO: use a proper toleration structure?
 | 	// TODO: use a proper toleration structure?
 | ||||||
| 	PodToleration              map[string]string   `json:"toleration,omitempty"` | 	PodToleration              map[string]string   `json:"toleration,omitempty"` | ||||||
|  |  | ||||||
|  | @ -327,7 +327,7 @@ func generateCapabilities(capabilities []string) *v1.Capabilities { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func nodeAffinity(nodeReadinessLabel map[string]string, nodeAffinity *v1.NodeAffinity) *v1.Affinity { | func (c *Cluster) nodeAffinity(nodeReadinessLabel map[string]string, nodeAffinity *v1.NodeAffinity) *v1.Affinity { | ||||||
| 	if len(nodeReadinessLabel) == 0 && nodeAffinity == nil { | 	if len(nodeReadinessLabel) == 0 && nodeAffinity == nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  | @ -352,21 +352,17 @@ func nodeAffinity(nodeReadinessLabel map[string]string, nodeAffinity *v1.NodeAff | ||||||
| 				}, | 				}, | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			if len(nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms) > 1 { | 			if c.OpConfig.NodeReadinessLabelMerge == "OR" { | ||||||
| 				// if there are multiple node selector terms specified, append the node readiness label expressions (OR condition)
 |  | ||||||
| 				manifestTerms := nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms | 				manifestTerms := nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms | ||||||
| 				manifestTerms = append(manifestTerms, nodeReadinessSelectorTerm) | 				manifestTerms = append(manifestTerms, nodeReadinessSelectorTerm) | ||||||
| 				nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution = &v1.NodeSelector{ | 				nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution = &v1.NodeSelector{ | ||||||
| 					NodeSelectorTerms: manifestTerms, | 					NodeSelectorTerms: manifestTerms, | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else if c.OpConfig.NodeReadinessLabelMerge == "AND" { | ||||||
| 				// if there is just one term defined merge it with the readiness label term (AND condition)
 | 				for i, nodeSelectorTerm := range nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms { | ||||||
| 				manifestExpressions := nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions | 					manifestExpressions := nodeSelectorTerm.MatchExpressions | ||||||
| 					manifestExpressions = append(manifestExpressions, matchExpressions...) | 					manifestExpressions = append(manifestExpressions, matchExpressions...) | ||||||
| 				nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution = &v1.NodeSelector{ | 					nodeAffinityCopy.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[i] = v1.NodeSelectorTerm{MatchExpressions: manifestExpressions} | ||||||
| 					NodeSelectorTerms: []v1.NodeSelectorTerm{ |  | ||||||
| 						v1.NodeSelectorTerm{MatchExpressions: manifestExpressions}, |  | ||||||
| 					}, |  | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -109,6 +109,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur | ||||||
| 	result.DeleteAnnotationDateKey = fromCRD.Kubernetes.DeleteAnnotationDateKey | 	result.DeleteAnnotationDateKey = fromCRD.Kubernetes.DeleteAnnotationDateKey | ||||||
| 	result.DeleteAnnotationNameKey = fromCRD.Kubernetes.DeleteAnnotationNameKey | 	result.DeleteAnnotationNameKey = fromCRD.Kubernetes.DeleteAnnotationNameKey | ||||||
| 	result.NodeReadinessLabel = fromCRD.Kubernetes.NodeReadinessLabel | 	result.NodeReadinessLabel = fromCRD.Kubernetes.NodeReadinessLabel | ||||||
|  | 	result.NodeReadinessLabelMerge = fromCRD.Kubernetes.NodeReadinessLabelMerge | ||||||
| 	result.PodPriorityClassName = fromCRD.Kubernetes.PodPriorityClassName | 	result.PodPriorityClassName = fromCRD.Kubernetes.PodPriorityClassName | ||||||
| 	result.PodManagementPolicy = util.Coalesce(fromCRD.Kubernetes.PodManagementPolicy, "ordered_ready") | 	result.PodManagementPolicy = util.Coalesce(fromCRD.Kubernetes.PodManagementPolicy, "ordered_ready") | ||||||
| 	result.MasterPodMoveTimeout = util.CoalesceDuration(time.Duration(fromCRD.Kubernetes.MasterPodMoveTimeout), "10m") | 	result.MasterPodMoveTimeout = util.CoalesceDuration(time.Duration(fromCRD.Kubernetes.MasterPodMoveTimeout), "10m") | ||||||
|  |  | ||||||
|  | @ -54,6 +54,7 @@ type Resources struct { | ||||||
| 	PodEnvironmentConfigMap       spec.NamespacedName `name:"pod_environment_configmap"` | 	PodEnvironmentConfigMap       spec.NamespacedName `name:"pod_environment_configmap"` | ||||||
| 	PodEnvironmentSecret          string              `name:"pod_environment_secret"` | 	PodEnvironmentSecret          string              `name:"pod_environment_secret"` | ||||||
| 	NodeReadinessLabel            map[string]string   `name:"node_readiness_label" default:""` | 	NodeReadinessLabel            map[string]string   `name:"node_readiness_label" default:""` | ||||||
|  | 	NodeReadinessLabelMerge       string              `name:"node_readiness_label_merge" default:"OR"` | ||||||
| 	MaxInstances                  int32               `name:"max_instances" default:"-1"` | 	MaxInstances                  int32               `name:"max_instances" default:"-1"` | ||||||
| 	MinInstances                  int32               `name:"min_instances" default:"-1"` | 	MinInstances                  int32               `name:"min_instances" default:"-1"` | ||||||
| 	ShmVolume                     *bool               `name:"enable_shm_volume" default:"true"` | 	ShmVolume                     *bool               `name:"enable_shm_volume" default:"true"` | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue