Skip to content
This repository has been archived by the owner on Jun 19, 2024. It is now read-only.

Commit

Permalink
Fixed IngressEnricher and RouteEnricher
Browse files Browse the repository at this point in the history
  • Loading branch information
Devang Gaur committed Nov 8, 2019
1 parent 73878e0 commit 7d79251
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,14 @@ public class ResourceConfig {
@Parameter
private List<ServiceAccountConfig> serviceAccounts;

@Parameter
private List<IngressRule> ingressRules;

/**
* Host/domain for Route/Ingress.
*/
private String routeDomain;

public Optional<Map<String, String>> getEnv() {
return Optional.ofNullable(env);
}
Expand Down Expand Up @@ -170,6 +176,9 @@ public List<String> getRemotes() {
public List<String> getCrdContexts() { return customResourceDefinitions; }

public List<IngressRule> getIngressRules() { return ingressRules; }

public String getRouteDomain() { return routeDomain; }

// =============================================================================================

public static class Builder {
Expand Down Expand Up @@ -198,6 +207,7 @@ public Builder(ResourceConfig config) {
this.config.namespace = config.getNamespace();
this.config.remotes = config.getRemotes();
this.config.ingressRules = config.getIngressRules();
this.config.routeDomain= config.getRouteDomain();
}
}

Expand Down Expand Up @@ -271,6 +281,11 @@ public Builder withCustomResourceDefinitions(List<String> customResourceDefiniti
return this;
}

public Builder withRouteDomain(String routeDomain) {
config.routeDomain = routeDomain;
return this;
}

public ResourceConfig build() {
return config;
}
Expand Down Expand Up @@ -302,4 +317,4 @@ public ResourceConfig build() {
// fabric8.namespaceEnvVar

// fabric8.provider
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import io.fabric8.maven.enricher.api.MavenEnricherContext;
import io.fabric8.openshift.api.model.Project;
import io.fabric8.openshift.api.model.ProjectBuilder;
import io.fabric8.openshift.api.model.ProjectStatus;

import java.util.Arrays;

Expand Down Expand Up @@ -132,14 +133,18 @@ public void visit(ObjectMetaBuilder metaBuilder) {
builder.accept(new TypedVisitor<NamespaceBuilder>() {
@Override
public void visit(NamespaceBuilder builder) {
builder.withNewStatus("active").editMetadata().withNamespace(null).endMetadata().build();
if (builder.getStatus().equals("active")) {
builder.editOrNewStatus().endStatus().build();
}
}
});

builder.accept(new TypedVisitor<ProjectBuilder>() {
@Override
public void visit(ProjectBuilder builder) {
builder.withNewStatus("active").editMetadata().withNamespace(null).endMetadata().build();
if (builder.getStatus().equals(new ProjectStatus("active"))) {
builder.editOrNewStatus().endStatus().build();
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,41 @@
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.ObjectMeta;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.api.model.ServicePort;
import io.fabric8.kubernetes.api.model.ServiceSpec;
import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPath;
import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPathBuilder;
import io.fabric8.kubernetes.api.model.extensions.HTTPIngressRuleValue;
import io.fabric8.kubernetes.api.model.extensions.Ingress;
import io.fabric8.kubernetes.api.model.extensions.IngressBackend;
import io.fabric8.kubernetes.api.model.extensions.IngressBackendBuilder;
import io.fabric8.kubernetes.api.model.extensions.IngressBuilder;
import io.fabric8.kubernetes.api.model.extensions.IngressList;
import io.fabric8.kubernetes.api.model.extensions.IngressRule;
import io.fabric8.kubernetes.api.model.extensions.IngressSpec;
import io.fabric8.kubernetes.api.model.extensions.IngressSpecBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.maven.core.config.PlatformMode;
import io.fabric8.maven.core.config.ResourceConfig;
import io.fabric8.maven.core.util.Configs;
import io.fabric8.maven.core.util.FileUtil;
import io.fabric8.maven.core.util.kubernetes.Fabric8Annotations;
import io.fabric8.maven.core.util.kubernetes.KubernetesHelper;
import io.fabric8.maven.enricher.api.BaseEnricher;
import io.fabric8.maven.enricher.api.MavenEnricherContext;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

/**
Expand All @@ -48,41 +64,80 @@ public IngressEnricher(MavenEnricherContext buildContext) {
super(buildContext, "fmp-ingress");
}

private String routeDomainPostfix;

@Override
public void create(PlatformMode platformMode, final KubernetesListBuilder listBuilder) {
ResourceConfig resourceConfig = getConfiguration().getResource().orElse(null);
routeDomainPostfix = resourceConfig.getRouteDomain();

if (platformMode == PlatformMode.kubernetes) {
final List<Ingress> ingresses = new ArrayList<>();
listBuilder.accept(new TypedVisitor<ServiceBuilder>() {
@Override
public void visit(ServiceBuilder serviceBuilder) {
addIngress(listBuilder, serviceBuilder);
}
});

}
}

private void addIngress(KubernetesListBuilder listBuilder, ServiceBuilder serviceBuilder) {
ObjectMeta metadata = serviceBuilder.getMetadata();
if (metadata != null && isExposedService(serviceBuilder)) {
String name = metadata.getName();
if (!hasIngress(listBuilder, name)) {
if (metadata != null && isExposedService(serviceBuilder) && shouldCreateExternalURLForService(serviceBuilder)) {
String serviceName = metadata.getName();
if (!hasIngress(listBuilder, serviceName)) {
Integer servicePort = getServicePort(serviceBuilder);
if (servicePort != null) {
ResourceConfig resourceConfig = getConfiguration().getResource().orElse(null);

if (StringUtils.isNotBlank(routeDomainPostfix)) {
routeDomainPostfix = serviceName + "." + FileUtil.stripPrefix(routeDomainPostfix, ".");
}

IngressBuilder ingressBuilder = new IngressBuilder().
withMetadata(serviceBuilder.getMetadata()).
withNewSpec().

endSpec();
IngressSpecBuilder specBuilder = new IngressSpecBuilder().withBackend(new IngressBackendBuilder().
withNewServiceName(name).
withNewServiceName(serviceName).
withNewServicePort(getServicePort(serviceBuilder)).
build());

if (resourceConfig != null) {
specBuilder.addAllToRules(resourceConfig.getIngressRules());
if (resourceConfig.getIngressRules() != null) {
specBuilder.addAllToRules(resourceConfig.getIngressRules());
} else {
List<HTTPIngressPath> paths = new ArrayList<>();
List<ServicePort> ports = serviceBuilder.getSpec().getPorts();
if (ports != null) {
for (ServicePort port : ports) {
Integer portNumber = port.getPort();
if (portNumber != null) {
HTTPIngressPath path =
new HTTPIngressPathBuilder()
.withNewBackend()
.withServiceName(serviceName)
.withServicePort(KubernetesHelper.createIntOrString(portNumber))
.endBackend()
.build();
paths.add(path);
}
}
}
if (paths.isEmpty()) {
ingressBuilder = ingressBuilder.withSpec(specBuilder.build());
listBuilder.addToIngressItems(ingressBuilder.build());
return;
}

ingressBuilder = ingressBuilder.withSpec(specBuilder.addNewRule().
withHost(routeDomainPostfix).
withNewHttp().
withPaths(paths).
endHttp().
endRule().build());
listBuilder.addToIngressItems(ingressBuilder.build());
}
}
}
}
Expand Down Expand Up @@ -145,4 +200,35 @@ private boolean isExposedService(Service service) {
}
return false;
}

/**
* Should we try to create an external URL for the given service?
* <p/>
* By default lets ignore the kubernetes services and any service which does not expose ports 80 and 443
*
* @return true if we should create an Ingress for this service.
*/
private boolean shouldCreateExternalURLForService(ServiceBuilder service) {
String serviceName = service.getMetadata().getName();
if ("kubernetes".equals(serviceName) || "kubernetes-ro".equals(serviceName)) {
return false;
}
ServiceSpec spec = service.getSpec();
List<ServicePort> ports = spec.getPorts();
log.debug("Service " + serviceName + " has ports: " + ports);
if (ports.size() == 1) {
String type = null;
if (spec != null) {
type = spec.getType();
if (Objects.equals(type, "LoadBalancer")) {
return true;
}
}
log.info("Not generating Ingress for service " + serviceName + " type is not LoadBalancer: " + type);
return false;
} else {
log.info("Not generating Ingress for service " + serviceName + " as only single port services are supported. Has ports: " + ports);
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
package io.fabric8.maven.enricher.standard.openshift;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import io.fabric8.kubernetes.api.builder.TypedVisitor;
Expand All @@ -30,12 +32,15 @@
import io.fabric8.kubernetes.api.model.ServicePort;
import io.fabric8.kubernetes.api.model.ServiceSpec;
import io.fabric8.maven.core.config.PlatformMode;
import io.fabric8.maven.core.config.ResourceConfig;
import io.fabric8.maven.core.util.FileUtil;
import io.fabric8.maven.core.util.kubernetes.Fabric8Annotations;
import io.fabric8.maven.enricher.api.BaseEnricher;
import io.fabric8.maven.enricher.api.MavenEnricherContext;
import io.fabric8.openshift.api.model.Route;
import io.fabric8.openshift.api.model.RouteBuilder;
import io.fabric8.openshift.api.model.RoutePort;
import org.apache.commons.lang3.StringUtils;

/**
* Enricher which generates a Route for each exposed Service
Expand All @@ -48,8 +53,16 @@ public RouteEnricher(MavenEnricherContext buildContext) {
this.generateRoute = getValueFromConfig(GENERATE_ROUTE, true);
}

private String routeDomainPostfix;

@Override
public void create(PlatformMode platformMode, final KubernetesListBuilder listBuilder) {
ResourceConfig resourceConfig = getConfiguration().getResource().orElse(null);

if (resourceConfig != null && resourceConfig.getRouteDomain() != null) {
routeDomainPostfix = resourceConfig.getRouteDomain();
}

if(platformMode == PlatformMode.openshift && generateRoute.equals(Boolean.TRUE)) {
final List<Route> routes = new ArrayList<>();
listBuilder.accept(new TypedVisitor<ServiceBuilder>() {
Expand All @@ -68,25 +81,6 @@ public void visit(ServiceBuilder serviceBuilder) {
}
}

private void addRoute(KubernetesListBuilder listBuilder, ServiceBuilder serviceBuilder, List<Route> routes) {
ObjectMeta metadata = serviceBuilder.getMetadata();
if (metadata != null && isExposedService(serviceBuilder)) {
String name = metadata.getName();
if (!hasRoute(listBuilder, name)) {
RoutePort routePort = createRoutePort(serviceBuilder);
if (routePort != null) {
// TODO one day lets support multiple ports on a Route when the model supports it
routes.add(new RouteBuilder().
withMetadata(serviceBuilder.getMetadata()).
withNewSpec().
withPort(routePort).
withNewTo().withKind("Service").withName(name).endTo().
endSpec().
build());
}
}
}
}

private RoutePort createRoutePort(ServiceBuilder serviceBuilder) {
RoutePort routePort = null;
Expand All @@ -107,6 +101,74 @@ private RoutePort createRoutePort(ServiceBuilder serviceBuilder) {
return routePort;
}

private String prepareHostForRoute(String routeDomainPostfix, String name) {
String ret = FileUtil.stripPostfix(name,"-service");
ret = FileUtil.stripPostfix(ret,".");
ret += ".";
ret += FileUtil.stripPrefix(routeDomainPostfix, ".");
return ret;
}

private Set<Integer> getPorts(ServiceBuilder service) {
Set<Integer> answer = new HashSet<>();
if (service != null) {
ServiceSpec spec = getOrCreateSpec(service);
for (ServicePort port : spec.getPorts()) {
answer.add(port.getPort());
}
}
return answer;
}

public static ServiceSpec getOrCreateSpec(ServiceBuilder entity) {
ServiceSpec spec = entity.getSpec();
if (spec == null) {
spec = new ServiceSpec();
entity.editOrNewSpec().endSpec();
}
return spec;
}

private boolean hasExactlyOneServicePort(ServiceBuilder service, String id) {
Set<Integer> ports = getPorts(service);
if (ports.size() != 1) {
log.info("Not generating route for service " + id + " as only single port services are supported. Has ports: " +
ports);
return false;
} else {
return true;
}
}

private void addRoute(KubernetesListBuilder listBuilder, ServiceBuilder serviceBuilder, List<Route> routes) {
ObjectMeta metadata = serviceBuilder.getMetadata();

if (metadata != null && StringUtils.isNotBlank(metadata.getName())
&& hasExactlyOneServicePort(serviceBuilder, metadata.getName()) && isExposedService(serviceBuilder)) {
String name = metadata.getName();
if (!hasRoute(listBuilder, name)) {
if (StringUtils.isNotBlank(routeDomainPostfix)) {
routeDomainPostfix = prepareHostForRoute(routeDomainPostfix, name);
} else {
routeDomainPostfix = "";
}

RoutePort routePort = createRoutePort(serviceBuilder);
if (routePort != null) {
// TODO one day lets support multiple ports on a Route when the model supports it
routes.add(new RouteBuilder().
withMetadata(serviceBuilder.getMetadata()).
withNewSpec().
withPort(routePort).
withNewTo().withKind("Service").withName(name).endTo().
withHost(routeDomainPostfix).
endSpec().
build());
}
}
}
}

/**
* Returns true if we already have a route created for the given name
*/
Expand Down
Loading

0 comments on commit 7d79251

Please sign in to comment.