Skip to content

Commit cf14642

Browse files
committed
feat: remove reference validation
1 parent 975b0a0 commit cf14642

32 files changed

Lines changed: 412 additions & 2038 deletions

stackgres-k8s/src/common/src/main/java/io/stackgres/common/ErrorType.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ public enum ErrorType {
1818
POOL_CONFIG_BLOCKLIST("pooling-blocklist",
1919
"The pgbouncer configuration contains blocklisted parameters"),
2020
PG_VERSION_MISMATCH("postgres-major-version-mismatch", "Postgres versions doesn't match"),
21-
INVALID_CR_REFERENCE("invalid-configuration-reference",
22-
"Invalid configuration reference"),
2321
DEFAULT_CONFIGURATION("default-configuration",
2422
"Default configurations cannot be altered"),
2523
FORBIDDEN_CR_DELETION("forbidden-configuration-deletion",
@@ -28,16 +26,14 @@ public enum ErrorType {
2826
"Forbidden configuration update"),
2927
FORBIDDEN_CR_CREATION("forbidden-configuration-creation",
3028
"Forbidden configuration creation"),
29+
FORBIDDEN_CLUSTER_CREATE("forbidden-cluster-create",
30+
"Forbidden cluster create"),
3131
FORBIDDEN_CLUSTER_UPDATE("forbidden-cluster-update",
3232
"Forbidden cluster update"),
3333
FORBIDDEN_STREAM_UPDATE("forbidden-stream-update",
3434
"Forbidden stream update"),
3535
FORBIDDEN_AUTHORIZATION("forbidden-authorization",
3636
"Forbidden API role-based access control"),
37-
INVALID_STORAGE_CLASS("invalid-storage-class",
38-
"Invalid storage class"),
39-
INVALID_SECRET("invalid-secret",
40-
"Invalid secret"),
4137
EXTENSION_NOT_FOUND("extension-not-found",
4238
"Extension not found"),
4339
PG_CONFIG_PARAMETER("postgres-parameter",

stackgres-k8s/src/operator/src/main/java/io/stackgres/operator/conciliation/backup/BackupRequiredResourcesGenerator.java

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import java.util.Collection;
99
import java.util.List;
10-
import java.util.Objects;
1110
import java.util.Optional;
1211
import java.util.Set;
1312
import java.util.function.Function;
@@ -78,9 +77,10 @@ public List<HasMetadata> getRequiredResources(StackGresBackup config) {
7877
final String clusterNamespace = StackGresUtil.getNamespaceFromRelativeId(
7978
spec.getSgCluster(), backupNamespace);
8079

81-
final Optional<StackGresCluster> cluster = clusterFinder
80+
final Optional<StackGresCluster> foundCluster = clusterFinder
8281
.findByNameAndNamespace(clusterName, clusterNamespace);
83-
final Optional<StackGresProfile> profile = cluster
82+
83+
final Optional<StackGresProfile> foundProfile = foundCluster
8484
.map(StackGresCluster::getSpec)
8585
.map(StackGresClusterSpec::getSgInstanceProfile)
8686
.flatMap(profileName -> profileFinder
@@ -90,47 +90,51 @@ public List<HasMetadata> getRequiredResources(StackGresBackup config) {
9090

9191
var contextBuilder = ImmutableStackGresBackupContext.builder()
9292
.source(config)
93-
.foundCluster(cluster)
94-
.foundProfile(profile)
93+
.foundCluster(foundCluster)
94+
.foundProfile(foundProfile)
9595
.clusterBackupNamespaces(clusterBackupNamespaces);
9696

97-
if (cluster.isPresent()
98-
&& isBackupInTheSameSgClusterNamespace(config, clusterNamespace)
97+
if (clusterNamespace.equals(backupNamespace)
9998
&& !isBackupFinished(config)) {
100-
final var specConfiguration = cluster
99+
if (foundCluster.isEmpty()) {
100+
throw new IllegalArgumentException(
101+
StackGresCluster.KIND + " " + clusterName + " was not found");
102+
}
103+
104+
if (foundProfile.isEmpty()) {
105+
throw new IllegalArgumentException(
106+
StackGresProfile.KIND + " " + foundCluster.get().getSpec().getSgInstanceProfile() + " was not found");
107+
}
108+
109+
final var specConfiguration = foundCluster
101110
.map(StackGresCluster::getSpec)
102111
.map(StackGresClusterSpec::getConfigurations);
103112

104-
final Optional<String> sgObjectStorageName = specConfiguration
113+
final var sgObjectStorageName = specConfiguration
105114
.map(StackGresClusterConfigurations::getBackups)
106115
.map(Collection::stream)
107116
.flatMap(Stream::findFirst)
108117
.map(StackGresClusterBackupConfiguration::getSgObjectStorage);
109118

110119
if (sgObjectStorageName.isEmpty()) {
111120
throw new IllegalArgumentException(
112-
"SGBackup " + backupNamespace + "." + backupName
113-
+ " target SGCluster " + spec.getSgCluster()
114-
+ " without an SGObjectStorage");
121+
StackGresBackup.KIND + " " + backupNamespace + "." + backupName
122+
+ " target " + StackGresCluster.KIND + " " + spec.getSgCluster()
123+
+ " without an " + StackGresObjectStorage.KIND);
115124
}
116125

117126
sgObjectStorageName.ifPresent(objectStorageName -> contextBuilder.objectStorage(
118127
objectStorageFinder.findByNameAndNamespace(objectStorageName, backupNamespace)
119128
.orElseThrow(
120129
() -> new IllegalArgumentException(
121-
"SGBackup " + backupNamespace + "." + backupName
122-
+ " target SGCluster " + spec.getSgCluster()
123-
+ " with a non existent SGObjectStorage " + objectStorageName))));
130+
StackGresBackup.KIND + " " + backupNamespace + "." + backupName
131+
+ " target " + StackGresBackup.KIND + " " + spec.getSgCluster()
132+
+ " with a non existent " + StackGresObjectStorage.KIND + " " + objectStorageName))));
124133
}
125134

126135
return discoverer.generateResources(contextBuilder.build());
127136
}
128137

129-
private boolean isBackupInTheSameSgClusterNamespace(
130-
StackGresBackup backup, String clusterNamespace) {
131-
return Objects.equals(backup.getMetadata().getNamespace(), clusterNamespace);
132-
}
133-
134138
private boolean isBackupFinished(StackGresBackup backup) {
135139
return Optional.of(backup)
136140
.map(StackGresBackup::getStatus)

stackgres-k8s/src/operator/src/main/java/io/stackgres/operator/conciliation/dbops/DbOpsRequiredResourcesGenerator.java

Lines changed: 136 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,27 @@
55

66
package io.stackgres.operator.conciliation.dbops;
77

8+
import static io.stackgres.common.StackGresUtil.getPostgresFlavorComponent;
9+
810
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Objects;
913
import java.util.Optional;
14+
import java.util.function.Function;
15+
import java.util.stream.Stream;
1016

17+
import com.google.common.collect.ImmutableMap;
1118
import io.fabric8.kubernetes.api.model.HasMetadata;
1219
import io.fabric8.kubernetes.api.model.ObjectMeta;
20+
import io.fabric8.kubernetes.api.model.OwnerReference;
21+
import io.stackgres.common.DbOpsUtil;
22+
import io.stackgres.common.StackGresComponent;
23+
import io.stackgres.common.StackGresVersion;
1324
import io.stackgres.common.crd.sgcluster.StackGresCluster;
25+
import io.stackgres.common.crd.sgcluster.StackGresClusterDbOpsMajorVersionUpgradeStatus;
26+
import io.stackgres.common.crd.sgcluster.StackGresClusterDbOpsStatus;
1427
import io.stackgres.common.crd.sgcluster.StackGresClusterSpec;
28+
import io.stackgres.common.crd.sgcluster.StackGresClusterStatus;
1529
import io.stackgres.common.crd.sgconfig.StackGresConfig;
1630
import io.stackgres.common.crd.sgdbops.StackGresDbOps;
1731
import io.stackgres.common.crd.sgdbops.StackGresDbOpsBenchmark;
@@ -20,13 +34,17 @@
2034
import io.stackgres.common.crd.sgdbops.StackGresDbOpsSamplingStatus;
2135
import io.stackgres.common.crd.sgdbops.StackGresDbOpsSpec;
2236
import io.stackgres.common.crd.sgdbops.StackGresDbOpsStatus;
37+
import io.stackgres.common.crd.sgdistributedlogs.StackGresDistributedLogs;
38+
import io.stackgres.common.crd.sgpgconfig.StackGresPostgresConfig;
2339
import io.stackgres.common.crd.sgprofile.StackGresProfile;
2440
import io.stackgres.common.resource.CustomResourceFinder;
2541
import io.stackgres.common.resource.CustomResourceScanner;
2642
import io.stackgres.operator.conciliation.RequiredResourceGenerator;
2743
import io.stackgres.operator.conciliation.ResourceGenerationDiscoverer;
2844
import jakarta.enterprise.context.ApplicationScoped;
2945
import jakarta.inject.Inject;
46+
import org.jooq.lambda.Seq;
47+
import org.jooq.lambda.tuple.Tuple2;
3048
import org.slf4j.Logger;
3149
import org.slf4j.LoggerFactory;
3250

@@ -37,10 +55,21 @@ public class DbOpsRequiredResourcesGenerator
3755
protected static final Logger LOGGER = LoggerFactory
3856
.getLogger(DbOpsRequiredResourcesGenerator.class);
3957

58+
private final Map<StackGresComponent, Map<StackGresVersion, List<String>>> supportedPostgresVersions =
59+
Stream.of(StackGresComponent.POSTGRESQL, StackGresComponent.BABELFISH)
60+
.collect(ImmutableMap.toImmutableMap(Function.identity(),
61+
component -> component.getComponentVersions()
62+
.entrySet()
63+
.stream()
64+
.collect(ImmutableMap.toImmutableMap(Map.Entry::getKey,
65+
entry -> entry.getValue().streamOrderedVersions().toList()))));
66+
4067
private final CustomResourceScanner<StackGresConfig> configScanner;
4168

4269
private final CustomResourceFinder<StackGresCluster> clusterFinder;
4370

71+
private final CustomResourceFinder<StackGresPostgresConfig> postgresConfigFinder;
72+
4473
private final CustomResourceFinder<StackGresProfile> profileFinder;
4574

4675
private final CustomResourceFinder<StackGresDbOps> dbOpsFinder;
@@ -51,11 +80,13 @@ public class DbOpsRequiredResourcesGenerator
5180
public DbOpsRequiredResourcesGenerator(
5281
CustomResourceScanner<StackGresConfig> configScanner,
5382
CustomResourceFinder<StackGresCluster> clusterFinder,
83+
CustomResourceFinder<StackGresPostgresConfig> postgresConfigFinder,
5484
CustomResourceFinder<StackGresProfile> profileFinder,
5585
CustomResourceFinder<StackGresDbOps> dbOpsFinder,
5686
ResourceGenerationDiscoverer<StackGresDbOpsContext> discoverer) {
5787
this.configScanner = configScanner;
5888
this.clusterFinder = clusterFinder;
89+
this.postgresConfigFinder = postgresConfigFinder;
5990
this.profileFinder = profileFinder;
6091
this.dbOpsFinder = dbOpsFinder;
6192
this.discoverer = discoverer;
@@ -74,15 +105,107 @@ public List<HasMetadata> getRequiredResources(StackGresDbOps dbOps) {
74105
.orElseThrow(() -> new IllegalArgumentException(
75106
"SGConfig not found or more than one exists. Aborting reoconciliation!"));
76107

77-
final StackGresDbOpsSpec spec = dbOps.getSpec();
78-
final Optional<StackGresCluster> cluster = clusterFinder
79-
.findByNameAndNamespace(spec.getSgCluster(), dbOpsNamespace);
108+
final String clusterName = dbOps.getSpec().getSgCluster();
109+
final Optional<StackGresCluster> foundCluster = clusterFinder
110+
.findByNameAndNamespace(clusterName, dbOpsNamespace);
80111

81-
final Optional<StackGresProfile> profile = cluster
112+
final Optional<StackGresProfile> foundProfile = foundCluster
82113
.map(StackGresCluster::getSpec)
83114
.map(StackGresClusterSpec::getSgInstanceProfile)
84115
.flatMap(profileName -> profileFinder
85116
.findByNameAndNamespace(profileName, dbOpsNamespace));
117+
if (!DbOpsUtil.isAlreadyCompleted(dbOps)) {
118+
if (foundCluster.isEmpty()) {
119+
throw new IllegalArgumentException(
120+
StackGresCluster.KIND + " " + clusterName + " was not found");
121+
}
122+
final StackGresCluster cluster = foundCluster.get();
123+
124+
if (foundProfile.isEmpty()) {
125+
throw new IllegalArgumentException(
126+
StackGresProfile.KIND + " " + foundCluster.get().getSpec().getSgInstanceProfile() + " was not found");
127+
}
128+
129+
if (dbOps.getSpec().isOpMajorVersionUpgrade()) {
130+
var foundOwnerReference = Optional.of(cluster)
131+
.map(StackGresCluster::getMetadata)
132+
.map(ObjectMeta::getOwnerReferences)
133+
.stream()
134+
.flatMap(List::stream)
135+
.filter(ownerReference -> !Objects.equals(
136+
ownerReference.getKind(),
137+
HasMetadata.getKind(StackGresDistributedLogs.class)))
138+
.filter(ownerReference -> ownerReference.getController() != null
139+
&& ownerReference.getController())
140+
.findFirst();
141+
if (foundOwnerReference.isPresent()) {
142+
OwnerReference ownerReference = foundOwnerReference.get();
143+
throw new IllegalArgumentException(
144+
"Can not perform major version upgrade on " + StackGresCluster.KIND + " managed by "
145+
+ ownerReference.getKind() + " " + ownerReference.getName());
146+
}
147+
148+
final String givenPgVersion = dbOps.getSpec().getMajorVersionUpgrade().getPostgresVersion();
149+
if (givenPgVersion != null
150+
&& !isPostgresVersionSupported(cluster, givenPgVersion)) {
151+
final String message = "Unsupported postgres version " + givenPgVersion
152+
+ ". Supported postgres versions are: "
153+
+ Seq.seq(supportedPostgresVersions.get(getPostgresFlavorComponent(cluster))
154+
.get(StackGresVersion.getStackGresVersion(cluster))).toString(", ");
155+
throw new IllegalArgumentException(message);
156+
}
157+
158+
String givenMajorVersion = getPostgresFlavorComponent(cluster)
159+
.get(cluster).getMajorVersion(givenPgVersion);
160+
long givenMajorVersionIndex = getPostgresFlavorComponent(cluster)
161+
.get(cluster)
162+
.streamOrderedMajorVersions()
163+
.zipWithIndex()
164+
.filter(t -> t.v1.equals(givenMajorVersion))
165+
.map(Tuple2::v2)
166+
.findAny()
167+
.orElseThrow();
168+
String oldPgVersion = Optional.ofNullable(cluster.getStatus())
169+
.map(StackGresClusterStatus::getDbOps)
170+
.map(StackGresClusterDbOpsStatus::getMajorVersionUpgrade)
171+
.map(StackGresClusterDbOpsMajorVersionUpgradeStatus::getSourcePostgresVersion)
172+
.orElse(cluster.getSpec().getPostgres().getVersion());
173+
String oldMajorVersion = getPostgresFlavorComponent(cluster)
174+
.get(cluster)
175+
.getMajorVersion(oldPgVersion);
176+
long oldMajorVersionIndex = getPostgresFlavorComponent(cluster)
177+
.get(cluster)
178+
.streamOrderedMajorVersions()
179+
.zipWithIndex()
180+
.filter(t -> t.v1.equals(oldMajorVersion))
181+
.map(Tuple2::v2)
182+
.findAny()
183+
.orElseThrow();
184+
185+
if (givenMajorVersionIndex >= oldMajorVersionIndex) {
186+
throw new IllegalArgumentException(
187+
"postgres version must be a newer major version than the current one ("
188+
+ givenMajorVersion + " < " + oldMajorVersion + ")");
189+
}
190+
191+
Optional<StackGresPostgresConfig> postgresConfig = postgresConfigFinder
192+
.findByNameAndNamespace(
193+
dbOps.getSpec().getMajorVersionUpgrade().getSgPostgresConfig(),
194+
dbOps.getMetadata().getNamespace());
195+
if (postgresConfig.isPresent()) {
196+
if (!postgresConfig.get().getSpec().getPostgresVersion().equals(givenMajorVersion)) {
197+
throw new IllegalArgumentException(
198+
StackGresPostgresConfig.KIND + " must be for postgres version "
199+
+ givenMajorVersion + " but was for version "
200+
+ postgresConfig.get().getSpec().getPostgresVersion());
201+
}
202+
} else {
203+
throw new IllegalArgumentException(
204+
StackGresPostgresConfig.KIND + " "
205+
+ dbOps.getSpec().getMajorVersionUpgrade().getSgPostgresConfig() + " not found");
206+
}
207+
}
208+
}
86209

87210
final Optional<StackGresDbOpsSamplingStatus> samplingStatus = Optional.of(dbOps.getSpec())
88211
.map(StackGresDbOpsSpec::getBenchmark)
@@ -94,18 +217,24 @@ public List<HasMetadata> getRequiredResources(StackGresDbOps dbOps) {
94217
.map(StackGresDbOpsStatus::getBenchmark)
95218
.map(StackGresDbOpsBenchmarkStatus::getSampling)
96219
.orElseThrow(() -> new IllegalArgumentException(
97-
"SGDbOps " + samplingDbOpsName
220+
StackGresDbOps.KIND + " " + samplingDbOpsName
98221
+ " was not found or has no has no sampling status")));
99222

100223
StackGresDbOpsContext context = ImmutableStackGresDbOpsContext.builder()
101224
.config(config)
102225
.source(dbOps)
103-
.foundCluster(cluster)
104-
.foundProfile(profile)
226+
.foundCluster(foundCluster)
227+
.foundProfile(foundProfile)
105228
.samplingStatus(samplingStatus)
106229
.build();
107230

108231
return discoverer.generateResources(context);
109232
}
110233

234+
private boolean isPostgresVersionSupported(StackGresCluster cluster, String version) {
235+
return supportedPostgresVersions.get(getPostgresFlavorComponent(cluster))
236+
.get(StackGresVersion.getStackGresVersion(cluster))
237+
.contains(version);
238+
}
239+
111240
}

0 commit comments

Comments
 (0)