Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
tommaso-borgato committed May 18, 2023
1 parent e201f43 commit 02d8d15
Show file tree
Hide file tree
Showing 12 changed files with 5,957 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<version.io.strimzi-api>0.28.0</version.io.strimzi-api>
<version.com.fasterxml.jackson>2.13.1</version.com.fasterxml.jackson>
<version.io.fabric8>6.6.0</version.io.fabric8>
<version.openshift-client>5.12.2</version.openshift-client>

<!--
Version used for the activemq-artemis-operator;
Expand Down Expand Up @@ -285,6 +286,10 @@
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</exclusion>
<exclusion>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model-common</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- The following ones are used by the generated code for the Hyperfoil APIs -->
Expand Down
5 changes: 5 additions & 0 deletions testsuite/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
<groupId>org.jboss.intersmash</groupId>
<artifactId>intersmash-deployments-provider</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>openshift-client</artifactId>
<version>${version.openshift-client}</version>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/**
* Copyright (C) 2023 Red Hat, Inc.
*
* 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.jboss.intersmash.testsuite.provision.openshift;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.jboss.intersmash.tools.application.openshift.KeycloakQuarkusOperatorApplication;
import org.jboss.intersmash.tools.junit5.IntersmashExtension;
import org.jboss.intersmash.tools.provision.openshift.KeycloakQuarkusOperatorProvisioner;
import org.jboss.intersmash.tools.provision.openshift.operator.resources.OperatorGroup;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.keycloak.k8s.v2alpha1.Keycloak;
import org.keycloak.k8s.v2alpha1.KeycloakSpec;
import org.keycloak.k8s.v2alpha1.keycloakspec.Hostname;
import org.keycloak.k8s.v2alpha1.keycloakspec.Ingress;
import org.slf4j.event.Level;

import cz.xtf.core.config.OpenShiftConfig;
import cz.xtf.core.openshift.OpenShiftWaiters;
import cz.xtf.core.openshift.OpenShifts;
import cz.xtf.core.waiting.SimpleWaiter;
import cz.xtf.junit5.annotations.CleanBeforeAll;
import io.fabric8.kubernetes.api.model.DeletionPropagation;
import lombok.extern.slf4j.Slf4j;

/**
* Test the Keycloak Operator provisioning model and APIs
*
* See <br>
* - https://github.com/keycloak/keycloak-operator/tree/master/deploy/examples
* <p>
* Not all examples are actually run, but these tests are more about the framework functionality verification than
* about the Keycloak operator testing.
*/
@Slf4j
@CleanBeforeAll
//@Disabled("WIP - Disabled until global-test.properties is configured with the required property")
public class KeycloakQuarkusOperatorProvisionerTest {
// Be aware that since we're using the static mock application, not all provisioner methods will work as expected!
private static final KeycloakQuarkusOperatorProvisioner KEYCLOAK_OPERATOR_PROVISIONER = initializeOperatorProvisioner();

private static KeycloakQuarkusOperatorProvisioner initializeOperatorProvisioner() {
// oc get routes/console -n openshift-console -o jsonpath='{.spec.host}' --> e.g. console-openshift-console.apps.sultan-1eak.eapqe.psi.redhat.com
String console = getConsole();
KeycloakQuarkusOperatorProvisioner operatorProvisioner = new KeycloakQuarkusOperatorProvisioner(
new KeycloakQuarkusOperatorApplication() {
private static final String DEFAULT_KEYCLOAK_APP_NAME = "example-sso";

@Override
public Keycloak getKeycloak() {
Keycloak keycloak = new Keycloak();
keycloak.getMetadata().setName(DEFAULT_KEYCLOAK_APP_NAME);
KeycloakSpec spec = new KeycloakSpec();
spec.setInstances(1L);
Ingress ingress = new Ingress();
ingress.setEnabled(true);
spec.setIngress(ingress);
Hostname hostname = new Hostname();
hostname.setHostname(DEFAULT_KEYCLOAK_APP_NAME + "-" + OpenShiftConfig.namespace() + "."
+ console.replaceFirst("console-openshift-console.", ""));
spec.setHostname(hostname);
keycloak.setSpec(spec);
return keycloak;
}

@Override
public String getName() {
return DEFAULT_KEYCLOAK_APP_NAME;
}
});
return operatorProvisioner;
}

private static String getConsole() {
String console = OpenShifts.adminBinary().execute("get", "routes/console", "-n", "openshift-console", "-o",
"jsonpath={.spec.host}");
return console;
}

private String name;

private static final Map<String, String> matchLabels = new HashMap<>();

@BeforeAll
public static void createOperatorGroup() throws IOException {
KEYCLOAK_OPERATOR_PROVISIONER.configure();
matchLabels.put("app", "sso");
IntersmashExtension.operatorCleanup();
// create operator group - this should be done by InteropExtension
OpenShifts.adminBinary().execute("apply", "-f", OperatorGroup.SINGLE_NAMESPACE.save().getAbsolutePath());
// clean any leftovers
KEYCLOAK_OPERATOR_PROVISIONER.unsubscribe();
}

@AfterAll
public static void removeOperatorGroup() {
OpenShifts.adminBinary().execute("delete", "operatorgroup", "--all");
KEYCLOAK_OPERATOR_PROVISIONER.dismiss();
}

@AfterEach
public void customResourcesCleanup() {

// delete keycloaks
KEYCLOAK_OPERATOR_PROVISIONER.keycloakClient().list().getItems().stream()
.map(resource -> resource.getMetadata().getName()).forEach(name -> KEYCLOAK_OPERATOR_PROVISIONER
.keycloakClient().withName(name).withPropagationPolicy(DeletionPropagation.FOREGROUND).delete());
// delete realms
KEYCLOAK_OPERATOR_PROVISIONER.keycloakRealmImportClient().list().getItems().stream()
.map(resource -> resource.getMetadata().getName()).forEach(name -> KEYCLOAK_OPERATOR_PROVISIONER
.keycloakRealmImportClient().withName(name).withPropagationPolicy(DeletionPropagation.FOREGROUND)
.delete());
}

/**
* This test case creates and validates a basic {@link Keycloak} CR
*
* This is not an integration test, the goal here is to assess that the created CRs are configured as per the
* model specification.
*
* See
* <br> - https://github.com/keycloak/keycloak-operator/tree/master/deploy/examples/keycloak
*/
@Test
public void exampleSso() {
KEYCLOAK_OPERATOR_PROVISIONER.subscribe();
try {
name = "example-sso";

Keycloak keycloak = new Keycloak();
keycloak.getMetadata().setName(name);
keycloak.getMetadata().setLabels(matchLabels);
KeycloakSpec spec = new KeycloakSpec();
spec.setInstances(1L);
Ingress ingress = new Ingress();
ingress.setEnabled(true);
spec.setIngress(ingress);
Hostname hostname = new Hostname();
hostname.setHostname(name + "-" + OpenShiftConfig.namespace() + "."
+ getConsole().replaceFirst("console-openshift-console.", ""));
spec.setHostname(hostname);
keycloak.setSpec(spec);

verifyKeycloak(keycloak, true);
} finally {
KEYCLOAK_OPERATOR_PROVISIONER.unsubscribe();
}
}

private void verifyKeycloak(Keycloak keycloak, boolean waitForPods) {
// create and verify that object exists
KEYCLOAK_OPERATOR_PROVISIONER.keycloakClient().createOrReplace(keycloak);
KEYCLOAK_OPERATOR_PROVISIONER.waitFor(keycloak);
// two pods expected keycloak-0 and keycloak-postgresql-*, keycloak-0 won't start unless keycloak-postgresql-* is ready
if (waitForPods) {
OpenShiftWaiters.get(OpenShifts.master(), () -> false)
.areExactlyNPodsReady(2, "app", keycloak.getKind().toLowerCase()).level(Level.DEBUG).waitFor();
log.debug(KEYCLOAK_OPERATOR_PROVISIONER.keycloakClient().withName(name).get().getStatus().toString());
}
Assertions.assertEquals(keycloak.getSpec(),
KEYCLOAK_OPERATOR_PROVISIONER.keycloakClient().withName(name).get().getSpec());

// delete and verify that object was removed
KEYCLOAK_OPERATOR_PROVISIONER.keycloakClient().withName(name).withPropagationPolicy(DeletionPropagation.FOREGROUND)
.delete();
new SimpleWaiter(() -> KEYCLOAK_OPERATOR_PROVISIONER.keycloakClient().list().getItems().size() == 0).level(Level.DEBUG)
.waitFor();
if (waitForPods) {
OpenShiftWaiters.get(OpenShifts.master(), () -> false)
.areExactlyNPodsReady(0, "app", keycloak.getKind().toLowerCase()).level(Level.DEBUG).waitFor();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
import org.jboss.intersmash.tools.application.openshift.InfinispanOperatorApplication;
import org.jboss.intersmash.tools.application.openshift.KafkaOperatorApplication;
import org.jboss.intersmash.tools.application.openshift.KeycloakOperatorApplication;
import org.jboss.intersmash.tools.application.openshift.KeycloakQuarkusOperatorApplication;
import org.jboss.intersmash.tools.application.openshift.WildflyOperatorApplication;
import org.jboss.intersmash.tools.junit5.IntersmashExtension;
import org.jboss.intersmash.tools.provision.openshift.ActiveMQOperatorProvisioner;
import org.jboss.intersmash.tools.provision.openshift.InfinispanOperatorProvisioner;
import org.jboss.intersmash.tools.provision.openshift.KafkaOperatorProvisioner;
import org.jboss.intersmash.tools.provision.openshift.KeycloakOperatorProvisioner;
import org.jboss.intersmash.tools.provision.openshift.KeycloakQuarkusOperatorProvisioner;
import org.jboss.intersmash.tools.provision.openshift.WildflyOperatorProvisioner;
import org.jboss.intersmash.tools.provision.openshift.operator.OperatorProvisioner;
import org.jboss.intersmash.tools.provision.openshift.operator.resources.OperatorGroup;
Expand Down Expand Up @@ -89,6 +91,15 @@ public void keycloakOperatorProvisionerSubscriptionTest() {
operatorSubscriptionTest();
}

/**
* Try the {@link KeycloakQuarkusOperatorProvisioner} subscription.
*/
@Test
public void keycloakQuarkusOperatorProvisionerSubscriptionTest() {
operatorProvisioner = new KeycloakQuarkusOperatorProvisioner(mock(KeycloakQuarkusOperatorApplication.class));
operatorSubscriptionTest();
}

/**
* Try the {@link InfinispanOperatorProvisioner} subscription.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,18 @@ public class IntersmashConfig {
private static final String PRODUCT_INFINISPAN_OPERATOR_PACKAGE_MANIFEST = "datagrid";
private static final String DEFAULT_INFINISPAN_OPERATOR_PACKAGE_MANIFEST = COMMUNITY_INFINISPAN_OPERATOR_PACKAGE_MANIFEST;
private static final String KEYCLOAK_OPERATOR_CATALOG_SOURCE_NAME = "intersmash.keycloak.operators.catalog_source";
private static final String KEYCLOAK_QUARKUS_OPERATOR_CATALOG_SOURCE_NAME = "intersmash.keycloak.quarkus.operators.catalog_source";

private static final String KEYCLOAK_OPERATOR_INDEX_IMAGE = "intersmash.keycloak.operators.index_image";
private static final String KEYCLOAK_QUARKUS_OPERATOR_INDEX_IMAGE = "intersmash.keycloak.quarkus.operators.index_image";
private static final String KEYCLOAK_OPERATOR_CHANNEL = "intersmash.keycloak.operators.channel";
private static final String KEYCLOAK_QUARKUS_OPERATOR_CHANNEL = "intersmash.keycloak.quarkus.operators.channel";
private static final String KEYCLOAK_OPERATOR_PACKAGE_MANIFEST = "intersmash.keycloak.operators.package_manifest";
private static final String KEYCLOAK_QUARKUS_OPERATOR_PACKAGE_MANIFEST = "intersmash.keycloak.quarkus.operators.package_manifest";
private static final String COMMUNITY_KEYCLOAK_OPERATOR_PACKAGE_MANIFEST = "keycloak-operator";
private static final String PRODUCT_KEYCLOAK_OPERATOR_PACKAGE_MANIFEST = "rhsso-operator";
private static final String DEFAULT_KEYCLOAK_OPERATOR_PACKAGE_MANIFEST = COMMUNITY_KEYCLOAK_OPERATOR_PACKAGE_MANIFEST;
private static final String DEFAULT_KEYCLOAK_QUARKUS_OPERATOR_PACKAGE_MANIFEST = COMMUNITY_KEYCLOAK_OPERATOR_PACKAGE_MANIFEST;
private static final String WILDFLY_OPERATOR_CATALOG_SOURCE_NAME = "intersmash.wildfly.operators.catalog_source";
private static final String WILDFLY_OPERATOR_INDEX_IMAGE = "intersmash.wildfly.operators.index_image";
private static final String WILDFLY_OPERATOR_CHANNEL = "intersmash.wildfly.operators.channel";
Expand Down Expand Up @@ -102,6 +108,7 @@ public class IntersmashConfig {

// KEYCLOAK
private static final String KEYCLOAK_IMAGE_URL = "intersmash.keycloak.image";
private static final String KEYCLOAK_QUARKUS_IMAGE_URL = "intersmash.keycloak.quarks.image";
private static final String KEYCLOAK_TEMPLATES = "intersmash.keycloak.templates";

// ACTIVEMQ
Expand Down Expand Up @@ -163,6 +170,10 @@ public static String keycloakOperatorPackageManifest() {
return XTFConfig.get(KEYCLOAK_OPERATOR_PACKAGE_MANIFEST, DEFAULT_KEYCLOAK_OPERATOR_PACKAGE_MANIFEST);
}

public static String keycloakOperatorQuarkusPackageManifest() {
return XTFConfig.get(KEYCLOAK_OPERATOR_PACKAGE_MANIFEST, DEFAULT_KEYCLOAK_OPERATOR_PACKAGE_MANIFEST);
}

public static String wildflyOperatorCatalogSource() {
return XTFConfig.get(WILDFLY_OPERATOR_CATALOG_SOURCE_NAME, DEFAULT_OPERATOR_CATALOG_SOURCE_NAME);
}
Expand Down Expand Up @@ -277,6 +288,10 @@ public static String keycloakImageURL() {
return XTFConfig.get(KEYCLOAK_IMAGE_URL);
}

public static String keycloakQuarkusImageURL() {
return XTFConfig.get(KEYCLOAK_QUARKUS_IMAGE_URL);
}

public static String keycloakTemplates() {
return XTFConfig.get(KEYCLOAK_TEMPLATES);
}
Expand Down Expand Up @@ -386,4 +401,20 @@ public static String getWildflyHelmChartsRepo() {
public static String getWildflyHelmChartsBranch() {
return XTFConfig.get(WILDFLY_HELM_CHARTS_BRANCH);
}

public static String keycloakQuarkusOperatorCatalogSource() {
return XTFConfig.get(KEYCLOAK_QUARKUS_OPERATOR_CATALOG_SOURCE_NAME, DEFAULT_OPERATOR_CATALOG_SOURCE_NAME);
}

public static String keycloakQuarkusOperatorIndexImage() {
return XTFConfig.get(KEYCLOAK_QUARKUS_OPERATOR_INDEX_IMAGE);
}

public static String keycloakQuarkusOperatorChannel() {
return XTFConfig.get(KEYCLOAK_QUARKUS_OPERATOR_CHANNEL);
}

public static String keycloakQuarkusOperatorPackageManifest() {
return XTFConfig.get(KEYCLOAK_QUARKUS_OPERATOR_PACKAGE_MANIFEST, DEFAULT_KEYCLOAK_QUARKUS_OPERATOR_PACKAGE_MANIFEST);
}
}
4 changes: 4 additions & 0 deletions tools/intersmash-tools-provisioners/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,13 @@
<configuration>
<target>target/generated-sources</target>
<urls>
<!-- ActiveMQ Operator -->
<url>https://raw.githubusercontent.com/artemiscloud/activemq-artemis-operator/${version.intersmash.activemq.operators}/bundle/manifests/broker.amq.io_activemqartemises.yaml</url>
<url>https://raw.githubusercontent.com/artemiscloud/activemq-artemis-operator/${version.intersmash.activemq.operators}/bundle/manifests/broker.amq.io_activemqartemisaddresses.yaml</url>
<url>https://raw.githubusercontent.com/artemiscloud/activemq-artemis-operator/${version.intersmash.activemq.operators}/bundle/manifests/broker.amq.io_activemqartemisscaledowns.yaml</url>
<!-- Keycloak Operator -->
<url>https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/21.1.1/kubernetes/keycloaks.k8s.keycloak.org-v1.yml</url>
<url>https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/21.1.1/kubernetes/keycloakrealmimports.k8s.keycloak.org-v1.yml</url>
</urls>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (C) 2023 Red Hat, Inc.
*
* 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.jboss.intersmash.tools.application.openshift;

import java.util.Collections;
import java.util.List;

import org.jboss.intersmash.tools.provision.openshift.KeycloakQuarkusOperatorProvisioner;
import org.keycloak.k8s.v2alpha1.Keycloak;
import org.keycloak.k8s.v2alpha1.KeycloakRealmImport;

/**
* End user Application interface which presents Keycloak operator application on OpenShift Container Platform.
*
* The application will be deployed by:
* <ul>
* <li>{@link KeycloakQuarkusOperatorProvisioner}</li>
* </ul>
*/
public interface KeycloakQuarkusOperatorApplication extends OperatorApplication {

Keycloak getKeycloak();

default List<KeycloakRealmImport> getKeycloakRealmImports() {
return Collections.emptyList();
}
}
Loading

0 comments on commit 02d8d15

Please sign in to comment.