add pdb configuration toggle

This commit is contained in:
Felix Kunde 2019-06-07 12:50:09 +02:00
commit b8453e6075
7 changed files with 143 additions and 16 deletions

View File

@ -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: ""

View File

@ -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

View File

@ -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

View File

@ -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(),

View File

@ -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)
} }
} }
} }

View File

@ -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

View File

@ -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