add pdb configuration toggle
This commit is contained in:
		
						commit
						b8453e6075
					
				|  | @ -114,6 +114,7 @@ configKubernetesCRD: | ||||||
|   cluster_name_label: cluster-name |   cluster_name_label: cluster-name | ||||||
|   enable_pod_antiaffinity: false |   enable_pod_antiaffinity: false | ||||||
|   pod_antiaffinity_topology_key: "kubernetes.io/hostname" |   pod_antiaffinity_topology_key: "kubernetes.io/hostname" | ||||||
|  |   enable_pod_disruption_budget: true | ||||||
|   secret_name_template: "{username}.{cluster}.credentials.{tprkind}.{tprgroup}" |   secret_name_template: "{username}.{cluster}.credentials.{tprkind}.{tprgroup}" | ||||||
|   # inherited_labels: |   # inherited_labels: | ||||||
|   # - application |   # - application | ||||||
|  | @ -161,7 +162,7 @@ serviceAccount: | ||||||
|   # The name of the ServiceAccount to use. |   # The name of the ServiceAccount to use. | ||||||
|   # If not set and create is true, a name is generated using the fullname template |   # If not set and create is true, a name is generated using the fullname template | ||||||
|   # When relying solely on the OperatorConfiguration CRD, set this value to "operator" |   # When relying solely on the OperatorConfiguration CRD, set this value to "operator" | ||||||
|   # Otherwise, the operator tries to use the "default" service account which is forbidden  |   # Otherwise, the operator tries to use the "default" service account which is forbidden | ||||||
|   name: "" |   name: "" | ||||||
| 
 | 
 | ||||||
| priorityClassName: "" | priorityClassName: "" | ||||||
|  |  | ||||||
|  | @ -40,6 +40,7 @@ configuration: | ||||||
|     pod_management_policy: "ordered_ready" |     pod_management_policy: "ordered_ready" | ||||||
|     enable_pod_antiaffinity: false |     enable_pod_antiaffinity: false | ||||||
|     pod_antiaffinity_topology_key: "kubernetes.io/hostname" |     pod_antiaffinity_topology_key: "kubernetes.io/hostname" | ||||||
|  |     enable_pod_disruption_budget: true | ||||||
|   postgres_pod_resources: |   postgres_pod_resources: | ||||||
|     default_cpu_request: 100m |     default_cpu_request: 100m | ||||||
|     default_memory_request: 100Mi |     default_memory_request: 100Mi | ||||||
|  |  | ||||||
|  | @ -67,6 +67,7 @@ type KubernetesMetaConfiguration struct { | ||||||
| 	EnablePodAntiAffinity      bool          `json:"enable_pod_antiaffinity,omitempty"` | 	EnablePodAntiAffinity      bool          `json:"enable_pod_antiaffinity,omitempty"` | ||||||
| 	PodAntiAffinityTopologyKey string        `json:"pod_antiaffinity_topology_key,omitempty"` | 	PodAntiAffinityTopologyKey string        `json:"pod_antiaffinity_topology_key,omitempty"` | ||||||
| 	PodManagementPolicy        string        `json:"pod_management_policy,omitempty"` | 	PodManagementPolicy        string        `json:"pod_management_policy,omitempty"` | ||||||
|  | 	EnablePodDisruptionBudget  bool          `json:"enable_pod_disruption_budget,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // PostgresPodResourcesDefaults defines the spec of default resources
 | // PostgresPodResourcesDefaults defines the spec of default resources
 | ||||||
|  |  | ||||||
|  | @ -1274,6 +1274,11 @@ func (c *Cluster) generateCloneEnvironment(description *acidv1.CloneDescription) | ||||||
| func (c *Cluster) generatePodDisruptionBudget() *policybeta1.PodDisruptionBudget { | func (c *Cluster) generatePodDisruptionBudget() *policybeta1.PodDisruptionBudget { | ||||||
| 	minAvailable := intstr.FromInt(1) | 	minAvailable := intstr.FromInt(1) | ||||||
| 
 | 
 | ||||||
|  | 	// Is PodDisruptionBudget is disabled or if there is no master, set the budget to 0.
 | ||||||
|  | 	if (c.OpConfig.EnablePodDisruptionBudget != nil && !*c.OpConfig.EnablePodDisruptionBudget) || c.Spec.NumberOfInstances <= 0 { | ||||||
|  | 		minAvailable = intstr.FromInt(0) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return &policybeta1.PodDisruptionBudget{ | 	return &policybeta1.PodDisruptionBudget{ | ||||||
| 		ObjectMeta: metav1.ObjectMeta{ | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
| 			Name:      c.podDisruptionBudgetName(), | 			Name:      c.podDisruptionBudgetName(), | ||||||
|  |  | ||||||
|  | @ -1,6 +1,8 @@ | ||||||
| package cluster | package cluster | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 
 | ||||||
| 	"k8s.io/api/core/v1" | 	"k8s.io/api/core/v1" | ||||||
| 
 | 
 | ||||||
| 	"testing" | 	"testing" | ||||||
|  | @ -9,6 +11,10 @@ import ( | ||||||
| 	"github.com/zalando/postgres-operator/pkg/util/config" | 	"github.com/zalando/postgres-operator/pkg/util/config" | ||||||
| 	"github.com/zalando/postgres-operator/pkg/util/constants" | 	"github.com/zalando/postgres-operator/pkg/util/constants" | ||||||
| 	"github.com/zalando/postgres-operator/pkg/util/k8sutil" | 	"github.com/zalando/postgres-operator/pkg/util/k8sutil" | ||||||
|  | 
 | ||||||
|  | 	policyv1beta1 "k8s.io/api/policy/v1beta1" | ||||||
|  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
|  | 	"k8s.io/apimachinery/pkg/util/intstr" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func True() *bool { | func True() *bool { | ||||||
|  | @ -21,6 +27,11 @@ func False() *bool { | ||||||
| 	return &b | 	return &b | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func toIntStr(val int) *intstr.IntOrString { | ||||||
|  | 	b := intstr.FromInt(val) | ||||||
|  | 	return &b | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestGenerateSpiloJSONConfiguration(t *testing.T) { | func TestGenerateSpiloJSONConfiguration(t *testing.T) { | ||||||
| 	var cluster = New( | 	var cluster = New( | ||||||
| 		Config{ | 		Config{ | ||||||
|  | @ -143,6 +154,113 @@ func TestCreateLoadBalancerLogic(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestGeneratePodDisruptionBudget(t *testing.T) { | ||||||
|  | 	tests := []struct { | ||||||
|  | 		c   *Cluster | ||||||
|  | 		out policyv1beta1.PodDisruptionBudget | ||||||
|  | 	}{ | ||||||
|  | 		// With multiple instances.
 | ||||||
|  | 		{ | ||||||
|  | 			New( | ||||||
|  | 				Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-pdb"}}, | ||||||
|  | 				k8sutil.KubernetesClient{}, | ||||||
|  | 				acidv1.Postgresql{ | ||||||
|  | 					ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"}, | ||||||
|  | 					Spec:       acidv1.PostgresSpec{TeamID: "myapp", NumberOfInstances: 3}}, | ||||||
|  | 				logger), | ||||||
|  | 			policyv1beta1.PodDisruptionBudget{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 					Name:      "postgres-myapp-database-pdb", | ||||||
|  | 					Namespace: "myapp", | ||||||
|  | 					Labels:    map[string]string{"team": "myapp", "cluster-name": "myapp-database"}, | ||||||
|  | 				}, | ||||||
|  | 				Spec: policyv1beta1.PodDisruptionBudgetSpec{ | ||||||
|  | 					MinAvailable: toIntStr(1), | ||||||
|  | 					Selector: &metav1.LabelSelector{ | ||||||
|  | 						MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		// With zero instances.
 | ||||||
|  | 		{ | ||||||
|  | 			New( | ||||||
|  | 				Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-pdb"}}, | ||||||
|  | 				k8sutil.KubernetesClient{}, | ||||||
|  | 				acidv1.Postgresql{ | ||||||
|  | 					ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"}, | ||||||
|  | 					Spec:       acidv1.PostgresSpec{TeamID: "myapp", NumberOfInstances: 0}}, | ||||||
|  | 				logger), | ||||||
|  | 			policyv1beta1.PodDisruptionBudget{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 					Name:      "postgres-myapp-database-pdb", | ||||||
|  | 					Namespace: "myapp", | ||||||
|  | 					Labels:    map[string]string{"team": "myapp", "cluster-name": "myapp-database"}, | ||||||
|  | 				}, | ||||||
|  | 				Spec: policyv1beta1.PodDisruptionBudgetSpec{ | ||||||
|  | 					MinAvailable: toIntStr(0), | ||||||
|  | 					Selector: &metav1.LabelSelector{ | ||||||
|  | 						MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		// With PodDisruptionBudget disabled.
 | ||||||
|  | 		{ | ||||||
|  | 			New( | ||||||
|  | 				Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-pdb", EnablePodDisruptionBudget: False()}}, | ||||||
|  | 				k8sutil.KubernetesClient{}, | ||||||
|  | 				acidv1.Postgresql{ | ||||||
|  | 					ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"}, | ||||||
|  | 					Spec:       acidv1.PostgresSpec{TeamID: "myapp", NumberOfInstances: 3}}, | ||||||
|  | 				logger), | ||||||
|  | 			policyv1beta1.PodDisruptionBudget{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 					Name:      "postgres-myapp-database-pdb", | ||||||
|  | 					Namespace: "myapp", | ||||||
|  | 					Labels:    map[string]string{"team": "myapp", "cluster-name": "myapp-database"}, | ||||||
|  | 				}, | ||||||
|  | 				Spec: policyv1beta1.PodDisruptionBudgetSpec{ | ||||||
|  | 					MinAvailable: toIntStr(0), | ||||||
|  | 					Selector: &metav1.LabelSelector{ | ||||||
|  | 						MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		// With non-default PDBNameFormat and PodDisruptionBudget explicitly enabled.
 | ||||||
|  | 		{ | ||||||
|  | 			New( | ||||||
|  | 				Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-databass-budget", EnablePodDisruptionBudget: True()}}, | ||||||
|  | 				k8sutil.KubernetesClient{}, | ||||||
|  | 				acidv1.Postgresql{ | ||||||
|  | 					ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"}, | ||||||
|  | 					Spec:       acidv1.PostgresSpec{TeamID: "myapp", NumberOfInstances: 3}}, | ||||||
|  | 				logger), | ||||||
|  | 			policyv1beta1.PodDisruptionBudget{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 					Name:      "postgres-myapp-database-databass-budget", | ||||||
|  | 					Namespace: "myapp", | ||||||
|  | 					Labels:    map[string]string{"team": "myapp", "cluster-name": "myapp-database"}, | ||||||
|  | 				}, | ||||||
|  | 				Spec: policyv1beta1.PodDisruptionBudgetSpec{ | ||||||
|  | 					MinAvailable: toIntStr(1), | ||||||
|  | 					Selector: &metav1.LabelSelector{ | ||||||
|  | 						MatchLabels: map[string]string{"spilo-role": "master", "cluster-name": "myapp-database"}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, tt := range tests { | ||||||
|  | 		result := tt.c.generatePodDisruptionBudget() | ||||||
|  | 		if !reflect.DeepEqual(*result, tt.out) { | ||||||
|  | 			t.Errorf("Expected PodDisruptionBudget: %#v, got %#v", tt.out, *result) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestShmVolume(t *testing.T) { | func TestShmVolume(t *testing.T) { | ||||||
| 	testName := "TestShmVolume" | 	testName := "TestShmVolume" | ||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
|  | @ -269,6 +387,5 @@ func TestCloneEnv(t *testing.T) { | ||||||
| 			t.Errorf("%s %s: Expected env value %s, have %s instead", | 			t.Errorf("%s %s: Expected env value %s, have %s instead", | ||||||
| 				testName, tt.subTest, tt.env.Value, env.Value) | 				testName, tt.subTest, tt.env.Value, env.Value) | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -41,6 +41,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur | ||||||
| 	result.PodServiceAccountRoleBindingDefinition = fromCRD.Kubernetes.PodServiceAccountRoleBindingDefinition | 	result.PodServiceAccountRoleBindingDefinition = fromCRD.Kubernetes.PodServiceAccountRoleBindingDefinition | ||||||
| 	result.PodEnvironmentConfigMap = fromCRD.Kubernetes.PodEnvironmentConfigMap | 	result.PodEnvironmentConfigMap = fromCRD.Kubernetes.PodEnvironmentConfigMap | ||||||
| 	result.PodTerminateGracePeriod = time.Duration(fromCRD.Kubernetes.PodTerminateGracePeriod) | 	result.PodTerminateGracePeriod = time.Duration(fromCRD.Kubernetes.PodTerminateGracePeriod) | ||||||
|  | 	result.EnablePodDisruptionBudget = fromCRD.Kubernetes.EnablePodDisruptionBudget | ||||||
| 	result.SpiloPrivileged = fromCRD.Kubernetes.SpiloPrivileged | 	result.SpiloPrivileged = fromCRD.Kubernetes.SpiloPrivileged | ||||||
| 	result.SpiloFSGroup = fromCRD.Kubernetes.SpiloFSGroup | 	result.SpiloFSGroup = fromCRD.Kubernetes.SpiloFSGroup | ||||||
| 	result.ClusterDomain = fromCRD.Kubernetes.ClusterDomain | 	result.ClusterDomain = fromCRD.Kubernetes.ClusterDomain | ||||||
|  |  | ||||||
|  | @ -110,20 +110,21 @@ type Config struct { | ||||||
| 	EnablePodAntiAffinity                  bool              `name:"enable_pod_antiaffinity" default:"false"` | 	EnablePodAntiAffinity                  bool              `name:"enable_pod_antiaffinity" default:"false"` | ||||||
| 	PodAntiAffinityTopologyKey             string            `name:"pod_antiaffinity_topology_key" default:"kubernetes.io/hostname"` | 	PodAntiAffinityTopologyKey             string            `name:"pod_antiaffinity_topology_key" default:"kubernetes.io/hostname"` | ||||||
| 	// deprecated and kept for backward compatibility
 | 	// deprecated and kept for backward compatibility
 | ||||||
| 	EnableLoadBalancer       *bool             `name:"enable_load_balancer"` | 	EnableLoadBalancer        *bool             `name:"enable_load_balancer"` | ||||||
| 	MasterDNSNameFormat      StringTemplate    `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"` | 	MasterDNSNameFormat       StringTemplate    `name:"master_dns_name_format" default:"{cluster}.{team}.{hostedzone}"` | ||||||
| 	ReplicaDNSNameFormat     StringTemplate    `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"` | 	ReplicaDNSNameFormat      StringTemplate    `name:"replica_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"` | ||||||
| 	PDBNameFormat            StringTemplate    `name:"pdb_name_format" default:"postgres-{cluster}-pdb"` | 	PDBNameFormat             StringTemplate    `name:"pdb_name_format" default:"postgres-{cluster}-pdb"` | ||||||
| 	Workers                  uint32            `name:"workers" default:"4"` | 	Workers                   uint32            `name:"workers" default:"4"` | ||||||
| 	APIPort                  int               `name:"api_port" default:"8080"` | 	APIPort                   int               `name:"api_port" default:"8080"` | ||||||
| 	RingLogLines             int               `name:"ring_log_lines" default:"100"` | 	RingLogLines              int               `name:"ring_log_lines" default:"100"` | ||||||
| 	ClusterHistoryEntries    int               `name:"cluster_history_entries" default:"1000"` | 	ClusterHistoryEntries     int               `name:"cluster_history_entries" default:"1000"` | ||||||
| 	TeamAPIRoleConfiguration map[string]string `name:"team_api_role_configuration" default:"log_statement:all"` | 	TeamAPIRoleConfiguration  map[string]string `name:"team_api_role_configuration" default:"log_statement:all"` | ||||||
| 	PodTerminateGracePeriod  time.Duration     `name:"pod_terminate_grace_period" default:"5m"` | 	PodTerminateGracePeriod   time.Duration     `name:"pod_terminate_grace_period" default:"5m"` | ||||||
| 	PodManagementPolicy      string            `name:"pod_management_policy" default:"ordered_ready"` | 	PodManagementPolicy       string            `name:"pod_management_policy" default:"ordered_ready"` | ||||||
| 	ProtectedRoles           []string          `name:"protected_role_names" default:"admin"` | 	EnablePodDisruptionBudget *bool             `name:"enable_pod_disruption_budget" default:"true"` | ||||||
| 	PostgresSuperuserTeams   []string          `name:"postgres_superuser_teams" default:""` | 	ProtectedRoles            []string          `name:"protected_role_names" default:"admin"` | ||||||
| 	SetMemoryRequestToLimit  bool              `name:"set_memory_request_to_limit" defaults:"false"` | 	PostgresSuperuserTeams    []string          `name:"postgres_superuser_teams" default:""` | ||||||
|  | 	SetMemoryRequestToLimit   bool              `name:"set_memory_request_to_limit" default:"false"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // MustMarshal marshals the config or panics
 | // MustMarshal marshals the config or panics
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue