All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bikeemotion.kubernetes.KubernetesDao Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) Bikeemotion
 * 2014
 *
 * The reproduction, transmission or use of this document or its contents is not
 * permitted without express written authorization. All rights, including rights
 * created by patent grant or registration of a utility model or design, are
 * reserved. Modifications made to this document are restricted to authorized
 * personnel only. Technical specifications and features are binding only when
 * specifically and expressly agreed upon in a written contract.
 */
package com.bikeemotion.kubernetes;

import com.bikeemotion.kubernetes.api.resources.ResourceType;
import com.bikeemotion.kubernetes.api.resources.mappings.Endpoint;
import com.bikeemotion.kubernetes.api.resources.mappings.PodList;
import com.bikeemotion.kubernetes.api.resources.mappings.ReplicationController;
import com.bikeemotion.kubernetes.api.resources.mappings.Service;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.api.model.ConfigMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class KubernetesDao {

  //members
  private static final Logger log = LoggerFactory.getLogger(KubernetesDao.class);

  private static final String SERVICE_ACCOUNT_TOKEN = "/var/run/secrets/kubernetes.io/serviceaccount/token";

  private static final HostnameVerifier trustAllHosts = (hostname, session) -> true;
  private static final TrustManager[] trustAll = new TrustManager[] {
      new X509TrustManager() {

        public void checkServerTrusted(X509Certificate[] certs, String authType) {

        }

        public void checkClientTrusted(X509Certificate[] certs, String authType) {

        }

        public X509Certificate[] getAcceptedIssuers() {

          return null;
        }
      }
  };

  //public API
  public static boolean isInKubernetes() {

    return getEnvOrDefault("KUBERNETES_SERVICE_HOST", "NONE").compareTo("NONE") != 0;
  }

  public static String getEnvOrDefault(final String variableName, final String defaultValue) {

    final String value = System.getenv(variableName);
    return (value == null || value.isEmpty())
        ? defaultValue
        : value;
  }

  public static Portal queryService(
      final String serviceName,
      final String defaultHost,
      int defaultPort) {

    // if the service isn't there or this is simply not running on k8s it wont have results
    if (queryK8sResource(ResourceType.SERVICE, Service.class, serviceName, Collections.EMPTY_MAP) != null) {

      return new Portal(
          String.format(
              "%s:%s",
              serviceName, // using DNS resolution. don't care about IPs
              defaultPort), // screw dynamic ports for now
          defaultHost,
          defaultPort);
    } else {

      return new Portal(null, defaultHost, defaultPort);
    }
  }

  public static List queryPods(
      final String endpointName,
      final String defaultHost,
      final int defaultPort) {

    // endpoints have the POD's IPs
    final Endpoint value = queryK8sResource(
        ResourceType.ENDPOINT,
        Endpoint.class,
        endpointName,
        Collections.EMPTY_MAP);

    if (value != null && value.subsets != null) {

      final List result = new ArrayList<>();
      value.subsets
          .stream()
          .filter(subset -> subset.addresses != null)
          .forEach(subset -> subset.addresses
              .stream()
              .forEach(a -> result.add(new Portal(a.ip + ":" + defaultPort, defaultHost, defaultPort))));

      return result;
    } else {

      return Collections.EMPTY_LIST;
    }
  }

  public static Set queryPods(final String key, final String value) {

    // according to
    //    http://kubernetes.io/docs/api-reference/v1/operations/
    //    http://kubernetes.io/docs/user-guide/labels/

    final Map queryParams = new HashMap<>();
    String labelSelector = key + "%3D" + value;
    queryParams.put("labelSelector", labelSelector);

    final PodList podList = queryK8sResource(
        ResourceType.POD,
        PodList.class,
        "",
        queryParams);

    if (podList != null && podList.items != null && !podList.items.isEmpty()) {

      podList.items.stream()
          .flatMap(item -> item.status.containerStatuses.stream())
          .filter(containers -> containers.ready);

      return podList.items
          .stream()
          .map(e ->
              new Pod()
                  .setIP(e.status.podIP)
                  .setContainerID(e.status.containerStatuses
                      .stream()
                      .sorted(Comparator.comparing(c -> c.name))
                      .findFirst()
                      .get()
                      .containerID))
          .collect(Collectors.toSet());
    } else {

      log.warn("The label query [{}] didn't return any results", labelSelector);
      return Collections.EMPTY_SET;
    }
  }

  public static int queryReplicationControllerReplicas(final String replicationControllerName) {

    final ReplicationController rc = queryK8sResource(
        ResourceType.REPLICATIONCONTROLLER,
        ReplicationController.class,
        replicationControllerName,
        Collections.EMPTY_MAP);

    if (rc != null) {

      return rc.status.replicas;
    } else {

      return 0;
    }
  }

  public static Map queryConfigMapData(final String configMapName) {

    final ConfigMap configMap = queryK8sResource(
        ResourceType.CONFIGMAPS,
        ConfigMap.class,
        configMapName,
        Collections.EMPTY_MAP);


    return configMap != null ? configMap.getData() : null;
  }

  //internal API
  private static String getServiceAccountToken()
    throws IOException {

    return new String(Files.readAllBytes(Paths.get(SERVICE_ACCOUNT_TOKEN)));
  }

  private static  T queryK8sResource(
      final ResourceType resourceType,
      final Class clazz,
      final String artifactName,
      final Map queryParams) {

    T result = null;

    final String namespace = getEnvOrDefault("POD_NAMESPACE", "default");
    final String host = getEnvOrDefault("KUBERNETES_PORT_443_TCP_ADDR", "10.100.0.1");
    final String path = String.format(
        "https://%s/api/v1/namespaces/%s/%s/%s?%s",
        host,
        namespace,
        resourceType,
        artifactName,
        queryParams.keySet()
            .stream()
            .map((k) -> k + "=" + queryParams.get(k))
            .collect(Collectors.joining("&")));

    //log.info("URL -> {}", path);

    try {

      final String token = getServiceAccountToken();
      final SSLContext ctx = SSLContext.getInstance("SSL");
      final URL url = new URL(path);
      final HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

      ctx.init(null, trustAll, new SecureRandom());
      conn.setSSLSocketFactory(ctx.getSocketFactory());
      conn.setHostnameVerifier(trustAllHosts);
      conn.addRequestProperty("Authorization", "Bearer " + token);

      if (conn.getResponseCode() != 404) {

        result = new ObjectMapper().readValue(conn.getInputStream(), clazz);
      } else {

        log.warn("Couldn't find artifact [{}] on resource [{}]", artifactName, resourceType);
        result = null;
      }
    } catch (IOException | NoSuchAlgorithmException | KeyManagementException ex) {

      if (log.isDebugEnabled()) {

        log.error("Request to Kubernetes API failed with the following exception", ex);
      } else {
        log.warn("Request to Kubernetes API failed");
      }
    }

    return result;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy