io.fabric8.kubernetes.api.KubernetesHelper Maven / Gradle / Ivy
/**
* Copyright 2005-2016 Red Hat, Inc.
*
* Red Hat licenses this file to you 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.api;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.fabric8.kubernetes.api.extensions.Templates;
import io.fabric8.kubernetes.api.model.*;
import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPath;
import io.fabric8.kubernetes.api.model.extensions.HTTPIngressRuleValue;
import io.fabric8.kubernetes.api.model.extensions.Ingress;
import io.fabric8.kubernetes.api.model.extensions.IngressBackend;
import io.fabric8.kubernetes.api.model.extensions.IngressList;
import io.fabric8.kubernetes.api.model.extensions.IngressRule;
import io.fabric8.kubernetes.api.model.extensions.IngressSpec;
import io.fabric8.kubernetes.api.model.extensions.IngressTLS;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.utils.Utils;
import io.fabric8.openshift.api.model.DeploymentConfig;
import io.fabric8.openshift.api.model.DeploymentConfigSpec;
import io.fabric8.openshift.api.model.OAuthClient;
import io.fabric8.openshift.api.model.Parameter;
import io.fabric8.openshift.api.model.Route;
import io.fabric8.openshift.api.model.RouteList;
import io.fabric8.openshift.api.model.RouteSpec;
import io.fabric8.openshift.api.model.Template;
import io.fabric8.openshift.client.DefaultOpenShiftClient;
import io.fabric8.openshift.client.OpenShiftClient;
import io.fabric8.utils.Files;
import io.fabric8.utils.Filter;
import io.fabric8.utils.Filters;
import io.fabric8.utils.IOHelpers;
import io.fabric8.utils.KubernetesServices;
import io.fabric8.utils.Objects;
import io.fabric8.utils.Strings;
import io.fabric8.utils.Systems;
import io.fabric8.utils.URLUtils;
import io.fabric8.utils.ssl.TrustEverythingSSLTrustManager;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xbill.DNS.ARecord;
import org.xbill.DNS.Lookup;
import org.xbill.DNS.Record;
import org.xbill.DNS.SRVRecord;
import org.xbill.DNS.TextParseException;
import org.xbill.DNS.Type;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLKeyException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLProtocolException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.tools.FileObject;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import static io.fabric8.kubernetes.client.utils.Utils.isNotNullOrEmpty;
import static io.fabric8.utils.Lists.notNullList;
import static io.fabric8.utils.Strings.isNullOrBlank;
/**
* Kubernetes utility methods.
*/
public final class KubernetesHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(KubernetesHelper.class);
public static final String KUBERNETES_NAMESPACE_SYSTEM_PROPERTY = "kubernetes.namespace";
public static final String KUBERNETES_NAMESPACE_ENV = "KUBERNETES_NAMESPACE";
public static final String DEFAULT_NAMESPACE = "default";
private static final transient Logger LOG = LoggerFactory.getLogger(KubernetesHelper.class);
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static final int INTORSTRING_KIND_INT = 0;
public static final int INTORSTRING_KIND_STRING = 1;
public static final String DEFAULT_DOCKER_HOST = "tcp://localhost:2375";
public static final String defaultApiVersion = "v1";
public static final String defaultOsApiVersion = "v1";
private static final ConcurrentMap IS_OPENSHIFT = new ConcurrentHashMap<>();
private static final Config CONFIG = new ConfigBuilder().build();
private static final String DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssX";
public static String defaultNamespace() {
return CONFIG.getNamespace();
}
/**
* Returns the ID of the given object
*/
public static String getObjectId(Object object) {
if (object instanceof HasMetadata) {
return getName((HasMetadata) object);
} else {
return object != null ? object.toString() : null;
}
}
public static ObjectMeta getOrCreateMetadata(HasMetadata entity) {
ObjectMeta metadata = entity.getMetadata();
if (metadata == null) {
metadata = new ObjectMeta();
entity.setMetadata(metadata);
}
return metadata;
}
/**
* Returns the resource version for the entity or null if it does not have one
*/
public static String getResourceVersion(HasMetadata entity) {
if (entity != null) {
ObjectMeta metadata = entity.getMetadata();
if (metadata != null) {
String resourceVersion = metadata.getResourceVersion();
if (Strings.isNotBlank(resourceVersion)) {
return resourceVersion;
}
}
}
return null;
}
/**
* Returns true if this entity has a valid non blank resourceVersion in its metadata
*/
public static boolean hasResourceVersion(HasMetadata entity) {
return getResourceVersion(entity) != null;
}
public static String getName(ObjectMeta entity) {
if (entity != null) {
return Strings.firstNonBlank(entity.getName(),
getAdditionalPropertyText(entity.getAdditionalProperties(), "id"),
entity.getUid());
} else {
return null;
}
}
/**
* Returns the kind of the entity
*/
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;
}
}
public static String getQualifiedName(HasMetadata entity) {
if (entity != null) {
return "" + getNamespace(entity) + "/" + getName(entity);
} else {
return null;
}
}
public static String getName(HasMetadata entity) {
if (entity != null) {
return getName(entity.getMetadata());
} else {
return null;
}
}
public static void setName(HasMetadata entity, String name) {
getOrCreateMetadata(entity).setName(name);
}
public static void setName(HasMetadata entity, String namespace, String name) {
ObjectMeta metadata = getOrCreateMetadata(entity);
metadata.setNamespace(namespace);
metadata.setName(name);
}
public static void setNamespace(HasMetadata entity, String namespace) {
getOrCreateMetadata(entity).setNamespace(namespace);
}
public static String getNamespace(ObjectMeta entity) {
if (entity != null) {
return entity.getNamespace();
} else {
return null;
}
}
public static String getNamespace(HasMetadata entity) {
if (entity != null) {
return getNamespace(entity.getMetadata());
} else {
return null;
}
}
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;
}
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
*/
@SuppressWarnings("unchecked")
public static Map getLabels(ObjectMeta metadata) {
if (metadata != null) {
Map labels = metadata.getLabels();
if (labels != null) {
return labels;
}
}
return Collections.EMPTY_MAP;
}
@SuppressWarnings("unchecked")
public static Map getLabels(HasMetadata entity) {
if (entity != null) {
return getLabels(entity.getMetadata());
}
return Collections.EMPTY_MAP;
}
public static ServiceSpec getOrCreateSpec(Service entity) {
ServiceSpec spec = entity.getSpec();
if (spec == null) {
spec = new ServiceSpec();
entity.setSpec(spec);
}
return spec;
}
public static String getPortalIP(Service entity) {
String answer = null;
if (entity != null) {
ServiceSpec spec = getOrCreateSpec(entity);
return spec.getClusterIP();
}
return answer;
}
@SuppressWarnings("unchecked")
public static Map getSelector(Service entity) {
Map answer = null;
if (entity != null) {
ServiceSpec spec = getOrCreateSpec(entity);
answer = spec.getSelector();
}
return answer != null ? answer : Collections.EMPTY_MAP;
}
public static void setSelector(Service entity, Map labels) {
ServiceSpec spec = getOrCreateSpec(entity);
spec.setSelector(labels);
}
public static Set getPorts(Service entity) {
Set answer = new HashSet<>();
if (entity != null) {
ServiceSpec spec = getOrCreateSpec(entity);
for (ServicePort port : spec.getPorts()) {
answer.add(port.getPort());
}
}
return answer;
}
protected static String getAdditionalPropertyText(Map additionalProperties, String name) {
if (additionalProperties != null) {
Object value = additionalProperties.get(name);
if (value != null) {
return value.toString();
}
}
return null;
}
protected static Map getMetadata(Map additionalProperties, boolean create) {
Map answer = getAdditionalPropertyMap(additionalProperties, "metadata");
if (answer == null) {
answer = new LinkedHashMap<>();
if (create) {
additionalProperties.put("metadata", answer);
}
}
return answer;
}
@SuppressWarnings("unchecked")
protected static Map getAdditionalPropertyMap(Map additionalProperties, String name) {
if (additionalProperties != null) {
Object value = additionalProperties.get(name);
if (value instanceof Map) {
return (Map) value;
}
}
return null;
}
public static String getDockerIp() {
String url = resolveDockerHost();
int idx = url.indexOf("://");
if (idx > 0) {
url = url.substring(idx + 3);
}
idx = url.indexOf(":");
if (idx > 0) {
url = url.substring(0, idx);
}
return url;
}
public static String resolveDockerHost() {
String dockerHost = System.getenv("DOCKER_HOST");
if (isNullOrBlank(dockerHost)) {
dockerHost = System.getProperty("docker.host");
}
if (isNullOrBlank(dockerHost)) {
return DEFAULT_DOCKER_HOST;
} else {
return dockerHost;
}
}
public static String toJson(Object dto) throws JsonProcessingException {
if (dto == null) {
return "null";
}
Class> clazz = dto.getClass();
return OBJECT_MAPPER.writerFor(clazz).writeValueAsString(dto);
}
public static String toPrettyJson(Object dto) throws JsonProcessingException {
if (dto == null) {
return "null";
}
Class> clazz = dto.getClass();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
return objectMapper.writerFor(clazz).writeValueAsString(dto);
}
/**
* Returns the given json data as a DTO such as
* {@link Pod}, {@link ReplicationController} or
* {@link io.fabric8.kubernetes.api.model.Service}
* from the Kubernetes REST API
*/
public static Object loadJson(File file) throws IOException {
byte[] data = Files.readBytes(file);
return loadJson(data);
}
/**
* Returns the given json data as a DTO such as
* {@link Pod}, {@link ReplicationController} or
* {@link io.fabric8.kubernetes.api.model.Service}
* from the Kubernetes REST API
*/
public static Object loadJson(InputStream in) throws IOException {
byte[] data = Files.readBytes(in);
return loadJson(data);
}
public static Object loadJson(String json) throws IOException {
byte[] data = json.getBytes();
return loadJson(data);
}
/**
* Returns the given json data as a DTO such as
* {@link Pod}, {@link ReplicationController} or
* {@link io.fabric8.kubernetes.api.model.Service}
* from the Kubernetes REST API
*/
public static Object loadJson(byte[] json) throws IOException {
if (json != null && json.length > 0) {
return OBJECT_MAPPER.readerFor(KubernetesResource.class).readValue(json);
}
return null;
}
/**
* Loads the YAML file for the given DTO class
*/
public static T loadYaml(InputStream in, Class clazz) throws IOException {
byte[] data = Files.readBytes(in);
return loadYaml(data, clazz);
}
/**
* Loads the YAML file for the given DTO class
*/
public static T loadYaml(File file, Class clazz) throws IOException {
byte[] data = Files.readBytes(file);
return loadYaml(data, clazz);
}
/**
* Loads the YAML file for the kubernetes resource
*/
public static T loadYaml(File file) throws IOException {
return (T) loadYaml(file, KubernetesResource.class);
}
/**
* Loads the YAML text for the given DTO class
*/
public static T loadYaml(String text, Class clazz) throws IOException {
byte[] data = text.getBytes();
return loadYaml(data, clazz);
}
/**
* Loads the YAML text for the kubernetes resource
*/
public static T loadYaml(String text) throws IOException {
return (T) loadYaml(text, KubernetesResource.class);
}
/**
* Loads the YAML file for the given DTO class
*/
public static T loadYaml(byte[] data, Class clazz) throws IOException {
ObjectMapper mapper = createYamlObjectMapper();
return mapper.readValue(data, clazz);
}
public static void saveYaml(Object data, File file) throws IOException {
ObjectMapper mapper = createYamlObjectMapper();
mapper.writeValue(file, data);
}
public static void saveYaml(Object data, FileObject fileObject) throws IOException{
ObjectMapper mapper = createYamlObjectMapper();
try (Writer writer = fileObject.openWriter()) {
mapper.writeValue(writer, data);
}
}
public static String toYaml(Object data) throws IOException {
ObjectMapper mapper = createYamlObjectMapper();
return mapper.writeValueAsString(data);
}
public static ObjectMapper createYamlObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
return objectMapper;
}
/**
* Loads the Kubernetes JSON and converts it to a list of entities
*/
@SuppressWarnings("unchecked")
public static List toItemList(Object entity) throws IOException {
if (entity instanceof List) {
return (List) entity;
} else if (entity instanceof HasMetadata[]) {
HasMetadata[] array = (HasMetadata[]) entity;
return Arrays.asList(array);
} else if (entity instanceof KubernetesList) {
KubernetesList config = (KubernetesList) entity;
return config.getItems();
} else if (entity instanceof Template) {
Template objects = (Template) entity;
return objects.getObjects();
} else {
List answer = new ArrayList<>();
if (entity instanceof HasMetadata) {
answer.add((HasMetadata) entity);
}
return answer;
}
}
/**
* Saves the json object to the given file
*/
public static void saveJson(File json, Object object) throws IOException {
OBJECT_MAPPER.writer().withDefaultPrettyPrinter().writeValue(json, object);
}
/**
* Returns a map indexed by pod id of the pods
*/
public static Map toPodMap(PodList podSchema) {
return toFilteredPodMap(podSchema, Filters.trueFilter());
}
protected static Map toFilteredPodMap(PodList podSchema, Filter filter) {
List list = podSchema != null ? podSchema.getItems() : null;
List filteredList = Filters.filter(list, filter);
return toPodMap(filteredList);
}
/**
* Returns a map indexed by pod id of the pods
*/
public static Map toPodMap(List pods) {
List list = notNullList(pods);
Map answer = new HashMap<>();
for (Pod pod : list) {
String id = getName(pod);
if (Strings.isNotBlank(id)) {
answer.put(id, pod);
}
}
return answer;
}
/**
* Returns a map indexed by service id of the services
*/
public static Map toServiceMap(ServiceList serviceSchema) {
return toServiceMap(serviceSchema != null ? serviceSchema.getItems() : null);
}
/**
* Returns a map indexed by service id of the services
*/
public static Map toServiceMap(List services) {
List list = notNullList(services);
Map answer = new HashMap<>();
for (Service service : list) {
String id = getName(service);
if (Strings.isNotBlank(id)) {
answer.put(id, service);
}
}
return answer;
}
public static Map toFilteredServiceMap(ServiceList serviceList, Filter filter) {
List list = serviceList != null ? serviceList.getItems() : null;
List filteredList = Filters.filter(list, filter);
return toServiceMap(filteredList);
}
/**
* Returns a map indexed by replicationController id of the replicationControllers
*/
public static Map toReplicationControllerMap(ReplicationControllerList replicationControllerSchema) {
Filter filter = createReplicationControllerFilter((String) null);
return toFilteredReplicationControllerMap(replicationControllerSchema, filter);
}
protected static Map toFilteredReplicationControllerMap(ReplicationControllerList replicationControllerSchema, Filter filter) {
List list = replicationControllerSchema != null ? replicationControllerSchema.getItems() : null;
List filteredList = Filters.filter(list, filter);
return toReplicationControllerMap(filteredList);
}
/**
* Returns a map indexed by replicationController id of the replicationControllers
*/
public static Map toReplicationControllerMap(List replicationControllers) {
List list = notNullList(replicationControllers);
Map answer = new HashMap<>();
for (ReplicationController replicationControllerSchema : list) {
String id = getName(replicationControllerSchema);
if (Strings.isNotBlank(id)) {
answer.put(id, replicationControllerSchema);
}
}
return answer;
}
public static Map getPodMap(KubernetesClient kubernetes) {
return getPodMap(kubernetes, null);
}
public static Map getPodMap(KubernetesClient kubernetes, String namespace) {
PodList pods = null;
try {
pods = kubernetes.pods().inNamespace(namespace).list();
} catch (KubernetesClientException e) {
if (e.getCode() == 404) {
// ignore not found
} else {
throw e;
}
}
return toPodMap(pods);
}
public static Map getSelectedPodMap(KubernetesClient kubernetes, String selector) {
return getSelectedPodMap(kubernetes, null, selector);
}
public static Map getSelectedPodMap(KubernetesClient kubernetes, String namespace, String selector) {
return getFilteredPodMap(kubernetes, namespace, createPodFilter(selector));
}
public static Map getFilteredPodMap(KubernetesClient kubernetes, Filter filter) {
return getFilteredPodMap(kubernetes, null, filter);
}
public static Map getFilteredPodMap(KubernetesClient kubernetes, String namespace, Filter filter) {
return toFilteredPodMap(kubernetes.pods().inNamespace(namespace).list(), filter);
}
public static Map getServiceMap(KubernetesClient kubernetes) {
return getServiceMap(kubernetes, null);
}
public static Map getServiceMap(KubernetesClient kubernetes, String namespace) {
return toServiceMap(kubernetes.services().inNamespace(namespace).list());
}
public static Map getReplicationControllerMap(KubernetesClient kubernetes) {
return getReplicationControllerMap(kubernetes, null);
}
public static Map getReplicationControllerMap(KubernetesClient kubernetes, String namespace) {
return toReplicationControllerMap(kubernetes.replicationControllers().inNamespace(namespace).list());
}
public static Map getSelectedReplicationControllerMap(KubernetesClient kubernetes, String selector) {
return getSelectedReplicationControllerMap(kubernetes, null, selector);
}
public static Map getSelectedReplicationControllerMap(KubernetesClient kubernetes, String namespace, String selector) {
return toReplicationControllerMap(kubernetes.replicationControllers().inNamespace(namespace).withLabels(toLabelsMap(selector)).list());
}
/**
* Removes empty pods returned by Kubernetes
*/
public static void removeEmptyPods(PodList podSchema) {
List list = notNullList(podSchema.getItems());
List removeItems = new ArrayList();
for (Pod pod : list) {
if (Strings.isNullOrBlank(getName(pod))) {
removeItems.add(pod);
}
}
list.removeAll(removeItems);
}
/**
* Returns the pod id for the given container id
*/
public static String containerNameToPodId(String containerName) {
// TODO use prefix?
return containerName;
}
/**
* Returns a string for the labels using "," to separate values
*/
public static String toLabelsString(Map labelMap) {
StringBuilder buffer = new StringBuilder();
if (labelMap != null) {
Set> entries = labelMap.entrySet();
for (Map.Entry entry : entries) {
if (buffer.length() > 0) {
buffer.append(",");
}
buffer.append(entry.getKey());
buffer.append("=");
buffer.append(entry.getValue());
}
}
return buffer.toString();
}
public static Map toLabelsMap(String labels) {
Map map = new HashMap<>();
if (labels != null && !labels.isEmpty()) {
String[] elements = labels.split(",");
if (elements.length > 0) {
for (String str : elements) {
String[] keyValue = str.split("=");
if (keyValue.length == 2) {
String key = keyValue[0];
String value = keyValue[1];
if (key != null && value != null) {
map.put(key.trim(), value.trim());
}
}
}
}
}
return map;
}
/**
* Creates a filter on a pod using the given text string
*/
public static Filter createPodFilter(final String textFilter) {
if (isNullOrBlank(textFilter)) {
return Filters.trueFilter();
} else {
return new Filter() {
public String toString() {
return "PodFilter(" + textFilter + ")";
}
public boolean matches(Pod entity) {
return filterMatchesIdOrLabels(textFilter, getName(entity), entity.getMetadata().getLabels());
}
};
}
}
/**
* Creates a filter on a pod using the given set of labels
*/
public static Filter createPodFilter(final Map labelSelector) {
if (labelSelector == null || labelSelector.isEmpty()) {
return Filters.trueFilter();
} else {
return new Filter() {
public String toString() {
return "PodFilter(" + labelSelector + ")";
}
public boolean matches(Pod entity) {
return filterLabels(labelSelector, entity.getMetadata().getLabels());
}
};
}
}
/**
* Creates a filter on a pod annotations using the given set of attribute values
*/
public static Filter createPodAnnotationFilter(final Map annotationSelector) {
if (annotationSelector == null || annotationSelector.isEmpty()) {
return Filters.trueFilter();
} else {
return new Filter() {
public String toString() {
return "PodAnnotationFilter(" + annotationSelector + ")";
}
public boolean matches(Pod entity) {
return filterLabels(annotationSelector, entity.getMetadata().getAnnotations());
}
};
}
}
/**
* Creates a filter on a service using the given text string
*/
public static Filter createServiceFilter(final String textFilter) {
if (isNullOrBlank(textFilter)) {
return Filters.trueFilter();
} else {
return new Filter() {
public String toString() {
return "ServiceFilter(" + textFilter + ")";
}
public boolean matches(Service entity) {
return filterMatchesIdOrLabels(textFilter, getName(entity), entity.getMetadata().getLabels());
}
};
}
}
/**
* Creates a filter on a service if it matches the given namespace
*/
public static Filter createNamespaceServiceFilter(final String namespace) {
if (isNullOrBlank(namespace)) {
return Filters.trueFilter();
} else {
return new Filter() {
public String toString() {
return "NamespaceServiceFilter(" + namespace + ")";
}
public boolean matches(Service entity) {
return Objects.equal(namespace, getNamespace(entity.getMetadata()));
}
};
}
}
/**
* Creates a filter on a service using the given text string
*/
public static Filter createServiceFilter(final Map labelSelector) {
if (labelSelector == null || labelSelector.isEmpty()) {
return Filters.trueFilter();
} else {
return new Filter() {
public String toString() {
return "ServiceFilter(" + labelSelector + ")";
}
public boolean matches(Service entity) {
return filterLabels(labelSelector, entity.getMetadata().getLabels());
}
};
}
}
/**
* Creates a filter on a replicationController using the given text string
*/
public static Filter createReplicationControllerFilter(final String textFilter) {
if (isNullOrBlank(textFilter)) {
return Filters.trueFilter();
} else {
return new Filter() {
public String toString() {
return "ReplicationControllerFilter(" + textFilter + ")";
}
public boolean matches(ReplicationController entity) {
return filterMatchesIdOrLabels(textFilter, getName(entity), entity.getMetadata().getLabels());
}
};
}
}
/**
* Creates a filter on a replicationController using the given text string
*/
public static Filter createReplicationControllerFilter(final Map labelSelector) {
if (labelSelector == null || labelSelector.isEmpty()) {
return Filters.trueFilter();
} else {
return new Filter() {
public String toString() {
return "ReplicationControllerFilter(" + labelSelector + ")";
}
public boolean matches(ReplicationController entity) {
return filterLabels(labelSelector, entity.getMetadata().getLabels());
}
};
}
}
/**
* Returns true if the given textFilter matches either the id or the labels
*/
public static boolean filterMatchesIdOrLabels(String textFilter, String id, Map labels) {
String text = toLabelsString(labels);
boolean result = (text != null && text.contains(textFilter)) || (id != null && id.contains(textFilter));
if (!result) {
//labels can be in different order to selector
Map selectorMap = toLabelsMap(textFilter);
if (!selectorMap.isEmpty() && labels != null && !labels.isEmpty()) {
result = true;
for (Map.Entry entry : selectorMap.entrySet()) {
String value = labels.get(entry.getKey());
if (value == null || !value.matches(entry.getValue())) {
result = false;
break;
}
}
}
}
return result;
}
/**
* Returns true if the given filterLabels matches the actual labels
*/
public static boolean filterLabels(Map filterLabels, Map labels) {
if (labels == null) {
return false;
}
Set> entries = filterLabels.entrySet();
for (Map.Entry entry : entries) {
String key = entry.getKey();
String expectedValue = entry.getValue();
String actualValue = labels.get(key);
if (!Objects.equal(expectedValue, actualValue)) {
return false;
}
}
return true;
}
/**
* For positive non-zero values return the text of the number or return blank
*/
public static String toPositiveNonZeroText(Integer port) {
if (port != null) {
int value = port;
if (value > 0) {
return "" + value;
}
}
return "";
}
/**
* Returns all the containers from the given pod
*/
@SuppressWarnings("unchecked")
public static List getContainers(Pod pod) {
if (pod != null) {
PodSpec podSpec = pod.getSpec();
return getContainers(podSpec);
}
return Collections.EMPTY_LIST;
}
/**
* Returns all the containers from the given Replication Controller
*/
@SuppressWarnings("unchecked")
public static List getContainers(ReplicationController replicationController) {
if (replicationController != null) {
ReplicationControllerSpec replicationControllerSpec = replicationController.getSpec();
return getContainers(replicationControllerSpec);
}
return Collections.EMPTY_LIST;
}
/**
* Returns all the containers from the given Replication Controller's replicationControllerSpec
*/
@SuppressWarnings("unchecked")
public static List getContainers(ReplicationControllerSpec replicationControllerSpec) {
if (replicationControllerSpec != null) {
PodTemplateSpec podTemplateSpec = replicationControllerSpec.getTemplate();
return getContainers(podTemplateSpec);
}
return Collections.EMPTY_LIST;
}
@SuppressWarnings("unchecked")
public static List getContainers(PodSpec podSpec) {
if (podSpec != null) {
return podSpec.getContainers();
}
return Collections.EMPTY_LIST;
}
@SuppressWarnings("unchecked")
public static List getContainers(PodTemplateSpec podTemplateSpec) {
if (podTemplateSpec != null) {
return getContainers(podTemplateSpec.getSpec());
}
return Collections.EMPTY_LIST;
}
/**
* Returns all the containers from the given Replication Controller
*/
@SuppressWarnings("unchecked")
public static List getCurrentContainers(ReplicationController replicationController) {
if (replicationController != null) {
// TODO
}
return Collections.EMPTY_LIST;
}
/**
* Returns all the current containers from the given currentState
*/
@SuppressWarnings("unchecked")
public static Map getCurrentContainers(Pod pod) {
if (pod != null) {
PodStatus currentStatus = pod.getStatus();
return getCurrentContainers(currentStatus);
}
return Collections.EMPTY_MAP;
}
/**
* Returns all the current containers from the given podStatus
*/
@SuppressWarnings("unchecked")
public static Map getCurrentContainers(PodStatus podStatus) {
if (podStatus != null) {
List containerStatuses = podStatus.getContainerStatuses();
Map info = new Hashtable<>(containerStatuses.size());
for (ContainerStatus status : containerStatuses) {
info.put(status.getContainerID(), status);
}
return info;
}
return Collections.EMPTY_MAP;
}
/**
* Returns the host of the pod
*/
public static String getHost(Pod pod) {
if (pod != null) {
PodStatus currentState = pod.getStatus();
if (currentState != null) {
return currentState.getHostIP();
}
}
return null;
}
/**
* Returns the container port number for the given service
*/
@SuppressWarnings("unchecked")
public static Set getContainerPorts(Service service) {
Set answer = Collections.EMPTY_SET;
String id = getName(service);
ServiceSpec spec = service.getSpec();
if (spec != null) {
List servicePorts = spec.getPorts();
Objects.notNull(servicePorts, "servicePorts for service " + id);
answer = new HashSet<>(servicePorts.size());
String message = "service " + id;
for (ServicePort port : servicePorts) {
IntOrString intOrStringValue = port.getTargetPort();
Integer intValue = intOrStringToInteger(intOrStringValue, message);
if (intValue != null) {
answer.add(intValue);
}
}
}
return answer;
}
/**
* Returns the IntOrString converted to an Integer value or throws an exception with the given message
*/
public static Integer intOrStringToInteger(IntOrString intOrStringValue, String message) {
Integer intValue = intOrStringValue.getIntVal();
if (intValue == null) {
String containerPortText = intOrStringValue.getStrVal();
if (Strings.isNullOrBlank(containerPortText)) {
throw new IllegalArgumentException("No port for " +
message);
}
try {
intValue = Integer.parseInt(containerPortText);
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid servicePorts expression " + containerPortText + " for " +
message + ". " + e, e);
}
}
return intValue;
}
/**
* Returns the container port number for the given service
*/
@SuppressWarnings("unchecked")
public static Set getContainerPortsStrings(Service service) {
Set answer = Collections.EMPTY_SET;
String id = getName(service);
ServiceSpec spec = service.getSpec();
if (spec != null) {
List servicePorts = spec.getPorts();
Objects.notNull(servicePorts, "servicePorts for service " + id);
answer = new HashSet<>(servicePorts.size());
for (ServicePort port : servicePorts) {
IntOrString intOrStringValue = port.getTargetPort();
Integer intValue = intOrStringValue.getIntVal();
if (intValue != null) {
answer.add(intValue.toString());
} else {
String containerPortText = intOrStringValue.getStrVal();
if (Strings.isNullOrBlank(containerPortText)) {
throw new IllegalArgumentException("No servicePorts for service " + id);
}
answer.add(containerPortText);
}
}
}
return answer;
}
/**
* Combines the JSON objects into a config object
*/
public static Object combineJson(Object... objects) throws IOException {
KubernetesList list = findOrCreateList(objects);
List items = list.getItems();
if (items == null) {
items = new ArrayList<>();
list.setItems(items);
}
for (Object object : objects) {
if (object != list) {
addObjectsToItemArray(items, object);
}
}
KubernetesList fullList = new KubernetesList();
fullList.setItems(items);
moveServicesToFrontOfArray(items);
removeDuplicates(items);
Object answer = Templates.combineTemplates(fullList);
items = toItemList(answer);
removeDuplicates(items);
return answer;
}
/**
* Lets move all Service resources before any other to avoid ordering issues creating things
*/
public static void moveServicesToFrontOfArray(List list) {
int size = list.size();
int lastNonService = -1;
for (int i = 0; i < size; i++) {
HasMetadata item = list.get(i);
if (item instanceof Service) {
if (lastNonService >= 0) {
HasMetadata nonService = list.get(lastNonService);
list.set(i, nonService);
list.set(lastNonService, item);
lastNonService++;
}
} else if (lastNonService < 0) {
lastNonService = i;
}
}
}
/**
* Remove any duplicate resources using the kind and id
*/
protected static void removeDuplicates(List itemArray) {
int size = itemArray.size();
int lastNonService = -1;
Set keys = new HashSet<>();
for (int i = 0; i < size; i++) {
HasMetadata item = itemArray.get(i);
if (item == null) {
itemArray.remove(i);
i--;
size--;
} else {
String id = getObjectId(item);
String kind = item.getClass().getSimpleName();
if (Strings.isNotBlank(id)) {
String key = kind + ":" + id;
if (!keys.add(key)) {
// lets remove this one
itemArray.remove(i);
i--;
size--;
}
}
}
}
}
@SuppressWarnings("unchecked")
protected static void addObjectsToItemArray(List destinationList, Object object) throws IOException {
if (object instanceof KubernetesList) {
KubernetesList kubernetesList = (KubernetesList) object;
List items = kubernetesList.getItems();
if (items != null) {
destinationList.addAll(items);
}
} else if (object instanceof Collection) {
Collection collection = (Collection) object;
destinationList.addAll(collection);
} else {
destinationList.add(object);
}
}
protected static KubernetesList findOrCreateList(Object[] objects) {
KubernetesList list = null;
for (Object object : objects) {
if (object instanceof KubernetesList) {
list = (KubernetesList) object;
break;
}
}
if (list == null) {
list = new KubernetesList();
}
return list;
}
/**
* Returns the URL to access the service; using the service clusterIP and port
*/
public static String getServiceURL(Service service) {
if (service != null) {
String answer = getOrCreateAnnotations(service).get(Annotations.Service.EXPOSE_URL);
if (Strings.isNotBlank(answer)) {
return answer;
}
ServiceSpec spec = service.getSpec();
if (spec != null) {
String portalIP = spec.getClusterIP();
if (portalIP != null) {
Integer port = spec.getPorts().iterator().next().getPort();
if (port != null && port > 0) {
portalIP += ":" + port;
}
String protocol = "http://";
if (KubernetesHelper.isServiceSsl(spec.getClusterIP(), port, Utils.getSystemPropertyOrEnvVar(io.fabric8.kubernetes.client.Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, false))) {
protocol = "https://";
}
return protocol + portalIP;
}
}
}
return null;
}
/**
* Returns the URL to access the service; using the environment variables, routes
* or service clusterIP address
*
* @throws IllegalArgumentException if the URL cannot be found for the serviceName and namespace
*/
public static String getServiceURL(KubernetesClient client, String serviceName, String serviceNamespace, String serviceProtocol, boolean serviceExternal) {
return getServiceURL(client, serviceName, serviceNamespace, serviceProtocol, null, serviceExternal);
}
/**
* Returns the URL to access the service; using the environment variables, routes
* or service clusterIP address
*
* @throws IllegalArgumentException if the URL cannot be found for the serviceName and namespace
*/
public static String getServiceURL(KubernetesClient client, String serviceName, String serviceNamespace, String serviceProtocol, String servicePortName, boolean serviceExternal) {
Service srv = null;
String serviceHost = KubernetesServices.serviceToHostOrBlank(serviceName);
String servicePort = KubernetesServices.serviceToPortOrBlank(serviceName, servicePortName);
String serviceProto = serviceProtocol != null ? serviceProtocol : KubernetesServices.serviceToProtocol(serviceName, servicePort);
//Use specified or fallback namespace.
String actualNamespace = Strings.isNotBlank(serviceNamespace) ? serviceNamespace : client.getNamespace();
//1. Inside Kubernetes: Services as ENV vars
if (!serviceExternal && Strings.isNotBlank(serviceHost) && Strings.isNotBlank(servicePort) && Strings.isNotBlank(serviceProtocol)) {
return serviceProtocol + "://" + serviceHost + ":" + servicePort;
//2. Anywhere: When namespace is passed System / Env var. Mostly needed for integration tests.
} else if (Strings.isNotBlank(actualNamespace)) {
try {
srv = client.services().inNamespace(actualNamespace).withName(serviceName).get();
} catch (Exception e) {
LOGGER.warn("Could not lookup service:"+serviceName+" in namespace:"+actualNamespace+", due to: " + e.getMessage());
}
}
if (srv == null) {
// lets try use environment variables
String hostAndPort = Systems.getServiceHostAndPort(serviceName, "", "");
if (!hostAndPort.startsWith(":")) {
return serviceProto + "://" + hostAndPort;
}
}
if (srv == null) {
throw new IllegalArgumentException("No kubernetes service could be found for name: " + serviceName + " in namespace: " + actualNamespace);
}
String answer = getOrCreateAnnotations(srv).get(Annotations.Service.EXPOSE_URL);
if (Strings.isNotBlank(answer)) {
return answer;
}
try {
if (Strings.isNullOrBlank(servicePortName) && isOpenShift(client)) {
OpenShiftClient openShiftClient = client.adapt(OpenShiftClient.class);
Route route = openShiftClient.routes().inNamespace(actualNamespace).withName(serviceName).get();
if (route != null) {
return (serviceProto + "://" + route.getSpec().getHost()).toLowerCase();
}
}
} catch (KubernetesClientException e) {
if (e.getCode() == 403) {
LOGGER.warn("Could not lookup route:"+serviceName+" in namespace:"+actualNamespace+", due to: " + e.getMessage());
} else {
throw e;
}
}
ServicePort port = findServicePortByName(srv, servicePortName);
if (port == null) {
throw new RuntimeException("Couldn't find port: " + servicePortName + " for service:" + serviceName);
}
String clusterIP = srv.getSpec().getClusterIP();
if ("None".equals(clusterIP)) {
throw new IllegalStateException("Service: " + serviceName + " in namespace:" + serviceNamespace + "is head-less. Search for endpoints instead.");
}
Integer portNumber = port.getPort();
if (Strings.isNullOrBlank(clusterIP)) {
IngressList ingresses = client.extensions().ingresses().inNamespace(serviceNamespace).list();
if (ingresses != null) {
List items = ingresses.getItems();
if (items != null) {
for (Ingress item : items) {
String ns = getNamespace(item);
if (Objects.equal(serviceNamespace, ns)) {
IngressSpec spec = item.getSpec();
if (spec != null) {
List rules = spec.getRules();
List tls = spec.getTls();
if (rules != null) {
for (IngressRule rule : rules) {
HTTPIngressRuleValue http = rule.getHttp();
if (http != null) {
List paths = http.getPaths();
if (paths != null) {
for (HTTPIngressPath path : paths) {
IngressBackend backend = path.getBackend();
if (backend != null) {
String backendServiceName = backend.getServiceName();
if (serviceName.equals(backendServiceName) && portsMatch(port, backend.getServicePort())) {
String pathPostfix = path.getPath();
if (tls != null) {
for (IngressTLS tlsHost : tls) {
List hosts = tlsHost.getHosts();
if (hosts != null) {
for (String host : hosts) {
if (Strings.isNotBlank(host)) {
if (Strings.isNullOrBlank(pathPostfix)) {
pathPostfix = "/";
}
return "https://" + URLUtils.pathJoin(host, pathPostfix);
}
}
}
}
}
answer = rule.getHost();
if (Strings.isNotBlank(answer)) {
if (Strings.isNullOrBlank(pathPostfix)) {
pathPostfix = "/";
}
return "http://" + URLUtils.pathJoin(answer, pathPostfix);
}
}
}
}
}
}
}
}
}
}
}
}
}
// lets try use the status on GKE
ServiceStatus status = srv.getStatus();
if (status != null) {
LoadBalancerStatus loadBalancerStatus = status.getLoadBalancer();
if (loadBalancerStatus != null) {
List loadBalancerIngresses = loadBalancerStatus.getIngress();
if (loadBalancerIngresses != null) {
for (LoadBalancerIngress loadBalancerIngress : loadBalancerIngresses) {
String ip = loadBalancerIngress.getIp();
if (Strings.isNotBlank(ip)) {
clusterIP = ip;
break;
}
}
}
}
}
}
if (Strings.isNullOrBlank(clusterIP)) {
// on vanilla kubernetes we can use nodePort to access things externally
boolean found = false;
Integer nodePort = port.getNodePort();
if (nodePort != null) {
try {
NodeList nodeList = client.nodes().list();
if (nodeList != null) {
List items = nodeList.getItems();
if (items != null) {
for (Node item : items) {
NodeStatus status = item.getStatus();
if (!found && status != null) {
List addresses = status.getAddresses();
if (addresses != null) {
for (NodeAddress address : addresses) {
String ip = address.getAddress();
if (Strings.isNotBlank(ip)) {
clusterIP = ip;
portNumber = nodePort;
found = true;
break;
}
}
}
}
if (!found) {
NodeSpec spec = item.getSpec();
if (spec != null) {
clusterIP = spec.getExternalID();
if (Strings.isNotBlank(clusterIP)) {
portNumber = nodePort;
break;
}
}
}
}
}
}
} catch (Exception e) {
// ignore could not find a node!
LOG.warn("Could not find a node!: " + e, e);
}
}
}
return (serviceProto + "://" + clusterIP + ":" + portNumber).toLowerCase();
}
/**
* Returns true if the given servicePort matches the intOrString value
*/
private static boolean portsMatch(ServicePort servicePort, IntOrString intOrString) {
if (intOrString != null) {
Integer port = servicePort.getPort();
Integer intVal = intOrString.getIntVal();
String strVal = intOrString.getStrVal();
if (intVal != null) {
if (port != null) {
return port.intValue() == intVal.intValue();
} else {
/// should we find the port by name now?
}
} else if (strVal != null ){
return Objects.equal(strVal, servicePort.getName());
}
}
return false;
}
/**
* Returns the URL to access the service; using the environment variables, routes
* or service clusterIP address
*
* @throws IllegalArgumentException if the URL cannot be found for the serviceName and namespace
*/
public static String getServiceURLInCurrentNamespace(KubernetesClient client, String serviceName, String serviceProtocol, String servicePortName, boolean serviceExternal) {
Service srv = null;
String serviceHost = KubernetesServices.serviceToHostOrBlank(serviceName);
String servicePort = KubernetesServices.serviceToPortOrBlank(serviceName, servicePortName);
String serviceProto = serviceProtocol != null ? serviceProtocol : KubernetesServices.serviceToProtocol(serviceName, servicePort);
//1. Inside Kubernetes: Services as ENV vars
if (!serviceExternal && Strings.isNotBlank(serviceHost) && Strings.isNotBlank(servicePort) && Strings.isNotBlank(serviceProtocol)) {
return serviceProtocol + "://" + serviceHost + ":" + servicePort;
//2. Anywhere: When namespace is passed System / Env var. Mostly needed for integration tests.
} else {
srv = client.services().withName(serviceName).get();
}
if (srv == null) {
throw new IllegalArgumentException("No kubernetes service could be found for name: " + serviceName);
}
if (Strings.isNullOrBlank(servicePortName) && isOpenShift(client)) {
OpenShiftClient openShiftClient = client.adapt(OpenShiftClient.class);
RouteList routeList = openShiftClient.routes().list();
for (Route route : routeList.getItems()) {
if (route.getSpec().getTo().getName().equals(serviceName)) {
return (serviceProto + "://" + route.getSpec().getHost()).toLowerCase();
}
}
}
ServicePort port = findServicePortByName(srv, servicePortName);
if (port == null) {
throw new RuntimeException("Couldn't find port: " + servicePortName + " for service:" + serviceName);
}
String clusterIP = srv.getSpec().getClusterIP();
if ("None".equals(clusterIP)) {
throw new IllegalStateException("Service: " + serviceName + " in current namespace is head-less. Search for endpoints instead.");
}
return (serviceProto + "://" + clusterIP + ":" + port.getPort()).toLowerCase();
}
/**
* Returns the port for the given port number on the pod
*/
public static ContainerPort findContainerPort(Pod pod, Integer portNumber) {
List containers = KubernetesHelper.getContainers(pod);
for (Container container : containers) {
List ports = container.getPorts();
for (ContainerPort port : ports) {
if (Objects.equal(portNumber, port.getContainerPort())) {
return port;
}
}
}
return null;
}
public static ServicePort findServicePortByName(Service service, String portName) {
if (Strings.isNullOrBlank(portName)) {
return service.getSpec().getPorts().iterator().next();
}
for (ServicePort servicePort : service.getSpec().getPorts()) {
if (Objects.equal(servicePort.getName(), portName)) {
return servicePort;
}
}
return null;
}
/**
* Returns the port for the given port name
*/
public static ContainerPort findContainerPortByName(Pod pod, String name) {
List containers = KubernetesHelper.getContainers(pod);
for (Container container : containers) {
List ports = container.getPorts();
for (ContainerPort port : ports) {
if (Objects.equal(name, port.getName())) {
return port;
}
}
}
return null;
}
/**
* Returns the port for the given port number or name
*/
public static ContainerPort findContainerPortByNumberOrName(Pod pod, String numberOrName) {
Integer portNumber = toOptionalNumber(numberOrName);
if (portNumber != null) {
return findContainerPort(pod, portNumber);
} else {
return findContainerPortByName(pod, numberOrName);
}
}
/**
* Returns the number if it can be parsed or null
*/
protected static Integer toOptionalNumber(String text) {
if (Strings.isNotBlank(text)) {
try {
return Integer.parseInt(text);
} catch (NumberFormatException e) {
// ignore parse errors
}
}
return null;
}
public static PodStatusType getPodStatus(Pod pod) {
String text = getPodStatusText(pod);
if (Strings.isNotBlank(text)) {
text = text.toLowerCase();
if (text.startsWith("run")) {
return PodStatusType.OK;
} else if (text.startsWith("wait")) {
return PodStatusType.WAIT;
} else {
return PodStatusType.ERROR;
}
}
return PodStatusType.WAIT;
}
/**
* Returns true if the pod is running
*/
public static boolean isPodRunning(Pod pod) {
PodStatusType status = getPodStatus(pod);
return Objects.equal(status, PodStatusType.OK);
}
/**
* Returns true if the pod is running and ready
*/
public static boolean isPodReady(Pod pod) {
if (!isPodRunning(pod)) {
return false;
}
PodStatus podStatus = pod.getStatus();
if (podStatus == null) {
return true;
}
List conditions = podStatus.getConditions();
if (conditions == null || conditions.isEmpty()) {
return true;
}
// Check "ready" condition
for (PodCondition condition : conditions) {
if ("ready".equalsIgnoreCase(condition.getType())) {
return Boolean.parseBoolean(condition.getStatus());
}
}
return true;
}
public static String getPodStatusText(Pod pod) {
if (pod != null) {
PodStatus podStatus = pod.getStatus();
if (podStatus != null) {
return podStatus.getPhase();
}
}
return null;
}
/**
* Returns the environment variable value for the first container which has a value for it in th epod
*/
public static String getPodEnvVar(Pod pod, String envVarName) {
if (pod != null) {
PodSpec spec = pod.getSpec();
if (spec != null) {
List containers = spec.getContainers();
if (containers != null) {
for (Container container : containers) {
String answer = getContainerEnvVar(container, envVarName);
if (Strings.isNotBlank(answer)) {
return answer;
}
}
}
}
}
return null;
}
/**
* Returns the environment variable value for the given container and name
*/
public static String getContainerEnvVar(Container container, String envVarName) {
if (container != null) {
List env = container.getEnv();
if (env != null) {
for (EnvVar envVar : env) {
if (Objects.equal(envVarName, envVar.getName())) {
return envVar.getValue();
}
}
}
}
return null;
}
/**
* Returns the pods for the given replication controller
*/
@SuppressWarnings("unchecked")
public static List getPodsForReplicationController(ReplicationController replicationController, Iterable pods) {
ReplicationControllerSpec replicationControllerSpec = replicationController.getSpec();
if (replicationControllerSpec == null) {
LOG.warn("Cannot instantiate replication controller: " + getName(replicationController) + " due to missing ReplicationController.Spec!");
} else {
Map replicaSelector = replicationControllerSpec.getSelector();
Filter podFilter = KubernetesHelper.createPodFilter(replicaSelector);
return Filters.filter(pods, podFilter);
}
return Collections.EMPTY_LIST;
}
/**
* Returns the pods for the given service
*/
public static List getPodsForService(Service service, Iterable pods) {
Map selector = getSelector(service);
Filter podFilter = KubernetesHelper.createPodFilter(selector);
return Filters.filter(pods, podFilter);
}
/**
* Looks up the service endpoints in DNS.
*
* Endpoints are registered as SRV records in DNS so this method returns
* endpoints in the format "host:port". This is a list as SRV records are ordered
* by priority & weight before being returned to the client.
*
* See https://github.com/GoogleCloudPlatform/kubernetes/blob/master/cluster/addons/dns/README.md
*/
public static List lookupServiceEndpointsInDns(String serviceName) throws IllegalArgumentException, UnknownHostException {
try {
Lookup l = new Lookup(serviceName, Type.SRV);
Record[] records = l.run();
if (l.getResult() == Lookup.SUCCESSFUL) {
SRVRecord[] srvRecords = Arrays.copyOf(records, records.length, SRVRecord[].class);
Arrays.sort(srvRecords, new Comparator() {
@Override
public int compare(SRVRecord a, SRVRecord b) {
int ret = Integer.compare(b.getPriority(), a.getPriority());
if (ret == 0) {
ret = Integer.compare(b.getWeight(), a.getWeight());
}
return ret;
}
});
List endpointAddresses = new ArrayList<>(srvRecords.length);
for (SRVRecord srvRecord : srvRecords) {
endpointAddresses.add(srvRecord.getTarget().toString(true).concat(":").concat(String.valueOf(srvRecord.getPort())));
}
return endpointAddresses;
} else {
LOG.warn("Lookup {} result: {}", serviceName, l.getErrorString());
}
} catch (TextParseException e) {
LOG.error("Unparseable service name: {}", serviceName, e);
} catch (ClassCastException e) {
LOG.error("Invalid response from DNS server - should have been A records", e);
}
return Collections.EMPTY_LIST;
}
/**
* Looks up the service in DNS.
* If this is a headless service, this call returns the endpoint IPs from DNS.
* If this is a non-headless service, this call returns the service IP only.
*
* See https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/services.md#headless-services
*/
public static Set lookupServiceInDns(String serviceName) throws IllegalArgumentException, UnknownHostException {
try {
Lookup l = new Lookup(serviceName);
Record[] records = l.run();
if (l.getResult() == Lookup.SUCCESSFUL) {
Set endpointAddresses = new HashSet<>(records.length);
for (int i = 0; i < records.length; i++) {
ARecord aRecord = (ARecord) records[i];
endpointAddresses.add(aRecord.getAddress().getHostAddress());
}
return endpointAddresses;
} else {
LOG.warn("Lookup {} result: {}", serviceName, l.getErrorString());
}
} catch (TextParseException e) {
LOG.error("Unparseable service name: {}", serviceName, e);
} catch (ClassCastException e) {
LOG.error("Invalid response from DNS server - should have been A records", e);
}
return Collections.EMPTY_SET;
}
public static boolean isServiceSsl(String host, int port, boolean trustAllCerts) {
try {
LOG.info("Checking if a service is SSL on " + host + ":" + port);
SSLSocketFactory sslsocketfactory;
if (trustAllCerts) {
sslsocketfactory = TrustEverythingSSLTrustManager.getTrustingSSLSocketFactory();
} else {
sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
}
Socket socket = sslsocketfactory.createSocket();
// Connect, with an explicit timeout value
socket.connect(new InetSocketAddress(host, port), 1 * 1000);
try {
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// Write a test byte to get a reaction :)
out.write(1);
while (in.available() > 0) {
System.out.print(in.read());
}
return true;
} finally {
LOG.info("Checked if a service is SSL on " + host + ":" + port);
socket.close();
}
} catch (SSLHandshakeException e) {
LOG.error("SSL handshake failed - this probably means that you need to trust the kubernetes root SSL certificate or set the environment variable " + Utils.convertSystemPropertyNameToEnvVar(io.fabric8.kubernetes.client.Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY), e);
} catch (SSLProtocolException e) {
LOG.error("SSL protocol error", e);
} catch (SSLKeyException e) {
LOG.error("Bad SSL key", e);
} catch (SSLPeerUnverifiedException e) {
LOG.error("Could not verify server", e);
} catch (SSLException e) {
LOG.debug("Address does not appear to be SSL-enabled - falling back to http", e);
} catch (IOException e) {
LOG.debug("Failed to validate service", e);
}
return false;
}
/**
* Validates that the given value is valid according to the kubernetes ID parsing rules, throwing an exception if not.
*/
public static String validateKubernetesId(String currentValue, String description) throws IllegalArgumentException {
if (isNullOrBlank(currentValue)) {
throw new IllegalArgumentException("No " + description + " is specified!");
}
int size = currentValue.length();
for (int i = 0; i < size; i++) {
char ch = currentValue.charAt(i);
if (Character.isUpperCase(ch)) {
throw new IllegalArgumentException("Invalid upper case letter '" + ch + "' at index " + i + " for " + description + " value: " + currentValue);
}
}
return currentValue;
}
public static Date parseDate(String text) {
try {
return new SimpleDateFormat(DATE_TIME_FORMAT).parse(text);
} catch (ParseException e) {
LOG.warn("Failed to parse date: " + text + ". Reason: " + e);
return null;
}
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(Object object) {
if (object instanceof Route) {
return summaryText((Route) object);
} else if (object instanceof Service) {
return summaryText((Service) object);
} else if (object instanceof ReplicationController) {
return summaryText((ReplicationController) object);
} else if (object instanceof Pod) {
return summaryText((Pod) object);
} else if (object instanceof Template) {
return summaryText((Template) object);
} else if (object instanceof DeploymentConfig) {
return summaryText((DeploymentConfig) object);
} else if (object instanceof OAuthClient) {
return summaryText((OAuthClient) object);
} else if (object instanceof String) {
return object.toString();
}
return "";
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(Route entity) {
RouteSpec spec = entity.getSpec();
if (spec == null) {
return "No spec!";
}
return "host: " + spec.getHost();
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(ContainerState entity) {
ContainerStateRunning running = entity.getRunning();
if (running != null) {
return "Running";
}
ContainerStateWaiting waiting = entity.getWaiting();
if (waiting != null) {
return "Waiting";
}
ContainerStateTerminated termination = entity.getTerminated();
if (termination != null) {
return "Terminated";
}
return "Unknown";
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(Template entity) {
StringBuilder buffer = new StringBuilder();
List parameters = entity.getParameters();
if (parameters != null) {
for (Parameter parameter : parameters) {
String name = parameter.getName();
appendText(buffer, name);
}
}
return "parameters: " + buffer;
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(OAuthClient entity) {
return "redirectURIs: " + entity.getRedirectURIs();
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(Service entity) {
StringBuilder portText = new StringBuilder();
ServiceSpec spec = entity.getSpec();
if (spec == null) {
return "No spec";
} else {
List ports = spec.getPorts();
if (ports != null) {
for (ServicePort port : ports) {
Integer number = port.getPort();
if (number != null) {
if (portText.length() > 0) {
portText.append(", ");
}
portText.append("").append(number);
}
}
}
return "selector: " + spec.getSelector() + " ports: " + portText;
}
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(ReplicationController entity) {
StringBuilder buffer = new StringBuilder();
ReplicationControllerSpec spec = entity.getSpec();
if (spec != null) {
buffer.append("replicas: ").append(spec.getReplicas());
PodTemplateSpec podTemplateSpec = spec.getTemplate();
if (podTemplateSpec != null) {
appendSummaryText(buffer, podTemplateSpec);
}
}
return buffer.toString();
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(DeploymentConfig entity) {
StringBuilder buffer = new StringBuilder();
DeploymentConfigSpec spec = entity.getSpec();
if (spec != null) {
buffer.append("replicas: " + spec.getReplicas());
PodTemplateSpec podTemplateSpec = spec.getTemplate();
if (podTemplateSpec != null) {
appendSummaryText(buffer, podTemplateSpec);
}
}
return buffer.toString();
}
/**
* Returns a short summary text message for the given kubernetes resource
*/
public static String summaryText(Pod entity) {
StringBuilder buffer = new StringBuilder();
PodSpec podSpec = entity.getSpec();
appendSummaryText(buffer, podSpec);
return buffer.toString();
}
protected static void appendSummaryText(StringBuilder buffer, PodTemplateSpec podTemplateSpec) {
if (podTemplateSpec != null) {
appendSummaryText(buffer, podTemplateSpec.getSpec());
}
}
protected static void appendSummaryText(StringBuilder buffer, PodSpec podSpec) {
if (podSpec != null) {
List containers = podSpec.getContainers();
if (containers != null) {
for (Container container : containers) {
String image = container.getImage();
appendText(buffer, "image: " + image);
}
}
}
}
protected static void appendText(StringBuilder buffer, String text) {
if (buffer.length() > 0) {
buffer.append(", ");
}
buffer.append(text);
}
/**
* Creates an IntOrString from the given string which could be a number or a name
*/
public static IntOrString createIntOrString(int intVal) {
IntOrString answer = new IntOrString();
answer.setIntVal(intVal);
answer.setKind(INTORSTRING_KIND_INT);
return answer;
}
/**
* Creates an IntOrString from the given string which could be a number or a name
*/
public static IntOrString createIntOrString(String nameOrNumber) {
if (isNullOrBlank(nameOrNumber)) {
return null;
} else {
IntOrString answer = new IntOrString();
Integer intVal = null;
try {
intVal = Integer.parseInt(nameOrNumber);
} catch (Exception e) {
// ignore invalid number
}
if (intVal != null) {
answer.setIntVal(intVal);
answer.setKind(INTORSTRING_KIND_INT);
} else {
answer.setStrVal(nameOrNumber);
answer.setKind(INTORSTRING_KIND_STRING);
}
return answer;
}
}
public static String getStatusText(PodStatus podStatus) {
String status;
List statusList = new ArrayList<>();
List containerStatuses = podStatus.getContainerStatuses();
for (ContainerStatus containerStatus : containerStatuses) {
ContainerState state = containerStatus.getState();
String statusText = summaryText(state);
if (statusText != null) {
statusList.add(statusText);
}
}
if (statusList.size() == 1) {
status = statusList.get(0);
} else {
status = statusList.toString();
}
return status;
}
public static Secret validateSecretExists(KubernetesClient kubernetes, String namespace, String secretName) {
Secret secret = null;
try {
secret = kubernetes.secrets().inNamespace(namespace).withName(secretName).get();
} catch (KubernetesClientException e) {
if (e.getCode() == 404 || e.getCode() == 403) {
// does not exist or namespace does not exists
} else {
throw e;
}
}
if (secret == null) {
throw new IllegalArgumentException("No secret named: " + secretName +
" for namespace " + namespace + " is available on Kubernetes" +
". For how to create secrets see: http://fabric8.io/guide/fabric8OnOpenShift.html#requirements ");
} else {
return secret;
}
}
/**
* Converts the DTO loaded from JSON to a {@link KubernetesList} assuming its not a {@link Template}
*/
public static KubernetesList asKubernetesList(Object dto) throws IOException {
if (dto instanceof KubernetesList) {
return (KubernetesList) dto;
} else {
KubernetesList answer = new KubernetesList();
List items = toItemList(dto);
answer.setItems(items);
return answer;
}
}
/**
* Returns true if this object is a pure kubernetes DTO
*/
public static boolean isPureKubernetes(HasMetadata item) {
if (item != null) {
String name = item.getClass().getName();
return name.startsWith("io.fabric8.kubernetes");
}
return false;
}
public static boolean isOpenShift(KubernetesClient client) {
URL masterUrl = client.getMasterUrl();
if (IS_OPENSHIFT.containsKey(masterUrl)) {
return IS_OPENSHIFT.get(masterUrl);
} else {
RootPaths rootPaths = client.rootPaths();
if (rootPaths != null) {
List paths = rootPaths.getPaths();
if (paths != null) {
for (String path : paths) {
if (java.util.Objects.equals("/oapi", path) || java.util.Objects.equals("oapi", path)) {
IS_OPENSHIFT.putIfAbsent(masterUrl, true);
return true;
}
}
}
}
}
IS_OPENSHIFT.putIfAbsent(masterUrl, false);
return false;
}
/**
* Returns the kubernetes resources on the classpath of the current project
*/
public static List findKubernetesResourcesOnClasspath(Controller controller) throws IOException {
String resourceName = "kubernetes.yml";
if (controller.getOpenShiftClientOrNull() != null) {
resourceName = "openshift.yml";
}
URL configUrl = findConfigResource("/META-INF/fabric8/" + resourceName);
if (configUrl == null) {
configUrl = findConfigResource("kubernetes.json");
}
if (configUrl != null) {
String configText = IOHelpers.loadFully(configUrl);
Object dto = null;
String configPath = configUrl.getPath();
if (configPath.endsWith(".yml") || configPath.endsWith(".yaml")) {
dto = loadYaml(configText, KubernetesResource.class);
} else {
dto = loadJson(configText);
}
KubernetesList kubeList = KubernetesHelper.asKubernetesList(dto);
List items = kubeList.getItems();
return items;
} else {
return new ArrayList<>();
}
}
private static URL findConfigResource(String resourceName) {
return KubernetesHelper.class.getResource(resourceName);
}
// this method is a workaround until we default to NON_EMPTY on the kubernetes model
// see: https://github.com/fabric8io/kubernetes-model/issues/154
public static void saveYamlNotEmpty(HasMetadata entity, File outFile) throws IOException {
String yaml = toYaml(entity);
ObjectMapper objectMapper = createYamlObjectMapper();
// TODO we must convert to YAML, parse as JsonNode
// then remove empty nodes then write to YAML
// again which is a hack around this issue:
// https://github.com/fabric8io/kubernetes-model/issues/154
JsonNode jsonNode = objectMapper.readTree(yaml);
removeNullOrEmptyValues(jsonNode);
objectMapper.writeValue(outFile, jsonNode);
}
private static void removeNullOrEmptyValues(JsonNode jsonNode) {
if (jsonNode instanceof ObjectNode) {
List removeFields = new ArrayList<>();
ObjectNode object = (ObjectNode) jsonNode;
for (Iterator iter = object.fieldNames(); iter.hasNext(); ) {
String field = iter.next();
JsonNode value = object.get(field);
if (isEmptyValue(value)) {
removeFields.add(field);
} else {
removeNullOrEmptyValues(value);;
}
}
for (String field : removeFields) {
object.remove(field);
}
} else if (jsonNode instanceof ArrayNode) {
ArrayNode arrayNode = (ArrayNode) jsonNode;
for (int i = 0, size = arrayNode.size(); i < size; i++) {
JsonNode value = arrayNode.get(i);
removeNullOrEmptyValues(value);
}
}
}
private static boolean isEmptyValue(JsonNode value) {
if (value.isArray()) {
int size = value.size();
return size == 0;
}
if (value.isTextual()) {
String text = value.textValue();
return isNullOrBlank(text);
}
if (value.isObject()) {
removeNullOrEmptyValues(value);
Iterator iter = value.fieldNames();
int count = 0;
while (iter.hasNext()) {
iter.next();
count++;
}
return count == 0;
}
return false;
}
public static OpenShiftClient createJenkinshiftOpenShiftClient(String jenkinshiftUrl) {
Config config = createJenkinshiftConfig(jenkinshiftUrl);
// TODO until jenkinshift supports HTTPS lets disable HTTPS by default
// openShiftClient = new DefaultOpenShiftClient(jenkinshiftUrl);
JenkinShiftClient jenkinShiftClient = new JenkinShiftClient(config);
jenkinShiftClient.updateHttpClient(config);
return jenkinShiftClient;
}
private static Config createJenkinshiftConfig(String jenkinshiftUrl) {
Config config = new Config();
config.setMasterUrl(jenkinshiftUrl);
return config;
}
/**
* Returns the default namespace for the given client
*/
public static String getNamespace(KubernetesClient kubernetesClient) {
String answer = kubernetesClient.getNamespace();
if (Strings.isNullOrBlank(answer)) {
answer = defaultNamespace();
}
return answer;
}
protected static class JenkinShiftClient extends DefaultOpenShiftClient {
public JenkinShiftClient(Config config) throws KubernetesClientException {
super(config);
updateHttpClient(config);
}
protected void updateHttpClient(Config config) {
this.httpClient = createHttpClient(config);
}
// TODO until jenkinshift supports HTTPS lets disable HTTPS by default
private OkHttpClient createHttpClient(final Config config) {
try {
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
// Follow any redirects
httpClientBuilder.followRedirects(true);
httpClientBuilder.followSslRedirects(true);
if (config.isTrustCerts()) {
httpClientBuilder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
}
if (isNotNullOrEmpty(config.getUsername()) && isNotNullOrEmpty(config.getPassword())) {
httpClientBuilder.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request authReq = chain.request().newBuilder().addHeader("Authorization", Credentials.basic(config.getUsername(), config.getPassword())).build();
return chain.proceed(authReq);
}
});
} else if (config.getOauthToken() != null) {
httpClientBuilder.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request authReq = chain.request().newBuilder().addHeader("Authorization", "Bearer " + config.getOauthToken()).build();
return chain.proceed(authReq);
}
});
}
Logger reqLogger = LoggerFactory.getLogger(HttpLoggingInterceptor.class);
if (reqLogger.isTraceEnabled()) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClientBuilder.addNetworkInterceptor(loggingInterceptor);
}
if (config.getConnectionTimeout() > 0) {
httpClientBuilder.connectTimeout(config.getConnectionTimeout(), TimeUnit.MILLISECONDS);
}
if (config.getRequestTimeout() > 0) {
httpClientBuilder.readTimeout(config.getRequestTimeout(), TimeUnit.MILLISECONDS);
}
// Only check proxy if it's a full URL with protocol
/*
if (config.getMasterUrl().toLowerCase().startsWith(Config.HTTP_PROTOCOL_PREFIX) || config.getMasterUrl().startsWith(Config.HTTPS_PROTOCOL_PREFIX)) {
try {
URL proxyUrl = getProxyUrl(config);
if (proxyUrl != null) {
httpClientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyUrl.getHost(), proxyUrl.getPort())));
}
} catch (MalformedURLException e) {
throw new KubernetesClientException("Invalid proxy server configuration", e);
}
}
*/
if (config.getUserAgent() != null && !config.getUserAgent().isEmpty()) {
httpClientBuilder.addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request agent = chain.request().newBuilder().header("User-Agent", config.getUserAgent()).build();
return chain.proceed(agent);
}
});
}
return httpClientBuilder.build();
} catch (Exception e) {
throw KubernetesClientException.launderThrowable(e);
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy