com.predic8.membrane.core.kubernetes.KubernetesWatcher Maven / Gradle / Ivy
/* Copyright 2009, 2021 predic8 GmbH, www.predic8.com
Licensed 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 com.predic8.membrane.core.kubernetes;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.predic8.membrane.core.Router;
import com.predic8.membrane.core.config.spring.K8sHelperGeneratorAutoGenerated;
import com.predic8.membrane.core.interceptor.kubernetes.KubernetesValidationInterceptor;
import com.predic8.membrane.core.rules.Rule;
import io.fabric8.kubernetes.client.*;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import org.jose4j.json.internal.json_simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Creates watcher on all known CustomResourceDefinitions listed at {@link K8sHelperGeneratorAutoGenerated}
*/
public class KubernetesWatcher {
private static final Logger LOG = LoggerFactory.getLogger(KubernetesWatcher.class);
private final String NAMESPACE = "membrane-soa";
private final Router router;
private KubernetesClient client;
private final List watchers = new ArrayList<>();
private final List knownPods = new ArrayList<>();
private List crdContexts;
public KubernetesWatcher(Router router) {
this.router = router;
}
public void start() {
if (!k8sValidatingInterceptorIsActive()) {
return;
}
client = getClient();
createCrdContexts();
crdContexts.forEach(this::createWatcher);
}
private KubernetesClient getClient() {
return isInK8sCluster() ? new DefaultKubernetesClient()
: new DefaultKubernetesClient(new ConfigBuilder()
.withMasterUrl("localhost:8001")
.build());
}
private boolean k8sValidatingInterceptorIsActive() {
return router.getRules().stream()
.flatMap(rule -> rule.getInterceptors().stream())
.anyMatch(inter -> inter instanceof KubernetesValidationInterceptor);
}
private boolean isInK8sCluster() {
return System.getenv("KUBERNETES_SERVICE_HOST") != null;
}
private void createCrdContexts() {
crdContexts = K8sHelperGeneratorAutoGenerated.crdPluralNames.stream()
.map(name -> new CustomResourceDefinitionContext.Builder()
.withGroup("membrane-soa.org")
.withScope("Namespaced")
.withVersion("v1beta1")
.withPlural(name)
.build()
).collect(Collectors.toList());
}
@SuppressWarnings("rawtypes")
private void createWatcher(CustomResourceDefinitionContext crd) {
try {
watchers.add(client.customResource(crd).watch(NAMESPACE, new Watcher() {
@Override
public void eventReceived(Action action, String s) {
try {
JSONObject json = new JSONObject(new ObjectMapper().readValue(s, Map.class));
String uid = getUid(json);
if (knownPods.contains(uid)) {
return;
}
JSONObject spec = new JSONObject((Map) json.get("spec"));
String kind = lowerFirstChar((String) json.get("kind"));
Class kindClass = K8sHelperGeneratorAutoGenerated
.elementMapping.get(kind);
Object parse = GenericJsonParser.parse(kindClass, spec);
router.add((Rule) parse);
knownPods.add(uid);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onClose(WatcherException e) {
LOG.error("Watcher for {} closed unexpectedly", crd.getPlural());
}
}));
LOG.debug("Added Watcher for {}", crd.getPlural());
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("rawtypes")
private String getUid(JSONObject json) {
JSONObject metadata = new JSONObject((Map) json.get("metadata"));
return (String) metadata.get("uid");
}
private String lowerFirstChar(String str) {
if (str == null || str.isEmpty())
return "";
if (str.length() == 1)
return str.toLowerCase();
return str.substring(0, 1).toLowerCase() + str.substring(1);
}
}