diff --git a/pom.xml b/pom.xml index dadd925..d45f501 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,11 @@ kubernetes-model-common 5.4.1 + + io.verticle.apex + gateway-crd-model + v1alpha1 + org.springframework.boot diff --git a/src/main/java/io/verticle/kubernetes/authgateway/GatewayClass.java b/src/main/java/io/verticle/kubernetes/authgateway/GatewayClass.java new file mode 100644 index 0000000..01f7f02 --- /dev/null +++ b/src/main/java/io/verticle/kubernetes/authgateway/GatewayClass.java @@ -0,0 +1,72 @@ +package io.verticle.kubernetes.authgateway; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class GatewayClass { + + private static final Logger log = LoggerFactory.getLogger(GatewayClass.class); + + @Value("${"+ENV_GATEWAY_NAME+":unknown}") + String gatewayNameFromEnv; + + public static final String LABEL_IO_VERTICLE_GATEWAY_NAME = "io.verticle.gateway.name"; + public static final String ENV_GATEWAY_NAME = "GATEWAY_NAME"; + + @Autowired + KubernetesClient kubernetesClient; + + public enum Feature { + apikey, oidc + } + + Map enabledFeatures = new HashMap<>(); + + @PostConstruct + private void init(){ + + Map configMapData = getConfigMapData(); + + if (configMapData.size() > 0){ + enabledFeatures.put(Feature.apikey, isEnabled(configMapData,"apikeyEnabled")); + enabledFeatures.put(Feature.oidc, isEnabled(configMapData,"oidcEnabled")); + } + + log.info("enabled features: " + enabledFeatures.size()); + enabledFeatures.forEach((feature, aBoolean) -> { + log.info("feature " + feature.name() + ": " + aBoolean); + }); + } + + private boolean isEnabled(Map config, String feature){ + return config.containsKey(feature) && Boolean.valueOf(config.get(feature)); + } + + @Cacheable + public Map getConfigMapData(){ + List configMaps = kubernetesClient + .configMaps() + .withLabel(LABEL_IO_VERTICLE_GATEWAY_NAME, gatewayNameFromEnv) + .list().getItems(); + if (configMaps.size() == 0) + return new HashMap<>(); + else + return configMaps.get(0).getData(); + } + + public boolean hasFeature(Feature feature){ + return enabledFeatures.getOrDefault(feature, false); + } +} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/HttpRouteController.java b/src/main/java/io/verticle/kubernetes/authgateway/HttpRouteController.java index 20342b1..f108c60 100644 --- a/src/main/java/io/verticle/kubernetes/authgateway/HttpRouteController.java +++ b/src/main/java/io/verticle/kubernetes/authgateway/HttpRouteController.java @@ -2,9 +2,8 @@ import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; import io.javaoperatorsdk.operator.api.*; -import io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute.HTTPRoute; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HTTPRoute; import io.verticle.kubernetes.authgateway.route.RouteConfigService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/ConditionsSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/ConditionsSpec.java deleted file mode 100644 index 9a13c02..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/ConditionsSpec.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.gateway; - -public class ConditionsSpec { - - String type; - String status; - String Reason; - String Message; - String lastTransitionTime; - - public String getLastTransitionTime() { - return lastTransitionTime; - } - - public void setLastTransitionTime(String lastTransitionTime) { - this.lastTransitionTime = lastTransitionTime; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public String getReason() { - return Reason; - } - - public void setReason(String reason) { - Reason = reason; - } - - public String getMessage() { - return Message; - } - - public void setMessage(String message) { - Message = message; - } -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/Gateway.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/Gateway.java deleted file mode 100644 index 648e934..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/Gateway.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.gateway; - -import io.fabric8.kubernetes.api.model.Namespaced; -import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.model.annotation.Group; -import io.fabric8.kubernetes.model.annotation.ShortNames; -import io.fabric8.kubernetes.model.annotation.Version; - -@Group("networking.x-k8s.io") -@Version("v1alpha1") -@ShortNames("gtw") -public class Gateway extends CustomResource implements Namespaced { -} \ No newline at end of file diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/GatewaySpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/GatewaySpec.java deleted file mode 100644 index ea1642c..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/GatewaySpec.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.gateway; - -public class GatewaySpec { - - private String gatewayClassName; - - private Object listeners; - - private Object addresses; - - public String getGatewayClassName() { - return gatewayClassName; - } - - public void setGatewayClassName(String gatewayClassName) { - this.gatewayClassName = gatewayClassName; - } - - public Object getListeners() { - return listeners; - } - - public void setListeners(Object listeners) { - this.listeners = listeners; - } - - public Object getAddresses() { - return addresses; - } - - public void setAddresses(Object addresses) { - this.addresses = addresses; - } -} \ No newline at end of file diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/GatewayStatus.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/GatewayStatus.java deleted file mode 100644 index 007a4ea..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/gateway/GatewayStatus.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.gateway; - -public class GatewayStatus { - - ConditionsSpec[] conditions; - - public ConditionsSpec[] getConditions() { - return conditions; - } - - public void setConditions(ConditionsSpec[] conditions) { - this.conditions = conditions; - } -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayAllowTypeSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayAllowTypeSpec.java deleted file mode 100644 index 6f66a2e..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayAllowTypeSpec.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public enum GatewayAllowTypeSpec { - - All, FromList, SameNamespace - -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayReferenceListSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayReferenceListSpec.java deleted file mode 100644 index 1a0699f..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayReferenceListSpec.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -import java.util.ArrayList; - -public class GatewayReferenceListSpec extends ArrayList { - - -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayReferenceSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayReferenceSpec.java deleted file mode 100644 index 8e72078..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/GatewayReferenceSpec.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public class GatewayReferenceSpec { - - String name; - String namespace; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getNamespace() { - return namespace; - } - - public void setNamespace(String namespace) { - this.namespace = namespace; - } -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPPathMatchSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPPathMatchSpec.java deleted file mode 100644 index d8d9b34..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPPathMatchSpec.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public class HTTPPathMatchSpec { - - PathMatchType type; - String value; - - public PathMatchType getType() { - return type; - } - - public void setType(PathMatchType type) { - this.type = type; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - enum PathMatchType { - Exact, Prefix - } -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRoute.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRoute.java deleted file mode 100644 index 3abd73a..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRoute.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -import io.fabric8.kubernetes.api.model.Namespaced; -import io.fabric8.kubernetes.client.CustomResource; -import io.fabric8.kubernetes.model.annotation.Group; -import io.fabric8.kubernetes.model.annotation.ShortNames; -import io.fabric8.kubernetes.model.annotation.Version; - -@Group("networking.x-k8s.io") -@Version("v1alpha1") -@ShortNames("hr") -public class HTTPRoute extends CustomResource implements Namespaced { -} \ No newline at end of file diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteFilterSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteFilterSpec.java deleted file mode 100644 index 7db502c..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteFilterSpec.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public class HTTPRouteFilterSpec { -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteForwardToListSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteForwardToListSpec.java deleted file mode 100644 index b453301..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteForwardToListSpec.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -import java.util.ArrayList; - -public class HTTPRouteForwardToListSpec extends ArrayList { - - -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteForwardToSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteForwardToSpec.java deleted file mode 100644 index 4a47d82..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteForwardToSpec.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public class HTTPRouteForwardToSpec { - - int port; - String serviceName; - int weight; - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public String getServiceName() { - return serviceName; - } - - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - - public int getWeight() { - return weight; - } - - public void setWeight(int weight) { - this.weight = weight; - } -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteMatchListSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteMatchListSpec.java deleted file mode 100644 index cbab306..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteMatchListSpec.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -import java.util.ArrayList; - -public class HTTPRouteMatchListSpec extends ArrayList { -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteMatchSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteMatchSpec.java deleted file mode 100644 index 1d2c1d2..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteMatchSpec.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public class HTTPRouteMatchSpec { - - HTTPPathMatchSpec path; - //HTTPHeaderMatch headers; - //HTTPQueryParamMatch queryParams; - //LocalObjectReference extensionRef - - - public HTTPPathMatchSpec getPath() { - return path; - } - - public void setPath(HTTPPathMatchSpec path) { - this.path = path; - } -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteRuleListSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteRuleListSpec.java deleted file mode 100644 index 9b80221..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteRuleListSpec.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -import java.util.ArrayList; - -public class HTTPRouteRuleListSpec extends ArrayList { - - -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteRuleSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteRuleSpec.java deleted file mode 100644 index 584403f..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteRuleSpec.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public class HTTPRouteRuleSpec { - - HTTPRouteMatchListSpec matches; - HTTPRouteForwardToListSpec forwardTo; - - public HTTPRouteMatchListSpec getMatches() { - return matches; - } - - public void setMatches(HTTPRouteMatchListSpec matches) { - this.matches = matches; - } - - public HTTPRouteForwardToListSpec getForwardTo() { - return forwardTo; - } - - public void setForwardTo(HTTPRouteForwardToListSpec forwardTo) { - this.forwardTo = forwardTo; - } -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteSpec.java deleted file mode 100644 index 1f6fc28..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteSpec.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - - -public class HTTPRouteSpec { - - - RouteGatewaySpec gateways; - - HostnameSpec hostnames; - - HTTPRouteRuleListSpec rules; - - public RouteGatewaySpec getGateways() { - return gateways; - } - - public void setGateways(RouteGatewaySpec gateways) { - this.gateways = gateways; - } - - public HostnameSpec getHostnames() { - return hostnames; - } - - public void setHostnames(HostnameSpec hostnames) { - this.hostnames = hostnames; - } - - public HTTPRouteRuleListSpec getRules() { - return rules; - } - - public void setRules(HTTPRouteRuleListSpec rules) { - this.rules = rules; - } -} \ No newline at end of file diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteStatus.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteStatus.java deleted file mode 100644 index 1ecc0bc..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HTTPRouteStatus.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public class HTTPRouteStatus { - - -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HostnameSpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HostnameSpec.java deleted file mode 100644 index 30a264d..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/HostnameSpec.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -import java.util.ArrayList; - -public class HostnameSpec extends ArrayList { - -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/RouteGatewaySpec.java b/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/RouteGatewaySpec.java deleted file mode 100644 index bdd3f79..0000000 --- a/src/main/java/io/verticle/kubernetes/authgateway/crd/v1alpha1/httproute/RouteGatewaySpec.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute; - -public class RouteGatewaySpec { - - GatewayAllowTypeSpec allow; - GatewayReferenceListSpec gatewayRefs; - public RouteGatewaySpec() { - } - - public GatewayAllowTypeSpec getAllow() { - return allow; - } - - public void setAllow(GatewayAllowTypeSpec allow) { - this.allow = allow; - } - - public GatewayReferenceListSpec getGatewayRefs() { - return gatewayRefs; - } - - public void setGatewayRefs(GatewayReferenceListSpec gatewayRefs) { - this.gatewayRefs = gatewayRefs; - } - - /* - public List getGatewayRefs() { - return gatewayRefs; - } - - public void setGatewayRefs(List gatewayRefs) { - this.gatewayRefs = gatewayRefs; - } - - */ -} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/route/RouteConfigService.java b/src/main/java/io/verticle/kubernetes/authgateway/route/RouteConfigService.java index 5e13ed7..9cf7e5a 100644 --- a/src/main/java/io/verticle/kubernetes/authgateway/route/RouteConfigService.java +++ b/src/main/java/io/verticle/kubernetes/authgateway/route/RouteConfigService.java @@ -1,14 +1,16 @@ package io.verticle.kubernetes.authgateway.route; -import io.verticle.kubernetes.authgateway.ApikeyHeaderGatewayFilterFactory; -import io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute.HTTPRoute; -import io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute.HTTPRouteRuleListSpec; -import io.verticle.kubernetes.authgateway.crd.v1alpha1.httproute.HostnameSpec; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HTTPRoute; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HTTPRouteFilterTypeEnum; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HTTPRouteRuleListSpec; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HostnameSpec; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.event.RefreshRoutesEvent; +import org.springframework.cloud.gateway.route.InMemoryRouteDefinitionRepository; import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.route.RouteDefinitionWriter; import org.springframework.cloud.gateway.route.RouteLocator; @@ -31,6 +33,15 @@ public class RouteConfigService implements ApplicationEventPublisherAware, Appli Log log = LogFactory.getLog(this.getClass()); + @Autowired + InMemoryRouteDefinitionRepository repository; + + @Autowired + RoutePredicateConfigurer routePredicateConfigurer; + + @Autowired + RouteFilterConfigurer routeFilterConfigurer; + @Autowired RuntimeRouteLocator runtimeRouteLocator; @@ -40,9 +51,6 @@ public class RouteConfigService implements ApplicationEventPublisherAware, Appli @Autowired RouteLocatorBuilder builder; - @Autowired - ApikeyHeaderGatewayFilterFactory apikeyHeaderGateway; - @Autowired RouteDefinitionWriter routeDefinitionWriter; @@ -51,6 +59,7 @@ public class RouteConfigService implements ApplicationEventPublisherAware, Appli private ApplicationContext applicationContext; + public void mapCustomResource(HTTPRoute resource) { log.info(resource); @@ -66,32 +75,56 @@ public void mapCustomResource(HTTPRoute resource) { httpRouteRuleSpec -> { AtomicReference b = new AtomicReference<>(); + b.set(r.alwaysTrue()); + + // PREDICATES // match paths - httpRouteRuleSpec.getMatches().forEach( - httpRouteMatchSpec -> { - b.set(r.path(httpRouteMatchSpec.getPath().getValue())); - } - ); + routePredicateConfigurer.applyPathPredicate(r, b, httpRouteRuleSpec); // match hostnames - hostnameSpec.forEach(hostname -> { - b.get().and().host(hostname); - }); + routePredicateConfigurer.applyHostPredicate(r, b, hostnameSpec); + // FILTERS // apply filters - b.get().filters(f -> f.filter(apikeyHeaderGateway.apply(config -> { - }))); + // apikey via GatewayClass + routeFilterConfigurer.applyApikeyHeaderFilter(b); + + // configured filters + if (ObjectUtils.isNotEmpty(httpRouteRuleSpec.getFilters())){ + + httpRouteRuleSpec.getFilters().forEach(httpRouteFilterSpec -> { + if (httpRouteFilterSpec.getRequestHeaderModifier() != null) { + routeFilterConfigurer.applyHeaderFilter(r, b, httpRouteFilterSpec.getRequestHeaderModifier()); + } + + if (httpRouteFilterSpec.getRequestMirror() != null) { + // TODO routeFilterConfigurer.applyHeaderFilter(r, b, httpRouteFilterSpec.getRequestMirror()); + } + + // custom filters + if (HTTPRouteFilterTypeEnum.ExtensionRef.equals(httpRouteFilterSpec.getType())) { + routeFilterConfigurer.applyCustomFilter(r, b, httpRouteFilterSpec.getExtensionRef()); + } + + }); + } + + + + // TARGET httpRouteRuleSpec.getForwardTo().forEach( httpRouteForwardToSpec -> { + routePredicateConfigurer.applyWeightPredicate(r, b, httpRouteForwardToSpec); + URI uri = new DefaultUriBuilderFactory().builder() .scheme("http") .host(httpRouteForwardToSpec.getServiceName()) .port(httpRouteForwardToSpec.getPort()) .build(); - // TODO: add weights - ObjectUtils.defaultIfNull(httpRouteForwardToSpec.getWeight(), 100); + route.set(b.get().uri(uri)); }); @@ -107,7 +140,6 @@ public void mapCustomResource(HTTPRoute resource) { } - @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.publisher = applicationEventPublisher; diff --git a/src/main/java/io/verticle/kubernetes/authgateway/route/RouteFilterConfigurer.java b/src/main/java/io/verticle/kubernetes/authgateway/route/RouteFilterConfigurer.java new file mode 100644 index 0000000..c11bb6d --- /dev/null +++ b/src/main/java/io/verticle/kubernetes/authgateway/route/RouteFilterConfigurer.java @@ -0,0 +1,175 @@ +package io.verticle.kubernetes.authgateway.route; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; +import io.verticle.kubernetes.authgateway.GatewayClass; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HTTPRequestHeaderFilterSpec; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.LocalObjectReference; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory; +import org.springframework.cloud.gateway.route.builder.BooleanSpec; +import org.springframework.cloud.gateway.route.builder.PredicateSpec; +import org.springframework.cloud.gateway.support.ConfigurationService; +import org.springframework.stereotype.Service; +import org.yaml.snakeyaml.Yaml; + +import javax.annotation.PostConstruct; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +@Service +public class RouteFilterConfigurer { + + @Autowired + ConfigurationService configurationService; + + @Autowired + GatewayClass gatewayClass; + + static final String FEATURE_APIKEY_ENABELED = "apikeyEnabled"; + + @Autowired + KubernetesClient kubernetesClient; + + // verticle filters + + + @Autowired + List gatewayFilterList = new ArrayList<>(); + Map gatewayFilters = new HashMap<>(); + + + @PostConstruct + public void initialize(){ + gatewayFilterList.forEach(filter -> { + gatewayFilters.put(filter.name(), filter); + }); + } + + protected void applyApikeyHeaderFilter(AtomicReference b) { + + GatewayFilterFactory factory = gatewayFilters.get("ApikeyHeader"); + + if (gatewayClass.hasFeature(GatewayClass.Feature.apikey)){ + b.get().filters(f -> f.filter(factory.apply(config -> { + // NO CFG + }))); + } + } + + /** + * implements https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPHeaderMatch + * @param r + * @param b + */ + protected void applyHeaderFilter(PredicateSpec r, AtomicReference b, HTTPRequestHeaderFilterSpec hfs){ + + + //add + final GatewayFilterFactory addfactory = gatewayFilters.get("AddRequestHeader"); + if (hfs.getAdd().size() > 0){ + b.get().filters(f -> f.filter(addfactory.apply( + configurationService.with(addfactory) + .properties(hfs.getAdd()) + .bind() + ))); + } + + // set (map) + final GatewayFilterFactory setFactory = gatewayFilters.get("SetRequestHeader"); + if (hfs.getSet().size() > 0) { + b.get().filters(f -> f.filter(setFactory.apply( + configurationService.with(setFactory) + .properties(hfs.getAdd()) + .bind() + ))); + } + + // remove + final GatewayFilterFactory removeFactory = gatewayFilters.get("RemoveRequestHeader"); + if (hfs.getRemove().size() > 0) { + b.get().filters(f -> f.filter(removeFactory.apply( + configurationService.with(removeFactory) + .properties(hfs.getAdd()) + .bind() + ))); + } + } + + + protected void applyNamedFilter(AtomicReference b, Map configMap, String filterFactoryName){ + + GatewayFilterFactory factory = gatewayFilters.get(filterFactoryName); + + b.get().filters(f -> f.filter(factory.apply( + configurationService.with(factory) + .name(filterFactoryName) + .properties(configMap) + .bind() + ))); + } + + + + public void applyCustomFilter(PredicateSpec r, AtomicReference b, LocalObjectReference extensionRef) { + Map extensionConfig = locateExtensionAsConfigMap(extensionRef); + String filterName = extensionConfig.getOrDefault("name", ""); + Map args = parseArgs(extensionConfig.getOrDefault("args", "")); + + GatewayFilterFactory factory = gatewayFilters.get(filterName); + + b.get().filters(f -> f.filter(factory.apply( + configurationService.with(factory) + .name(filterName) + .properties(args) + .bind() + ))); + + + } + + private Map locateExtensionAsConfigMap(LocalObjectReference extensionRef){ + + if (extensionRef.getKind().equals("ConfigMap") + && extensionRef.getGroup().equals("v1")){ + + ConfigMap configMap = kubernetesClient + .configMaps() + .withName(extensionRef.getName()).get(); + if (ObjectUtils.allNotNull(configMap)) + return configMap.getData(); + } + + return Collections.emptyMap(); + + } + + private Map parseArgs(String args){ + Yaml yaml = new Yaml(); + + Map map = yaml.load(args); + Map newMap =new HashMap(); + for (Map.Entry entry : map.entrySet()) { + if(entry.getValue() instanceof String){ + newMap.put(entry.getKey(), (String) entry.getValue()); + } else { + newMap.put(entry.getKey(),String.valueOf(entry.getValue())); + } + } + + return newMap; + } + + private Map locateExtensionAsMap(LocalObjectReference extensionRef){ + + CustomResourceDefinitionContext customResourceDefinitionContext = new CustomResourceDefinitionContext.Builder() + .withKind(extensionRef.getKind()) + .withGroup(extensionRef.getGroup()) + .withName(extensionRef.getName()) + .build(); + + return kubernetesClient.customResource(customResourceDefinitionContext).list(); + } +} diff --git a/src/main/java/io/verticle/kubernetes/authgateway/route/RoutePredicateConfigurer.java b/src/main/java/io/verticle/kubernetes/authgateway/route/RoutePredicateConfigurer.java new file mode 100644 index 0000000..8027247 --- /dev/null +++ b/src/main/java/io/verticle/kubernetes/authgateway/route/RoutePredicateConfigurer.java @@ -0,0 +1,213 @@ +package io.verticle.kubernetes.authgateway.route; + +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HTTPRouteFilterSpec; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HTTPRouteForwardToSpec; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HTTPRouteRuleSpec; +import io.verticle.apex.gateway.crd.v1alpha1.httproute.HostnameSpec; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.handler.predicate.*; +import org.springframework.cloud.gateway.route.builder.BooleanSpec; +import org.springframework.cloud.gateway.route.builder.PredicateSpec; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +@Service +public class RoutePredicateConfigurer { + + Log log = LogFactory.getLog(this.getClass()); + + @Autowired + HostRoutePredicateFactory hostRoutePredicateFactory; + + @Autowired + PathRoutePredicateFactory pathRoutePredicateFactory; + + @Autowired + HeaderRoutePredicateFactory headerRoutePredicateFactory; + + @Autowired + MethodRoutePredicateFactory methodRoutePredicateFactory; + + @Autowired + QueryRoutePredicateFactory queryRoutePredicateFactory; + + @Autowired + RemoteAddrRoutePredicateFactory remoteAddrRoutePredicateFactory; + + @Autowired + CookieRoutePredicateFactory cookieRoutePredicateFactory; + + @Autowired + AfterRoutePredicateFactory afterRoutePredicateFactory; + + @Autowired + BeforeRoutePredicateFactory beforeRoutePredicateFactory; + + @Autowired + BetweenRoutePredicateFactory betweenRoutePredicateFactory; + + @Autowired + WeightRoutePredicateFactory weightRoutePredicateFactory; + + + public RoutePredicateConfigurer() { + } + + protected void applyHostPredicate(PredicateSpec r, AtomicReference b, HostnameSpec hostnameSpec) { + + if (hostnameSpec.size() > 0){ + b.get().and().predicate(hostRoutePredicateFactory.apply(config -> { + List patterns = new ArrayList(); + hostnameSpec.forEach( + host -> { + patterns.add(host); + } + ); + config.setPatterns(patterns); + })); + } + } + + /** + * implements https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPPathMatch + * @param r + * @param b + * @param httpRouteRuleSpec + */ + protected void applyPathPredicate(PredicateSpec r, AtomicReference b, HTTPRouteRuleSpec httpRouteRuleSpec){ + + if (httpRouteRuleSpec.getMatches().size() > 0){ + b.get().and().predicate(pathRoutePredicateFactory.apply(config -> { + + List patterns = new ArrayList<>(); + httpRouteRuleSpec.getMatches().forEach( + httpRouteMatchSpec -> { + patterns.add(httpRouteMatchSpec.getPath().getValue()); + } + ); + config.setPatterns(patterns); + // TODO config.setMatchTrailingSlash(httpRouteMatchSpec); + })); + } + } + + /** + * adds a weight predicate + * implements Custom filter + * https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPRouteFilter + * @param r + * @param b + * @param httpRouteForwardToSpec + */ + protected void applyWeightPredicate(PredicateSpec r, AtomicReference b, HTTPRouteForwardToSpec httpRouteForwardToSpec){ + + if (httpRouteForwardToSpec.getWeight() > 0){ + b.get().and().predicate(weightRoutePredicateFactory.apply(config -> { + config.setWeight(httpRouteForwardToSpec.getWeight()); + config.setRouteId("weight_" + httpRouteForwardToSpec.getServiceName() + "_" + httpRouteForwardToSpec.getWeight()); + config.setGroup("weight_" + httpRouteForwardToSpec.getServiceName()); + })); + } + + } + + /** + * implements Custom filter + * https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPRouteFilter + * @param r + * @param b + */ + protected void applyCookiePredicate(PredicateSpec r, AtomicReference b){ + b.get().and().predicate(cookieRoutePredicateFactory.apply(config -> { + // TODO implement + })); + } + + /** + * implements Custom filter + * https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPRouteFilter + * @param r + * @param b + */ + protected void applyAfterPredicate(PredicateSpec r, AtomicReference b){ + b.get().and().predicate(afterRoutePredicateFactory.apply(config -> { + // TODO implement + })); + } + + /** + * implements Custom filter + * https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPRouteFilter + * @param r + * @param b + */ + protected void applyBeforePredicate(PredicateSpec r, AtomicReference b){ + b.get().and().predicate(beforeRoutePredicateFactory.apply(config -> { + // TODO implement + })); + } + + /** + * implements Custom filter + * https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPRouteFilter + * @param r + * @param b + */ + protected void applyBetweenPredicate(PredicateSpec r, AtomicReference b){ + b.get().and().predicate(betweenRoutePredicateFactory.apply(config -> { + // TODO implement + })); + } + + /** + * implements Custom filter + * https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPRouteFilter + * @param r + * @param b + */ + protected void applyMethodPredicate(PredicateSpec r, AtomicReference b){ + b.get().and().predicate(methodRoutePredicateFactory.apply(config -> { + // TODO implement + })); + } + + /** + * implements https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPQueryParamMatch + * @param r + * @param b + */ + protected void applyQueryPredicate(PredicateSpec r, AtomicReference b){ + b.get().and().predicate(queryRoutePredicateFactory.apply(config -> { + // TODO implement + })); + } + + /** + * implements https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPHeaderMatch + * @param r + * @param b + * @param f + */ + protected void applyHeaderPredicate(PredicateSpec r, AtomicReference b, HTTPRouteFilterSpec f){ + b.get().and().predicate(queryRoutePredicateFactory.apply(config -> { + // TODO implement + })); + } + + /** + * implements Custom filter + * https://gateway-api.sigs.k8s.io/references/spec/#networking.x-k8s.io/v1alpha1.HTTPRouteFilter + * @param r + * @param b + */ + protected void applyRemoteAddrPredicate(PredicateSpec r, AtomicReference b){ + b.get().and().predicate(remoteAddrRoutePredicateFactory.apply(config -> { + // TODO implement + })); + } +} \ No newline at end of file