Skip to content

Commit

Permalink
Add disable-init-tasks property to disable generation of tasks by name
Browse files Browse the repository at this point in the history
Fix #33097
  • Loading branch information
Sgitario committed May 18, 2023
1 parent 1a6b852 commit 70403dd
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import io.dekorate.kubernetes.config.EnvBuilder;
import io.dekorate.kubernetes.decorator.AddEnvVarDecorator;
Expand All @@ -26,7 +27,9 @@ public class InitTaskProcessor {
static void process(
String target, // kubernetes, openshift, etc.
String name,
ContainerImageInfoBuildItem image, List<InitTaskBuildItem> initTasks,
ContainerImageInfoBuildItem image,
List<InitTaskBuildItem> initTasks,
Optional<List<String>> disableInitJobs,
BuildProducer<KubernetesJobBuildItem> jobs,
BuildProducer<KubernetesInitContainerBuildItem> initContainers,
BuildProducer<KubernetesEnvBuildItem> env,
Expand All @@ -35,30 +38,30 @@ static void process(
BuildProducer<DecoratorBuildItem> decorators) {

List<String> initContainerWaiterArgs = new ArrayList<>(initTasks.size() + 1);
initContainerWaiterArgs.add("job");
for (InitTaskBuildItem task : initTasks) {
if (disableInitJobs.isEmpty() || !disableInitJobs.get().contains(task.getName())) {
initContainerWaiterArgs.add(task.getName());
jobs.produce(KubernetesJobBuildItem.create(image.getImage())
.withName(task.getName())
.withTarget(target)
.withEnvVars(task.getTaskEnvVars())
.withCommand(task.getCommand())
.withArguments(task.getArguments())
.withSharedEnvironment(task.isSharedEnvironment())
.withSharedFilesystem(task.isSharedFilesystem()));

initTasks.forEach(task -> {
initContainerWaiterArgs.add(task.getName());
jobs.produce(KubernetesJobBuildItem.create(image.getImage())
.withName(task.getName())
.withTarget(target)
.withEnvVars(task.getTaskEnvVars())
.withCommand(task.getCommand())
.withArguments(task.getArguments())
.withSharedEnvironment(task.isSharedEnvironment())
.withSharedFilesystem(task.isSharedFilesystem()));

task.getAppEnvVars().forEach((k, v) -> {
decorators.produce(new DecoratorBuildItem(target,
new AddEnvVarDecorator(ApplicationContainerDecorator.ANY, name, new EnvBuilder()
.withName(k)
.withValue(v)
.build())));
task.getAppEnvVars().forEach((k, v) -> {
decorators.produce(new DecoratorBuildItem(target,
new AddEnvVarDecorator(ApplicationContainerDecorator.ANY, name, new EnvBuilder()
.withName(k)
.withValue(v)
.build())));

});
});
});
}
}

if (!initTasks.isEmpty()) {
if (!initContainerWaiterArgs.isEmpty()) {
roles.produce(new KubernetesRoleBuildItem("view-jobs", Collections.singletonList(
new PolicyRule(
Collections.singletonList("batch"),
Expand All @@ -67,6 +70,7 @@ static void process(
target));
roleBindings.produce(new KubernetesRoleBindingBuildItem(null, "view-jobs", false, target));

initContainerWaiterArgs.add(0, "job");
initContainers.produce(KubernetesInitContainerBuildItem.create(INIT_CONTAINER_WAITER_NAME,
INIT_CONTAINER_WAITER_DEFAULT_IMAGE)
.withTarget(target)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,20 @@ public enum DeploymentResourceKind {
* Flag to enable init task externalization.
* When enabled (default), all initialization tasks
* created by extensions, will be externalized as Jobs.
* In addition the deployment will wait for these jobs.
* In addition, the deployment will wait for these jobs.
*/
@ConfigItem(defaultValue = "true")
boolean externalizeInit;

/**
* List of init tasks to be disabled and hence not to be generated. The init tasks are automatically generated by
* extensions like Flyway to perform the database migration before staring up the application.
*
* This property is only taken into account if `quarkus.kubernetes.externalize-init` is true.
*/
@ConfigItem
Optional<List<String>> disableInitTasks;

/**
* Switch used to control whether non-idempotent fields are included in generated kubernetes resources to improve
* git-ops compatibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,15 @@ public EnvVarsConfig getEnv() {
@ConfigItem(defaultValue = "true")
boolean externalizeInit;

/**
* List of init tasks to be disabled and hence not to be generated. The init tasks are automatically generated by
* extensions like Flyway to perform the database migration before staring up the application.
*
* This property is only taken into account if `quarkus.openshift.externalize-init` is true.
*/
@ConfigItem
Optional<List<String>> disableInitTasks;

/**
* Switch used to control whether non-idempotent fields are included in generated kubernetes resources to improve
* git-ops compatibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,8 @@ void externalizeInitTasks(
BuildProducer<DecoratorBuildItem> decorators) {
final String name = ResourceNameUtil.getResourceName(config, applicationInfo);
if (config.externalizeInit) {
InitTaskProcessor.process(OPENSHIFT, name, image, initTasks, jobs, initContainers, env, roles, roleBindings,
decorators);
InitTaskProcessor.process(OPENSHIFT, name, image, initTasks, config.disableInitTasks,
jobs, initContainers, env, roles, roleBindings, decorators);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ void externalizeInitTasks(
BuildProducer<DecoratorBuildItem> decorators) {
final String name = ResourceNameUtil.getResourceName(config, applicationInfo);
if (config.externalizeInit) {
InitTaskProcessor.process(KUBERNETES, name, image, initTasks, jobs, initContainers, env, roles, roleBindings,
decorators);
InitTaskProcessor.process(KUBERNETES, name, image, initTasks, config.disableInitTasks,
jobs, initContainers, env, roles, roleBindings, decorators);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.quarkus.it.kubernetes;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

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

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.fabric8.kubernetes.api.model.batch.v1.Job;
import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
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 KubernetesWithFlywayInitWithJobDisabledTest {

private static final String NAME = "kubernetes-with-flyway-with-job-disabled";

@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addClasses(GreetingResource.class))
.setApplicationName(NAME)
.setApplicationVersion("0.1-SNAPSHOT")
.setLogFileName("k8s.log")
.overrideConfigKey("quarkus.kubernetes.disable-init-tasks", NAME + "-flyway-init")
.setForcedDependencies(Arrays.asList(
new AppArtifact("io.quarkus", "quarkus-kubernetes", Version.getVersion()),
new AppArtifact("io.quarkus", "quarkus-flyway", 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"));

Optional<Deployment> deployment = kubernetesList.stream()
.filter(d -> "Deployment".equals(d.getKind())
&& NAME.equals(d.getMetadata().getName()))
.map(d -> (Deployment) d).findAny();

assertTrue(deployment.isPresent());
assertThat(deployment).satisfies(j -> j.isPresent());
assertThat(deployment.get()).satisfies(d -> {
assertThat(d.getMetadata()).satisfies(m -> {
assertThat(m.getName()).isEqualTo(NAME);
});

assertThat(d.getSpec()).satisfies(deploymentSpec -> {
assertThat(deploymentSpec.getTemplate()).satisfies(t -> {
assertThat(t.getSpec()).satisfies(podSpec -> {
assertThat(podSpec.getInitContainers()).noneSatisfy(container -> {
assertThat(container.getName()).isEqualTo("init");
});
});
});
});
});

Optional<Job> job = kubernetesList.stream()
.filter(j -> "Job".equals(j.getKind()) && (NAME + "-flyway-init").equals(j.getMetadata().getName()))
.map(j -> (Job) j)
.findAny();
assertFalse(job.isPresent());

Optional<RoleBinding> roleBinding = kubernetesList.stream().filter(
r -> r instanceof RoleBinding && (NAME + "-view-jobs").equals(r.getMetadata().getName()))
.map(r -> (RoleBinding) r).findFirst();
assertFalse(roleBinding.isPresent());
}
}

0 comments on commit 70403dd

Please sign in to comment.