Skip to content

Commit

Permalink
Add ingress rules for kind/minikube clusters
Browse files Browse the repository at this point in the history
  • Loading branch information
mcruzdev committed Oct 29, 2024
1 parent 6c6a730 commit 7e53a5a
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.kubernetes.deployment;

import static io.quarkus.kubernetes.deployment.Constants.INGRESS;
import static io.quarkus.kubernetes.deployment.Constants.KUBERNETES;
import static io.quarkus.kubernetes.deployment.Constants.LIVENESS_PROBE;
import static io.quarkus.kubernetes.deployment.Constants.MAX_NODE_PORT_VALUE;
Expand All @@ -22,8 +23,11 @@

import io.dekorate.kubernetes.annotation.ServiceType;
import io.dekorate.kubernetes.config.EnvBuilder;
import io.dekorate.kubernetes.config.IngressRuleBuilder;
import io.dekorate.kubernetes.config.Port;
import io.dekorate.kubernetes.decorator.AddAnnotationDecorator;
import io.dekorate.kubernetes.decorator.AddEnvVarDecorator;
import io.dekorate.kubernetes.decorator.AddIngressRuleDecorator;
import io.dekorate.kubernetes.decorator.ApplicationContainerDecorator;
import io.dekorate.kubernetes.decorator.ApplyImagePullPolicyDecorator;
import io.dekorate.project.Project;
Expand Down Expand Up @@ -155,6 +159,23 @@ public static List<DecoratorBuildItem> createDecorators(String clusterKind,
ports,
config.ports()));

for (Map.Entry<String, String> annotation : config.ingress().annotations().entrySet()) {
result.add(new DecoratorBuildItem(clusterKind,
new AddAnnotationDecorator(name, annotation.getKey(), annotation.getValue(), INGRESS)));
}

for (IngressConfig.IngressRuleConfig rule : config.ingress().rules().values()) {
result.add(new DecoratorBuildItem(clusterKind, new AddIngressRuleDecorator(name, port,
new IngressRuleBuilder()
.withHost(rule.host())
.withPath(rule.path())
.withPathType(rule.pathType())
.withServiceName(rule.serviceName().orElse(null))
.withServicePortName(rule.servicePortName().orElse(null))
.withServicePortNumber(rule.servicePortNumber().orElse(-1))
.build())));
}

// Handle init Containers
result.addAll(KubernetesCommonHelper.createInitContainerDecorators(clusterKind, name, initContainers, result));
result.addAll(KubernetesCommonHelper.createInitJobDecorators(clusterKind, name, jobs, result));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package io.quarkus.it.kubernetes;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

import org.assertj.core.api.SoftAssertions;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.fabric8.kubernetes.api.model.networking.v1.IngressRule;
import io.quarkus.builder.Version;
import io.quarkus.maven.dependency.Dependency;
import io.quarkus.test.ProdBuildResults;
import io.quarkus.test.ProdModeTestResults;
import io.quarkus.test.QuarkusProdModeTest;

public class KubernetesWithKindIngress {

private static final String LOCALHOST = "localhost";
@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class))
.setApplicationName("kind-ingress")
.setApplicationVersion("0.1-SNAPSHOT")
.setLogFileName("k8s.log")
// Configuration provided by issue: https://github.com/quarkusio/quarkus/issues/42294
.overrideConfigKey("quarkus.kubernetes.ingress.expose", "true")
.overrideConfigKey("quarkus.kubernetes.ingress.annotations.\"nginx.ingress.kubernetes.io/rewrite-target\"", "/$2")
.overrideConfigKey("quarkus.kubernetes.ingress.rules.1.host", LOCALHOST)
.overrideConfigKey("quarkus.kubernetes.ingress.rules.1.path", "/game(/|$)(.*)")
.overrideConfigKey("quarkus.kubernetes.ingress.rules.1.path-type", "ImplementationSpecific")
.overrideConfigKey("quarkus.kubernetes.ingress.ingress-class-name", "Nginx")
.setForcedDependencies(Arrays.asList(
Dependency.of("io.quarkus", "quarkus-kind", Version.getVersion()),
Dependency.of("io.quarkus", "quarkus-kubernetes", Version.getVersion())));
private static final Logger log = LoggerFactory.getLogger(KubernetesWithKindIngress.class);

@ProdBuildResults
private ProdModeTestResults prodModeTestResults;

