Skip to content

Commit

Permalink
Fix #2141: Decouple OpenShift Model dependency from Kubernetes Client
Browse files Browse the repository at this point in the history
  • Loading branch information
rohanKanojia committed Sep 17, 2020
1 parent dcae060 commit c65b454
Show file tree
Hide file tree
Showing 23 changed files with 648 additions and 291 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#### Improvements
* Fix #2473: Removed unused ValidationMessages.properties
* Fix #2408: Add documentation for Pod log options
* Fix #2141: Decouple OpenShift Model from Kubernetes Client

#### Dependency Upgrade
* Bump Knative Serving to v0.17.2 & Knative Eventing to v0.17.3
Expand Down
4 changes: 0 additions & 4 deletions kubernetes-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,6 @@
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model-storageclass</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>openshift-model</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@

package io.fabric8.kubernetes.client;

import io.fabric8.openshift.api.model.ClusterVersion;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class VersionInfo {
public final class VERSION_KEYS {
public static final class VersionKeys {
private VersionKeys() {}
public static final String BUILD_DATE = "buildDate";
public static final String GIT_COMMIT = "gitCommit";
public static final String GIT_VERSION = "gitVersion";
Expand Down Expand Up @@ -83,17 +82,6 @@ public String getCompiler() {

private VersionInfo() { }

public static VersionInfo parseVersionInfoFromClusterVersion(ClusterVersion clusterVersion) throws ParseException {
String[] versionParts = clusterVersion.getStatus().getDesired().getVersion().split("\\.");
VersionInfo.Builder versionInfoBuilder = new VersionInfo.Builder();
if (versionParts.length == 3) {
versionInfoBuilder.withMajor(versionParts[0]);
versionInfoBuilder.withMinor(versionParts[1] + "." + versionParts[2]);
}
versionInfoBuilder.withBuildDate(clusterVersion.getMetadata().getCreationTimestamp());
return versionInfoBuilder.build();
}

public static class Builder {
private VersionInfo versionInfo = new VersionInfo();

Expand All @@ -114,7 +102,7 @@ public Builder(VersionInfo versionInfo) {
}

public Builder withBuildDate(String buildDate) throws ParseException {
this.versionInfo.buildDate = new SimpleDateFormat(VERSION_KEYS.BUILD_DATE_FORMAT).parse(buildDate);
this.versionInfo.buildDate = new SimpleDateFormat(VersionKeys.BUILD_DATE_FORMAT).parse(buildDate);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,25 @@

package io.fabric8.kubernetes.client.dsl.internal;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.client.Version;
import io.fabric8.kubernetes.client.VersionInfo;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.dsl.base.OperationContext;
import io.fabric8.kubernetes.client.dsl.base.OperationSupport;
import io.fabric8.kubernetes.client.utils.Serialization;
import io.fabric8.kubernetes.client.utils.URLUtils;
import io.fabric8.openshift.api.model.ClusterVersionList;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

public class ClusterOperationsImpl extends OperationSupport {
private String versionEndpoint;
protected final String versionEndpoint;
public static final String KUBERNETES_VERSION_ENDPOINT = "version";
public static final String OPENSHIFT_VERSION_ENDPOINT = "version/openshift";
public static final String OPENSHIFT4_VERSION_ENDPOINT = "apis/config.openshift.io/v1/clusterversions";
public static final ObjectMapper objectMapper = new ObjectMapper();

public ClusterOperationsImpl(OkHttpClient client, Config config, String item) {
super(new OperationContext().withOkhttpClient(client).withConfig(config));
Expand All @@ -50,48 +44,34 @@ public ClusterOperationsImpl(OkHttpClient client, Config config, String item) {
public VersionInfo fetchVersion() {
try {
Response response = handleVersionGet(versionEndpoint);
// Handle Openshift 4 version case
if (HttpURLConnection.HTTP_NOT_FOUND == response.code() && versionEndpoint.equals(OPENSHIFT_VERSION_ENDPOINT)) {
response.close();
return fetchOpenshift4Version();
}
Map<String, String> myMap = new HashMap<>();

Map<String, String> myMap = objectMapper.readValue(response.body().string(), HashMap.class);
if (response.body() != null) {
myMap = Serialization.jsonMapper().readValue(response.body().string(), HashMap.class);
}
return fetchVersionInfoFromResponse(myMap);
} catch(Exception e) {
KubernetesClientException.launderThrowable(e);
throw KubernetesClientException.launderThrowable(e);
}
return null;
}

private Response handleVersionGet(String versionEndpointToBeUsed) throws IOException {
protected Response handleVersionGet(String versionEndpointToBeUsed) throws IOException {
Request.Builder requestBuilder = new Request.Builder()
.get()
.url(URLUtils.join(config.getMasterUrl(), versionEndpointToBeUsed));
return client.newCall(requestBuilder.build()).execute();
}

private VersionInfo fetchOpenshift4Version() throws IOException, ParseException {
Response response = handleVersionGet(OPENSHIFT4_VERSION_ENDPOINT);
if (response.isSuccessful() && response.body() != null) {
ClusterVersionList clusterVersionList = objectMapper.readValue(response.body().string(), ClusterVersionList.class);
if (!clusterVersionList.getItems().isEmpty()) {
return VersionInfo.parseVersionInfoFromClusterVersion(clusterVersionList.getItems().get(0));
}
}
return null;
}

private VersionInfo fetchVersionInfoFromResponse(Map<String, String> responseAsMap) throws ParseException {
return new VersionInfo.Builder().withBuildDate(responseAsMap.get(VersionInfo.VERSION_KEYS.BUILD_DATE))
.withGitCommit(responseAsMap.get(VersionInfo.VERSION_KEYS.GIT_COMMIT))
.withGitVersion(responseAsMap.get(VersionInfo.VERSION_KEYS.GIT_VERSION))
.withMajor(responseAsMap.get(VersionInfo.VERSION_KEYS.MAJOR))
.withMinor(responseAsMap.get(VersionInfo.VERSION_KEYS.MINOR))
.withGitTreeState(responseAsMap.get(VersionInfo.VERSION_KEYS.GIT_TREE_STATE))
.withPlatform(responseAsMap.get(VersionInfo.VERSION_KEYS.PLATFORM))
.withGoVersion(responseAsMap.get(VersionInfo.VERSION_KEYS.GO_VERSION))
.withCompiler(responseAsMap.get(VersionInfo.VERSION_KEYS.COMPILER))
protected static VersionInfo fetchVersionInfoFromResponse(Map<String, String> responseAsMap) throws ParseException {
return new VersionInfo.Builder().withBuildDate(responseAsMap.get(VersionInfo.VersionKeys.BUILD_DATE))
.withGitCommit(responseAsMap.get(VersionInfo.VersionKeys.GIT_COMMIT))
.withGitVersion(responseAsMap.get(VersionInfo.VersionKeys.GIT_VERSION))
.withMajor(responseAsMap.get(VersionInfo.VersionKeys.MAJOR))
.withMinor(responseAsMap.get(VersionInfo.VersionKeys.MINOR))
.withGitTreeState(responseAsMap.get(VersionInfo.VersionKeys.GIT_TREE_STATE))
.withPlatform(responseAsMap.get(VersionInfo.VersionKeys.PLATFORM))
.withGoVersion(responseAsMap.get(VersionInfo.VersionKeys.GO_VERSION))
.withCompiler(responseAsMap.get(VersionInfo.VersionKeys.COMPILER))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@
package io.fabric8.kubernetes.client.dsl.internal;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mifmif.common.regex.Generex;
import io.fabric8.kubernetes.api.builder.TypedVisitor;
import io.fabric8.kubernetes.api.builder.VisitableBuilder;
import io.fabric8.kubernetes.api.builder.Visitor;
import io.fabric8.kubernetes.api.model.DeletionPropagation;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesList;
import io.fabric8.kubernetes.api.model.KubernetesListBuilder;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.client.Config;
Expand All @@ -39,8 +37,6 @@
import io.fabric8.kubernetes.client.utils.KubernetesResourceUtil;
import io.fabric8.kubernetes.client.utils.Serialization;
import io.fabric8.kubernetes.client.utils.Utils;
import io.fabric8.openshift.api.model.Parameter;
import io.fabric8.openshift.api.model.Template;

import java.net.HttpURLConnection;
import java.util.function.Predicate;
Expand All @@ -67,8 +63,8 @@ public class NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImp
Waitable<List<HasMetadata>, HasMetadata>, Readiable {

private static final Logger LOGGER = LoggerFactory.getLogger(NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl.class);
private static final String EXPRESSION = "expression";
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
protected static final String EXPRESSION = "expression";
protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

private final String fallbackNamespace;
private final String explicitNamespace;
Expand Down Expand Up @@ -181,7 +177,7 @@ public List<HasMetadata> waitUntilCondition(Predicate<HasMetadata> condition, lo
@Override
public Boolean isReady() {
for (final HasMetadata meta : acceptVisitors(get(), visitors)) {
if (!Readiness.isReady(meta)) {
if (!isResourceReady(meta)) {
return false;
}
}
Expand Down Expand Up @@ -394,17 +390,14 @@ public Deletable<Boolean> cascading(boolean cascading) {
return new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl(client, config, fallbackNamespace, explicitNamespace, fromServer, true, visitors, item, null, null, gracePeriodSeconds, propagationPolicy, cascading, watchRetryInitialBackoffMillis, watchRetryBackoffMultiplier);
}

private static <T> List<HasMetadata> asHasMetadata(T item, Boolean enableProccessing) {
protected boolean isResourceReady(HasMetadata meta) {
return Readiness.isReady(meta);
}

protected <T> List<HasMetadata> asHasMetadata(T item, Boolean enableProccessing) {
List<HasMetadata> result = new ArrayList<>();
if (item instanceof KubernetesList) {
result.addAll(((KubernetesList) item).getItems());
} else if (item instanceof Template) {

if (!enableProccessing) {
result.addAll(((Template) item).getObjects());
} else {
result.addAll(processTemplate((Template)item, false));
}
} else if (item instanceof KubernetesResourceList) {
result.addAll(((KubernetesResourceList) item).getItems());
} else if (item instanceof HasMetadata) {
Expand Down Expand Up @@ -435,43 +428,6 @@ private static <T> ResourceHandler handlerOf(T item) {
}
}

private static List<HasMetadata> processTemplate(Template template, Boolean failOnMissing) {
List<Parameter> parameters = template != null ? template.getParameters() : null;
KubernetesList list = new KubernetesListBuilder()
.withItems(template.getObjects())
.build();

try {
String json = OBJECT_MAPPER.writeValueAsString(list);
if (parameters != null && !parameters.isEmpty()) {
// lets make a few passes in case there's expressions in values
for (int i = 0; i < 5; i++) {
for (Parameter parameter : parameters) {
String name = parameter.getName();
String regex = "${" + name + "}";
String value;
if (Utils.isNotNullOrEmpty(parameter.getValue())) {
value = parameter.getValue();
} else if (EXPRESSION.equals(parameter.getGenerate())) {
Generex generex = new Generex(parameter.getFrom());
value = generex.random();
} else if (failOnMissing) {
throw new IllegalArgumentException("No value available for parameter name: " + name);
} else {
value = "";
}
json = json.replace(regex, value);
}
}
}

list = OBJECT_MAPPER.readValue(json, KubernetesList.class);
} catch (IOException e) {
throw KubernetesClientException.launderThrowable(e);
}
return list.getItems();
}

/**
* Waits until the latch reaches to zero and then checks if the expected result
* @param latch The latch.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,25 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.client.internal.patchmixins.BuildMixIn;
import io.fabric8.kubernetes.client.internal.patchmixins.ObjectMetaMixIn;
import io.fabric8.openshift.api.model.Build;

public class PatchUtils {
private PatchUtils() { }

private static class SingletonHolder {
public static final ObjectMapper patchMapper;

static {
patchMapper = new ObjectMapper();
patchMapper.addMixIn(ObjectMeta.class, ObjectMetaMixIn.class);
patchMapper.addMixIn(Build.class, BuildMixIn.class);
patchMapper.setConfig(patchMapper.getSerializationConfig().without(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS));
}
}

public static void addMixInToMapper(Class<?> target, Class<?> mixInSource) {
SingletonHolder.patchMapper.addMixIn(target, mixInSource);
}

public static ObjectMapper patchMapper() {
return SingletonHolder.patchMapper;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@
import io.fabric8.kubernetes.api.model.apps.StatefulSetSpec;
import io.fabric8.kubernetes.api.model.apps.StatefulSetStatus;
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.DeploymentConfigStatus;

public class Readiness {

Expand All @@ -51,7 +48,6 @@ public static boolean isReadinessApplicable(Class<? extends HasMetadata> itemCla
|| io.fabric8.kubernetes.api.model.extensions.Deployment.class.isAssignableFrom(itemClass)
|| ReplicaSet.class.isAssignableFrom(itemClass)
|| Pod.class.isAssignableFrom(itemClass)
|| DeploymentConfig.class.isAssignableFrom(itemClass)
|| ReplicationController.class.isAssignableFrom(itemClass)
|| Endpoints.class.isAssignableFrom(itemClass)
|| Node.class.isAssignableFrom(itemClass)
Expand All @@ -60,6 +56,14 @@ public static boolean isReadinessApplicable(Class<? extends HasMetadata> itemCla
}

public static boolean isReady(HasMetadata item) {
if (isReadiableKubernetesResource(item)) {
return isKubernetesResourceReady(item);
} else {
throw new IllegalArgumentException("Item needs to be one of [Node, Deployment, ReplicaSet, StatefulSet, Pod, ReplicationController], but was: [" + (item != null ? item.getKind() : "Unknown (null)") + "]");
}
}

private static boolean isKubernetesResourceReady(HasMetadata item) {
if (item instanceof Deployment) {
return isDeploymentReady((Deployment) item);
} else if (item instanceof io.fabric8.kubernetes.api.model.extensions.Deployment) {
Expand All @@ -68,8 +72,6 @@ public static boolean isReady(HasMetadata item) {
return isReplicaSetReady((ReplicaSet) item);
} else if (item instanceof Pod) {
return isPodReady((Pod) item);
} else if (item instanceof DeploymentConfig) {
return isDeploymentConfigReady((DeploymentConfig) item);
} else if (item instanceof ReplicationController) {
return isReplicationControllerReady((ReplicationController) item);
} else if (item instanceof Endpoints) {
Expand All @@ -78,9 +80,8 @@ public static boolean isReady(HasMetadata item) {
return isNodeReady((Node) item);
} else if (item instanceof StatefulSet) {
return isStatefulSetReady((StatefulSet) item);
} else {
throw new IllegalArgumentException("Item needs to be one of [Node, Deployment, ReplicaSet, StatefulSet, Pod, DeploymentConfig, ReplicationController], but was: [" + (item != null ? item.getKind() : "Unknown (null)") + "]");
}
return false;
}

public static boolean isStatefulSetReady(StatefulSet ss) {
Expand Down Expand Up @@ -157,24 +158,6 @@ public static boolean isReplicaSetReady(ReplicaSet r) {
}


public static boolean isDeploymentConfigReady(DeploymentConfig d) {
Utils.checkNotNull(d, "Deployment can't be null.");
DeploymentConfigSpec spec = d.getSpec();
DeploymentConfigStatus status = d.getStatus();

if (status == null || status.getReplicas() == null || status.getAvailableReplicas() == null) {
return false;
}

//Can be true in testing, so handle it to make test writing easier.
if (spec == null || spec.getReplicas() == null) {
return false;
}

return spec.getReplicas().intValue() == status.getReplicas() &&
spec.getReplicas().intValue() <= status.getAvailableReplicas();
}

public static boolean isReplicationControllerReady(ReplicationController r) {
Utils.checkNotNull(r, "ReplicationController can't be null.");
ReplicationControllerSpec spec = r.getSpec();
Expand Down Expand Up @@ -270,6 +253,17 @@ private static NodeCondition getNodeReadyCondition(Node node) {
}
return null;
}

protected static boolean isReadiableKubernetesResource(HasMetadata item) {
return (item instanceof Deployment ||
item instanceof io.fabric8.kubernetes.api.model.extensions.Deployment ||
item instanceof ReplicaSet ||
item instanceof Pod ||
item instanceof ReplicationController ||
item instanceof Endpoints ||
item instanceof Node ||
item instanceof StatefulSet);
}
}


Loading

0 comments on commit c65b454

Please sign in to comment.