converts the keycloak services to dependent resources (#22257)

Closes #22207
This commit is contained in:
Steven Hawkins 2023-08-10 09:56:13 -04:00 committed by GitHub
parent b4e876364a
commit 1d444ff862
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 144 additions and 134 deletions

View file

@ -41,6 +41,7 @@ import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatus; import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatus;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusAggregator; import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusAggregator;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -50,7 +51,9 @@ import static io.javaoperatorsdk.operator.api.reconciler.Constants.WATCH_CURRENT
@ControllerConfiguration(namespaces = WATCH_CURRENT_NAMESPACE, @ControllerConfiguration(namespaces = WATCH_CURRENT_NAMESPACE,
dependents = { dependents = {
@Dependent(type = KeycloakAdminSecretDependentResource.class) @Dependent(type = KeycloakAdminSecretDependentResource.class),
@Dependent(type = KeycloakServiceDependentResource.class, useEventSourceWithName = "serviceSource"),
@Dependent(type = KeycloakDiscoveryServiceDependentResource.class, useEventSourceWithName = "serviceSource")
}) })
public class KeycloakController implements Reconciler<Keycloak>, EventSourceInitializer<Keycloak>, ErrorStatusHandler<Keycloak> { public class KeycloakController implements Reconciler<Keycloak>, EventSourceInitializer<Keycloak>, ErrorStatusHandler<Keycloak> {
@ -95,9 +98,11 @@ public class KeycloakController implements Reconciler<Keycloak>, EventSourceInit
EventSource servicesEvent = new InformerEventSource<>(servicesIC, context); EventSource servicesEvent = new InformerEventSource<>(servicesIC, context);
EventSource ingressesEvent = new InformerEventSource<>(ingressesIC, context); EventSource ingressesEvent = new InformerEventSource<>(ingressesIC, context);
return EventSourceInitializer.nameEventSources(statefulSetEvent, Map<String, EventSource> sources = new HashMap<>();
servicesEvent, sources.put("serviceSource", servicesEvent);
ingressesEvent, watchedSecrets.getWatchedSecretsEventSource()); sources.putAll(EventSourceInitializer.nameEventSources(statefulSetEvent,
ingressesEvent, watchedSecrets.getWatchedSecretsEventSource()));
return sources;
} }
@Override @Override
@ -121,11 +126,6 @@ public class KeycloakController implements Reconciler<Keycloak>, EventSourceInit
kcDeployment.createOrUpdateReconciled(); kcDeployment.createOrUpdateReconciled();
kcDeployment.updateStatus(statusAggregator); kcDeployment.updateStatus(statusAggregator);
var kcService = new KeycloakService(client, kc);
kcService.createOrUpdateReconciled();
var kcDiscoveryService = new KeycloakDiscoveryService(client, kc);
kcDiscoveryService.createOrUpdateReconciled();
var kcIngress = new KeycloakIngress(client, kc); var kcIngress = new KeycloakIngress(client, kc);
kcIngress.createOrUpdateReconciled(); kcIngress.createOrUpdateReconciled();

View file

@ -232,7 +232,7 @@ public class KeycloakDeployment extends OperatorManagedResource<StatefulSet> {
// probes // probes
var tlsConfigured = isTlsConfigured(keycloakCR); var tlsConfigured = isTlsConfigured(keycloakCR);
var protocol = !tlsConfigured ? "HTTP" : "HTTPS"; var protocol = !tlsConfigured ? "HTTP" : "HTTPS";
var kcPort = KeycloakService.getServicePort(keycloakCR); var kcPort = KeycloakServiceDependentResource.getServicePort(keycloakCR);
// Relative path ends with '/' // Relative path ends with '/'
var kcRelativePath = Optional.ofNullable(readConfigurationValue(Constants.KEYCLOAK_HTTP_RELATIVE_PATH_KEY)) var kcRelativePath = Optional.ofNullable(readConfigurationValue(Constants.KEYCLOAK_HTTP_RELATIVE_PATH_KEY))

View file

@ -1,69 +0,0 @@
/*
* Copyright 2021 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.operator.controllers;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.api.model.ServiceSpec;
import io.fabric8.kubernetes.api.model.ServiceSpecBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.keycloak.operator.Constants;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import java.util.Optional;
public class KeycloakDiscoveryService extends OperatorManagedResource {
public KeycloakDiscoveryService(KubernetesClient client, Keycloak keycloakCR) {
super(client, keycloakCR);
}
private ServiceSpec getServiceSpec() {
return new ServiceSpecBuilder()
.addNewPort()
.withProtocol("TCP")
.withPort(Constants.KEYCLOAK_DISCOVERY_SERVICE_PORT)
.endPort()
.withSelector(getInstanceLabels())
.withClusterIP("None")
.withPublishNotReadyAddresses(Boolean.TRUE)
.build();
}
@Override
protected Optional<HasMetadata> getReconciledResource() {
return Optional.of(newService());
}
private Service newService() {
Service service = new ServiceBuilder()
.withNewMetadata()
.withName(getName())
.withNamespace(getNamespace())
.endMetadata()
.withSpec(getServiceSpec())
.build();
return service;
}
@Override
public String getName() {
return cr.getMetadata().getName() + Constants.KEYCLOAK_DISCOVERY_SERVICE_SUFFIX;
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright 2021 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.operator.controllers;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.api.model.ServiceSpec;
import io.fabric8.kubernetes.api.model.ServiceSpecBuilder;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
import org.keycloak.operator.Constants;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import java.util.Optional;
@KubernetesDependent(labelSelector = Constants.DEFAULT_LABELS_AS_STRING, resourceDiscriminator = KeycloakDiscoveryServiceDependentResource.NameResourceDiscriminator.class)
public class KeycloakDiscoveryServiceDependentResource extends CRUDKubernetesDependentResource<Service, Keycloak> {
public static class NameResourceDiscriminator implements ResourceDiscriminator<Service, Keycloak> {
@Override
public Optional<Service> distinguish(Class<Service> resource, Keycloak primary, Context<Keycloak> context) {
return KeycloakServiceDependentResource.getService(KeycloakDiscoveryServiceDependentResource::getName, primary, context);
}
}
public KeycloakDiscoveryServiceDependentResource() {
super(Service.class);
}
private ServiceSpec getServiceSpec(Keycloak keycloak) {
return new ServiceSpecBuilder()
.addNewPort()
.withProtocol("TCP")
.withPort(Constants.KEYCLOAK_DISCOVERY_SERVICE_PORT)
.endPort()
.withSelector(OperatorManagedResource.allInstanceLabels(keycloak))
.withClusterIP("None")
.withPublishNotReadyAddresses(Boolean.TRUE)
.build();
}
@Override
protected Service desired(Keycloak primary, Context<Keycloak> context) {
Service service = new ServiceBuilder()
.withNewMetadata()
.withName(getName(primary))
.withNamespace(primary.getMetadata().getNamespace())
.addToLabels(OperatorManagedResource.allInstanceLabels(primary))
.endMetadata()
.withSpec(getServiceSpec(primary))
.build();
return service;
}
public static String getName(Keycloak keycloak) {
return keycloak.getMetadata().getName() + Constants.KEYCLOAK_DISCOVERY_SERVICE_SUFFIX;
}
}

View file

@ -55,7 +55,7 @@ public class KeycloakIngress extends OperatorManagedResource {
} }
private Ingress newIngress() { private Ingress newIngress() {
var port = KeycloakService.getServicePort(keycloak); var port = KeycloakServiceDependentResource.getServicePort(keycloak);
var annotations = new HashMap<String, String>(); var annotations = new HashMap<String, String>();
// set default annotations // set default annotations
@ -80,7 +80,7 @@ public class KeycloakIngress extends OperatorManagedResource {
.withIngressClassName(optionalSpec.map(IngressSpec::getIngressClassName).orElse(null)) .withIngressClassName(optionalSpec.map(IngressSpec::getIngressClassName).orElse(null))
.withNewDefaultBackend() .withNewDefaultBackend()
.withNewService() .withNewService()
.withName(KeycloakService.getServiceName(keycloak)) .withName(KeycloakServiceDependentResource.getServiceName(keycloak))
.withNewPort() .withNewPort()
.withNumber(port) .withNumber(port)
.withName("") // for SSA to clear the name if already set .withName("") // for SSA to clear the name if already set
@ -94,7 +94,7 @@ public class KeycloakIngress extends OperatorManagedResource {
.withPathType("ImplementationSpecific") .withPathType("ImplementationSpecific")
.withNewBackend() .withNewBackend()
.withNewService() .withNewService()
.withName(KeycloakService.getServiceName(keycloak)) .withName(KeycloakServiceDependentResource.getServiceName(keycloak))
.withNewPort() .withNewPort()
.withNumber(port) .withNumber(port)
.withName("") // for SSA to clear the name if already set .withName("") // for SSA to clear the name if already set

View file

@ -21,26 +21,44 @@ import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServiceBuilder; import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.api.model.ServiceSpec; import io.fabric8.kubernetes.api.model.ServiceSpec;
import io.fabric8.kubernetes.api.model.ServiceSpecBuilder; import io.fabric8.kubernetes.api.model.ServiceSpecBuilder;
import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
import io.javaoperatorsdk.operator.processing.event.ResourceID;
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
import org.keycloak.operator.Constants; import org.keycloak.operator.Constants;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.spec.HttpSpec; import org.keycloak.operator.crds.v2alpha1.deployment.spec.HttpSpec;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function;
import static org.keycloak.operator.crds.v2alpha1.CRDUtils.isTlsConfigured; import static org.keycloak.operator.crds.v2alpha1.CRDUtils.isTlsConfigured;
public class KeycloakService extends OperatorManagedResource { @KubernetesDependent(labelSelector = Constants.DEFAULT_LABELS_AS_STRING, resourceDiscriminator = KeycloakServiceDependentResource.NameResourceDiscriminator.class)
public class KeycloakServiceDependentResource extends CRUDKubernetesDependentResource<Service, Keycloak> {
private final Keycloak keycloak; public static class NameResourceDiscriminator implements ResourceDiscriminator<Service, Keycloak> {
@Override
public KeycloakService(KubernetesClient client, Keycloak keycloakCR) { public Optional<Service> distinguish(Class<Service> resource, Keycloak primary, Context<Keycloak> context) {
super(client, keycloakCR); return getService(KeycloakServiceDependentResource::getServiceName, primary, context);
this.keycloak = keycloakCR; }
} }
private ServiceSpec getServiceSpec() { public static Optional<Service> getService(Function<Keycloak, String> nameFunction, Keycloak primary, Context<Keycloak> context) {
InformerEventSource<Service, Keycloak> ies = (InformerEventSource<Service, Keycloak>) context
.eventSourceRetriever().getResourceEventSourceFor(Service.class);
return ies.get(new ResourceID(nameFunction.apply(primary), primary.getMetadata().getNamespace()));
}
public KeycloakServiceDependentResource() {
super(Service.class);
}
private ServiceSpec getServiceSpec(Keycloak keycloak) {
String name = isTlsConfigured(keycloak) ? Constants.KEYCLOAK_HTTPS_PORT_NAME : Constants.KEYCLOAK_HTTP_PORT_NAME; String name = isTlsConfigured(keycloak) ? Constants.KEYCLOAK_HTTPS_PORT_NAME : Constants.KEYCLOAK_HTTP_PORT_NAME;
return new ServiceSpecBuilder() return new ServiceSpecBuilder()
.addNewPort() .addNewPort()
@ -48,31 +66,23 @@ public class KeycloakService extends OperatorManagedResource {
.withName(name) .withName(name)
.withProtocol(Constants.KEYCLOAK_SERVICE_PROTOCOL) .withProtocol(Constants.KEYCLOAK_SERVICE_PROTOCOL)
.endPort() .endPort()
.withSelector(getInstanceLabels()) .withSelector(OperatorManagedResource.allInstanceLabels(keycloak))
.build(); .build();
} }
@Override @Override
protected Optional<HasMetadata> getReconciledResource() { protected Service desired(Keycloak primary, Context<Keycloak> context) {
return Optional.of(newService());
}
private Service newService() {
Service service = new ServiceBuilder() Service service = new ServiceBuilder()
.withNewMetadata() .withNewMetadata()
.withName(getName()) .withName(getServiceName(primary))
.withNamespace(getNamespace()) .withNamespace(primary.getMetadata().getNamespace())
.addToLabels(OperatorManagedResource.allInstanceLabels(primary))
.endMetadata() .endMetadata()
.withSpec(getServiceSpec()) .withSpec(getServiceSpec(primary))
.build(); .build();
return service; return service;
} }
@Override
public String getName() {
return getServiceName(cr);
}
public static String getServiceName(HasMetadata keycloak) { public static String getServiceName(HasMetadata keycloak) {
return keycloak.getMetadata().getName() + Constants.KEYCLOAK_SERVICE_SUFFIX; return keycloak.getMetadata().getName() + Constants.KEYCLOAK_SERVICE_SUFFIX;
} }

View file

@ -31,7 +31,7 @@ import io.restassured.RestAssured;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.keycloak.operator.Constants; import org.keycloak.operator.Constants;
import org.keycloak.operator.controllers.KeycloakService; import org.keycloak.operator.controllers.KeycloakServiceDependentResource;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition; import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport; import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport;
@ -172,8 +172,7 @@ public class ClusteringTest extends BaseOperatorTest {
.untilAsserted(() -> assertThat(crSelector.scale().getStatus().getReplicas()).isEqualTo(2)); .untilAsserted(() -> assertThat(crSelector.scale().getStatus().getReplicas()).isEqualTo(2));
// get the service // get the service
var service = new KeycloakService(k8sclient, kc); String url = "https://" + KeycloakServiceDependentResource.getServiceName(kc) + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT;
String url = "https://" + service.getName() + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT;
Awaitility.await().atMost(5, MINUTES).untilAsserted(() -> { Awaitility.await().atMost(5, MINUTES).untilAsserted(() -> {
Log.info("Starting curl Pod to test if the realm is available"); Log.info("Starting curl Pod to test if the realm is available");
@ -275,7 +274,7 @@ public class ClusteringTest extends BaseOperatorTest {
// This is to test passing through the "Service", not 100% deterministic, but a smoke test that things are working as expected // This is to test passing through the "Service", not 100% deterministic, but a smoke test that things are working as expected
// Executed here to avoid paying the setup time again // Executed here to avoid paying the setup time again
var service = new KeycloakService(k8sclient, kc); String serviceName = KeycloakServiceDependentResource.getServiceName(kc);
Awaitility.await() Awaitility.await()
.atMost(20, MINUTES) .atMost(20, MINUTES)
.pollDelay(5, SECONDS) .pollDelay(5, SECONDS)
@ -286,7 +285,7 @@ public class ClusteringTest extends BaseOperatorTest {
for (int i = 0; i < (targetInstances + 1); i++) { for (int i = 0; i < (targetInstances + 1); i++) {
if (token2 == null) { if (token2 == null) {
var tokenUrl = "https://" + service.getName() + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/realms/token-test/protocol/openid-connect/token"; var tokenUrl = "https://" + serviceName + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/realms/token-test/protocol/openid-connect/token";
Log.info("Checking url: " + tokenUrl); Log.info("Checking url: " + tokenUrl);
var tokenOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "--data", "grant_type=password&client_id=token-test-client&username=test&password=test&scope=openid", tokenUrl); var tokenOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "--data", "grant_type=password&client_id=token-test-client&username=test&password=test&scope=openid", tokenUrl);
@ -296,7 +295,7 @@ public class ClusteringTest extends BaseOperatorTest {
token2 = tokenAnswer.get("access_token").asText(); token2 = tokenAnswer.get("access_token").asText();
} }
String url = "https://" + service.getName() + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/realms/token-test/protocol/openid-connect/userinfo"; String url = "https://" + serviceName + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/realms/token-test/protocol/openid-connect/userinfo";
Log.info("Checking url: " + url); Log.info("Checking url: " + url);
var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "-H", "Authorization: Bearer " + token2, url); var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "-H", "Authorization: Bearer " + token2, url);

View file

@ -38,7 +38,7 @@ import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.keycloak.operator.Constants; import org.keycloak.operator.Constants;
import org.keycloak.operator.controllers.KeycloakAdminSecretDependentResource; import org.keycloak.operator.controllers.KeycloakAdminSecretDependentResource;
import org.keycloak.operator.controllers.KeycloakDistConfigurator; import org.keycloak.operator.controllers.KeycloakDistConfigurator;
import org.keycloak.operator.controllers.KeycloakService; import org.keycloak.operator.controllers.KeycloakServiceDependentResource;
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak; import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition; import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition;
import org.keycloak.operator.crds.v2alpha1.deployment.ValueOrSecret; import org.keycloak.operator.crds.v2alpha1.deployment.ValueOrSecret;
@ -254,11 +254,10 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
var kc = getTestKeycloakDeployment(true); var kc = getTestKeycloakDeployment(true);
deployKeycloak(k8sclient, kc, true); deployKeycloak(k8sclient, kc, true);
var service = new KeycloakService(k8sclient, kc);
Awaitility.await() Awaitility.await()
.ignoreExceptions() .ignoreExceptions()
.untilAsserted(() -> { .untilAsserted(() -> {
String url = "https://" + service.getName() + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT; String url = "https://" + KeycloakServiceDependentResource.getServiceName(kc) + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT;
Log.info("Checking url: " + url); Log.info("Checking url: " + url);
var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "-w", "%{certs}", url); var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "-w", "%{certs}", url);
@ -283,11 +282,10 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
var kc = getTestKeycloakDeployment(true); var kc = getTestKeycloakDeployment(true);
deployKeycloak(k8sclient, kc, true); deployKeycloak(k8sclient, kc, true);
var service = new KeycloakService(k8sclient, kc);
Awaitility.await() Awaitility.await()
.ignoreExceptions() .ignoreExceptions()
.untilAsserted(() -> { .untilAsserted(() -> {
String url = "https://" + service.getName() + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/admin/master/console/"; String url = "https://" + KeycloakServiceDependentResource.getServiceName(kc) + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/admin/master/console/";
Log.info("Checking url: " + url); Log.info("Checking url: " + url);
var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "-s", "--insecure", "-H", "Host: foo.bar", url); var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "-s", "--insecure", "-H", "Host: foo.bar", url);
@ -308,11 +306,10 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
deployKeycloak(k8sclient, kc, true); deployKeycloak(k8sclient, kc, true);
var service = new KeycloakService(k8sclient, kc);
Awaitility.await() Awaitility.await()
.ignoreExceptions() .ignoreExceptions()
.untilAsserted(() -> { .untilAsserted(() -> {
String url = "https://" + service.getName() + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/admin/master/console/"; String url = "https://" + KeycloakServiceDependentResource.getServiceName(kc) + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/admin/master/console/";
Log.info("Checking url: " + url); Log.info("Checking url: " + url);
var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "-s", "--insecure", "-H", "Host: foo.bar", url); var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "-s", "--insecure", "-H", "Host: foo.bar", url);
@ -395,7 +392,6 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
deployDB(); deployDB();
deployKeycloak(k8sclient, kc, true); deployKeycloak(k8sclient, kc, true);
var decoder = Base64.getDecoder(); var decoder = Base64.getDecoder();
var service = new KeycloakService(k8sclient, kc);
AtomicReference<String> adminUsername = new AtomicReference<>(); AtomicReference<String> adminUsername = new AtomicReference<>();
AtomicReference<String> adminPassword = new AtomicReference<>(); AtomicReference<String> adminPassword = new AtomicReference<>();
@ -412,7 +408,7 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
adminUsername.set(new String(decoder.decode(adminSecret.getData().get("username").getBytes(StandardCharsets.UTF_8)))); adminUsername.set(new String(decoder.decode(adminSecret.getData().get("username").getBytes(StandardCharsets.UTF_8))));
adminPassword.set(new String(decoder.decode(adminSecret.getData().get("password").getBytes(StandardCharsets.UTF_8)))); adminPassword.set(new String(decoder.decode(adminSecret.getData().get("password").getBytes(StandardCharsets.UTF_8))));
String url = "https://" + service.getName() + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/realms/master/protocol/openid-connect/token"; String url = "https://" + KeycloakServiceDependentResource.getServiceName(kc) + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/realms/master/protocol/openid-connect/token";
Log.info("Checking url: " + url); Log.info("Checking url: " + url);
var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "--data", "grant_type=password&client_id=admin-cli&username=" + adminUsername.get() + "&password=" + adminPassword.get(), url); var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "--data", "grant_type=password&client_id=admin-cli&username=" + adminUsername.get() + "&password=" + adminPassword.get(), url);
@ -437,7 +433,7 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
var newPassword = new String(decoder.decode(adminSecret.getData().get("password").getBytes(StandardCharsets.UTF_8))); var newPassword = new String(decoder.decode(adminSecret.getData().get("password").getBytes(StandardCharsets.UTF_8)));
String url = "https://" + service.getName() + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/realms/master/protocol/openid-connect/token"; String url = "https://" + KeycloakServiceDependentResource.getServiceName(kc) + "." + namespace + ":" + Constants.KEYCLOAK_HTTPS_PORT + "/realms/master/protocol/openid-connect/token";
Log.info("Checking url: " + url); Log.info("Checking url: " + url);
var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "--data", "grant_type=password&client_id=admin-cli&username=" + adminUsername.get() + "&password=" + adminPassword.get(), url); var curlOutput = K8sUtils.inClusterCurl(k8sclient, namespace, "--insecure", "-s", "--data", "grant_type=password&client_id=admin-cli&username=" + adminUsername.get() + "&password=" + adminPassword.get(), url);
@ -631,7 +627,7 @@ public class KeycloakDeploymentTest extends BaseOperatorTest {
.untilAsserted(() -> { .untilAsserted(() -> {
String protocol = https ? "https" : "http"; String protocol = https ? "https" : "http";
String serviceName = KeycloakService.getServiceName(kc); String serviceName = KeycloakServiceDependentResource.getServiceName(kc);
assertThat(k8sclient.resources(Service.class).withName(serviceName).require().getSpec().getPorts() assertThat(k8sclient.resources(Service.class).withName(serviceName).require().getSpec().getPorts()
.stream().map(ServicePort::getName).anyMatch(protocol::equals)); .stream().map(ServicePort::getName).anyMatch(protocol::equals));

View file

@ -20,10 +20,11 @@ package org.keycloak.operator.testsuite.integration;
import io.fabric8.kubernetes.api.model.ServiceSpecBuilder; import io.fabric8.kubernetes.api.model.ServiceSpecBuilder;
import io.quarkus.logging.Log; import io.quarkus.logging.Log;
import io.quarkus.test.junit.QuarkusTest; import io.quarkus.test.junit.QuarkusTest;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.keycloak.operator.controllers.KeycloakDiscoveryService; import org.keycloak.operator.controllers.KeycloakDiscoveryServiceDependentResource;
import org.keycloak.operator.controllers.KeycloakService; import org.keycloak.operator.controllers.KeycloakServiceDependentResource;
import org.keycloak.operator.testsuite.utils.K8sUtils; import org.keycloak.operator.testsuite.utils.K8sUtils;
import java.time.Duration; import java.time.Duration;
@ -37,8 +38,8 @@ public class KeycloakServicesTest extends BaseOperatorTest {
public void testMainServiceDurability() { public void testMainServiceDurability() {
var kc = getTestKeycloakDeployment(true); var kc = getTestKeycloakDeployment(true);
K8sUtils.deployKeycloak(k8sclient, kc, true); K8sUtils.deployKeycloak(k8sclient, kc, true);
var service = new KeycloakService(k8sclient, kc); String serviceName = KeycloakServiceDependentResource.getServiceName(kc);
var serviceSelector = k8sclient.services().inNamespace(namespace).withName(service.getName()); var serviceSelector = k8sclient.services().inNamespace(namespace).withName(serviceName);
Log.info("Trying to delete the service"); Log.info("Trying to delete the service");
assertThat(serviceSelector.delete()).isNotNull(); assertThat(serviceSelector.delete()).isNotNull();
@ -61,7 +62,6 @@ public class KeycloakServicesTest extends BaseOperatorTest {
var origSpecs = new ServiceSpecBuilder(currentService.getSpec()).build(); // deep copy var origSpecs = new ServiceSpecBuilder(currentService.getSpec()).build(); // deep copy
// a managed change // a managed change
currentService.getSpec().getPorts().get(0).setProtocol("UDP");
currentService.getSpec().getPorts().get(0).setName(null); currentService.getSpec().getPorts().get(0).setName(null);
currentService.getMetadata().getLabels().putAll(labels); currentService.getMetadata().getLabels().putAll(labels);
@ -86,8 +86,7 @@ public class KeycloakServicesTest extends BaseOperatorTest {
public void testDiscoveryServiceDurability() { public void testDiscoveryServiceDurability() {
var kc = getTestKeycloakDeployment(true); var kc = getTestKeycloakDeployment(true);
K8sUtils.deployKeycloak(k8sclient, kc, true); K8sUtils.deployKeycloak(k8sclient, kc, true);
var discoveryService = new KeycloakDiscoveryService(k8sclient, kc); var discoveryServiceSelector = k8sclient.services().inNamespace(namespace).withName(KeycloakDiscoveryServiceDependentResource.getName(kc));
var discoveryServiceSelector = k8sclient.services().inNamespace(namespace).withName(discoveryService.getName());
Log.info("Trying to delete the discovery service"); Log.info("Trying to delete the discovery service");
assertThat(discoveryServiceSelector.delete()).isNotNull(); assertThat(discoveryServiceSelector.delete()).isNotNull();
@ -113,7 +112,7 @@ public class KeycloakServicesTest extends BaseOperatorTest {
var origDiscoverySpecs = new ServiceSpecBuilder(currentDiscoveryService.getSpec()).build(); // deep copy var origDiscoverySpecs = new ServiceSpecBuilder(currentDiscoveryService.getSpec()).build(); // deep copy
// a managed change // a managed change
currentDiscoveryService.getSpec().getPorts().get(0).setProtocol("UDP"); currentDiscoveryService.getSpec().getPorts().get(0).setName(null);
currentDiscoveryService.getMetadata().setResourceVersion(null); currentDiscoveryService.getMetadata().setResourceVersion(null);
k8sclient.resource(currentDiscoveryService).update(); k8sclient.resource(currentDiscoveryService).update();

View file

@ -26,10 +26,10 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.keycloak.operator.controllers.KeycloakServiceDependentResource;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport;
import org.keycloak.operator.testsuite.utils.CRAssert; import org.keycloak.operator.testsuite.utils.CRAssert;
import org.keycloak.operator.testsuite.utils.K8sUtils; import org.keycloak.operator.testsuite.utils.K8sUtils;
import org.keycloak.operator.controllers.KeycloakService;
import org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImport;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -39,11 +39,11 @@ import static java.util.concurrent.TimeUnit.SECONDS;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.keycloak.operator.Constants.KEYCLOAK_HTTPS_PORT; import static org.keycloak.operator.Constants.KEYCLOAK_HTTPS_PORT;
import static org.keycloak.operator.controllers.KeycloakDistConfigurator.getKeycloakOptionEnvVarName; import static org.keycloak.operator.controllers.KeycloakDistConfigurator.getKeycloakOptionEnvVarName;
import static org.keycloak.operator.testsuite.utils.K8sUtils.deployKeycloak;
import static org.keycloak.operator.testsuite.utils.K8sUtils.inClusterCurl;
import static org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatusCondition.DONE; import static org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatusCondition.DONE;
import static org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatusCondition.HAS_ERRORS; import static org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatusCondition.HAS_ERRORS;
import static org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatusCondition.STARTED; import static org.keycloak.operator.crds.v2alpha1.realmimport.KeycloakRealmImportStatusCondition.STARTED;
import static org.keycloak.operator.testsuite.utils.K8sUtils.deployKeycloak;
import static org.keycloak.operator.testsuite.utils.K8sUtils.inClusterCurl;
@QuarkusTest @QuarkusTest
public class RealmImportTest extends BaseOperatorTest { public class RealmImportTest extends BaseOperatorTest {
@ -123,7 +123,7 @@ public class RealmImportTest extends BaseOperatorTest {
assertThat(job.getSpec().getTemplate().getSpec().getImagePullSecrets().get(0).getName()).isEqualTo("my-empty-secret"); assertThat(job.getSpec().getTemplate().getSpec().getImagePullSecrets().get(0).getName()).isEqualTo("my-empty-secret");
String url = String url =
"https://" + KeycloakService.getServiceName(kc) + "." + namespace + ":" + KEYCLOAK_HTTPS_PORT + "/realms/count0"; "https://" + KeycloakServiceDependentResource.getServiceName(kc) + "." + namespace + ":" + KEYCLOAK_HTTPS_PORT + "/realms/count0";
Awaitility.await().atMost(10, MINUTES).ignoreExceptions().untilAsserted(() -> { Awaitility.await().atMost(10, MINUTES).ignoreExceptions().untilAsserted(() -> {
Log.info("Starting curl Pod to test if the realm is available"); Log.info("Starting curl Pod to test if the realm is available");