This commit is contained in:
Steven Berler 2025-12-12 20:01:03 +01:00 committed by GitHub
commit c5f9a8b7bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 73 additions and 22 deletions

View File

@ -178,6 +178,10 @@ spec:
type: array type: array
items: items:
type: string type: string
dropped_pod_capabilities:
type: array
items:
type: string
cluster_domain: cluster_domain:
type: string type: string
default: "cluster.local" default: "cluster.local"

View File

@ -98,6 +98,10 @@ configKubernetes:
# additional_pod_capabilities: # additional_pod_capabilities:
# - "SYS_NICE" # - "SYS_NICE"
# list of dropped capabilities for postgres container
# dropped_pod_capabilities:
# - "ALL"
# default DNS domain of K8s cluster where operator is running # default DNS domain of K8s cluster where operator is running
cluster_domain: cluster.local cluster_domain: cluster.local
# additional labels assigned to the cluster objects # additional labels assigned to the cluster objects

View File

@ -525,6 +525,10 @@ configuration they are grouped under the `kubernetes` key.
PodSecruityPolicy allows the capabilities listed here. Otherwise, the PodSecruityPolicy allows the capabilities listed here. Otherwise, the
container will not start. The default is empty. container will not start. The default is empty.
* **dropped_pod_capabilities**
list of capabilities to be dropped from the postgres container's
SecurityContext (e.g. ALL etc.).
* **master_pod_move_timeout** * **master_pod_move_timeout**
The period of time to wait for the success of migration of master pods from The period of time to wait for the success of migration of master pods from
an unschedulable node. The migration includes Patroni switchovers to an unschedulable node. The migration includes Patroni switchovers to

View File

@ -5,6 +5,7 @@ metadata:
data: data:
# additional_owner_roles: "cron_admin" # additional_owner_roles: "cron_admin"
# additional_pod_capabilities: "SYS_NICE" # additional_pod_capabilities: "SYS_NICE"
# dropped_pod_capabilities: "ALL"
# additional_secret_mount: "some-secret-name" # additional_secret_mount: "some-secret-name"
# additional_secret_mount_path: "/some/dir" # additional_secret_mount_path: "/some/dir"
api_port: "8080" api_port: "8080"

View File

@ -176,6 +176,10 @@ spec:
type: array type: array
items: items:
type: string type: string
dropped_pod_capabilities:
type: array
items:
type: string
cluster_domain: cluster_domain:
type: string type: string
default: "cluster.local" default: "cluster.local"

View File

@ -44,6 +44,8 @@ configuration:
kubernetes: kubernetes:
# additional_pod_capabilities: # additional_pod_capabilities:
# - "SYS_NICE" # - "SYS_NICE"
# dropped_pod_capabilities:
# - "ALL"
cluster_domain: cluster.local cluster_domain: cluster.local
cluster_labels: cluster_labels:
application: spilo application: spilo

View File

@ -67,6 +67,7 @@ type KubernetesMetaConfiguration struct {
SpiloRunAsGroup *int64 `json:"spilo_runasgroup,omitempty"` SpiloRunAsGroup *int64 `json:"spilo_runasgroup,omitempty"`
SpiloFSGroup *int64 `json:"spilo_fsgroup,omitempty"` SpiloFSGroup *int64 `json:"spilo_fsgroup,omitempty"`
AdditionalPodCapabilities []string `json:"additional_pod_capabilities,omitempty"` AdditionalPodCapabilities []string `json:"additional_pod_capabilities,omitempty"`
DroppedPodCapabilities []string `json:"dropped_pod_capabilities,omitempty"`
WatchedNamespace string `json:"watched_namespace,omitempty"` WatchedNamespace string `json:"watched_namespace,omitempty"`
PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"` PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"`
PDBMasterLabelSelector *bool `json:"pdb_master_label_selector,omitempty"` PDBMasterLabelSelector *bool `json:"pdb_master_label_selector,omitempty"`

View File

@ -188,6 +188,11 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.DroppedPodCapabilities != nil {
in, out := &in.DroppedPodCapabilities, &out.DroppedPodCapabilities
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.PDBMasterLabelSelector != nil { if in.PDBMasterLabelSelector != nil {
in, out := &in.PDBMasterLabelSelector, &out.PDBMasterLabelSelector in, out := &in.PDBMasterLabelSelector, &out.PDBMasterLabelSelector
*out = new(bool) *out = new(bool)

View File

@ -485,17 +485,30 @@ func getLocalAndBoostrapPostgreSQLParameters(parameters map[string]string) (loca
return return
} }
func generateCapabilities(capabilities []string) *v1.Capabilities { func generateCapabilities(added, dropped []string) *v1.Capabilities {
additionalCapabilities := make([]v1.Capability, 0, len(capabilities)) if len(added) == 0 && len(dropped) == 0 {
for _, capability := range capabilities { return nil
additionalCapabilities = append(additionalCapabilities, v1.Capability(strings.ToUpper(capability)))
} }
if len(additionalCapabilities) > 0 {
return &v1.Capabilities{ capabilities := &v1.Capabilities{}
Add: additionalCapabilities,
if len(added) > 0 {
additionalCapabilities := make([]v1.Capability, 0, len(added))
for _, capability := range added {
additionalCapabilities = append(additionalCapabilities, v1.Capability(strings.ToUpper(capability)))
} }
capabilities.Add = additionalCapabilities
} }
return nil
if len(dropped) > 0 {
droppedCapabilities := make([]v1.Capability, 0, len(dropped))
for _, capability := range dropped {
droppedCapabilities = append(droppedCapabilities, v1.Capability(strings.ToUpper(capability)))
}
capabilities.Drop = droppedCapabilities
}
return capabilities
} }
func (c *Cluster) nodeAffinity(nodeReadinessLabel map[string]string, nodeAffinity *v1.NodeAffinity) *v1.Affinity { func (c *Cluster) nodeAffinity(nodeReadinessLabel map[string]string, nodeAffinity *v1.NodeAffinity) *v1.Affinity {
@ -1394,7 +1407,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef
volumeMounts, volumeMounts,
c.OpConfig.Resources.SpiloPrivileged, c.OpConfig.Resources.SpiloPrivileged,
c.OpConfig.Resources.SpiloAllowPrivilegeEscalation, c.OpConfig.Resources.SpiloAllowPrivilegeEscalation,
generateCapabilities(c.OpConfig.AdditionalPodCapabilities), generateCapabilities(c.OpConfig.AdditionalPodCapabilities, c.OpConfig.DroppedPodCapabilities),
) )
// Patroni responds 200 to probe only if it either owns the leader lock or postgres is running and DCS is accessible // Patroni responds 200 to probe only if it either owns the leader lock or postgres is running and DCS is accessible

View File

@ -4128,41 +4128,53 @@ func TestGenerateLogicalBackupPodEnvVars(t *testing.T) {
func TestGenerateCapabilities(t *testing.T) { func TestGenerateCapabilities(t *testing.T) {
tests := []struct { tests := []struct {
subTest string subTest string
configured []string added []string
dropped []string
capabilities *v1.Capabilities capabilities *v1.Capabilities
err error
}{ }{
{ {
subTest: "no capabilities", subTest: "no capabilities",
configured: nil,
capabilities: nil, capabilities: nil,
err: fmt.Errorf("could not parse capabilities configuration of nil"),
}, },
{ {
subTest: "empty capabilities", subTest: "empty capabilities",
configured: []string{}, added: []string{},
dropped: []string{},
capabilities: nil, capabilities: nil,
err: fmt.Errorf("could not parse empty capabilities configuration"),
}, },
{ {
subTest: "configured capability", subTest: "added one capability",
configured: []string{"SYS_NICE"}, added: []string{"SYS_NICE"},
capabilities: &v1.Capabilities{ capabilities: &v1.Capabilities{
Add: []v1.Capability{"SYS_NICE"}, Add: []v1.Capability{"SYS_NICE"},
}, },
err: fmt.Errorf("could not generate one configured capability"),
}, },
{ {
subTest: "configured capabilities", subTest: "added two capabilities",
configured: []string{"SYS_NICE", "CHOWN"}, added: []string{"SYS_NICE", "CHOWN"},
capabilities: &v1.Capabilities{ capabilities: &v1.Capabilities{
Add: []v1.Capability{"SYS_NICE", "CHOWN"}, Add: []v1.Capability{"SYS_NICE", "CHOWN"},
}, },
err: fmt.Errorf("could not generate multiple configured capabilities"), },
{
subTest: "dropped capabilities",
dropped: []string{"ALL"},
capabilities: &v1.Capabilities{
Drop: []v1.Capability{"ALL"},
},
},
{
subTest: "added and dropped capabilities",
added: []string{"CHOWN"},
dropped: []string{"SYS_NICE"},
capabilities: &v1.Capabilities{
Add: []v1.Capability{"CHOWN"},
Drop: []v1.Capability{"SYS_NICE"},
},
}, },
} }
for _, tt := range tests { for _, tt := range tests {
caps := generateCapabilities(tt.configured) caps := generateCapabilities(tt.added, tt.dropped)
if !reflect.DeepEqual(caps, tt.capabilities) { if !reflect.DeepEqual(caps, tt.capabilities) {
t.Errorf("%s %s: expected `%v` but got `%v`", t.Errorf("%s %s: expected `%v` but got `%v`",
t.Name(), tt.subTest, tt.capabilities, caps) t.Name(), tt.subTest, tt.capabilities, caps)

View File

@ -39,6 +39,7 @@ type Resources struct {
SpiloPrivileged bool `name:"spilo_privileged" default:"false"` SpiloPrivileged bool `name:"spilo_privileged" default:"false"`
SpiloAllowPrivilegeEscalation *bool `name:"spilo_allow_privilege_escalation" default:"true"` SpiloAllowPrivilegeEscalation *bool `name:"spilo_allow_privilege_escalation" default:"true"`
AdditionalPodCapabilities []string `name:"additional_pod_capabilities" default:""` AdditionalPodCapabilities []string `name:"additional_pod_capabilities" default:""`
DroppedPodCapabilities []string `name:"dropped_pod_capabilities" default:""`
ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"` ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"`
InheritedLabels []string `name:"inherited_labels" default:""` InheritedLabels []string `name:"inherited_labels" default:""`
InheritedAnnotations []string `name:"inherited_annotations" default:""` InheritedAnnotations []string `name:"inherited_annotations" default:""`