Skip to content

Commit 29cb15d

Browse files
authored
Add v1 version (#4198)
- Add kubebuilder markers to v1beta1 to mark as storage version - Add v1 files for changed version (postgrescluster) - Add rule to disallow userInterface - Add v1 conversion test, runtime scheme - Add a helper for kube version tests - Remove ref to webhook in v1beta1 Issues: [PGO-2524]
1 parent 82909e9 commit 29cb15d

File tree

12 files changed

+20275
-9
lines changed

12 files changed

+20275
-9
lines changed

config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml

Lines changed: 18631 additions & 0 deletions
Large diffs are not rendered by default.

internal/controller/runtime/runtime.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"sigs.k8s.io/controller-runtime/pkg/manager"
1616

1717
"github.com/crunchydata/postgres-operator/internal/logging"
18+
v1 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1"
1819
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
1920
)
2021

@@ -34,6 +35,9 @@ func init() {
3435
if err := v1beta1.AddToScheme(Scheme); err != nil {
3536
panic(err)
3637
}
38+
if err := v1.AddToScheme(Scheme); err != nil {
39+
panic(err)
40+
}
3741
if err := volumesnapshotv1.AddToScheme(Scheme); err != nil {
3842
panic(err)
3943
}

internal/testing/require/kubernetes.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import (
1515
"golang.org/x/tools/go/packages"
1616
"gotest.tools/v3/assert"
1717
corev1 "k8s.io/api/core/v1"
18+
"k8s.io/apimachinery/pkg/util/version"
19+
"k8s.io/client-go/discovery"
1820
"k8s.io/client-go/rest"
1921
"sigs.k8s.io/controller-runtime/pkg/client"
2022
"sigs.k8s.io/controller-runtime/pkg/envtest"
@@ -73,6 +75,34 @@ func Kubernetes(t TestingT) client.Client {
7375
return cc
7476
}
7577

78+
// KubernetesAtLeast is the same as [Kubernetes] but also calls t.Skip when
79+
// the connected Kubernetes API is earlier than minVersion, like "1.28" or "1.27.7".
80+
func KubernetesAtLeast(t TestingT, minVersion string) client.Client {
81+
t.Helper()
82+
83+
expectedVersion, err := version.ParseGeneric(minVersion)
84+
assert.NilError(t, err)
85+
86+
// Start or connect to Kubernetes
87+
env, cc := kubernetes3(t)
88+
89+
dc, err := discovery.NewDiscoveryClientForConfig(env.Config)
90+
assert.NilError(t, err)
91+
92+
serverInfo, err := dc.ServerVersion()
93+
assert.NilError(t, err)
94+
95+
serverVersion, err := version.ParseGeneric(serverInfo.GitVersion)
96+
assert.NilError(t, err)
97+
98+
if serverVersion.LessThan(expectedVersion) {
99+
t.Log("Kubernetes version", serverVersion, "is before", expectedVersion)
100+
t.SkipNow()
101+
}
102+
103+
return cc
104+
}
105+
76106
// Kubernetes2 is the same as [Kubernetes] but also returns a copy of the client
77107
// configuration.
78108
func Kubernetes2(t TestingT) (*rest.Config, client.Client) {

internal/testing/validation/postgrescluster_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/crunchydata/postgres-operator/internal/controller/runtime"
1919
"github.com/crunchydata/postgres-operator/internal/testing/cmp"
2020
"github.com/crunchydata/postgres-operator/internal/testing/require"
21+
v1 "github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1"
2122
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
2223
)
2324

@@ -519,3 +520,101 @@ func TestPostgresUserOptions(t *testing.T) {
519520
assert.NilError(t, cc.Create(ctx, cluster, client.DryRunAll))
520521
})
521522
}
523+
524+
func TestPostgresUserInterfaceAcrossVersions(t *testing.T) {
525+
ctx := context.Background()
526+
cc := require.Kubernetes(t)
527+
t.Parallel()
528+
529+
namespace := require.Namespace(t, cc)
530+
531+
base := v1beta1.NewPostgresCluster()
532+
// Start with a bunch of required fields.
533+
base.Namespace = namespace.Name
534+
base.Name = "postgres-pgadmin"
535+
require.UnmarshalInto(t, &base.Spec, `{
536+
userInterface: {
537+
pgAdmin: {
538+
dataVolumeClaimSpec: {
539+
accessModes: [ReadWriteOnce],
540+
resources: { requests: { storage: 1Mi } },
541+
},
542+
},
543+
},
544+
postgresVersion: 16,
545+
backups: {
546+
pgbackrest: {
547+
repos: [{ name: repo1 }],
548+
},
549+
},
550+
instances: [{
551+
dataVolumeClaimSpec: {
552+
accessModes: [ReadWriteOnce],
553+
resources: { requests: { storage: 1Mi } },
554+
},
555+
}],
556+
}`)
557+
558+
v1base := v1.NewPostgresCluster()
559+
// Start with a bunch of required fields.
560+
v1base.Namespace = namespace.Name
561+
v1base.Name = "postgres-pgadmin"
562+
require.UnmarshalInto(t, &v1base.Spec, `{
563+
userInterface: {
564+
pgAdmin: {
565+
dataVolumeClaimSpec: {
566+
accessModes: [ReadWriteOnce],
567+
resources: { requests: { storage: 1Mi } },
568+
},
569+
},
570+
},
571+
postgresVersion: 16,
572+
backups: {
573+
pgbackrest: {
574+
repos: [{ name: repo1 }],
575+
},
576+
},
577+
instances: [{
578+
dataVolumeClaimSpec: {
579+
accessModes: [ReadWriteOnce],
580+
resources: { requests: { storage: 1Mi } },
581+
},
582+
}],
583+
}`)
584+
585+
t.Run("v1beta1 is valid with pgadmin", func(t *testing.T) {
586+
assert.NilError(t, cc.Create(ctx, base.DeepCopy(), client.DryRunAll),
587+
"expected this base cluster to be valid")
588+
})
589+
t.Run("v1 is invalid with pgadmin", func(t *testing.T) {
590+
assert.ErrorContains(t, cc.Create(ctx, v1base.DeepCopy(), client.DryRunAll),
591+
"userInterface not available in v1")
592+
})
593+
594+
t.Run("v1 is valid with pgadmin but only if unchanged from v1beta1", func(t *testing.T) {
595+
// Validation ratcheting is enabled starting in Kubernetes 1.30
596+
require.KubernetesAtLeast(t, "1.30")
597+
598+
// A v1 that has been updated from a v1beta1 with no change to the userInterface is valid
599+
assert.NilError(t, cc.Create(ctx, base),
600+
"expected this base cluster to be valid")
601+
v1base.ResourceVersion = base.ResourceVersion
602+
assert.NilError(t, cc.Update(ctx, v1base),
603+
"expected this v1 cluster to be a valid update")
604+
605+
// But will not be valid if there's a change to the userInterface
606+
require.UnmarshalInto(t, &v1base.Spec, `{
607+
userInterface: {
608+
pgAdmin: {
609+
dataVolumeClaimSpec: {
610+
accessModes: [ReadWriteOnce, ReadWriteMany],
611+
resources: { requests: { storage: 2Mi } },
612+
},
613+
},
614+
},
615+
}`)
616+
617+
assert.ErrorContains(t, cc.Update(ctx, v1base),
618+
"userInterface not available in v1")
619+
})
620+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2021 - 2025 Crunchy Data Solutions, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
// package v1 contains API Schema definitions for the postgres-operator v1beta1 API group
6+
// +kubebuilder:object:generate=true
7+
// +groupName=postgres-operator.crunchydata.com
8+
package v1
9+
10+
import (
11+
"k8s.io/apimachinery/pkg/runtime/schema"
12+
"sigs.k8s.io/controller-runtime/pkg/scheme"
13+
)
14+
15+
var (
16+
// GroupVersion is group version used to register these objects
17+
GroupVersion = schema.GroupVersion{Group: "postgres-operator.crunchydata.com", Version: "v1"}
18+
19+
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
20+
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
21+
22+
// AddToScheme adds the types in this group-version to the given scheme.
23+
AddToScheme = SchemeBuilder.AddToScheme
24+
)

0 commit comments

Comments
 (0)