Skip to content

Commit

Permalink
Fix setting service account in Kubernetes/Openshift extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
Sgitario committed Apr 27, 2023
1 parent 2c39693 commit 59d06f7
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -304,16 +304,16 @@ private static Collection<DecoratorBuildItem> createRbacDecorators(String name,
}

// Add service account from extensions: use the one provided by the user always
String defaultServiceAccount = null;
Optional<String> defaultServiceAccount = config.getServiceAccount();
String defaultServiceAccountNamespace = null;
for (KubernetesServiceAccountBuildItem sa : serviceAccountsFromExtensions) {
String saName = defaultIfEmpty(sa.getName(), name);
result.add(new DecoratorBuildItem(target, new AddServiceAccountResourceDecorator(name, saName,
sa.getNamespace(),
sa.getLabels())));

if (sa.isUseAsDefault() || defaultServiceAccount == null) {
defaultServiceAccount = saName;
if (sa.isUseAsDefault() || defaultServiceAccount.isEmpty()) {
defaultServiceAccount = Optional.of(saName);
defaultServiceAccountNamespace = sa.getNamespace();
}
}
Expand All @@ -325,8 +325,8 @@ private static Collection<DecoratorBuildItem> createRbacDecorators(String name,
sa.getValue().namespace.orElse(null),
sa.getValue().labels)));

if (sa.getValue().isUseAsDefault() || defaultServiceAccount == null) {
defaultServiceAccount = saName;
if (sa.getValue().isUseAsDefault() || defaultServiceAccount.isEmpty()) {
defaultServiceAccount = Optional.of(saName);
defaultServiceAccountNamespace = sa.getValue().namespace.orElse(null);
}
}
Expand Down Expand Up @@ -364,7 +364,7 @@ private static Collection<DecoratorBuildItem> createRbacDecorators(String name,
if (roleBinding.subjects.isEmpty()) {
requiresServiceAccount = true;
subjects.add(new Subject(null, SERVICE_ACCOUNT,
defaultIfEmpty(defaultServiceAccount, config.getServiceAccount().orElse(name)),
defaultServiceAccount.orElse(name),
defaultServiceAccountNamespace));
} else {
for (Map.Entry<String, SubjectConfig> s : roleBinding.subjects.entrySet()) {
Expand Down Expand Up @@ -426,7 +426,7 @@ private static Collection<DecoratorBuildItem> createRbacDecorators(String name,
Collections.emptyMap(),
new RoleRef(defaultRoleName, defaultClusterWide),
new Subject(null, SERVICE_ACCOUNT,
defaultIfEmpty(defaultServiceAccount, config.getServiceAccount().orElse(name)),
defaultServiceAccount.orElse(name),
defaultServiceAccountNamespace))));
} else if (kubernetesClientRequiresRbacGeneration) {
// the property `quarkus.kubernetes-client.generate-rbac` is enabled
Expand All @@ -437,24 +437,24 @@ private static Collection<DecoratorBuildItem> createRbacDecorators(String name,
Collections.emptyMap(),
new RoleRef(DEFAULT_ROLE_NAME_VIEW, true),
new Subject(null, SERVICE_ACCOUNT,
defaultIfEmpty(defaultServiceAccount, config.getServiceAccount().orElse(name)),
defaultServiceAccount.orElse(name),
defaultServiceAccountNamespace))));
}
}

// generate service account if none is set, and it's required by other resources
if (defaultServiceAccount == null && requiresServiceAccount) {
// use the application name
defaultServiceAccount = config.getServiceAccount().orElse(name);
if (requiresServiceAccount) {
// and generate the resource
result.add(new DecoratorBuildItem(target,
new AddServiceAccountResourceDecorator(name, defaultServiceAccount, defaultServiceAccountNamespace,
new AddServiceAccountResourceDecorator(name, defaultServiceAccount.orElse(name),
defaultServiceAccountNamespace,
Collections.emptyMap())));
}

// set service account in deployment resource
if (defaultServiceAccount != null) {
result.add(new DecoratorBuildItem(target, new ApplyServiceAccountNameDecorator(name, defaultServiceAccount)));
if (defaultServiceAccount.isPresent() || requiresServiceAccount) {
result.add(new DecoratorBuildItem(target,
new ApplyServiceAccountNameDecorator(name, defaultServiceAccount.orElse(name))));
}

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 java.util.Optional;

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.ServiceAccount;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.quarkus.test.ProdBuildResults;
import io.quarkus.test.ProdModeTestResults;
import io.quarkus.test.QuarkusProdModeTest;

public class KubernetesWithServiceAccountTest {

private static final String APP_NAME = "kubernetes-with-service-account";
private static final String SERVICE_ACCOUNT = "my-service-account";

@RegisterExtension
static final QuarkusProdModeTest config = new QuarkusProdModeTest()
.withApplicationRoot((jar) -> jar.addClasses(GreetingResource.class))
.setApplicationName(APP_NAME)
.setApplicationVersion("0.1-SNAPSHOT")
.overrideConfigKey("quarkus.kubernetes.service-account", SERVICE_ACCOUNT);

@ProdBuildResults
private ProdModeTestResults prodModeTestResults;

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

Deployment deployment = getDeploymentByName(kubernetesList, APP_NAME).get();
assertThat(deployment.getSpec().getTemplate().getSpec().getServiceAccountName()).isEqualTo(SERVICE_ACCOUNT);

Optional<ServiceAccount> serviceAccount = getServiceAccountByName(kubernetesList, SERVICE_ACCOUNT);
assertThat(serviceAccount.isPresent()).isFalse();
}

private Optional<Deployment> getDeploymentByName(List<HasMetadata> kubernetesList, String name) {
return getResourceByName(kubernetesList, Deployment.class, name);
}

private Optional<ServiceAccount> getServiceAccountByName(List<HasMetadata> kubernetesList, String saName) {
return getResourceByName(kubernetesList, ServiceAccount.class, saName);
}

private <T extends HasMetadata> Optional<T> getResourceByName(List<HasMetadata> kubernetesList, Class<T> clazz,
String name) {
return kubernetesList.stream()
.filter(r -> r.getMetadata().getName().equals(name))
.filter(clazz::isInstance)
.map(clazz::cast)
.findFirst();
}
}

0 comments on commit 59d06f7

Please sign in to comment.