Skip to content

Commit

Permalink
fix #4662: a few cleanups and exposing more control over the discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
shawkins authored and manusa committed May 30, 2023
1 parent 0c1eefb commit 296aafd
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.fabric8.kubernetes.client;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.client.http.HttpClient;
import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
import io.fabric8.kubernetes.client.utils.HttpClientUtils;
Expand Down Expand Up @@ -49,7 +48,7 @@ default void onClose(Executor executor) {
private Class<KubernetesClient> clazz;
private ExecutorSupplier executorSupplier;
private Consumer<HttpClient.Builder> builderConsumer;
private KubernetesSerialization kubernetesSerialization = new KubernetesSerialization(new ObjectMapper());
private KubernetesSerialization kubernetesSerialization = new KubernetesSerialization();

public KubernetesClientBuilder() {
// basically the same logic as in KubernetesResourceUtil for finding list types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesResource;
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
import io.fabric8.kubernetes.api.model.runtime.RawExtension;
Expand All @@ -58,23 +59,35 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;

public class KubernetesSerialization {

private final ObjectMapper mapper;
private final UnmatchedFieldTypeModule unmatchedFieldTypeModule = new UnmatchedFieldTypeModule();
private KubernetesDeserializer kubernetesDeserializer;
private final boolean searchClassloaders;

/**
* Creates a new instance with a fresh ObjectMapper
*/
public KubernetesSerialization() {
this(new ObjectMapper());
this(new ObjectMapper(), true);
}

public KubernetesSerialization(ObjectMapper mapper) {
/**
* Creates a new instance with the given ObjectMapper, which will be configured for use for
* kubernetes resource serialization / deserialization.
*
* @param searchClassloaders if {@link KubernetesResource} should be automatically discovered via {@link ServiceLoader}
*/
public KubernetesSerialization(ObjectMapper mapper, boolean searchClassloaders) {
this.mapper = mapper;
this.searchClassloaders = searchClassloaders;
configureMapper(mapper);
}

private void configureMapper(ObjectMapper mapper) {
protected void configureMapper(ObjectMapper mapper) {
mapper.registerModules(new JavaTimeModule(), unmatchedFieldTypeModule);
mapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
HandlerInstantiator instanciator = mapper.getDeserializationConfig().getHandlerInstantiator();
Expand Down Expand Up @@ -131,8 +144,7 @@ public TypeIdResolver typeIdResolverInstance(MapperConfig<?> config, Annotated a
private synchronized KubernetesDeserializer getKubernetesDeserializer() {
// created lazily to avoid holding all model classes in memory by default
if (this.kubernetesDeserializer == null) {
// TODO: expose control over KubernetesDeserializer class registration
this.kubernetesDeserializer = new KubernetesDeserializer(true);
this.kubernetesDeserializer = new KubernetesDeserializer(searchClassloaders);
}
return kubernetesDeserializer;
}
Expand Down Expand Up @@ -244,17 +256,6 @@ public <T> T unmarshal(InputStream is, TypeReference<T> type) {
}
}

private boolean isLikelyYaml(BufferedInputStream bis) throws IOException {
bis.mark(-1);
int intch;
do {
intch = bis.read();
} while (intch > -1 && Character.isWhitespace(intch));
bis.reset();

return intch != '{' && intch != '[';
}

/**
* If multiple docs exist, only non-null resources will be kept. Results spanning multiple docs
* will be returned as a List of KubernetesResource
Expand Down Expand Up @@ -368,7 +369,7 @@ public Type constructParametricType(Class<?> parameterizedClass, Class<?> parame
return mapper.getTypeFactory().constructParametricType(parameterizedClass, parameterType);
}

public Class<? extends KubernetesResource> getRegisteredKind(String apiVersion, String kind) {
public Class<? extends KubernetesResource> getRegisteredKubernetesResource(String apiVersion, String kind) {
return this.getKubernetesDeserializer().getRegisteredKind(apiVersion, kind);
}

Expand All @@ -381,16 +382,16 @@ ObjectMapper getMapper() {
}

/**
* Registers a Custom Resource Definition Kind
* Registers a new resource, which can then be recognized for deserialization
*/
public void registerCustomKind(String kind, Class<? extends KubernetesResource> clazz) {
registerCustomKind(null, kind, clazz);
public void registerKubernetesResource(Class<? extends KubernetesResource> clazz) {
registerKubernetesResource(null, HasMetadata.getKind(clazz), clazz);
}

/**
* Registers a Custom Resource Definition Kind
* Registers a new resource, which can then be recognized for deserialization
*/
public void registerCustomKind(String apiVersion, String kind, Class<? extends KubernetesResource> clazz) {
public void registerKubernetesResource(String apiVersion, String kind, Class<? extends KubernetesResource> clazz) {
getKubernetesDeserializer().registerCustomKind(apiVersion, kind, clazz);
}

Expand All @@ -399,7 +400,7 @@ public String convertToJson(String input) {
mapper.readTree(input);
return input; // valid json
} catch (JsonProcessingException e) {
return Serialization.asJson(Serialization.unmarshal(input, JsonNode.class));
return asJson(unmarshal(input, JsonNode.class));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.fabric8.kubernetes.client.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.fabric8.kubernetes.api.model.AuthInfo;
import io.fabric8.kubernetes.api.model.NamedAuthInfo;
import io.fabric8.kubernetes.api.model.NamedContext;
Expand Down Expand Up @@ -333,12 +332,12 @@ public static boolean idTokenExpired(Config config) {
String[] jwtParts = accessToken.split(JWT_PARTS_DELIMITER_REGEX);
String jwtPayload = jwtParts[1];
String jwtPayloadDecoded = new String(Base64.getDecoder().decode(jwtPayload));
Map<String, Object> jwtPayloadMap = Serialization.jsonMapper().readValue(jwtPayloadDecoded, Map.class);
Map<String, Object> jwtPayloadMap = Serialization.unmarshal(jwtPayloadDecoded, Map.class);
int expiryTimestampInSeconds = (Integer) jwtPayloadMap.get(JWT_TOKEN_EXPIRY_TIMESTAMP_KEY);
return Instant.ofEpochSecond(expiryTimestampInSeconds)
.minusSeconds(TOKEN_EXPIRY_DELTA)
.isBefore(Instant.now());
} catch (JsonProcessingException e) {
} catch (Exception e) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,10 @@ public static <T> T unmarshal(InputStream is, final Class<T> type) {
* @param type The {@link TypeReference}.
* @param <T> Template argument denoting type
* @return returns de-serialized object
*
* @deprecated use {@link KubernetesSerialization#unmarshal(InputStream, TypeReference)}
*/
@Deprecated
public static <T> T unmarshal(InputStream is, TypeReference<T> type) {
return kubernetesSerialization.unmarshal(is, type);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package io.fabric8.kubernetes.client.informers.cache;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodBuilder;
import io.fabric8.kubernetes.client.utils.KubernetesSerialization;
Expand All @@ -30,7 +29,7 @@ class ReducedStateItemStoreTest {
@Test
void testStoreRestore() {
ReducedStateItemStore<Pod> store = new ReducedStateItemStore<>(ReducedStateItemStore.UID_KEY_STATE,
Pod.class, new KubernetesSerialization(new ObjectMapper()), "metadata.labels", "foo.bar");
Pod.class, new KubernetesSerialization(), "metadata.labels", "foo.bar");

Pod pod = new PodBuilder().withNewSpec().endSpec().withNewMetadata().withUid("x").withName("y").addToLabels("one", "1")
.addToLabels("two", "2").withResourceVersion("2").endMetadata().withNewStatus().endStatus().build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public ResourceDefinitionContext getResourceDefinitionContext(String apiVersion,
Client client) {
// check if it's built-in
Class<? extends KubernetesResource> clazz = client.adapt(BaseClient.class).getKubernetesSerialization()
.getRegisteredKind(apiVersion, kind);
.getRegisteredKubernetesResource(apiVersion, kind);

ResourceDefinitionContext rdc = null;
if (clazz != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.kubernetes.client.impl.BaseClient;
import io.fabric8.kubernetes.client.mock.crd.CronTab;
import io.fabric8.kubernetes.client.mock.crd.CronTabSpec;
import io.fabric8.kubernetes.client.mock.crd.CronTabStatus;
Expand All @@ -48,7 +47,7 @@ class CustomResourceCrudTest {

@BeforeEach
void setUp() {
client.adapt(BaseClient.class).getKubernetesSerialization().registerCustomKind("stable.example.com/v1", "CronTab",
client.getKubernetesSerialization().registerKubernetesResource("stable.example.com/v1", "CronTab",
CronTab.class);
cronTabCrd = client
.apiextensions()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class CustomResourceCrudWithCRDContextTest {
@Test
void testCreateAndGet() {
// Given
client.adapt(BaseClient.class).getKubernetesSerialization().registerCustomKind("demo.fabric8.io/v1alpha1",
client.getKubernetesSerialization().registerKubernetesResource("demo.fabric8.io/v1alpha1",
"EntandoBundleRelease", EntandoBundleRelease.class);
MixedOperation<EntandoBundleRelease, EntandoBundleReleaseList, Resource<EntandoBundleRelease>> ebrClient = client
.resources(EntandoBundleRelease.class, EntandoBundleReleaseList.class);
Expand All @@ -55,7 +55,7 @@ void testCreateAndGet() {
@Test
void testCreateAndGetWithInferredContext() {
// Given
client.adapt(BaseClient.class).getKubernetesSerialization().registerCustomKind("demo.fabric8.io/v1alpha1",
client.adapt(BaseClient.class).getKubernetesSerialization().registerKubernetesResource("demo.fabric8.io/v1alpha1",
"EntandoBundleRelease", EntandoBundleRelease.class);
MixedOperation<EntandoBundleRelease, KubernetesResourceList<EntandoBundleRelease>, Resource<EntandoBundleRelease>> ebrClient = client
.resources(EntandoBundleRelease.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import io.fabric8.kubernetes.client.WatcherException;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.kubernetes.client.dsl.base.ResourceDefinitionContext;
import io.fabric8.kubernetes.client.impl.BaseClient;
import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
import io.fabric8.kubernetes.client.informers.SharedInformerFactory;
Expand Down Expand Up @@ -1166,7 +1165,7 @@ void testGenericKubernetesResourceSharedIndexInformerWithAdditionalDeserializers
r -> new WatchEvent(getAnimal("red-panda", "Carnivora", r), "ADDED"), null, null);

// When
client.adapt(BaseClient.class).getKubernetesSerialization().registerCustomKind("jungle.example.com/v1", "Animal",
client.getKubernetesSerialization().registerKubernetesResource("jungle.example.com/v1", "Animal",
CronTab.class);
SharedIndexInformer<GenericKubernetesResource> animalSharedIndexInformer = client
.genericKubernetesResources(animalContext)
Expand Down

0 comments on commit 296aafd

Please sign in to comment.