Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ExposedApp tests should now properly run, including in native mode #572

Merged
merged 11 commits into from
May 9, 2023
Merged
2 changes: 1 addition & 1 deletion .github/workflows/build-for-quarkus-version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
run: mvn -B formatter:validate install --file pom.xml

- name: Build with Maven (Native)
run: mvn -B formatter:validate install -Dnative --file pom.xml
run: mvn -B formatter:validate install -Dnative --file pom.xml -pl '!docs'

- name: Kubernetes KinD Cluster
uses: container-tools/kind-action@v2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static Version loadFromProperties() {
log.warnf("Couldn't load extension version information: {0}", e.getMessage());
}
} else {
log.warn("Couldn't find version.properties file. Default version information will be used.");
log.warn("Couldn't find extension-version.properties file. Default version information will be used.");
}

Date builtTime;
Expand Down
48 changes: 48 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,53 @@
<module>samples</module>
</modules>
</profile>
<profile>
<id>native-image</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>${native.surefire.skip}</skipTests>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager
</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>
${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager
</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<quarkus.package.type>native</quarkus.package.type>
<skipDocs>true</skipDocs>
</properties>
</profile>
</profiles>
</project>
9 changes: 0 additions & 9 deletions samples/exposedapp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,4 @@
</plugin>
</plugins>
</build>

<profiles>
<profile>
<id>native</id>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ public UpdateControl<ExposedApp> reconcile(ExposedApp exposedApp, Context<Expose
if (wrs.allDependentResourcesReady()) {
final var url = IngressDependent.getExposedURL(
context.getSecondaryResource(Ingress.class).orElseThrow());
log.info("App {} is exposed and ready to be used at {}", name, url);
exposedApp.setStatus(new ExposedAppStatus(url));
exposedApp.setStatus(new ExposedAppStatus(url, exposedApp.getSpec().getEndpoint()));
log.info("App {} is exposed and ready to be used at {}", name, exposedApp.getStatus().getHost());
return UpdateControl.updateStatus(exposedApp);
} else {
final var duration = Duration.ofSeconds(5);
final var duration = Duration.ofSeconds(1);
log.info("App {} is not ready yet, rescheduling reconciliation after {}s", name, duration.toSeconds());
return UpdateControl.<ExposedApp> noUpdate().rescheduleAfter(duration);
}
Expand Down
10 changes: 10 additions & 0 deletions samples/exposedapp/src/main/java/io/halkyon/ExposedAppSpec.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ public class ExposedAppSpec {
private String imageRef;
private Map<String, String> env;

private String endpoint;

public String getEndpoint() {
return endpoint;
}

public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}

public String getImageRef() {
return imageRef;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public ExposedAppStatus() {
message = "processing";
}

public ExposedAppStatus(String hostname) {
public ExposedAppStatus(String hostname, String endpoint) {
this.message = "exposed";
this.host = hostname;
this.host = endpoint != null && !endpoint.isBlank() ? hostname + '/' + endpoint : hostname;
ready = true;
waitTime = System.currentTimeMillis() - waitTime;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,41 @@

import java.util.Map;

import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder;
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.GenericKubernetesResourceMatcher;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.ResourceUpdatePreProcessor;
import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;

public class IngressDependent extends CRUDKubernetesDependentResource<Ingress, ExposedApp> implements
Condition<Ingress, ExposedApp> {
Condition<Ingress, ExposedApp>, Matcher<Ingress, ExposedApp>, ResourceUpdatePreProcessor<Ingress> {

public IngressDependent() {
super(Ingress.class);
}

@Override
public Result<Ingress> match(Ingress actualResource, ExposedApp primary,
Context<ExposedApp> context) {
return GenericKubernetesResourceMatcher.match(this, actualResource, primary, context, true);
}

@Override
@SuppressWarnings("unchecked")
public Ingress desired(ExposedApp exposedApp, Context context) {
final var labels = (Map<String, String>) context.managedDependentResourceContext()
.getMandatory(LABELS_CONTEXT_KEY, Map.class);
final var metadata = createMetadata(exposedApp, labels);
metadata.setAnnotations(Map.of(
"nginx.ingress.kubernetes.io/rewrite-target", "/",
"kubernetes.io/ingress.class", "nginx"));

/*
* metadata.setAnnotations(Map.of(
* "nginx.ingress.kubernetes.io/rewrite-target", "/",
* "kubernetes.io/ingress.class", "nginx"));
*/
return new IngressBuilder()
.withMetadata(metadata)
.withNewSpec()
Expand Down Expand Up @@ -77,4 +88,12 @@ public boolean isMet(DependentResource<Ingress, ExposedApp> dependentResource,
return false;
}).orElse(false);
}

@Override
public Ingress replaceSpecOnActual(Ingress actual, Ingress desired, Context<?> context) {
final var metadata = new ObjectMetaBuilder(desired.getMetadata()).build();
actual.setMetadata(metadata);
actual.setSpec(desired.getSpec());
return actual;
}
}
2 changes: 1 addition & 1 deletion samples/exposedapp/src/main/resources/app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ kind: ExposedApp
metadata:
name: hello-quarkus
spec:
imageRef: 'claprun/hello:1.0.0-SNAPSHOT'
imageRef: 'quay.io/metacosm/hello:1.0.0-SNAPSHOT'
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@
# set to true to automatically apply CRDs to the cluster when they get regenerated
quarkus.operator-sdk.crd.apply=true
quarkus.kubernetes-client.devservices.override-kubeconfig=true
%test.quarkus.operator-sdk.close-client-on-stop=false
%test.quarkus.operator-sdk.close-client-on-stop=false
%test.quarkus.operator-sdk.start-operator=true
quarkus.kubernetes-client.devservices.flavor=k3s
Original file line number Diff line number Diff line change
Expand Up @@ -7,66 +7,21 @@

import java.util.concurrent.TimeUnit;

import jakarta.inject.Inject;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;

import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.Operator;
import io.quarkus.kubernetes.client.runtime.KubernetesClientUtils;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
class ExposedAppReconcilerTest {

public static final String TEST_APP = "test-app";
@Inject
KubernetesClient client;

@Inject
Operator operator;

@BeforeEach
void startOperator() {
operator.start();
}

@AfterEach
void stopOperator() {
operator.stop();
}
protected final KubernetesClient client = KubernetesClientUtils.createClient();

@Test
@Order(2)
void deleteShouldWork() {
final var app = new ExposedApp();
final var metadata = new ObjectMetaBuilder()
.withName(TEST_APP)
.withNamespace(client.getNamespace())
.build();
app.setMetadata(metadata);
app.getSpec().setImageRef("group/imageName:tag");

client.resource(app).delete();

await().atMost(30, TimeUnit.SECONDS).untilAsserted(() -> {
assertThat(client.apps().deployments()
.inNamespace(metadata.getNamespace())
.withName(metadata.getName()).get(), nullValue());
assertThat(client.services()
.inNamespace(metadata.getNamespace())
.withName(metadata.getName()).get(), nullValue());
assertThat(client.network().v1().ingresses()
.inNamespace(metadata.getNamespace())
.withName(metadata.getName()).get(), nullValue());
});
}

@Test
@Order(1)
void reconcileShouldWork() {
final var app = new ExposedApp();
final var metadata = new ObjectMetaBuilder()
Expand Down Expand Up @@ -100,9 +55,12 @@ void reconcileShouldWork() {
// check that the ingress is created
final var ingress = client.network().v1().ingresses()
.inNamespace(metadata.getNamespace()).withName(metadata.getName()).get();
final var annotations = ingress.getMetadata().getAnnotations();
assertThat(annotations.size(), is(2));
assertThat(annotations.get("kubernetes.io/ingress.class"), is("nginx"));
// not using nginx controller on k3s
/*
* final var annotations = ingress.getMetadata().getAnnotations();
* assertThat(annotations.size(), is(2));
* assertThat(annotations.get("kubernetes.io/ingress.class"), is("nginx"));
*/
final var rules = ingress.getSpec().getRules();
assertThat(rules.size(), is(1));
final var paths = rules.get(0).getHttp().getPaths();
Expand All @@ -114,5 +72,19 @@ void reconcileShouldWork() {
assertThat(serviceBackend.getName(), is(service.getMetadata().getName()));
assertThat(serviceBackend.getPort().getNumber(), is(port));
});

client.resource(app).delete();

await().atMost(30, TimeUnit.SECONDS).untilAsserted(() -> {
assertThat(client.apps().deployments()
.inNamespace(metadata.getNamespace())
.withName(metadata.getName()).get(), nullValue());
assertThat(client.services()
.inNamespace(metadata.getNamespace())
.withName(metadata.getName()).get(), nullValue());
assertThat(client.network().v1().ingresses()
.inNamespace(metadata.getNamespace())
.withName(metadata.getName()).get(), nullValue());
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.halkyon;

import org.junit.jupiter.api.Disabled;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
@Disabled("Currently not possible to inject the dev service-provided k8s client in native app")
public class NativeExposedAppReconcilerIT extends ExposedAppReconcilerTest {

}