Skip to content

Commit

Permalink
Fix fabric8io#931: Add ServiceAccount enricher and configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
rohanKanojia committed Mar 5, 2019
1 parent 31132a3 commit bc84390
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ After this we will switch probably to real [Semantic Versioning 2.0.0](http://se
* Fix 1460: Upgraded kubernetes client to 4.1.1
* Fix 690: Removes deprecated _legacyPortMapping_ property.
* Fix 1458: Support for from Image configuration in openshift docker build strategy
* Fix 931: Add ServiceAccount enricher and configuration
* Fix 732: Added 'skip' options to goals.
* Refactor 1520: Move XML configuration code from Mojo to enrichers
* Fix 1486: Remove Kompose Support
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,14 @@ public class ResourceConfig {
@Parameter
private int replicas = 1;

// Service account to use
@Parameter
private String namespace;

@Parameter
private String serviceAccount;

@Parameter
private String namespace;
private List<ServiceAccountConfig> serviceAccounts;

public Optional<Map<String, String>> getEnv() {
return Optional.ofNullable(env);
Expand Down Expand Up @@ -144,6 +146,10 @@ public String getServiceAccount() {
return serviceAccount;
}

public List<ServiceAccountConfig> getServiceAccounts() {
return serviceAccounts;
}

public String getNamespace() {
return namespace;
}
Expand Down Expand Up @@ -173,6 +179,7 @@ public Builder(ResourceConfig config) {
this.config.readiness = config.getReadiness();
this.config.annotations = config.getAnnotations();
this.config.serviceAccount = config.getServiceAccount();
this.config.serviceAccounts = config.getServiceAccounts();
this.config.configMap = config.getConfigMap();
this.config.volumes = config.getVolumes();
this.config.labels = config.getLabels();
Expand Down Expand Up @@ -215,6 +222,11 @@ public Builder withServiceAccount(String serviceAccount) {
return this;
}

public Builder withServiceAccounts(List<ServiceAccountConfig> serviceAccounts) {
config.serviceAccounts = serviceAccounts;
return this;
}

public Builder withConfigMap(ConfigMap configMap) {
config.configMap = configMap;
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright 2016 Red Hat, Inc.
*
* Red Hat licenses this file to you under the Apache License, version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package io.fabric8.maven.core.config;

import org.apache.maven.plugins.annotations.Parameter;

public class ServiceAccountConfig {
@Parameter
private String name;

@Parameter
private String deploymentRef;

public ServiceAccountConfig(String name) {
this.name = name;
}

public String getName() {
return name;
}

public String getDeploymentRef() {
return deploymentRef;
}
}
3 changes: 3 additions & 0 deletions doc/src/main/asciidoc/inc/_enricher.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ fabric8-maven-plugin comes with a set of enrichers which are enabled by default.

| <<fmp-secret-file>>
| Add Secret elements defined as annotation.

| <<fmp-fmp-serviceaccount>>
| Add a ServiceAccount defined as XML or mentioned in resource fragement.
|===

[[enrichers-standard]]
Expand Down
6 changes: 6 additions & 0 deletions doc/src/main/asciidoc/inc/_introduction.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,12 @@ A working example can be found in the https://github.com/fabric8io/fabric8-mave
<headless>true</headless>
</service>
</services>
<serviceAccounts>
<serviceAccount>
<name>build-robot</name>
</serviceAccount>
</serviceAccounts>
</resources>
</configuration>
----
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* Copyright 2016 Red Hat, Inc.
*
* Red Hat licenses this file to you under the Apache License, version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package io.fabric8.maven.enricher.standard;

import io.fabric8.kubernetes.api.builder.TypedVisitor;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesListBuilder;
import io.fabric8.kubernetes.api.model.ServiceAccount;
import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.maven.core.config.PlatformMode;
import io.fabric8.maven.core.config.ResourceConfig;
import io.fabric8.maven.core.config.ServiceAccountConfig;
import io.fabric8.maven.enricher.api.BaseEnricher;
import io.fabric8.maven.enricher.api.MavenEnricherContext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ServiceAccountEnricher extends BaseEnricher {
public ServiceAccountEnricher(MavenEnricherContext enricherContext) {
super(enricherContext, "fmp-serviceaccount");
}

@Override
public void create(PlatformMode mode, KubernetesListBuilder builder) {
Map<String, String> deploymentToSaPair = new HashMap<>();
List<ServiceAccount> serviceAccounts = new ArrayList<>();

// Check XML config and see if there are any service accounts specified
ResourceConfig xmlResourceConfig = getConfiguration().getResource().orElse(null);
if(xmlResourceConfig != null && xmlResourceConfig.getServiceAccounts() != null) {
for(ServiceAccountConfig serviceAccountConfig : xmlResourceConfig.getServiceAccounts()) {
if(serviceAccountConfig.getName() != null) {
serviceAccounts.add(createServiceAccount(builder, serviceAccountConfig.getName()));
}
if(serviceAccountConfig.getDeploymentRef() != null) {
deploymentToSaPair.put(serviceAccountConfig.getDeploymentRef(), serviceAccountConfig.getName());
}
}
}

// If any service account is referenced in deployment spec, then
// create sa on fly.
builder.accept(new TypedVisitor<DeploymentBuilder>() {
@Override
public void visit(DeploymentBuilder deploymentBuilder) {
String serviceAccountName = getServiceAccountNameFromSpec(deploymentBuilder);
if(serviceAccountName != null && getServiceAccountFromList(builder, serviceAccountName) == null) {
serviceAccounts.add(createServiceAccount(builder, serviceAccountName));
}
if(deploymentToSaPair.containsKey(deploymentBuilder.buildMetadata().getName())) {
deploymentBuilder.editSpec()
.editTemplate()
.editSpec()
.withServiceAccountName(deploymentToSaPair.get(deploymentBuilder.buildMetadata().getName()))
.endSpec()
.endTemplate()
.endSpec();
}
}
});

builder.addAllToServiceAccountItems(serviceAccounts);
}

private ServiceAccount createServiceAccount(KubernetesListBuilder builder, String serviceAccountName) {
return new ServiceAccountBuilder()
.withNewMetadata().withName(serviceAccountName).endMetadata()
.build();
}

private String getServiceAccountNameFromSpec(DeploymentBuilder builder) {
if(builder.buildSpec().getTemplate().getSpec().getServiceAccountName() != null) {
return builder.buildSpec().getTemplate().getSpec().getServiceAccountName();
}
if(builder.buildSpec().getTemplate().getSpec().getServiceAccount() != null) {
return builder.buildSpec().getTemplate().getSpec().getServiceAccount();
}
return null;
}

private ServiceAccount getServiceAccountFromList(KubernetesListBuilder builder, String serviceAccountName) {
for(HasMetadata item : builder.buildItems()) {
if(item instanceof ServiceAccount && item.getMetadata().getName().equals(serviceAccountName)) {
return (ServiceAccount)item;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ io.fabric8.maven.enricher.standard.ConfigMapEnricher
# (see https://docs.okd.io/latest/dev_guide/secrets.html#service-serving-certificate-secrets)
io.fabric8.maven.enricher.standard.openshift.AutoTLSEnricher

# Add a service account
io.fabric8.maven.enricher.standard.ServiceAccountEnricher

# Add a route on demand when on OpenShift
io.fabric8.maven.enricher.standard.openshift.RouteEnricher

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright 2016 Red Hat, Inc.
*
* Red Hat licenses this file to you under the Apache License, version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package io.fabric8.maven.enricher.standard;

import io.fabric8.kubernetes.api.model.KubernetesListBuilder;
import io.fabric8.kubernetes.api.model.ServiceAccount;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.maven.core.config.PlatformMode;
import io.fabric8.maven.core.config.ResourceConfig;
import io.fabric8.maven.core.config.ServiceAccountConfig;
import io.fabric8.maven.core.model.Configuration;
import io.fabric8.maven.enricher.api.MavenEnricherContext;
import mockit.Expectations;
import mockit.Mocked;
import org.junit.Test;

import java.util.Collections;

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

public class ServiceAccountEnricherTest {
@Mocked
private MavenEnricherContext context;

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@Test
public void testServiceAccountCreationFromConfig() {
new Expectations() {{
context.getConfiguration();
result = new Configuration.Builder()
.resource(new ResourceConfig.Builder()
.withServiceAccounts(Collections.singletonList(new ServiceAccountConfig("ribbon"))).build())
.build();
}};
final KubernetesListBuilder builder = new KubernetesListBuilder();

enrichAndAssert(builder);
}

@Test
public void testServiceAccountCreationFromFragment() {
final KubernetesListBuilder builder = new KubernetesListBuilder()
.withItems(new DeploymentBuilder().withNewMetadata().withName("cheese").endMetadata()
.withNewSpec().withNewTemplate().withNewSpec()
.addNewContainer().withImage("cheese-image").endContainer()
.withServiceAccount("ribbon")
.endSpec().endTemplate().endSpec().build());

enrichAndAssert(builder);
}

private void enrichAndAssert(KubernetesListBuilder builder) {
final ServiceAccountEnricher saEnricher = new ServiceAccountEnricher(context);
saEnricher.create(PlatformMode.kubernetes, builder);

final ServiceAccount serviceAccount = (ServiceAccount) builder.buildLastItem();
assertThat(serviceAccount).isNotNull();
assertThat(serviceAccount.getMetadata().getName()).isEqualTo("ribbon");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- fmp-pod-annotations
- fmp-git
- fmp-maven-scm
- fmp-serviceaccount
- fmp-maven-issue-mgmt
# TODO: Documents and verify enrichers below
- fmp-debug
Expand Down

0 comments on commit bc84390

Please sign in to comment.