@Test
void shouldCreateKindResourcesWithIngressAnnotationsCorrectly() throws IOException {
final Path kubernetesFile = prodModeTestResults.getBuildDir().resolve("kubernetes").resolve("kind.yml");
List<HasMetadata> kubernetesList = DeserializationUtil.deserializeAsList(kubernetesFile);

SoftAssertions.assertSoftly(softly -> {
softly.assertThat(kubernetesList).filteredOn(k -> k.getKind().equals("Ingress"))
.singleElement().isInstanceOfSatisfying(Ingress.class, ingress -> {

softly.assertThat(ingress.getMetadata().getAnnotations())
.anySatisfy((key, value) -> {
assertThat(key).isEqualTo("nginx.ingress.kubernetes.io/rewrite-target");
assertThat(value).isEqualTo("/$2");
});

softly.assertThat(ingress.getSpec()).satisfies(spec -> {

softly.assertThat(spec.getIngressClassName()).isEqualTo("Nginx");

softly.assertThat(spec.getRules()).hasSize(2);

softly.assertThat(spec.getRules()).filteredOn(byLocalhost())
.singleElement()
.satisfies(rule -> {

softly.assertThat(rule.getHttp().getPaths()).hasSize(1);
softly.assertThat(rule.getHttp().getPaths().get(0)).satisfies(path -> {

softly.assertThat(path.getPathType()).isEqualTo("ImplementationSpecific");
softly.assertThat(path.getPath()).isEqualTo("/game(/|$)(.*)");
softly.assertThat(path.getBackend().getService().getPort().getName())
.isEqualTo("http");
softly.assertThat(path.getBackend().getService().getName())
.isEqualTo("kind-ingress");

});
});
});
});
});
}

private static Predicate<IngressRule> byLocalhost() {
return rule -> rule.getHost() != null && rule.getHost().equals(LOCALHOST);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package io.quarkus.it.kubernetes;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

import org.assertj.core.api.SoftAssertions;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.networking.v1.Ingress;
import io.fabric8.kubernetes.api.model.networking.v1.IngressRule;
import io.quarkus.builder.Version;
import io.quarkus.maven.dependency.Dependency;
import io.quarkus.test.ProdBuildResults;
import io.quarkus.test.ProdModeTestResults;
import io.quarkus.test.QuarkusProdModeTest;

public class KubernetesWithMinikubeIngress {

private static final String LOCALHOST = "localhost";
@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class))
.setApplicationName("kind-ingress")
.setApplicationVersion("0.1-SNAPSHOT")
.setLogFileName("k8s.log")
// Configuration provided by issue: https://github.com/quarkusio/quarkus/issues/42294
.overrideConfigKey("quarkus.kubernetes.ingress.expose", "true")
.overrideConfigKey("quarkus.kubernetes.ingress.annotations.\"nginx.ingress.kubernetes.io/rewrite-target\"", "/$2")
.overrideConfigKey("quarkus.kubernetes.ingress.rules.1.host", LOCALHOST)
.overrideConfigKey("quarkus.kubernetes.ingress.rules.1.path", "/game(/|$)(.*)")
.overrideConfigKey("quarkus.kubernetes.ingress.rules.1.path-type", "ImplementationSpecific")
.overrideConfigKey("quarkus.kubernetes.ingress.ingress-class-name", "Nginx")
.setForcedDependencies(Arrays.asList(
Dependency.of("io.quarkus", "quarkus-minikube", Version.getVersion()),
Dependency.of("io.quarkus", "quarkus-kubernetes", Version.getVersion())));

@ProdBuildResults
private ProdModeTestResults prodModeTestResults;

@Test
void shouldCreateKindResourcesWithIngressAnnotationsCorrectly() throws IOException {
final Path kubernetesFile = prodModeTestResults.getBuildDir().resolve("kubernetes").resolve("minikube.yml");
List<HasMetadata> kubernetesList = DeserializationUtil.deserializeAsList(kubernetesFile);

SoftAssertions.assertSoftly(softly -> {
softly.assertThat(kubernetesList).filteredOn(k -> k.getKind().equals("Ingress"))
.singleElement().isInstanceOfSatisfying(Ingress.class, ingress -> {

softly.assertThat(ingress.getMetadata().getAnnotations())
.anySatisfy((key, value) -> {
assertThat(key).isEqualTo("nginx.ingress.kubernetes.io/rewrite-target");
assertThat(value).isEqualTo("/$2");
});

softly.assertThat(ingress.getSpec()).satisfies(spec -> {

softly.assertThat(spec.getIngressClassName()).isEqualTo("Nginx");

softly.assertThat(spec.getRules()).hasSize(2);

softly.assertThat(spec.getRules()).filteredOn(byLocalhost())
.singleElement()
.satisfies(rule -> {

softly.assertThat(rule.getHttp().getPaths()).hasSize(1);
softly.assertThat(rule.getHttp().getPaths().get(0)).satisfies(path -> {

softly.assertThat(path.getPathType()).isEqualTo("ImplementationSpecific");
softly.assertThat(path.getPath()).isEqualTo("/game(/|$)(.*)");
softly.assertThat(path.getBackend().getService().getPort().getName())
.isEqualTo("http");
softly.assertThat(path.getBackend().getService().getName())
.isEqualTo("kind-ingress");

});
});
});
});
});
}

private static Predicate<IngressRule> byLocalhost() {
return rule -> rule.getHost() != null && rule.getHost().equals(LOCALHOST);
}
}

0 comments on commit 7e53a5a

Please sign in to comment.