Skip to content

Commit

Permalink
Save changes
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosthe19916 committed Oct 10, 2024
1 parent 54aeb29 commit 3e2a4f7
Show file tree
Hide file tree
Showing 17 changed files with 737 additions and 51 deletions.
13 changes: 12 additions & 1 deletion src/main/java/org/trustify/operator/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class Constants {
public static final String TRUSTI_SERVER_NAME = "trustify-server";
public static final String TRUSTI_DB_NAME = "trustify-db";

public static final String OIDC_DB_NAME = "oidc-db";

//
public static final Map<String, String> DB_SELECTOR_LABELS = Map.of(
"trustify-operator/group", "db"
Expand All @@ -21,6 +23,10 @@ public class Constants {
"trustify-operator/group", "server"
);

public static final Map<String, String> OIDC_DB_SELECTOR_LABELS = Map.of(
"trustify-operator/group", "oidc"
);

//
public static final Integer HTTP_PORT = 8080;
public static final Integer HTTPS_PORT = 8443;
Expand All @@ -33,6 +39,11 @@ public class Constants {
public static final String DB_DEPLOYMENT_SUFFIX = "-" + TRUSTI_DB_NAME + "-deployment";
public static final String DB_SERVICE_SUFFIX = "-" + TRUSTI_DB_NAME + "-service";

public static final String OIDC_DB_PVC_SUFFIX = "-" + OIDC_DB_NAME + "-pvc";
public static final String OIDC_DB_SECRET_SUFFIX = "-" + OIDC_DB_NAME + "-secret";
public static final String OIDC_DB_DEPLOYMENT_SUFFIX = "-" + OIDC_DB_NAME + "-deployment";
public static final String OIDC_DB_SERVICE_SUFFIX = "-" + OIDC_DB_NAME + "-service";

public static final String SERVER_DEPLOYMENT_SUFFIX = "-" + TRUSTI_SERVER_NAME + "-deployment";
public static final String SERVER_SERVICE_SUFFIX = "-" + TRUSTI_SERVER_NAME + "-service";

Expand All @@ -42,7 +53,7 @@ public class Constants {
//
public static final String DB_SECRET_USERNAME = "username";
public static final String DB_SECRET_PASSWORD = "password";
public static final String DB_NAME = "trustify";
public static final String DB_NAME = "database";
public static final Integer DB_PORT= 5432;

public static final String POSTGRESQL_PVC_SIZE = "10G";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public record TrustifySpec(
@JsonPropertyDescription("In this section you can configure features related to HTTP and HTTPS")
HttpSpec httpSpec,

@JsonProperty("oidc")
@JsonPropertyDescription("In this section you can configure Oidc settings.")
OidcSpec oidcSpec,

@JsonProperty("serverResourceLimits")
@JsonPropertyDescription("In this section you can configure resource limits settings for the Server.")
ResourcesLimitSpec serverResourceLimitSpec
Expand All @@ -46,6 +50,7 @@ public TrustifySpec() {
null,
null,
null,
null,
null
);
}
Expand Down Expand Up @@ -89,6 +94,20 @@ public record HttpSpec(
) {
}

public record OidcSpec(
@JsonPropertyDescription("Enable Oidc Auth.")
String enabled,
@JsonPropertyDescription("Oidc server url.")
String serverUrl,
@JsonPropertyDescription("Oidc client id.")
String clientId,

@JsonProperty("db")
@JsonPropertyDescription("In this section you can find all properties related to connect to a database.")
DatabaseSpec databaseSpec
) {
}

public record ResourcesLimitSpec(
@JsonPropertyDescription("Requested CPU.")
String cpuRequest,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.trustify.operator.cdrs.v2alpha1.keycloak;

import org.trustify.operator.cdrs.v2alpha1.Trustify;
import org.trustify.operator.cdrs.v2alpha1.TrustifySpec;

import java.util.Optional;

public abstract class KeycloakDBActivationCondition {

protected boolean isMet(Trustify cr) {
return !Optional.ofNullable(cr.getSpec().oidcSpec())
.flatMap(oidcSpec -> Optional.ofNullable(oidcSpec.databaseSpec()))
.map(TrustifySpec.DatabaseSpec::externalDatabase)
.orElse(false);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
package org.trustify.operator.cdrs.v2alpha1.keycloak;

import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.api.model.apps.*;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.processing.dependent.Matcher;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.trustify.operator.Config;
import org.trustify.operator.Constants;
import org.trustify.operator.cdrs.v2alpha1.Trustify;
import org.trustify.operator.cdrs.v2alpha1.TrustifySpec;
import org.trustify.operator.utils.CRDUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@KubernetesDependent(labelSelector = KeycloakDBDeployment.LABEL_SELECTOR, resourceDiscriminator = KeycloakDBDeploymentDiscriminator.class)
@ApplicationScoped
public class KeycloakDBDeployment extends CRUDKubernetesDependentResource<Deployment, Trustify>
implements Matcher<Deployment, Trustify>, Condition<Deployment, Trustify> {

public static final String LABEL_SELECTOR = "app.kubernetes.io/managed-by=trustify-operator,component=oidc";

@Inject
Config config;

public KeycloakDBDeployment() {
super(Deployment.class);
}

@Override
protected Deployment desired(Trustify cr, Context<Trustify> context) {
return newDeployment(cr, context);
}

@Override
public Result<Deployment> match(Deployment actual, Trustify cr, Context<Trustify> context) {
final var container = actual.getSpec()
.getTemplate().getSpec().getContainers()
.stream()
.findFirst();

return Result.nonComputed(container
.map(c -> c.getImage() != null)
.orElse(false)
);
}

@Override
public boolean isMet(DependentResource<Deployment, Trustify> dependentResource, Trustify primary, Context<Trustify> context) {
return context.getSecondaryResource(Deployment.class, new KeycloakDBDeploymentDiscriminator())
.map(deployment -> {
final var status = deployment.getStatus();
if (status != null) {
final var readyReplicas = status.getReadyReplicas();
return readyReplicas != null && readyReplicas >= 1;
}
return false;
})
.orElse(false);
}

@SuppressWarnings("unchecked")
private Deployment newDeployment(Trustify cr, Context<Trustify> context) {
final var contextLabels = (Map<String, String>) context.managedDependentResourceContext()
.getMandatory(Constants.CONTEXT_LABELS_KEY, Map.class);

return new DeploymentBuilder()
.withNewMetadata()
.withName(getDeploymentName(cr))
.withNamespace(cr.getMetadata().getNamespace())
.withLabels(contextLabels)
.addToLabels("component", "oidc")
.addToLabels(Map.of(
"app.openshift.io/runtime", "postgresql"
))
.withOwnerReferences(CRDUtils.getOwnerReference(cr))
.endMetadata()
.withSpec(getDeploymentSpec(cr, context))
.build();
}

@SuppressWarnings("unchecked")
private DeploymentSpec getDeploymentSpec(Trustify cr, Context<Trustify> context) {
final var contextLabels = (Map<String, String>) context.managedDependentResourceContext()
.getMandatory(Constants.CONTEXT_LABELS_KEY, Map.class);

Map<String, String> selectorLabels = Constants.OIDC_DB_SELECTOR_LABELS;
String image = Optional.ofNullable(cr.getSpec().dbImage()).orElse(config.dbImage());
String imagePullPolicy = Optional.ofNullable(cr.getSpec().imagePullPolicy()).orElse(config.imagePullPolicy());

TrustifySpec.DatabaseSpec databaseSpec = Optional.ofNullable(cr.getSpec().oidcSpec())
.map(TrustifySpec.OidcSpec::databaseSpec)
.orElse(null);
TrustifySpec.ResourcesLimitSpec resourcesLimitSpec = CRDUtils.getValueFromSubSpec(databaseSpec, TrustifySpec.DatabaseSpec::resourceLimits)
.orElse(null);

return new DeploymentSpecBuilder()
.withStrategy(new DeploymentStrategyBuilder()
.withType("Recreate")
.build()
)
.withReplicas(1)
.withSelector(new LabelSelectorBuilder()
.withMatchLabels(selectorLabels)
.build()
)
.withTemplate(new PodTemplateSpecBuilder()
.withNewMetadata()
.withLabels(Stream
.concat(contextLabels.entrySet().stream(), selectorLabels.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
)
.endMetadata()
.withSpec(new PodSpecBuilder()
.withRestartPolicy("Always")
.withTerminationGracePeriodSeconds(60L)
.withImagePullSecrets(cr.getSpec().imagePullSecrets())
.withContainers(new ContainerBuilder()
.withName(Constants.OIDC_DB_NAME)
.withImage(image)
.withImagePullPolicy(imagePullPolicy)
.withEnv(getEnvVars(cr))
.withPorts(new ContainerPortBuilder()
.withName("tcp")
.withProtocol(Constants.SERVICE_PROTOCOL)
.withContainerPort(getDatabasePort(cr))
.build()
)
.withLivenessProbe(new ProbeBuilder()
.withExec(new ExecActionBuilder()
.withCommand("/bin/sh", "-c", "psql -U $POSTGRESQL_USER -d $POSTGRESQL_DATABASE -c 'SELECT 1'")
.build()
)
.withInitialDelaySeconds(10)
.withTimeoutSeconds(10)
.withPeriodSeconds(10)
.withSuccessThreshold(1)
.withFailureThreshold(3)
.build()
)
.withReadinessProbe(new ProbeBuilder()
.withExec(new ExecActionBuilder()
.withCommand("/bin/sh", "-c", "psql -U $POSTGRESQL_USER -d $POSTGRESQL_DATABASE -c 'SELECT 1'")
.build()
)
.withInitialDelaySeconds(5)
.withTimeoutSeconds(1)
.withPeriodSeconds(10)
.withSuccessThreshold(1)
.withFailureThreshold(3)
.build()
)
.withVolumeMounts(new VolumeMountBuilder()
.withName("db-pvol")
.withMountPath("/var/lib/pgsql/data")
.build()
)
.withResources(new ResourceRequirementsBuilder()
.withRequests(Map.of(
"cpu", new Quantity(CRDUtils.getValueFromSubSpec(resourcesLimitSpec, TrustifySpec.ResourcesLimitSpec::cpuRequest).orElse("50m")),
"memory", new Quantity(CRDUtils.getValueFromSubSpec(resourcesLimitSpec, TrustifySpec.ResourcesLimitSpec::memoryRequest).orElse("64Mi"))
))
.withLimits(Map.of(
"cpu", new Quantity(CRDUtils.getValueFromSubSpec(resourcesLimitSpec, TrustifySpec.ResourcesLimitSpec::cpuLimit).orElse("1")),
"memory", new Quantity(CRDUtils.getValueFromSubSpec(resourcesLimitSpec, TrustifySpec.ResourcesLimitSpec::memoryLimit).orElse("0.5Gi"))
))
.build()
)
.build()
)
.withVolumes(new VolumeBuilder()
.withName("db-pvol")
.withPersistentVolumeClaim(new PersistentVolumeClaimVolumeSourceBuilder()
.withClaimName(KeycloakDBPersistentVolumeClaim.getPersistentVolumeClaimName(cr))
.build()
)
.build()
)
.build()
)
.build()
)
.build();
}

private List<EnvVar> getEnvVars(Trustify cr) {
return Arrays.asList(
new EnvVarBuilder()
.withName("POSTGRESQL_USER")
.withValueFrom(new EnvVarSourceBuilder()
.withSecretKeyRef(getUsernameSecretKeySelector(cr))
.build()
)
.build(),
new EnvVarBuilder()
.withName("POSTGRESQL_PASSWORD")
.withValueFrom(new EnvVarSourceBuilder()
.withSecretKeyRef(getPasswordSecretKeySelector(cr))
.build()
)
.build(),
new EnvVarBuilder()
.withName("POSTGRESQL_DATABASE")
.withValue(getDatabaseName(cr))
.build()
);
}

public static String getDeploymentName(Trustify cr) {
return cr.getMetadata().getName() + Constants.DB_DEPLOYMENT_SUFFIX;
}

public static SecretKeySelector getUsernameSecretKeySelector(Trustify cr) {
return Optional.ofNullable(cr.getSpec().oidcSpec())
.flatMap(oidcSpec -> Optional.ofNullable(oidcSpec.databaseSpec()))
.map(TrustifySpec.DatabaseSpec::usernameSecret)
.map(secret -> new SecretKeySelectorBuilder()
.withName(secret.getName())
.withKey(secret.getKey())
.withOptional(false)
.build()
)
.orElseGet(() -> new SecretKeySelectorBuilder()
.withName(KeycloakDBSecret.getSecretName(cr))
.withKey(Constants.DB_SECRET_USERNAME)
.withOptional(false)
.build()
);
}

public static SecretKeySelector getPasswordSecretKeySelector(Trustify cr) {
return Optional.ofNullable(cr.getSpec().oidcSpec())
.flatMap(oidcSpec -> Optional.ofNullable(oidcSpec.databaseSpec()))
.map(TrustifySpec.DatabaseSpec::passwordSecret)
.map(secret -> new SecretKeySelectorBuilder()
.withName(secret.getName())
.withKey(secret.getKey())
.withOptional(false)
.build()
)
.orElseGet(() -> new SecretKeySelectorBuilder()
.withName(KeycloakDBSecret.getSecretName(cr))
.withKey(Constants.DB_SECRET_PASSWORD)
.withOptional(false)
.build()
);
}

public static String getDatabaseName(Trustify cr) {
return Optional.ofNullable(cr.getSpec().databaseSpec())
.map(TrustifySpec.DatabaseSpec::name)
.orElse(Constants.DB_NAME);
}

public static Integer getDatabasePort(Trustify cr) {
return Constants.DB_PORT;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.trustify.operator.cdrs.v2alpha1.keycloak;

import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;
import jakarta.enterprise.context.ApplicationScoped;
import org.trustify.operator.cdrs.v2alpha1.Trustify;

@ApplicationScoped
public class KeycloakDBDeploymentActivationCondition extends KeycloakDBActivationCondition implements Condition<Deployment, Trustify> {

@Override
public boolean isMet(DependentResource<Deployment, Trustify> resource, Trustify cr, Context<Trustify> context) {
return super.isMet(cr);
}

}
Loading

0 comments on commit 3e2a4f7

Please sign in to comment.