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

io.fabric8.kubernetes.client.utils.KubernetesResourceUtil Maven / Gradle / Ivy

/**
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * 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 io.fabric8.kubernetes.client.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.fabric8.kubernetes.api.builder.VisitableBuilder;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
import io.fabric8.kubernetes.api.model.Event;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesList;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.api.model.OwnerReference;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.api.model.SecretBuilder;
import io.fabric8.kubernetes.client.CustomResourceList;
import io.fabric8.kubernetes.client.internal.readiness.Readiness;

import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class KubernetesResourceUtil {
  private KubernetesResourceUtil() {}

  public static final Pattern KUBERNETES_DNS1123_LABEL_REGEX = Pattern.compile("[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?");
  private static final Pattern INVALID_LABEL_CHARS_PATTERN = Pattern.compile("[^-A-Za-z0-9]+");

  /**
   * Returns the resource version for the entity or null if it does not have one
   *
   * @param entity entity provided
   * @return returns resource version of provided entity
   */
  public static String getResourceVersion(HasMetadata entity) {
    if (entity != null) {
      ObjectMeta metadata = entity.getMetadata();
      if (metadata != null) {
        String resourceVersion = metadata.getResourceVersion();
        if (!Utils.isNullOrEmpty(resourceVersion)) {
          return resourceVersion;
        }
      }
    }
    return null;
  }

  /**
   * Set resource version of a kubernetes resource
   *
   * @param entity entity provided
   * @param resourceVersion updated resource version
   */
  public static void setResourceVersion(HasMetadata entity, String resourceVersion) {
    if (entity != null) {
      ObjectMeta metadata = entity.getMetadata();
      if (metadata != null) {
        metadata.setResourceVersion(resourceVersion);
      }
    }
  }

  /**
   * Returns the kind of the entity
   *
   * @param entity provided entity
   * @return returns kind of entity provided
   */
  public static String getKind(HasMetadata entity) {
    if (entity != null) {
      // TODO use reflection to find the kind?
      if (entity instanceof KubernetesList) {
        return "List";
      } else {
        return entity.getClass().getSimpleName();
      }
    } else {
      return null;
    }
  }

  /**
   * Returns Qualified name for the specified Kubernetes Resource
   *
   * @param entity Kubernetes resource
   * @return returns qualified name
   */
  public static String getQualifiedName(HasMetadata entity) {
    if (entity != null) {
      return "" + getNamespace(entity) + "/" + getName(entity);
    } else {
      return null;
    }
  }

  /**
   * Returns name of the resource from it's Metadata
   *
   * @param entity Kubernetes resource
   * @return returns name of resource
   */
  public static String getName(HasMetadata entity) {
    if (entity != null) {
      return getName(entity.getMetadata());
    } else {
      return null;
    }
  }

  /**
   * Returns true if this entity has a valid non blank resourceVersion in its metadata
   *
   * @param entity entity provided
   * @return returns a boolean value indicating whether it has a valid non blank resourceVersion
   */
  public static boolean hasResourceVersion(HasMetadata entity) {
    return getResourceVersion(entity) != null;
  }

  /**
   * Returns name of the resource from it's Metadata
   *
   * @param entity MetaData of kubernetes resource
   * @return returns name of resource
   */
  public static String getName(ObjectMeta entity) {
    if (entity != null) {
      return Utils.coalesce(entity.getName(),
        getAdditionalPropertyText(entity.getAdditionalProperties(), "id"),
        entity.getUid());
    } else {
      return null;
    }
  }

  /**
   * Used to get additional properties from Object's metadata
   *
   * @param additionalProperties additional properties
   * @param name name of resource
   * @return returns additional property text
   */
  protected static String getAdditionalPropertyText(Map additionalProperties, String name) {
    if (additionalProperties != null) {
      Object value = additionalProperties.get(name);
      if (value != null) {
        return value.toString();
      }
    }
    return null;
  }

  /**
   * Null safe get operation for getting namespace from Kubernetes Resource's MetaData
   *
   * @param entity Kubernetes Resource
   * @return returns namespace as plain string
   */
  public static String getNamespace(ObjectMeta entity) {
    if (entity != null) {
      return entity.getNamespace();
    } else {
      return null;
    }
  }

  /**
   * Getting namespace from Kubernetes Resource
   *
   * @param entity Kubernetes Resource
   * @return returns namespace as plain string
   */
  public static String getNamespace(HasMetadata entity) {
    if (entity != null) {
      return getNamespace(entity.getMetadata());
    } else {
      return null;
    }
  }

  /**
   * Null safe get for fetching annotations from MetaData of Kubernetes Resource
   *
   * @param entity Kubernetes resource
   * @return returns a hashmap containing annotations
   */
  public static Map getOrCreateAnnotations(HasMetadata entity) {
    ObjectMeta metadata = getOrCreateMetadata(entity);
    Map answer = metadata.getAnnotations();
    if (answer == null) {
      // use linked so the annotations can be in the FIFO order
      answer = new LinkedHashMap<>();
      metadata.setAnnotations(answer);
    }
    return answer;
  }

  /**
   * Returns an identifier from the given string that can be used as resource name.
   *
   * @param name which needs to be sanitized
   * @return sanitized name
   */
  public static String sanitizeName(String name) {
    if(name != null) {
      name = INVALID_LABEL_CHARS_PATTERN.matcher(name).replaceAll("-");
      if (!Character.isLetterOrDigit(name.charAt(0))) {
        name = "a" + name;
      }
      if (name.length() > 63) {
        name = name.substring(0, 63);
      }
      name = name.toLowerCase();
      final int lastChar = name.length() - 1;
      if (!Character.isLetterOrDigit(name.charAt(lastChar))) {
        name = name.substring(0, lastChar - 1) + "a";
      }
      return name;
    }
    return null;
  }

  /**
   * Null safe get method for getting Labels of a Kubernetes Resource
   *
   * @param entity Kubernetes Resource
   * @return returns a hashmap containing labels
   */
  public static Map getOrCreateLabels(HasMetadata entity) {
    ObjectMeta metadata = getOrCreateMetadata(entity);
    Map answer = metadata.getLabels();
    if (answer == null) {
      // use linked so the annotations can be in the FIFO order
      answer = new LinkedHashMap<>();
      metadata.setLabels(answer);
    }
    return answer;
  }

  /**
   * Returns the labels of the given metadata object or an empty map if the metadata or labels are null
   *
   * @param metadata ObjectMeta for resource's metadata
   * @return returns labels as a hashmap
   */

  @SuppressWarnings("unchecked")
  public static Map getLabels(ObjectMeta metadata) {
    if (metadata != null) {
      Map labels = metadata.getLabels();
      if (labels != null) {
        return labels;
      }
    }
    return Collections.emptyMap();
  }

  /**
   * Null safe operation for getting Metadata of a Kubernetes resource
   *
   * @param entity Kubernetes Resource
   * @return returns ObjectMeta as metadata
   */
  public static ObjectMeta getOrCreateMetadata(HasMetadata entity) {
    ObjectMeta metadata = entity.getMetadata();
    if (metadata == null) {
      metadata = new ObjectMeta();
      entity.setMetadata(metadata);
    }
    return metadata;
  }

  /**
   * Validates name of Kubernetes Resource name, label or annotation based on Kubernetes regex
   *
   * @param name Name of resource/label/annotation
   * @return returns a boolean value indicating whether it's valid or not
   */
  public static boolean isValidName(String name) {
    return Utils.isNotNullOrEmpty(name) && KUBERNETES_DNS1123_LABEL_REGEX.matcher(name).matches();
  }


  /**
   * Validates labels/annotations of Kubernetes resources
   *
   * @param map Label/Annotation of resource
   * @return returns a boolean value indicating whether it's valid or not
   */
  public static boolean isValidLabelOrAnnotation(Map map) {
    for(Map.Entry entry : map.entrySet()) {
      if(!(isValidName(entry.getKey()) && isValidName(entry.getValue()))) {
        return false;
      }
    }
    return true;
  }

  /**
   * Checks whether the resource has some controller(parent) or not.
   *
   * @param resource resource
   * @return boolean value indicating whether it's a child or not.
   */
  public static boolean hasController(HasMetadata resource) {
    return getControllerUid(resource) != null;
  }

  public static OwnerReference getControllerUid(HasMetadata resource) {
    if (resource.getMetadata() != null) {
      List ownerReferenceList = resource.getMetadata().getOwnerReferences();
      for (OwnerReference ownerReference : ownerReferenceList) {
        if (Boolean.TRUE.equals(ownerReference.getController())) {
          return ownerReference;
        }
      }
    }
    return null;
  }

  public static void sortEventListBasedOnTimestamp(List eventList) {
    if (eventList != null) {
      // Sort to get latest events in beginning, putting events without lastTimestamp first
      eventList.sort(Comparator.comparing(Event::getLastTimestamp, Comparator.nullsFirst(Comparator.comparing(Instant::parse).reversed())));
    }
  }

  public static List convertMapToEnvVarList(Map envVarMap) {
    List envVars = new ArrayList<>();
    for (Map.Entry entry : envVarMap.entrySet()) {
      if (entry.getKey() != null && entry.getValue() != null) {
        envVars.add(new EnvVarBuilder()
          .withName(entry.getKey())
          .withValue(entry.getValue())
          .build());
      }
    }
    return envVars;
  }

  /**
   * Check whether a Kubernetes resource is Ready or not. Applicable only to
   * Deployment, ReplicaSet, Pod, ReplicationController, Endpoints, Node and
   * StatefulSet
   * @param item item which needs to be checked
   * @return boolean value indicating it's status
   */
  public static boolean isResourceReady(HasMetadata item) {
    return Readiness.getInstance().isReady(item);
  }

  /**
   * Calculates age of a kubernetes resource
   * @param kubernetesResource
   * @return a positive duration indicating age of the kubernetes resource
   */
  public static Duration getAge(HasMetadata kubernetesResource) {
    Instant instant = Instant.parse(kubernetesResource.getMetadata().getCreationTimestamp());
    return Duration.between(instant, Instant.now()).abs();
  }

  public static  Class inferListType(Class type) {
    return (Class) loadRelated(type, "List", CustomResourceList.class);
  }
  
  public static > Class inferBuilderType(Class type) {
    return (Class) loadRelated(type, "Builder", null);
  }

  private static Class loadRelated(Class type, String suffix, Class defaultClass) {
    try {
      return Thread.currentThread().getContextClassLoader().loadClass(type.getName() + suffix);
    } catch (ClassNotFoundException | ClassCastException e) {
      try {
        return type.getClassLoader().loadClass(type.getName() + suffix);
      } catch (ClassNotFoundException | ClassCastException ex) {
        return defaultClass;
      }
    }
  }

  /**
   * Create Secret by using username and password.
   * @param dockerServer User to store key value pair for auths map
   * @param username username that needs to be used during secret creation
   * @param password password that needs to be used during secret creation
   * @return an object of Secret
   */
  public static Secret createDockerRegistrySecret(String dockerServer, String username, String password) throws JsonProcessingException {
    Map dockerConfigMap = new HashMap<>();
    Map auths = new HashMap<>();
    Map credentials = new HashMap<>();
    credentials.put("username", username);
    credentials.put("password", password);
    String usernameAndPasswordAuth = username + ":" + password;
    credentials.put("auth", Base64.getEncoder().encodeToString(usernameAndPasswordAuth.getBytes(StandardCharsets.UTF_8)));
    auths.put(dockerServer, credentials);
    dockerConfigMap.put("auths", auths);

    String dockerConfigAsStr = Serialization.jsonMapper().writeValueAsString(dockerConfigMap);

    return new SecretBuilder()
      .withNewMetadata().withName("harbor-secret").endMetadata()
      .withType("kubernetes.io/dockerconfigjson")
      .addToData(".dockerconfigjson", Base64.getEncoder().encodeToString(dockerConfigAsStr.getBytes(StandardCharsets.UTF_8)))
      .build();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy