From 020f77a6610e78b7b0cc4291ef23cf58c7a45fd5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Oct 2023 07:48:09 +0200 Subject: [PATCH 1/5] fix(deps): update golang.org/x/exp digest to 7918f67 (main) (#3013) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 12 ++++++------ go.sum | 26 +++++++++++++------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 0191e3087b..6e9da999e1 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/thoas/go-funk v0.9.3 go.uber.org/atomic v1.11.0 go.uber.org/zap v1.26.0 - golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/sys v0.13.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.28.2 @@ -87,14 +87,14 @@ require ( github.com/xlab/treeprint v1.2.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/net v0.15.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.16.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/term v0.12.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 2e56fa0595..8538219b77 100644 --- a/go.sum +++ b/go.sum @@ -214,11 +214,11 @@ go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20231005195138-3e424a577f31 h1:9k5exFQKQglLo+RoP+4zMjOFE14P6+vyR0baDAi0Rcs= -golang.org/x/exp v0.0.0-20231005195138-3e424a577f31/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -226,7 +226,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -237,8 +237,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.16.0 h1:7eBu7KsSvFDtSXUIDbh3aqlK4DPsZ1rByC8PFfBThos= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= @@ -249,8 +249,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -266,8 +266,8 @@ golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -284,8 +284,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 9356daa5bddc77ec15e0350447e04dac55ca2e0a Mon Sep 17 00:00:00 2001 From: John Long Date: Sat, 7 Oct 2023 04:56:43 -0400 Subject: [PATCH 2/5] feat: allow to configure ephemeral-storage limit (#2830) Closes #1548 Signed-off-by: John Long Signed-off-by: Jonathan Gonzalez V Signed-off-by: Leonardo Cecchi Signed-off-by: Armando Ruocco Signed-off-by: Gabriele Bartolini Co-authored-by: Jonathan Gonzalez V Co-authored-by: Leonardo Cecchi Co-authored-by: Armando Ruocco Co-authored-by: Gabriele Bartolini --- .wordlist-en-custom.txt | 6 +++ api/v1/cluster_types.go | 32 +++++++++++++++ api/v1/cluster_types_test.go | 19 +++++++++ api/v1/cluster_webhook.go | 13 ++++++ api/v1/cluster_webhook_test.go | 32 +++++++++++++++ api/v1/zz_generated.deepcopy.go | 30 ++++++++++++++ .../bases/postgresql.cnpg.io_clusters.yaml | 20 ++++++++++ docs/src/cloudnative-pg.v1.md | 40 +++++++++++++++++++ docs/src/cluster_conf.md | 19 +++++++++ docs/src/postgresql_conf.md | 10 +++++ pkg/specs/volumes.go | 7 +++- 11 files changed, 226 insertions(+), 2 deletions(-) diff --git a/.wordlist-en-custom.txt b/.wordlist-en-custom.txt index e81e14ba53..708c737ead 100644 --- a/.wordlist-en-custom.txt +++ b/.wordlist-en-custom.txt @@ -123,6 +123,8 @@ EnterpriseDB's EnvFrom EnvFromSource EnvVar +EphemeralVolumesSizeLimit +EphemeralVolumesSizeLimitConfiguration ExternalCluster Fei Filesystem @@ -366,6 +368,7 @@ TCP TLS TOC TODO +TemporaryData TimelineId TopologyKey TopologySpreadConstraint @@ -419,6 +422,7 @@ apiGroup apiGroups apiVersion apidoc +apimachinery apis apiserver apparmor @@ -623,6 +627,7 @@ endpointURL enterprisedb env envFrom +ephemeralVolumesSizeLimit executables expirations extensibility @@ -1077,6 +1082,7 @@ targetXID tbody tcp td +temporaryData th thead timeLineID diff --git a/api/v1/cluster_types.go b/api/v1/cluster_types.go index 723954853d..e3136eac88 100644 --- a/api/v1/cluster_types.go +++ b/api/v1/cluster_types.go @@ -315,6 +315,10 @@ type ClusterSpec struct { // +optional Resources corev1.ResourceRequirements `json:"resources,omitempty"` + // EphemeralVolumesSizeLimit allows the user to set the limits for the ephemeral + // volumes + EphemeralVolumesSizeLimit *EphemeralVolumesSizeLimitConfiguration `json:"ephemeralVolumesSizeLimit,omitempty"` + // Name of the priority class which will be used in every generated Pod, if the PriorityClass // specified does not exist, the pod will not be able to schedule. Please refer to // https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass @@ -429,6 +433,34 @@ const ( PhaseApplyingConfiguration = "Applying configuration" ) +// EphemeralVolumesSizeLimitConfiguration contains the configuration of the ephemeral +// storage +type EphemeralVolumesSizeLimitConfiguration struct { + // Shm is the size limit of the shared memory volume + Shm *resource.Quantity `json:"shm,omitempty"` + + // TemporaryData is the size limit of the temporary data volume + TemporaryData *resource.Quantity `json:"temporaryData,omitempty"` +} + +// GetShmLimit gets the `/dev/shm` memory size limit +func (e *EphemeralVolumesSizeLimitConfiguration) GetShmLimit() *resource.Quantity { + if e == nil { + return nil + } + + return e.Shm +} + +// GetTemporaryDataLimit gets the temporary storage size limit +func (e *EphemeralVolumesSizeLimitConfiguration) GetTemporaryDataLimit() *resource.Quantity { + if e == nil { + return nil + } + + return e.TemporaryData +} + // ServiceAccountTemplate contains the template needed to generate the service accounts type ServiceAccountTemplate struct { // Metadata are the metadata to be used for the generated diff --git a/api/v1/cluster_types_test.go b/api/v1/cluster_types_test.go index 342612c315..a78b2ea327 100644 --- a/api/v1/cluster_types_test.go +++ b/api/v1/cluster_types_test.go @@ -18,6 +18,7 @@ package v1 import ( corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" @@ -952,3 +953,21 @@ var _ = Describe("Cluster ShouldRecoveryCreateApplicationDatabase", func() { Expect(result).To(BeFalse()) }) }) + +var _ = Describe("Ephemeral volume size limits", func() { + It("doesn't panic if the specification is nil", func() { + var spec *EphemeralVolumesSizeLimitConfiguration + Expect(spec.GetShmLimit()).To(BeNil()) + Expect(spec.GetTemporaryDataLimit()).To(BeNil()) + }) + + It("works correctly when fully specified", func() { + spec := &EphemeralVolumesSizeLimitConfiguration{ + Shm: ptr.To(resource.MustParse("10Mi")), + TemporaryData: ptr.To(resource.MustParse("20Mi")), + } + + Expect(spec.GetShmLimit().String()).To(Equal("10Mi")) + Expect(spec.GetTemporaryDataLimit().String()).To(Equal("20Mi")) + }) +}) diff --git a/api/v1/cluster_webhook.go b/api/v1/cluster_webhook.go index a9b3c27b9d..ea879b0d32 100644 --- a/api/v1/cluster_webhook.go +++ b/api/v1/cluster_webhook.go @@ -987,6 +987,19 @@ func (r *Cluster) validateResources() field.ErrorList { } } + ephemeralStorageRequest := r.Spec.Resources.Requests.StorageEphemeral() + ephemeralStorageLimits := r.Spec.Resources.Limits.StorageEphemeral() + if !ephemeralStorageRequest.IsZero() && !ephemeralStorageLimits.IsZero() { + ephemeralStorageRequestGtThanLimit := ephemeralStorageRequest.Cmp(*ephemeralStorageLimits) > 0 + if ephemeralStorageRequestGtThanLimit { + result = append(result, field.Invalid( + field.NewPath("spec", "resources", "requests", "storage"), + ephemeralStorageRequest.String(), + "Ephemeral storage request is greater than the limit", + )) + } + } + return result } diff --git a/api/v1/cluster_webhook_test.go b/api/v1/cluster_webhook_test.go index d548c6aca4..12c5fdc47a 100644 --- a/api/v1/cluster_webhook_test.go +++ b/api/v1/cluster_webhook_test.go @@ -3236,6 +3236,38 @@ var _ = Describe("validateResources", func() { Expect(errors[0].Detail).To(Equal("Memory request is greater than the limit")) }) + It("returns no error when the ephemeral storage request is correctly set", func() { + cluster.Spec.Resources.Requests["ephemeral-storage"] = resource.MustParse("1") + cluster.Spec.Resources.Limits["ephemeral-storage"] = resource.MustParse("1") + + errors := cluster.validateResources() + Expect(errors).To(BeEmpty()) + }) + + It("returns an error when the ephemeral storage request is greater than ephemeral storage limit", func() { + cluster.Spec.Resources.Requests["ephemeral-storage"] = resource.MustParse("2") + cluster.Spec.Resources.Limits["ephemeral-storage"] = resource.MustParse("1") + + errors := cluster.validateResources() + Expect(errors).To(HaveLen(1)) + Expect(errors[0].Detail).To(Equal("Ephemeral storage request is greater than the limit")) + }) + + It("returns three errors when CPU, Memory, and ephemeral storage requests are greater than limits", func() { + cluster.Spec.Resources.Requests["cpu"] = resource.MustParse("2") + cluster.Spec.Resources.Limits["cpu"] = resource.MustParse("1") + cluster.Spec.Resources.Requests["memory"] = resource.MustParse("2Gi") + cluster.Spec.Resources.Limits["memory"] = resource.MustParse("1Gi") + cluster.Spec.Resources.Requests["ephemeral-storage"] = resource.MustParse("2") + cluster.Spec.Resources.Limits["ephemeral-storage"] = resource.MustParse("1") + + errors := cluster.validateResources() + Expect(errors).To(HaveLen(3)) + Expect(errors[0].Detail).To(Equal("CPU request is greater than the limit")) + Expect(errors[1].Detail).To(Equal("Memory request is greater than the limit")) + Expect(errors[2].Detail).To(Equal("Ephemeral storage request is greater than the limit")) + }) + It("returns two errors when both CPU and Memory requests are greater than their limits", func() { cluster.Spec.Resources.Requests["cpu"] = resource.MustParse("2") cluster.Spec.Resources.Limits["cpu"] = resource.MustParse("1") diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index ca85e5df40..acdd98bd63 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -684,6 +684,11 @@ func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { } } in.Resources.DeepCopyInto(&out.Resources) + if in.EphemeralVolumesSizeLimit != nil { + in, out := &in.EphemeralVolumesSizeLimit, &out.EphemeralVolumesSizeLimit + *out = new(EphemeralVolumesSizeLimitConfiguration) + (*in).DeepCopyInto(*out) + } if in.Backup != nil { in, out := &in.Backup, &out.Backup *out = new(BackupConfiguration) @@ -940,6 +945,31 @@ func (in *EmbeddedObjectMetadata) DeepCopy() *EmbeddedObjectMetadata { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EphemeralVolumesSizeLimitConfiguration) DeepCopyInto(out *EphemeralVolumesSizeLimitConfiguration) { + *out = *in + if in.Shm != nil { + in, out := &in.Shm, &out.Shm + x := (*in).DeepCopy() + *out = &x + } + if in.TemporaryData != nil { + in, out := &in.TemporaryData, &out.TemporaryData + x := (*in).DeepCopy() + *out = &x + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralVolumesSizeLimitConfiguration. +func (in *EphemeralVolumesSizeLimitConfiguration) DeepCopy() *EphemeralVolumesSizeLimitConfiguration { + if in == nil { + return nil + } + out := new(EphemeralVolumesSizeLimitConfiguration) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ExternalCluster) DeepCopyInto(out *ExternalCluster) { *out = *in diff --git a/config/crd/bases/postgresql.cnpg.io_clusters.yaml b/config/crd/bases/postgresql.cnpg.io_clusters.yaml index 2609d8979f..0d0b10e051 100644 --- a/config/crd/bases/postgresql.cnpg.io_clusters.yaml +++ b/config/crd/bases/postgresql.cnpg.io_clusters.yaml @@ -1842,6 +1842,26 @@ spec: x-kubernetes-map-type: atomic type: object type: array + ephemeralVolumesSizeLimit: + description: EphemeralVolumesSizeLimit allows the user to set the + limits for the ephemeral volumes + properties: + shm: + anyOf: + - type: integer + - type: string + description: Shm is the size limit of the shared memory volume + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + temporaryData: + anyOf: + - type: integer + - type: string + description: TemporaryData is the size limit of the temporary + data volume + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object externalClusters: description: The list of external clusters which are used in the configuration items: diff --git a/docs/src/cloudnative-pg.v1.md b/docs/src/cloudnative-pg.v1.md index d64398fe3e..3e801a225f 100644 --- a/docs/src/cloudnative-pg.v1.md +++ b/docs/src/cloudnative-pg.v1.md @@ -1546,6 +1546,14 @@ https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ for more information.

+ephemeralVolumesSizeLimit [Required]
+EphemeralVolumesSizeLimitConfiguration + + +

EphemeralVolumesSizeLimit allows the user to set the limits for the ephemeral +volumes

+ + priorityClassName
string @@ -2160,6 +2168,38 @@ a Role in a PostgreSQL instance

+## EphemeralVolumesSizeLimitConfiguration {#postgresql-cnpg-io-v1-EphemeralVolumesSizeLimitConfiguration} + + +**Appears in:** + +- [ClusterSpec](#postgresql-cnpg-io-v1-ClusterSpec) + + +

EphemeralVolumesSizeLimitConfiguration contains the configuration of the ephemeral +storage

+ + + + + + + + + + + + +
FieldDescription
shm [Required]
+k8s.io/apimachinery/pkg/api/resource.Quantity +
+

Shm is the size limit of the shared memory volume

+
temporaryData [Required]
+k8s.io/apimachinery/pkg/api/resource.Quantity +
+

TemporaryData is the size limit of the temporary data volume

+
+ ## ExternalCluster {#postgresql-cnpg-io-v1-ExternalCluster} diff --git a/docs/src/cluster_conf.md b/docs/src/cluster_conf.md index fd37d32454..c46ee7f2b1 100644 --- a/docs/src/cluster_conf.md +++ b/docs/src/cluster_conf.md @@ -35,6 +35,25 @@ spec: You can find a complete example using projected volume template to mount Secret and Configmap in the [cluster-example-projected-volume.yaml](samples/cluster-example-projected-volume.yaml) deployment manifest. +## Ephemeral volumes + +CloudNativePG relies on [ephemeral volumes](https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/) +for part of the internal activities. Ephemeral volumes exist for the sole duration of +a pod's life, without persisting across pod restarts. + +### Volume for temporary storage + +An ephemeral volume used for temporary storage. An upper bound on the size can be +configured via the `spec.ephemeralVolumesSizeLimit.temporaryData` field in the cluster +spec. + +### Volume for shared memory + +This volume is used as shared memory space for Postgres, also an ephemeral type but +stored in-memory. An upper bound on the size can be configured via the +`spec.ephemeralVolumesSizeLimit.shm` field in the cluster spec. This is used only +in case of [PostgreSQL running with `posix` shared memory dynamic allocation](postgresql_conf.md#dynamic-shared-memory-settings). + ## Environment variables Some system behavior can be customized using environment variables. One example is diff --git a/docs/src/postgresql_conf.md b/docs/src/postgresql_conf.md index 34fa3349b5..f69dd4fedb 100644 --- a/docs/src/postgresql_conf.md +++ b/docs/src/postgresql_conf.md @@ -440,6 +440,16 @@ You should get something similar to the following output: shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=******) ``` +If you would like to set a maximum size for the `shm` volume, you can do so by +setting the `spec.ephemeralVolumesSizeLimit.shm` field in the `Cluster` resource. +For example: + +```yaml +spec: + ephemeralVolumesSizeLimit: + shm: 1Gi +``` + ### System V shared memory In case your Kubernetes cluster has a high enough value for the `SHMMAX` diff --git a/pkg/specs/volumes.go b/pkg/specs/volumes.go index a31bb856a7..1b15c6ce09 100644 --- a/pkg/specs/volumes.go +++ b/pkg/specs/volumes.go @@ -44,14 +44,17 @@ func createPostgresVolumes(cluster apiv1.Cluster, podName string) []corev1.Volum { Name: "scratch-data", VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, + EmptyDir: &corev1.EmptyDirVolumeSource{ + SizeLimit: cluster.Spec.EphemeralVolumesSizeLimit.GetTemporaryDataLimit(), + }, }, }, { Name: "shm", VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{ - Medium: "Memory", + Medium: "Memory", + SizeLimit: cluster.Spec.EphemeralVolumesSizeLimit.GetShmLimit(), }, }, }, From 948327c92c83e822aa76c3c97f69f8eb0d08fcbc Mon Sep 17 00:00:00 2001 From: Leonardo Cecchi Date: Sat, 7 Oct 2023 11:12:21 +0200 Subject: [PATCH 3/5] fix: typo (#3019) Signed-off-by: Leonardo Cecchi --- pkg/management/postgres/instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/management/postgres/instance.go b/pkg/management/postgres/instance.go index 53f91bd661..118622ae3e 100644 --- a/pkg/management/postgres/instance.go +++ b/pkg/management/postgres/instance.go @@ -961,7 +961,7 @@ func (instance *Instance) GetInstanceCommandChan() <-chan InstanceCommand { } // RequestFastImmediateShutdown request the lifecycle manager to shut down -// PostegreSQL using the fast strategy and then the immediate strategy. +// PostgreSQL using the fast strategy and then the immediate strategy. func (instance *Instance) RequestFastImmediateShutdown() { instance.instanceCommandChan <- ShutDownFastImmediate } From dedf003241db7b4c1cbb94b63ae218340ac39094 Mon Sep 17 00:00:00 2001 From: Steven Miller Date: Sat, 7 Oct 2023 05:22:22 -0400 Subject: [PATCH 4/5] docs: S3 lifecycle policies (#2594) Signed-off-by: Steven Miller Signed-off-by: Gabriele Bartolini Co-authored-by: Gabriele Bartolini --- docs/src/appendixes/object_stores.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/src/appendixes/object_stores.md b/docs/src/appendixes/object_stores.md index a2ca00b5ba..6863a25d36 100644 --- a/docs/src/appendixes/object_stores.md +++ b/docs/src/appendixes/object_stores.md @@ -94,6 +94,17 @@ spec: [...] ``` +### S3 lifecycle policy + +Barman Cloud writes objects to S3, then does not update them until they are +deleted by the Barman Cloud retention policy. A recommended approach for an S3 +lifecycle policy is to expire the current version of objects a few days longer +than the Barman retention policy, enable object versioning, and expire +non-current versions after a number of days. Such a policy protects against +accidental deletion, and also allows for restricting permissions to the +CloudNativePG workload so that it may delete objects from S3 without granting +permissions to permanently delete objects. + ### Other S3-compatible Object Storages providers In case you're using S3-compatible object storage, like **MinIO** or From 311018a690b1b9d0145aca37a1f244eff83c88a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Fei?= Date: Mon, 9 Oct 2023 12:16:35 +0200 Subject: [PATCH 5/5] chore: investigate rolling-update E2Es failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Niccolò Fei --- tests/e2e/rolling_update_test.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/e2e/rolling_update_test.go b/tests/e2e/rolling_update_test.go index ff146ffcc5..44adeebae1 100644 --- a/tests/e2e/rolling_update_test.go +++ b/tests/e2e/rolling_update_test.go @@ -17,8 +17,11 @@ limitations under the License. package e2e import ( + "bytes" + "fmt" "os" "strconv" + "strings" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -245,6 +248,27 @@ var _ = Describe("Rolling updates", Label(tests.LabelPostgresConfiguration), fun Expect(err).ToNot(HaveOccurred()) clusterInstances := cluster.Spec.Instances + // Dump logs on failure + var buf bytes.Buffer + GinkgoWriter.Println("Putting Tail on the cluster logs") + go func() { + err = env.TailClusterLogs(cluster, &buf, false) + if err != nil { + _, _ = fmt.Fprintf(GinkgoWriter, "\nError tailing cluster logs: %v\n", err) + } + }() + DeferCleanup(func(ctx SpecContext) { + if CurrentSpecReport().Failed() { + specName := CurrentSpecReport().FullText() + capLines := 10 + GinkgoWriter.Printf("DUMPING tailed Cluster Logs with error/warning (at most %v lines). Failed Spec: %v\n", + capLines, specName) + GinkgoWriter.Println("================================================================================") + saveLogs(&buf, "cluster_logs_", strings.ReplaceAll(specName, " ", "_"), GinkgoWriter, capLines) + GinkgoWriter.Println("================================================================================") + } + }) + By("Gathering info on the current state", func() { originalPodNames, originalPodUID, originalPVCUID, err = gatherClusterInfo(namespace, clusterName) Expect(err).ToNot(HaveOccurred()) @@ -284,7 +308,7 @@ var _ = Describe("Rolling updates", Label(tests.LabelPostgresConfiguration), fun }) } - Context("Three Instances", func() { + FContext("Three Instances", func() { const namespacePrefix = "cluster-rolling-e2e-three-instances" const sampleFile = fixturesDir + "/rolling_updates/cluster-three-instances.yaml.template" const clusterName = "postgresql-three-instances"