kubernetes-client / javascript

Javascript client
Apache License 2.0
2.04k stars 523 forks source link

Inconsistent deserialization behaviour when using `KubernetesObjectApi.list` vs `KubernetesObjectApi.get` #2018

Open LFrobeen opened 5 days ago

LFrobeen commented 5 days ago

Describe the bug The data returned by KubernetesObjectApi.list() does not deserialize timestamps in the items[].metadata field which makes the results inconsistent with KubernetesObjectApi.get(). As a result, the returned manifests cannot directly be used with the KubernetesObjectApi.patch() method because the string-based timestamps will be rejected.

This issue might be related to the changes in https://github.com/kubernetes-client/javascript/pull/1695.

Client Version 0.22.1

Server Version v1.30.5

Steps to Reproduce & Example Code

The following code snippet reproduces the problem. The code tries to list VirtualServices and thus requires istio to be installed. However, the problem can be reproduced with any other resource kind that is not known to the kubernetes/client-node package.

import { KubeConfig, KubernetesObjectApi } from '@kubernetes/client-node';

const TEST_RESOURCES = {
  VirtualService: {
    apiVersion: 'networking.istio.io/v1',
    kind: 'VirtualService',
    namespace: 'default',
    name: 'my-service',
  },
  Pod: {
    apiVersion: 'v1',
    kind: 'Pod',
    namespace: 'default',
    name: 'my-pod',
  },
};

(async () => {
  const kc = new KubeConfig();
  kc.loadFromDefault();

  const client = KubernetesObjectApi.makeApiClient(kc);

  // const { apiVersion, kind, name, namespace } = TEST_RESOURCES.Pod; // known resource kinds work as expected
  const { apiVersion, kind, name, namespace } = TEST_RESOURCES.VirtualService; // "unknown" resource kinds have inconsistent timestamp types

  await client.list(apiVersion, kind, namespace);

  const pod1 = await client
    .list(apiVersion, kind, namespace)
    .then((response) => response.body.items.find((p) => p.metadata?.name === name)!);

  const pod2 = await client
    .read({ apiVersion, kind, metadata: { namespace, name } })
    .then((response) => response.body);

  // Types of timestamps will be different when listing VirtualServices
  console.log(pod1.metadata?.creationTimestamp, pod1.metadata?.creationTimestamp?.constructor.name);
  console.log(pod2.metadata?.creationTimestamp, pod2.metadata?.creationTimestamp?.constructor.name);

  console.log();
})();

Expected behavior The above code should print the same line twice, e.g.:

2023-07-19T12:59:47.000Z Date
2023-07-19T12:59:47.000Z Date

However, when listing VirtualServices (or any other resource that isn't known to this package) the timestamp types in the metadata are different, e.g.:

2023-07-19T12:59:47Z String
2023-07-19T12:59:47.000Z Date

Environment: Probably happens on any environment. For completeness, this is my test environment:

brendandburns commented 5 days ago

I think that this is because we aren't passing type information down here:

https://github.com/kubernetes-client/javascript/blob/master/src/object.ts#L478

requestPromise takes an optional type parameter, but we're not passing it.

If you want to investigate further, we'd be happy to take PRs to fix this.