Skip to content

Commit

Permalink
feat: Allow controlling init containers via spi
Browse files Browse the repository at this point in the history
  • Loading branch information
iocanel committed Nov 16, 2022
1 parent 16acc1e commit 7015944
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import io.quarkus.kubernetes.spi.KubernetesEnvBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesInitContainerBuildItem;
import io.quarkus.kubernetes.spi.KubernetesLabelBuildItem;
import io.quarkus.kubernetes.spi.KubernetesPortBuildItem;
import io.quarkus.kubernetes.spi.KubernetesResourceMetadataBuildItem;
Expand Down Expand Up @@ -93,6 +94,7 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
KubernetesConfig config,
PackageConfig packageConfig,
Optional<MetricsCapabilityBuildItem> metricsConfiguration,
List<KubernetesInitContainerBuildItem> initContainers,
List<KubernetesAnnotationBuildItem> annotations,
List<KubernetesLabelBuildItem> labels,
List<KubernetesEnvBuildItem> envs,
Expand All @@ -107,7 +109,8 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
Optional<CustomProjectRootBuildItem> customProjectRoot) {

return DevClusterHelper.createDecorators(KIND, applicationInfo, outputTarget, config, packageConfig,
metricsConfiguration, annotations, labels, envs, baseImage, image, command, ports, livenessPath, readinessPath,
metricsConfiguration, initContainers, annotations, labels, envs, baseImage, image, command, ports, livenessPath,
readinessPath,
roles, roleBindings, customProjectRoot);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import io.quarkus.kubernetes.spi.KubernetesEnvBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesInitContainerBuildItem;
import io.quarkus.kubernetes.spi.KubernetesLabelBuildItem;
import io.quarkus.kubernetes.spi.KubernetesPortBuildItem;
import io.quarkus.kubernetes.spi.KubernetesResourceMetadataBuildItem;
Expand Down Expand Up @@ -89,6 +90,7 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
KubernetesConfig config,
PackageConfig packageConfig,
Optional<MetricsCapabilityBuildItem> metricsConfiguration,
List<KubernetesInitContainerBuildItem> initContainers,
List<KubernetesAnnotationBuildItem> annotations,
List<KubernetesLabelBuildItem> labels,
List<KubernetesEnvBuildItem> envs,
Expand All @@ -103,7 +105,8 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
Optional<CustomProjectRootBuildItem> customProjectRoot) {

return DevClusterHelper.createDecorators(MINIKUBE, applicationInfo, outputTarget, config, packageConfig,
metricsConfiguration, annotations, labels, envs, baseImage, image, command, ports, livenessPath, readinessPath,
metricsConfiguration, initContainers, annotations, labels, envs, baseImage, image, command, ports, livenessPath,
readinessPath,
roles, roleBindings, customProjectRoot);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package io.quarkus.kubernetes.spi;

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

import io.quarkus.builder.item.MultiBuildItem;

/**
* A built item for generating init containers.
* The generated container will have the specified fields
* and may optionally inherit env vars and volumes from the app container.
*
* Env vars specified through this build item, will take precedence over inherited ones.
*/
public final class KubernetesInitContainerBuildItem extends MultiBuildItem {

private final String name;
private final String image;
private final List<String> command;
private final List<String> arguments;
private final Map<String, String> envVars;
private final boolean inheritEnvVars;
private final boolean inheritMounts;

public static KubernetesInitContainerBuildItem create(String image) {
return new KubernetesInitContainerBuildItem("init", image, Collections.emptyList(), Collections.emptyList(),
Collections.emptyMap(), false, false);
}

public KubernetesInitContainerBuildItem(String name, String image, List<String> command, List<String> arguments,
Map<String, String> envVars, boolean inheritEnvVars, boolean inheritMounts) {
this.name = name;
this.image = image;
this.command = command;
this.arguments = arguments;
this.envVars = envVars;
this.inheritEnvVars = inheritEnvVars;
this.inheritMounts = inheritMounts;
}

public String getName() {
return name;
}

public KubernetesInitContainerBuildItem withName(String name) {
return new KubernetesInitContainerBuildItem(name, image, command, arguments, envVars, inheritEnvVars, inheritMounts);
}

public String getImage() {
return image;
}

public KubernetesInitContainerBuildItem withImage(String image) {
return new KubernetesInitContainerBuildItem(name, image, command, arguments, envVars, inheritEnvVars, inheritMounts);
}

public List<String> getCommand() {
return command;
}

public KubernetesInitContainerBuildItem withCommand(List<String> command) {
return new KubernetesInitContainerBuildItem(name, image, command, arguments, envVars, inheritEnvVars, inheritMounts);
}

public List<String> getArguments() {
return arguments;
}

public KubernetesInitContainerBuildItem withArguments(List<String> arguments) {
return new KubernetesInitContainerBuildItem(name, image, command, arguments, envVars, inheritEnvVars, inheritMounts);
}

public Map<String, String> getEnvVars() {
return envVars;
}

public KubernetesInitContainerBuildItem withEnvVars(Map<String, String> envVars) {
return new KubernetesInitContainerBuildItem(name, image, command, arguments, envVars, inheritEnvVars, inheritMounts);
}

public boolean isInheritEnvVars() {
return inheritEnvVars;
}

public KubernetesInitContainerBuildItem withInheritEnvVars(boolean inheritEnvVars) {
return new KubernetesInitContainerBuildItem(name, image, command, arguments, envVars, inheritEnvVars, inheritMounts);
}

public boolean isInheritMounts() {
return inheritMounts;
}

public KubernetesInitContainerBuildItem withInheritMounts(boolean inheritMounts) {
return new KubernetesInitContainerBuildItem(name, image, command, arguments, envVars, inheritEnvVars, inheritMounts);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import io.quarkus.kubernetes.spi.KubernetesEnvBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesInitContainerBuildItem;
import io.quarkus.kubernetes.spi.KubernetesLabelBuildItem;
import io.quarkus.kubernetes.spi.KubernetesPortBuildItem;
import io.quarkus.kubernetes.spi.KubernetesRoleBindingBuildItem;
Expand All @@ -53,6 +54,7 @@ public static List<DecoratorBuildItem> createDecorators(String clusterKind,
KubernetesConfig config,
PackageConfig packageConfig,
Optional<MetricsCapabilityBuildItem> metricsConfiguration,
List<KubernetesInitContainerBuildItem> initContainers,
List<KubernetesAnnotationBuildItem> annotations,
List<KubernetesLabelBuildItem> labels,
List<KubernetesEnvBuildItem> envs,
Expand Down Expand Up @@ -114,6 +116,8 @@ public static List<DecoratorBuildItem> createDecorators(String clusterKind,
.findFirst().orElse(DEFAULT_HTTP_PORT);
result.add(new DecoratorBuildItem(clusterKind, new ApplyHttpGetActionPortDecorator(name, name, port)));

// Handle init Containers
result.addAll(KubernetesCommonHelper.createInitContainerDecorators(clusterKind, name, initContainers, result));
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
String name = ResourceNameUtil.getResourceName(config, applicationInfo);
Optional<Project> project = KubernetesCommonHelper.createProject(applicationInfo, customProjectRoot, outputTarget,
packageConfig);
result.addAll(KubernetesCommonHelper.createDecorators(project, KNATIVE, name, config, metricsConfiguration, annotations,
result.addAll(KubernetesCommonHelper.createDecorators(project, KNATIVE, name, config, metricsConfiguration,
annotations,
labels, command, ports, livenessPath, readinessPath, roles, roleBindings));

image.ifPresent(i -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import io.dekorate.utils.Annotations;
import io.dekorate.utils.Labels;
import io.dekorate.utils.Strings;
import io.fabric8.kubernetes.api.model.ContainerBuilder;
import io.quarkus.deployment.builditem.ApplicationInfoBuildItem;
import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem;
import io.quarkus.deployment.pkg.PackageConfig;
Expand All @@ -73,6 +74,7 @@
import io.quarkus.kubernetes.spi.KubernetesCommandBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesInitContainerBuildItem;
import io.quarkus.kubernetes.spi.KubernetesLabelBuildItem;
import io.quarkus.kubernetes.spi.KubernetesPortBuildItem;
import io.quarkus.kubernetes.spi.KubernetesRoleBindingBuildItem;
Expand Down Expand Up @@ -271,6 +273,77 @@ private static List<DecoratorBuildItem> createArgsDecorator(Optional<Project> pr
return result;
}

public static List<DecoratorBuildItem> createInitContainerDecorators(String target, String name,
List<KubernetesInitContainerBuildItem> items, List<DecoratorBuildItem> decorators) {
List<DecoratorBuildItem> result = new ArrayList<>();

List<AddEnvVarDecorator> envVarDecorators = decorators.stream()
.filter(d -> d.getGroup().equals(target))
.map(d -> d.getDecorator(AddEnvVarDecorator.class))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());

List<AddMountDecorator> mountDecorators = decorators.stream()
.filter(d -> d.getGroup().equals(target))
.map(d -> d.getDecorator(AddMountDecorator.class))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());

for (KubernetesInitContainerBuildItem item : items) {
io.dekorate.kubernetes.config.ContainerBuilder containerBuilder = new io.dekorate.kubernetes.config.ContainerBuilder()
.withName(item.getName())
.withImage(item.getImage())
.withCommand(item.getCommand().toArray(new String[item.getCommand().size()]))
.withArguments(item.getArguments().toArray(new String[item.getArguments().size()]));

if (item.isInheritEnvVars()) {
for (final AddEnvVarDecorator delegate : envVarDecorators) {
result.add(new DecoratorBuildItem(target,
new ApplicationContainerDecorator<ContainerBuilder>(name, item.getName()) {
@Override
public void andThenVisit(ContainerBuilder builder) {
delegate.andThenVisit(builder);
// Currently, we have no way to filter out provided env vars.
// So, we apply them on top of every change.
// This needs to be addressed in dekorate to make things more efficient
for (Map.Entry<String, String> e : item.getEnvVars().entrySet()) {
builder.removeMatchingFromEnv(p -> p.getName().equals(e.getKey()));
builder.addNewEnv()
.withName(e.getKey())
.withValue(e.getValue())
.endEnv();

}
}
}));
}
}

if (item.isInheritMounts()) {
for (final AddMountDecorator delegate : mountDecorators) {
result.add(new DecoratorBuildItem(target,
new ApplicationContainerDecorator<ContainerBuilder>(target, item.getName()) {
@Override
public void andThenVisit(ContainerBuilder builder) {
delegate.andThenVisit(builder);
}
}));
}
}

result.add(new DecoratorBuildItem(target,
new AddInitContainerDecorator(name, containerBuilder
.addAllToEnvVars(item.getEnvVars().entrySet().stream().map(e -> new EnvBuilder()
.withName(e.getKey())
.withValue(e.getValue())
.build()).collect(Collectors.toList()))
.build())));
}
return result;
}

/**
* Creates container decorator build items.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import io.quarkus.kubernetes.spi.KubernetesEnvBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesInitContainerBuildItem;
import io.quarkus.kubernetes.spi.KubernetesLabelBuildItem;
import io.quarkus.kubernetes.spi.KubernetesPortBuildItem;
import io.quarkus.kubernetes.spi.KubernetesResourceMetadataBuildItem;
Expand Down Expand Up @@ -167,6 +168,7 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
PackageConfig packageConfig,
Optional<MetricsCapabilityBuildItem> metricsConfiguration,
Capabilities capabilities,
List<KubernetesInitContainerBuildItem> initContainers,
List<KubernetesAnnotationBuildItem> annotations,
List<KubernetesLabelBuildItem> labels,
List<KubernetesEnvBuildItem> envs,
Expand Down Expand Up @@ -329,6 +331,8 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
config.remoteDebug.buildJavaToolOptionsEnv())));
}

// Handle init Containers
result.addAll(KubernetesCommonHelper.createInitContainerDecorators(OPENSHIFT, name, initContainers, result));
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import io.quarkus.kubernetes.spi.KubernetesEnvBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthLivenessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesHealthReadinessPathBuildItem;
import io.quarkus.kubernetes.spi.KubernetesInitContainerBuildItem;
import io.quarkus.kubernetes.spi.KubernetesLabelBuildItem;
import io.quarkus.kubernetes.spi.KubernetesPortBuildItem;
import io.quarkus.kubernetes.spi.KubernetesResourceMetadataBuildItem;
Expand Down Expand Up @@ -124,7 +125,10 @@ public List<ConfiguratorBuildItem> createConfigurators(KubernetesConfig config,
@BuildStep
public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applicationInfo,
OutputTargetBuildItem outputTarget, Capabilities capabilities, KubernetesConfig config, PackageConfig packageConfig,
Optional<MetricsCapabilityBuildItem> metricsConfiguration, List<KubernetesAnnotationBuildItem> annotations,
Optional<MetricsCapabilityBuildItem> metricsConfiguration,

List<KubernetesInitContainerBuildItem> initContainers,
List<KubernetesAnnotationBuildItem> annotations,
List<KubernetesLabelBuildItem> labels, List<KubernetesEnvBuildItem> envs,
Optional<ContainerImageInfoBuildItem> image, Optional<KubernetesCommandBuildItem> command,
List<KubernetesPortBuildItem> ports, Optional<KubernetesHealthLivenessPathBuildItem> livenessPath,
Expand All @@ -141,8 +145,9 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic

Optional<Project> project = KubernetesCommonHelper.createProject(applicationInfo, customProjectRoot, outputTarget,
packageConfig);
result.addAll(KubernetesCommonHelper.createDecorators(project, KUBERNETES, name, config, metricsConfiguration,
annotations, labels, command, ports, livenessPath, readinessPath, roles, roleBindings));
result.addAll(
KubernetesCommonHelper.createDecorators(project, KUBERNETES, name, config, metricsConfiguration, annotations,
labels, command, ports, livenessPath, readinessPath, roles, roleBindings));

KubernetesConfig.DeploymentResourceKind deploymentKind = config.getDeploymentResourceKind(capabilities);
if (deploymentKind != KubernetesConfig.DeploymentResourceKind.Deployment) {
Expand Down Expand Up @@ -248,6 +253,8 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic
config.remoteDebug.buildJavaToolOptionsEnv())));
}

// Handle init Containers
result.addAll(KubernetesCommonHelper.createInitContainerDecorators(KUBERNETES, name, initContainers, result));
return result;
}

Expand Down

0 comments on commit 7015944

Please sign in to comment.