Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.kubernetes.deployment;

import io.dekorate.kubernetes.decorator.NamedResourceDecorator;
import io.fabric8.knative.serving.v1.RevisionSpecFluent;
import io.fabric8.kubernetes.api.model.ObjectMeta;

public class AddImagePullSecretToRevisionSpecDecorator extends NamedResourceDecorator<RevisionSpecFluent<?>> {

private final String imagePullSecret;

public AddImagePullSecretToRevisionSpecDecorator(String name, String imagePullSecret) {
super(name);
this.imagePullSecret = imagePullSecret;
}

@Override
public void andThenVisit(RevisionSpecFluent<?> revisionSpec, ObjectMeta resourceMeta) {
revisionSpec.addNewImagePullSecret(imagePullSecret);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,14 @@ default String targetPlatformName() {
*/
@WithDefault("CreateOrUpdate")
DeployStrategy deployStrategy();

/**
* Whether to add image pull secrets to a generated ServiceAccount.
* When set to true (default), image pull secrets are added to a ServiceAccount resource.
* When set to false, image pull secrets are added directly to the pod spec.
* Setting this to false is useful when deploying to environments like IBM Code Engine where users do not have
* permission to create ServiceAccount resources.
*/
@WithDefault("true")
boolean addImagePullSecretsToServiceAccount();
}
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,20 @@ public List<DecoratorBuildItem> createDecorators(ApplicationInfoBuildItem applic

//Handle Image Pull Secrets
config.imagePullSecrets().ifPresent(imagePullSecrets -> {
String serviceAccountName = config.serviceAccount().orElse(name);
result.add(new DecoratorBuildItem(KNATIVE, new AddServiceAccountResourceDecorator(name)));
result.add(
new DecoratorBuildItem(KNATIVE, new ApplyServiceAccountToRevisionSpecDecorator(name, serviceAccountName)));
result.add(new DecoratorBuildItem(KNATIVE,
new AddImagePullSecretToServiceAccountDecorator(serviceAccountName, imagePullSecrets)));
if (config.addImagePullSecretsToServiceAccount()) {
String serviceAccountName = config.serviceAccount().orElse(name);
result.add(new DecoratorBuildItem(KNATIVE, new AddServiceAccountResourceDecorator(name)));
result.add(
new DecoratorBuildItem(KNATIVE,
new ApplyServiceAccountToRevisionSpecDecorator(name, serviceAccountName)));
result.add(new DecoratorBuildItem(KNATIVE,
new AddImagePullSecretToServiceAccountDecorator(serviceAccountName, imagePullSecrets)));
} else {
for (String imagePullSecret : imagePullSecrets) {
result.add(new DecoratorBuildItem(KNATIVE,
new AddImagePullSecretToRevisionSpecDecorator(name, imagePullSecret)));
}
}
});

return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
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.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.fabric8.knative.serving.v1.Service;
import io.fabric8.kubernetes.api.model.HasMetadata;
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 KnativeWithImagePullSecretsTest {

@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class))
.setApplicationName("knative-with-image-pull-secrets")
.setApplicationVersion("0.1-SNAPSHOT")
.overrideConfigKey("quarkus.kubernetes.deployment-target", "knative")
.overrideConfigKey("quarkus.knative.image-pull-secrets", "my-secret")
.overrideConfigKey("quarkus.knative.add-image-pull-secrets-to-service-account", "false")
.setForcedDependencies(List.of(Dependency.of("io.quarkus", "quarkus-kubernetes", Version.getVersion())));

@ProdBuildResults
private ProdModeTestResults prodModeTestResults;

@Test
public void assertGeneratedResources() throws IOException {
Path kubernetesDir = prodModeTestResults.getBuildDir().resolve("kubernetes");
assertThat(kubernetesDir)
.isDirectoryContaining(p -> p.getFileName().endsWith("knative.json"))
.isDirectoryContaining(p -> p.getFileName().endsWith("knative.yml"));
List<HasMetadata> kubernetesList = DeserializationUtil
.deserializeAsList(kubernetesDir.resolve("knative.yml"));

assertThat(kubernetesList).filteredOn(i -> "Service".equals(i.getKind())).singleElement().satisfies(i -> {
assertThat(i).isInstanceOfSatisfying(Service.class, s -> {
assertThat(s.getMetadata()).satisfies(m -> {
assertThat(m.getName()).isEqualTo("knative-with-image-pull-secrets");
});

assertThat(s.getSpec()).satisfies(spec -> {
assertThat(spec.getTemplate()).satisfies(template -> {
assertThat(template.getSpec()).satisfies(revisionSpec -> {
assertThat(revisionSpec.getImagePullSecrets()).hasSize(1);
assertThat(revisionSpec.getImagePullSecrets().get(0).getName()).isEqualTo("my-secret");
});
});
});
});
});

// Ensure no ServiceAccount was generated
assertThat(kubernetesList).filteredOn(i -> "ServiceAccount".equals(i.getKind())).isEmpty();
}
}