Skip to content

Commit aa01e3d

Browse files
committed
refactor: improve testability of context construction
1 parent b933bd7 commit aa01e3d

46 files changed

Lines changed: 4553 additions & 3531 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright (C) 2019 OnGres, Inc.
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
package io.stackgres.operator.conciliation;
7+
8+
public abstract class ContextAppender<C, T> {
9+
10+
protected abstract void appendContext(C inputContext, T contextBuilder);
11+
12+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (C) 2019 OnGres, Inc.
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
package io.stackgres.operator.conciliation;
7+
8+
import java.util.List;
9+
10+
import io.stackgres.common.CdiUtil;
11+
import jakarta.enterprise.inject.Instance;
12+
13+
public abstract class ContextFactory<C, B> {
14+
15+
private final List<ContextAppender<C, B>> contextAppenders;
16+
17+
protected ContextFactory(Instance<ContextAppender<C, B>> contextAppenders) {
18+
this.contextAppenders = contextAppenders
19+
.stream()
20+
.toList();
21+
}
22+
23+
protected ContextFactory() {
24+
CdiUtil.checkPublicNoArgsConstructorIsCalledToCreateProxy(getClass());
25+
this.contextAppenders = null;
26+
}
27+
28+
public void appendContext(C context, B contextBuilder) {
29+
contextAppenders.forEach(contextAppender -> {
30+
contextAppender.appendContext(context, contextBuilder);
31+
});
32+
}
33+
34+
}

stackgres-k8s/src/operator/src/main/java/io/stackgres/operator/conciliation/RequiredResourceGenerator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@
1313
public interface RequiredResourceGenerator<T extends CustomResource<?, ?>> {
1414

1515
List<HasMetadata> getRequiredResources(T config);
16+
1617
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ && isBackupInTheSameSgClusterNamespace(config, clusterNamespace)
114114
+ " without an SGObjectStorage");
115115
}
116116

117-
sgObjectStorageName.ifPresent(osName -> contextBuilder.objectStorage(
118-
objectStorageFinder.findByNameAndNamespace(osName, backupNamespace)
117+
sgObjectStorageName.ifPresent(objectStorageName -> contextBuilder.objectStorage(
118+
objectStorageFinder.findByNameAndNamespace(objectStorageName, backupNamespace)
119119
.orElseThrow(
120120
() -> new IllegalArgumentException(
121121
"SGBackup " + backupNamespace + "." + backupName
122122
+ " target SGCluster " + spec.getSgCluster()
123-
+ " with a non existent SGObjectStorage " + osName))));
123+
+ " with a non existent SGObjectStorage " + objectStorageName))));
124124
}
125125

126126
return discoverer.generateResources(contextBuilder.build());

stackgres-k8s/src/operator/src/main/java/io/stackgres/operator/conciliation/cluster/ClusterRequiredResourcesGenerator.java

Lines changed: 9 additions & 909 deletions
Large diffs are not rendered by default.

