Skip to content

Commit

Permalink
Fix broken sidecar handling
Browse files Browse the repository at this point in the history
  • Loading branch information
geoand committed Jun 29, 2020
1 parent 2810852 commit f23d210
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.quarkus.kubernetes.deployment;

import io.dekorate.deps.kubernetes.api.model.ContainerBuilder;
import io.dekorate.kubernetes.annotation.Protocol;
import io.dekorate.kubernetes.config.Port;
import io.dekorate.kubernetes.decorator.AddSidecarDecorator;
import io.dekorate.kubernetes.decorator.ContainerDecorator;
import io.dekorate.kubernetes.decorator.Decorator;
import io.dekorate.kubernetes.decorator.ResourceProvidingDecorator;

/**
* Adapted from Dekorate's {@link io.dekorate.kubernetes.decorator.AddPortDecorator} in order to
* address the limitation that the port was not being added (due to missing metadata)
*/
class AddContainerPortDecorator extends Decorator<ContainerBuilder> {

private final Port port;

AddContainerPortDecorator(Port port) {
this.port = port;
}

@Override
public void visit(ContainerBuilder containerBuilder) {
containerBuilder.addNewPort()
.withName(port.getName())
.withHostPort(port.getHostPort() > 0 ? port.getHostPort() : null)
.withContainerPort(port.getContainerPort())
.withProtocol(port.getProtocol() != null ? port.getProtocol().name() : Protocol.TCP.name())
.endPort();
}

public Class<? extends Decorator>[] after() {
return new Class[] { ResourceProvidingDecorator.class, ContainerDecorator.class, AddSidecarDecorator.class };
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.quarkus.kubernetes.deployment;

import io.dekorate.deps.kubernetes.api.model.ObjectMeta;
import io.dekorate.deps.kubernetes.api.model.PodSpecBuilder;
import io.dekorate.kubernetes.config.Container;
import io.dekorate.kubernetes.decorator.Decorator;
import io.dekorate.kubernetes.decorator.NamedResourceDecorator;
import io.dekorate.kubernetes.decorator.ResourceProvidingDecorator;

/**
* Copied from dekorate in order to fix some issues
*/
class AddSidecarDecorator extends NamedResourceDecorator<PodSpecBuilder> {

private final Container container;

public AddSidecarDecorator(Container container) {
this(ANY, container);
}

public AddSidecarDecorator(String deployment, Container container) {
super(deployment);
this.container = container;
}

@Override
public void andThenVisit(PodSpecBuilder podSpec, ObjectMeta resourceMeta) {
// this was changed to use our patched adapter
podSpec.addToContainers(ContainerAdapter.adapt(container));
}

public Class<? extends Decorator>[] after() {
return new Class[] { ResourceProvidingDecorator.class };
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.quarkus.kubernetes.deployment;

import io.dekorate.deps.kubernetes.api.model.Container;
import io.dekorate.deps.kubernetes.api.model.ContainerBuilder;
import io.dekorate.kubernetes.config.Env;
import io.dekorate.kubernetes.config.Mount;
import io.dekorate.kubernetes.config.Port;
import io.dekorate.kubernetes.decorator.AddEnvVarDecorator;
import io.dekorate.kubernetes.decorator.AddLivenessProbeDecorator;
import io.dekorate.kubernetes.decorator.AddMountDecorator;
import io.dekorate.kubernetes.decorator.AddReadinessProbeDecorator;
import io.dekorate.kubernetes.decorator.ApplyImagePullPolicyDecorator;
import io.dekorate.utils.Images;
import io.dekorate.utils.Strings;

/**
* Copied from dekorate in order to fix some issues
*/
public class ContainerAdapter {

public static Container adapt(io.dekorate.kubernetes.config.Container container) {
String name = container.getName();
if (Strings.isNullOrEmpty(name)) {
name = Images.getName(container.getImage());
}

ContainerBuilder builder = new ContainerBuilder()
.withName(name)
.withImage(container.getImage())
// this was changed to add working dir
.withWorkingDir(container.getWorkingDir())
.withCommand(container.getCommand())
.withArgs(container.getArguments());

for (Env env : container.getEnvVars()) {
builder.accept(new AddEnvVarDecorator(env));
}
for (Port port : container.getPorts()) {
// this was changed to use our patched port decorator
builder.accept(new AddContainerPortDecorator(port));
}
for (Mount mount : container.getMounts()) {
builder.accept(new AddMountDecorator(mount));
}

builder.accept(new ApplyImagePullPolicyDecorator(container.getImagePullPolicy()));

builder.accept(new AddLivenessProbeDecorator(name, container.getLivenessProbe()));
builder.accept(new AddReadinessProbeDecorator(name, container.getReadinessProbe()));
return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ public static Container convert(Map.Entry<String, ContainerConfig> e) {

private static ContainerBuilder convert(ContainerConfig c) {
ContainerBuilder b = new ContainerBuilder();
c.image.ifPresent(i -> b.withImage(i));
c.workingDir.ifPresent(w -> b.withWorkingDir(w));
c.image.ifPresent(b::withImage);
c.workingDir.ifPresent(b::withWorkingDir);
c.command.ifPresent(w -> b.withCommand(w.toArray(new String[0])));
c.arguments.ifPresent(w -> b.withArguments(w.toArray(new String[0])));
c.readinessProbe.ifPresent(p -> b.withReadinessProbe(ProbeConverter.convert(p)));
c.livenessProbe.ifPresent(p -> b.withLivenessProbe(ProbeConverter.convert(p)));
b.addAllToEnvVars(c.convertToEnvs());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ public Map<String, ContainerConfig> getInitContainers() {
return initContainers;
}

public Map<String, ContainerConfig> getContainers() {
public Map<String, ContainerConfig> getSidecars() {
return containers;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public class KubernetesConfig implements PlatformConfiguration {
* Sidecar containers
*/
@ConfigItem
Map<String, ContainerConfig> containers;
Map<String, ContainerConfig> sidecars;

/**
* The target deployment platform.
Expand Down Expand Up @@ -354,8 +354,8 @@ public Map<String, ContainerConfig> getInitContainers() {
return initContainers;
}

public Map<String, ContainerConfig> getContainers() {
return containers;
public Map<String, ContainerConfig> getSidecars() {
return sidecars;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ private void applyConfig(Session session, Project project, String target, String
session.resources().decorate(target, new AddInitContainerDecorator(name, ContainerConverter.convert(e)));
});

config.getContainers().entrySet().forEach(e -> {
config.getSidecars().entrySet().forEach(e -> {
session.resources().decorate(target, new AddSidecarDecorator(name, ContainerConverter.convert(e)));
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ public Map<String, ContainerConfig> getInitContainers() {
return initContainers;
}

public Map<String, ContainerConfig> getContainers() {
public Map<String, ContainerConfig> getSidecars() {
return containers;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public interface PlatformConfiguration extends EnvVarHolder {

Map<String, ContainerConfig> getInitContainers();

Map<String, ContainerConfig> getContainers();
Map<String, ContainerConfig> getSidecars();

default boolean isExpose() {
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.quarkus.it.kubernetes;

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

import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

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.apps.Deployment;
import io.quarkus.bootstrap.model.AppArtifact;
import io.quarkus.builder.Version;
import io.quarkus.test.ProdBuildResults;
import io.quarkus.test.ProdModeTestResults;
import io.quarkus.test.QuarkusProdModeTest;

public class KubernetesWithSidecarAndJibTest {

@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class))
.setApplicationName("sidecar-test")
.setApplicationVersion("0.1-SNAPSHOT")
.withConfigurationResource("kubernetes-with-sidecar-and-jib.properties")
.setLogFileName("k8s.log")
.setForcedDependencies(
Collections.singletonList(
new AppArtifact("io.quarkus", "quarkus-container-image-jib", Version.getVersion())));

@ProdBuildResults
private ProdModeTestResults prodModeTestResults;

@Test
public void assertGeneratedResources() throws IOException {
final Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes");
assertThat(kubernetesDir)
.isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.json"))
.isDirectoryContaining(p -> p.getFileName().endsWith("kubernetes.yml"));
List<HasMetadata> kubernetesList = DeserializationUtil
.deserializeAsList(kubernetesDir.resolve("kubernetes.yml"));
assertThat(kubernetesList.get(0)).isInstanceOfSatisfying(Deployment.class, d -> {
assertThat(d.getMetadata()).satisfies(m -> {
assertThat(m.getName()).isEqualTo("sidecar-test");
});

assertThat(d.getSpec()).satisfies(deploymentSpec -> {
assertThat(deploymentSpec.getTemplate()).satisfies(t -> {
assertThat(t.getSpec()).satisfies(podSpec -> {
assertThat(podSpec.getContainers()).hasSize(2);
assertThat(podSpec.getContainers()).filteredOn(ps -> "sc".equals(ps.getName()))
.hasOnlyOneElementSatisfying(c -> {
assertThat(c.getImage()).isEqualTo("quay.io/sidecar/image:2.1");
assertThat(c.getImagePullPolicy()).isEqualTo("IfNotPresent");
assertThat(c.getCommand()).containsOnly("ls");
assertThat(c.getArgs()).containsOnly("-l");
assertThat(c.getWorkingDir()).isEqualTo("/work");
assertThat(c.getVolumeMounts()).hasOnlyOneElementSatisfying(volumeMount -> {
assertThat(volumeMount.getName()).isEqualTo("app-config");
assertThat(volumeMount.getMountPath()).isEqualTo("/deployments/config");
});
assertThat(c.getPorts()).hasOnlyOneElementSatisfying(p -> {
assertThat(p.getContainerPort()).isEqualTo(3000);
});
});
assertThat(podSpec.getContainers()).filteredOn(ps -> "sidecar-test".equals(ps.getName()))
.hasOnlyOneElementSatisfying(c -> {
assertThat(c.getImage()).isEqualTo("docker.io/somegrp/sidecar-test:0.1-SNAPSHOT");
assertThat(c.getImagePullPolicy()).isEqualTo("Always");
assertThat(c.getCommand()).isEmpty();
assertThat(c.getArgs()).isEmpty();
assertThat(c.getWorkingDir()).isNull();
assertThat(c.getVolumeMounts()).isEmpty();
assertThat(c.getPorts()).hasOnlyOneElementSatisfying(p -> {
assertThat(p.getContainerPort()).isEqualTo(8080);
});
});
});
});
});
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
quarkus.kubernetes.deployment-target=kubernetes
quarkus.container-image.group=somegrp
quarkus.container-image.registry=docker.io
quarkus.kubernetes.sidecars.sc.image=quay.io/sidecar/image:2.1
quarkus.kubernetes.sidecars.sc.image-pull-policy=IfNotPresent
quarkus.kubernetes.sidecars.sc.command=ls
quarkus.kubernetes.sidecars.sc.working-dir=/work
quarkus.kubernetes.sidecars.sc.arguments=-l
quarkus.kubernetes.sidecars.sc.mounts.app-config.path=/deployments/config
quarkus.kubernetes.sidecars.sc.ports.http.container-port=3000

0 comments on commit f23d210

Please sign in to comment.