Skip to content

Commit

Permalink
Fix #184: IngressEnricher seems to be broken
Browse files Browse the repository at this point in the history
  • Loading branch information
rohanKanojia authored and manusa committed Jun 5, 2020
1 parent 578aca8 commit e11392a
Show file tree
Hide file tree
Showing 21 changed files with 595 additions and 405 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Usage:
### 1.0.0-SNAPSHOT
* Fix #173: Use OpenShift compliant git/vcs annotations
* Fix #182: Assembly is never null
* Fix #184: IngressEnricher seems to be broken, Port of fabric8io/fabric8-maven-plugin#1730
* Fix #198: Wildfly works in OpenShift with S2I binary build (Docker)
* Fix #199: BaseGenerator retrieves runtime mode from context (not from missing properties)
* Fix #201: Webapp-Wildfly supports S2I source builds too (3 modes Docker, OpenShift-Docker, OpenShift-S2I)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class ResourceConfig {
@Singular
private List<IngressRule> ingressRules;
private OpenshiftBuildConfig openshiftBuildConfig;
private String routeDomain;

public static ResourceConfigBuilder toBuilder(ResourceConfig original) {
return Optional.ofNullable(original).orElse(new ResourceConfig()).toBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public class BaseEnricher implements Enricher {
public static final String ENRICH_ALL_WITH_IMAGE_TRIGGERS = "jkube.openshift.enrichAllWithImageChangeTrigger";
public static final String OPENSHIFT_DEPLOY_TIMEOUT_SECONDS = "jkube.openshift.deployTimeoutSeconds";
private static final String SWITCH_TO_DEPLOYMENT = "jkube.build.switchToDeployment";
public static final String CREATE_EXTERNAL_URLS = "jkube.createExternalUrls";
public static final String JKUBE_DOMAIN = "jkube.domain";
protected static final String GENERATE_ROUTE = "jkube.openshift.generateRoute";

protected KitLogger log;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* Utility class for handling Kubernetes resource descriptors
*
* @author roland
*/
public class KubernetesResourceUtil {
private KubernetesResourceUtil() { }

private static final Logger LOG = LoggerFactory.getLogger(KubernetesResourceUtil.class);

Expand Down Expand Up @@ -881,6 +883,27 @@ public static HasMetadata mergeResources(HasMetadata item1, HasMetadata item2, K
return item1;
}

public static boolean containsLabelInMetadata(ObjectMeta metadata, String labelKey, String labelValue) {
if (metadata != null && metadata.getLabels() != null) {
Map<String, String> labels = metadata.getLabels();
return labels.containsKey(labelKey) && labelValue.equals(labels.get(labelKey));
}
return false;
}

public static ObjectMeta removeLabel(ObjectMeta metadata, String labelKey, String labelValue) {
Map<String, String> labels;
if (metadata != null) {
labels = metadata.getLabels();
if (labels != null && labelValue.equals(labels.get(labelKey))) {
labels.remove(labelKey);
}
}
return metadata;
}



protected static HasMetadata mergeConfigMaps(ConfigMap cm1, ConfigMap cm2, KitLogger log, boolean switchOnLocalCustomisation) {
ConfigMap cm1OrCopy = cm1;
if (!switchOnLocalCustomisation) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,22 @@ public void visit(ObjectMetaBuilder metaBuilder) {
});

// Removing namespace annotation from the namespace and project objects being generated.
// to avoid unncessary trouble while applying these resources.
// to avoid unnecessary trouble while applying these resources.
builder.accept(new TypedVisitor<NamespaceBuilder>() {
@Override
public void visit(NamespaceBuilder builder) {
builder.withNewStatus().withPhase("Active").endStatus().editMetadata().withNamespace(null).endMetadata().build();
if (builder.buildStatus().getPhase().equals("active")) {
builder.editOrNewStatus().endStatus().build();
}
}
});

builder.accept(new TypedVisitor<ProjectBuilder>() {
@Override
public void visit(ProjectBuilder builder) {
builder.withNewStatus().withPhase("Active").endStatus().editMetadata().withNamespace(null).endMetadata().build();
if (builder.buildStatus().getPhase().equals("active")) {
builder.editOrNewStatus().endStatus().build();
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,77 +16,116 @@
import io.fabric8.kubernetes.api.builder.TypedVisitor;
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.HTTPIngressPathBuilder;
import io.fabric8.kubernetes.api.model.extensions.Ingress;
import io.fabric8.kubernetes.api.model.extensions.IngressBackendBuilder;
import io.fabric8.kubernetes.api.model.extensions.IngressBuilder;
import io.fabric8.kubernetes.api.model.extensions.IngressSpecBuilder;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jkube.kit.common.KitLogger;
import org.eclipse.jkube.kit.common.util.FileUtil;
import org.eclipse.jkube.kit.common.util.KubernetesHelper;
import org.eclipse.jkube.kit.config.resource.JKubeAnnotations;
import org.eclipse.jkube.kit.config.resource.PlatformMode;
import org.eclipse.jkube.kit.config.resource.ResourceConfig;
import org.eclipse.jkube.kit.enricher.api.BaseEnricher;
import org.eclipse.jkube.kit.enricher.api.JKubeEnricherContext;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.containsLabelInMetadata;
import static org.eclipse.jkube.kit.enricher.api.util.KubernetesResourceUtil.removeLabel;

/**
* Enricher which generates an Ingress for each exposed Service
*/
public class IngressEnricher extends BaseEnricher {
public static final String EXPOSE_LABEL = "expose";

public IngressEnricher(JKubeEnricherContext buildContext) {
super(buildContext, "jkube-ingress");
}

@Override
public void create(PlatformMode platformMode, final KubernetesListBuilder listBuilder) {
ResourceConfig resourceConfig = getConfiguration().getResource();
Boolean shouldCreateIngress = getValueFromConfig(CREATE_EXTERNAL_URLS, false);
if (shouldCreateIngress.equals(Boolean.FALSE)) {
return;
}

if (platformMode == PlatformMode.kubernetes) {
listBuilder.accept(new TypedVisitor<ServiceBuilder>() {
@Override
public void visit(ServiceBuilder serviceBuilder) {
addIngress(listBuilder, serviceBuilder);
Ingress ingress = addIngress(listBuilder, serviceBuilder, getRouteDomain(resourceConfig), log);
if (ingress != null) {
listBuilder.addToItems(ingress);
}
}
});

}
}

private void addIngress(KubernetesListBuilder listBuilder, ServiceBuilder serviceBuilder) {
ObjectMeta metadata = serviceBuilder.getMetadata();
if (metadata != null && isExposedService(serviceBuilder)) {
String name = metadata.getName();
if (!hasIngress(listBuilder, name)) {
protected static Ingress addIngress(KubernetesListBuilder listBuilder, ServiceBuilder serviceBuilder, String routeDomainPostfix, KitLogger log) {
ObjectMeta serviceMetadata = serviceBuilder.buildMetadata();
if (serviceMetadata == null) {
log.info("No Metadata for service! ");
}
if (isExposedService(serviceMetadata) && shouldCreateExternalURLForService(serviceBuilder, log)) {
Objects.requireNonNull(serviceMetadata);
String serviceName = serviceMetadata.getName();
if (!hasIngress(listBuilder, serviceName)) {
Integer servicePort = getServicePort(serviceBuilder);
if (servicePort != null) {
ResourceConfig resourceConfig = getConfiguration().getResource();

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

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

if (resourceConfig != null) {
specBuilder.addAllToRules(resourceConfig.getIngressRules());
// removing `expose : true` label from metadata.
removeLabel(ingressBuilder.buildMetadata(), EXPOSE_LABEL, "true");
removeLabel(ingressBuilder.buildMetadata(), JKubeAnnotations.SERVICE_EXPOSE_URL.value(), "true");
ingressBuilder.withNewMetadataLike(ingressBuilder.buildMetadata());

if (StringUtils.isNotBlank(routeDomainPostfix)) {
routeDomainPostfix = serviceName + "." + FileUtil.stripPrefix(routeDomainPostfix, ".");
ingressBuilder = ingressBuilder.withSpec(new IngressSpecBuilder().addNewRule().
withHost(routeDomainPostfix).
withNewHttp().
withPaths(new HTTPIngressPathBuilder()
.withNewBackend()
.withServiceName(serviceName)
.withServicePort(KubernetesHelper.createIntOrString(getServicePort(serviceBuilder)))
.endBackend()
.build())
.endHttp().
endRule().build());
} else {
ingressBuilder.withSpec(new IngressSpecBuilder().withBackend(new IngressBackendBuilder().
withNewServiceName(serviceName)
.withNewServicePort(getServicePort(serviceBuilder))
.build()).build());
}

return ingressBuilder.build();
}
}
}
return null;
}

private Integer getServicePort(ServiceBuilder serviceBuilder) {
ServiceSpec spec = serviceBuilder.getSpec();
private static Integer getServicePort(ServiceBuilder serviceBuilder) {
ServiceSpec spec = serviceBuilder.buildSpec();
if (spec != null) {
List<ServicePort> ports = spec.getPorts();
if (ports != null && ports.size() > 0) {
if (ports != null && !ports.isEmpty()) {
for (ServicePort port : ports) {
if (port.getName().equals("http") || port.getProtocol().equals("http")) {
return port.getPort();
Expand All @@ -98,19 +137,19 @@ private Integer getServicePort(ServiceBuilder serviceBuilder) {
}
}
}
return null;
return 0;
}

/**
* Returns true if we already have a route created for the given name
*/
private boolean hasIngress(final KubernetesListBuilder listBuilder, final String name) {
private static boolean hasIngress(final KubernetesListBuilder listBuilder, final String name) {
final AtomicBoolean answer = new AtomicBoolean(false);
listBuilder.accept(new TypedVisitor<IngressBuilder>() {

@Override
public void visit(IngressBuilder builder) {
ObjectMeta metadata = builder.getMetadata();
ObjectMeta metadata = builder.buildMetadata();
if (metadata != null && name.equals(metadata.getName())) {
answer.set(true);
}
Expand All @@ -119,23 +158,49 @@ public void visit(IngressBuilder builder) {
return answer.get();
}

private boolean isExposedService(ServiceBuilder serviceBuilder) {
Service service = serviceBuilder.build();
return isExposedService(service);
}

private boolean isExposedService(Service service) {
ObjectMeta metadata = service.getMetadata();
if (metadata != null) {
Map<String, String> labels = metadata.getLabels();
if (labels != null) {
if ("true".equals(labels.get("expose")) || "true".equals(labels.get(JKubeAnnotations.SERVICE_EXPOSE_URL.value()))) {
/**
* 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 static boolean shouldCreateExternalURLForService(ServiceBuilder service, KitLogger log) {
String serviceName = service.buildMetadata().getName();
ServiceSpec spec = service.buildSpec();
if (spec != null && !isKuberentesSystemService(serviceName)) {
List<ServicePort> ports = spec.getPorts();
log.debug("Service " + serviceName + " has ports: " + ports);
if (ports.size() == 1) {
String type = spec.getType();
if (Objects.equals(type, "LoadBalancer")) {
return true;
}
log.info("Not generating Ingress for service " + serviceName + " type is not LoadBalancer: " + type);
} else {
log.info("Not generating Ingress for service " + serviceName + " as only single port services are supported. Has ports: " + ports);
}
} else {
log.info("No Metadata for service! " + service);
}
return false;
}

private static boolean isKuberentesSystemService(String serviceName) {
return "kubernetes".equals(serviceName) || "kubernetes-ro".equals(serviceName);
}

private String getRouteDomain(ResourceConfig resourceConfig) {
if (resourceConfig != null && resourceConfig.getRouteDomain() != null) {
return resourceConfig.getRouteDomain();
}
String routeDomainFromProperties = getValueFromConfig(JKUBE_DOMAIN, "");
if (StringUtils.isNotEmpty(routeDomainFromProperties)) {
return routeDomainFromProperties;
}
return null;
}

private static boolean isExposedService(ObjectMeta objectMeta) {
return containsLabelInMetadata(objectMeta, EXPOSE_LABEL, "true") ||
containsLabelInMetadata(objectMeta, JKubeAnnotations.SERVICE_EXPOSE_URL.value(), "true");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,22 @@
import java.util.Map;
import java.util.Set;


/**
* Enricher for enabling exposing of HTTP / HTTPS based services
*/
public class ExposeEnricher extends BaseEnricher {
public static final String EXPOSE_LABEL = "expose";

public ExposeEnricher(JKubeEnricherContext buildContext) {
super(buildContext, "jkube-openshift-service-expose");
}

private Set<Integer> webPorts = new HashSet<>(Arrays.asList(80, 443, 8080, 9080, 9090, 9443));

public static final String EXPOSE_LABEL = "expose";

@Override
public void create(PlatformMode platformMode, KubernetesListBuilder builder) {
List<HasMetadata> items = builder.getItems();
List<HasMetadata> items = builder.buildItems();
if (items != null) {
for (HasMetadata item : items) {
if (item instanceof Service) {
Expand Down Expand Up @@ -81,10 +81,8 @@ private boolean hasWebPort(Service service) {
if (ports != null) {
for (ServicePort port : ports) {
Integer portNumber = port.getPort();
if (portNumber != null) {
if (webPorts.contains(portNumber)) {
return true;
}
if (portNumber != null && webPorts.contains(portNumber)) {
return true;
}
}
}
Expand Down
Loading

0 comments on commit e11392a

Please sign in to comment.