stackgres-k8s/src/operator/src/main/java/io/stackgres/operator/conciliation/cluster/StackGresClusterContext.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@
4848
public interface StackGresClusterContext extends GenerationContext<StackGresCluster>,
4949
ClusterContext {
5050

51+
public static class Builder extends ImmutableStackGresClusterContext.Builder {
52+
}
53+
54+
public static Builder builder() {
55+
return new Builder();
56+
}
57+
5158
StackGresConfig getConfig();
5259

5360
Optional<VersionInfo> getKubernetesVersion();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (C) 2019 OnGres, Inc.
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
package io.stackgres.operator.conciliation.cluster.context;
7+
8+
import java.util.Optional;
9+
import java.util.Set;
10+
import java.util.function.Function;
11+
import java.util.function.Predicate;
12+
import java.util.stream.Collectors;
13+
14+
import io.fabric8.kubernetes.api.model.ObjectMeta;
15+
import io.stackgres.common.StackGresUtil;
16+
import io.stackgres.common.crd.sgbackup.StackGresBackup;
17+
import io.stackgres.common.crd.sgbackup.StackGresBackupSpec;
18+
import io.stackgres.common.crd.sgcluster.StackGresCluster;
19+
import io.stackgres.common.resource.CustomResourceScanner;
20+
import io.stackgres.operator.conciliation.ContextAppender;
21+
import io.stackgres.operator.conciliation.cluster.StackGresClusterContext;
22+
import io.stackgres.operator.conciliation.cluster.StackGresClusterContext.Builder;
23+
import jakarta.enterprise.context.ApplicationScoped;
24+
25+
@ApplicationScoped
26+
public class ClusterBackupNamespacesContextAppender
27+
extends ContextAppender<StackGresCluster, StackGresClusterContext.Builder> {
28+
29+
private final CustomResourceScanner<StackGresBackup> backupScanner;
30+
31+
public ClusterBackupNamespacesContextAppender(CustomResourceScanner<StackGresBackup> backupScanner) {
32+
this.backupScanner = backupScanner;
33+
}
34+
35+
@Override
36+
public void appendContext(StackGresCluster cluster, Builder contextBuilder) {
37+
final Set<String> clusterBackupNamespaces = getClusterBackupNamespaces(
38+
cluster.getMetadata().getNamespace());
39+
contextBuilder.clusterBackupNamespaces(clusterBackupNamespaces);
40+
}
41+
42+
private Set<String> getClusterBackupNamespaces(final String clusterNamespace) {
43+
return backupScanner.getResources()
44+
.stream()
45+
.map(Optional::of)
46+
.filter(backup -> backup
47+
.map(StackGresBackup::getSpec)
48+
.map(StackGresBackupSpec::getSgCluster)
49+
.map(StackGresUtil::isRelativeIdNotInSameNamespace)
50+
.orElse(false))
51+
.map(backup -> backup
52+
.map(StackGresBackup::getMetadata)
53+
.map(ObjectMeta::getNamespace))
54+
.flatMap(Optional::stream)
55+
.filter(Predicate.not(clusterNamespace::equals))
56+
.collect(Collectors.groupingBy(Function.identity()))
57+
.keySet();
58+
}
59+
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (C) 2019 OnGres, Inc.
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
package io.stackgres.operator.conciliation.cluster.context;
7+
8+
import java.util.List;
9+
10+
import io.stackgres.common.crd.sgcluster.StackGresCluster;
11+
import io.stackgres.common.crd.sgconfig.StackGresConfig;
12+
import io.stackgres.common.resource.CustomResourceScanner;
13+
import io.stackgres.operator.conciliation.ContextAppender;
14+
import io.stackgres.operator.conciliation.cluster.StackGresClusterContext;
15+
import io.stackgres.operator.conciliation.cluster.StackGresClusterContext.Builder;
16+
import jakarta.enterprise.context.ApplicationScoped;
17+
18+
@ApplicationScoped
19+
public class ClusterConfigContextAppender
20+
extends ContextAppender<StackGresCluster, StackGresClusterContext.Builder> {
21+
22+
private final CustomResourceScanner<StackGresConfig> configScanner;
23+
24+
public ClusterConfigContextAppender(CustomResourceScanner<StackGresConfig> configScanner) {
25+
this.configScanner = configScanner;
26+
}
27+
28+
@Override
29+
public void appendContext(StackGresCluster cluster, Builder contextBuilder) {
30+
final StackGresConfig config = configScanner.findResources()
31+
.stream()
32+
.filter(list -> list.size() == 1)
33+
.flatMap(List::stream)
34+
.findAny()
35+
.orElseThrow(() -> new IllegalArgumentException(
36+
"SGConfig not found or more than one exists. Aborting reoconciliation!"));
37+
contextBuilder.config(config);
38+
}
39+
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright (C) 2019 OnGres, Inc.
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
package io.stackgres.operator.conciliation.cluster.context;
7+
8+
import java.util.Optional;
9+
import java.util.function.Function;
10+
11+
import io.fabric8.kubernetes.api.model.Secret;
12+
import io.stackgres.common.CdiUtil;
13+
import io.stackgres.common.crd.SecretKeySelector;
14+
import io.stackgres.common.crd.sgcluster.StackGresCluster;
15+
import io.stackgres.common.resource.ResourceFinder;
16+
import io.stackgres.operator.conciliation.ContextAppender;
17+
import io.stackgres.operator.conciliation.cluster.StackGresClusterContext;
18+
import io.stackgres.operatorframework.resource.ResourceUtil;
19+
20+
public abstract class ClusterContextAppenderWithSecrets
21+
extends ContextAppender<StackGresCluster, StackGresClusterContext.Builder> {
22+
23+
private final ResourceFinder<Secret> secretFinder;
24+
25+
public ClusterContextAppenderWithSecrets(
26+
ResourceFinder<Secret> secretFinder) {
27+
this.secretFinder = secretFinder;
28+
}
29+
30+
public ClusterContextAppenderWithSecrets() {
31+
CdiUtil.checkPublicNoArgsConstructorIsCalledToCreateProxy(getClass());
32+
this.secretFinder = null;
33+
}
34+
35+
protected <T, S> Optional<String> getSecretAndKeyOrThrow(
36+
final String clusterNamespace,
37+
final Optional<T> secretSection,
38+
final Function<T, S> secretKeyRefGetter,
39+
final Function<S, SecretKeySelector> secretKeySelectorGetter,
40+
final Function<SecretKeySelector, String> onKeyNotFoundMessageGetter,
41+
final Function<SecretKeySelector, String> onSecretNotFoundMessageGetter) {
42+
return secretSection
43+
.map(secretKeyRefGetter)
44+
.map(secretKeySelectorGetter)
45+
.map(secretKeySelector -> secretFinder
46+
.findByNameAndNamespace(secretKeySelector.getName(), clusterNamespace)
47+
.flatMap(secret -> getSecretKeyOrThrow(secret, secretKeySelector.getKey(),
48+
onKeyNotFoundMessageGetter.apply(secretKeySelector)))
49+
.orElseThrow(() -> new IllegalArgumentException(
50+
onSecretNotFoundMessageGetter.apply(secretKeySelector))));
51+
}
52+
53+
protected <T> Optional<String> getSecretAndKeyOrThrow(
54+
final String clusterNamespace,
55+
final Optional<T> credential,
56+
final Function<T, SecretKeySelector> secretKeySelectorGetter,
57+
final Function<SecretKeySelector, String> onKeyNotFoundMessageGetter,
58+
final Function<SecretKeySelector, String> onSecretNotFoundMessageGetter) {
59+
return credential
60+
.map(secretKeySelectorGetter)
61+
.map(secretKeySelector -> secretFinder
62+
.findByNameAndNamespace(secretKeySelector.getName(), clusterNamespace)
63+
.flatMap(secret -> getSecretKeyOrThrow(secret, secretKeySelector.getKey(),
64+
onKeyNotFoundMessageGetter.apply(secretKeySelector)))
65+
.orElseThrow(() -> new IllegalArgumentException(
66+
onSecretNotFoundMessageGetter.apply(secretKeySelector))));
67+
}
68+
69+
protected Optional<String> getSecretKeyOrThrow(
70+
final Secret secret,
71+
final String key,
72+
final String onKeyNotFoundMessage) {
73+
return Optional.of(
74+
Optional.of(secret)
75+
.map(Secret::getData)
76+
.map(data -> data.get(key))
77+
.map(ResourceUtil::decodeSecret)
78+
.orElseThrow(() -> new IllegalArgumentException(onKeyNotFoundMessage)));
79+
}
80+
81+
protected <T> Optional<String> getSecretAndKey(
82+
final String clusterNamespace,
83+
final Optional<T> credential,
84+
final Function<T, SecretKeySelector> secretKeySelectorGetter) {
85+
return credential
86+
.map(secretKeySelectorGetter)
87+
.flatMap(secretKeySelector -> secretFinder
88+
.findByNameAndNamespace(secretKeySelector.getName(), clusterNamespace)
89+
.flatMap(secret -> getSecretKey(secret, secretKeySelector.getKey())));
90+
}
91+
92+
protected Optional<String> getSecretKey(
93+
final Secret secret,
94+
final String key) {
95+
return Optional.of(secret)
96+
.map(Secret::getData)
97+
.map(data -> data.get(key))
98+
.map(ResourceUtil::decodeSecret);
99+
}
100+
101+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (C) 2019 OnGres, Inc.
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
package io.stackgres.operator.conciliation.cluster.context;
7+
8+
import io.stackgres.common.crd.sgcluster.StackGresCluster;
9+
import io.stackgres.operator.conciliation.ContextAppender;
10+
import io.stackgres.operator.conciliation.ContextFactory;
11+
import io.stackgres.operator.conciliation.cluster.StackGresClusterContext;
12+
import io.stackgres.operator.conciliation.cluster.StackGresClusterContext.Builder;
13+
import jakarta.enterprise.context.ApplicationScoped;
14+
import jakarta.enterprise.inject.Instance;
15+
16+
@ApplicationScoped
17+
public class ClusterContextFactory
18+
extends ContextFactory<StackGresCluster, StackGresClusterContext.Builder> {
19+
20+
public ClusterContextFactory(Instance<ContextAppender<StackGresCluster, Builder>> contextAppenders) {
21+
super(contextAppenders);
22+
}
23+
24+
}

0 commit comments

Comments
 (0)