Getting exception from deleteNamespacedStatefulSet() call
chlung opened this issue Β· 50 comments
Hi,
I was getting exception when I issued deleteNamespacedStatefulSet() call. The call did delete statefulset, but it throw the exception back to caller.
Exception:
java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2004 path $.status
Here is my code,
V1DeleteOptions deleteOptions = new V1DeleteOptions()
Boolean orphanDependents = true
apiInstance.deleteNamespacedStatefulSet(name, namespace, deleteOptions, null, 60, orphanDependents, null)
Thanks.
I'll investigate this, I suspect that it is a problem with the Swagger/OpenAPI spec indicating the wrong code for Delete...
But we'll need to investigate to be sure.
@brendanburns thanks.
Ok, I figured out the issue here...
When you delete a StatefulSet (and probably a ReplicaSet too) it initially returns a StatefulSet
object, but eventually it returns a Status
object.
This means that the Swagger should be oneOf(StatefulSet, Status)
But the Kubernetes Swagger here:
https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json
Only has the Status
object.
Thus, the generated Java code barfs when it tries to parse a StatefulSet
object into a Status
object.
Unfortunately go-restful
when generates the swagger spec doesn't support oneOf
as far as I know, thus we're going to either need to massage the swagger spec before client generation, improve go-restful's swagger generation or switch to a different way of generating swagger...
None of these are great options, and none of them will happen very quickly. So for now, I think the best you can do is catch this Exception and move on...
Sorry!
@brendandburns ok. I can handle it in my code. Thanks for debugging this issue. Should we keep this issue for tracking purpose or close it for now?
Yes, let's definitely keep this open.
Bug also exists when trying to delete a namespaced Job. JSON output is here
{
"kind": "Job",
"apiVersion": "batch/v1",
"metadata": {
"name": "pi-s44bw",
"generateName": "pi-",
"namespace": "default",
"selfLink": "/apis/batch/v1/namespaces/default/jobs/pi-s44bw",
"uid": "a48d258d-faea-11e7-bdc1-42010a84018c",
"resourceVersion": "11082999",
"creationTimestamp": "2018-01-16T18:25:34Z",
"deletionTimestamp": "2018-01-16T18:25:55Z",
"deletionGracePeriodSeconds": 0,
"labels": {
"controller-uid": "a48d258d-faea-11e7-bdc1-42010a84018c",
"job-name": "pi-s44bw"
},
"finalizers": [
"orphan"
]
},
"spec": {
"parallelism": 1,
"completions": 1,
"backoffLimit": 4,
"selector": {
"matchLabels": {
"controller-uid": "a48d258d-faea-11e7-bdc1-42010a84018c"
}
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"controller-uid": "a48d258d-faea-11e7-bdc1-42010a84018c",
"job-name": "pi-s44bw"
}
},
"spec": {
"containers": [
{
"name": "perl",
"image": "perl",
"command": [
"perl",
"-Mbignum=bpi",
"-wle",
"print bpi(2000)"
],
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File",
"imagePullPolicy": "Always"
}
],
"restartPolicy": "Never",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"securityContext": {},
"schedulerName": "default-scheduler"
}
}
},
"status": {
"conditions": [
{
"type": "Complete",
"status": "True",
"lastProbeTime": "2018-01-16T18:25:41Z",
"lastTransitionTime": "2018-01-16T18:25:41Z"
}
],
"startTime": "2018-01-16T18:25:34Z",
"completionTime": "2018-01-16T18:25:41Z",
"succeeded": 1
}
}
However API says status is a string...
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 1152 path $.status
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.Gson.fromJson(Gson.java:879)
at com.google.gson.Gson.fromJson(Gson.java:844)
at com.google.gson.Gson.fromJson(Gson.java:793)
at io.kubernetes.client.JSON.deserialize(JSON.java:106)
at io.kubernetes.client.ApiClient.deserialize(ApiClient.java:668)
at io.kubernetes.client.ApiClient.handleResponse(ApiClient.java:871)
at io.kubernetes.client.ApiClient.execute(ApiClient.java:798)
at io.kubernetes.client.apis.BatchV1Api.deleteNamespacedJobWithHttpInfo(BatchV1Api.java:511)
at io.kubernetes.client.apis.BatchV1Api.deleteNamespacedJob(BatchV1Api.java:491)
at com.oscaro.kubernetes.ApiHelper._clinit__closure5$_closure7(ApiHelper.groovy:80)
at com.oscaro.kubernetes.ApiHelper._clinit__closure5(ApiHelper.groovy:73)
at com.oscaro.kubernetes.JobExecutorTest.it should return the expected output from the job "#ns/#prefix-*"(JobExecutorTest.groovy:53)
Caused by: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 1152 path $.status
at com.google.gson.stream.JsonReader.nextString(JsonReader.java:831)
at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:422)
at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:410)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
... 12 more
Yeah, this is may apply to all object deletes, we could try to wrap if we really wanted to...
Since we're using the async API variants, there isn't a good way to wrap this in our code. So, depending on how far away the OpenAPI v3 fix is I'd be grateful if this was wrapped -- at least so that it doesn't gum up the logs.
Reporting that I am also running into this issue. I guess it's pretty clear already, but here's my client debug log and stacktrace:
--> POST https://192.168.1.129:8443/api/v1/namespaces?pretty=false HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 164
Accept: application/json
User-Agent: Swagger-Codegen/1.0-SNAPSHOT/java
{"apiVersion":"v1","kind":"Namespace","metadata":{"labels":{"name":"7700e076-b66f-4715-a716-d67764ffc946"},"name":"7700e076-b66f-4715-a716-d67764ffc946"},"spec":{}}
--> END POST (164-byte body)
<-- HTTP/1.1 201 Created (166ms)
Content-Type: application/json
Date: Wed, 25 Apr 2018 07:46:45 GMT
Content-Length: 404
OkHttp-Sent-Millis: 1524642405060
OkHttp-Received-Millis: 1524642405070
{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"7700e076-b66f-4715-a716-d67764ffc946","selfLink":"/api/v1/namespaces/7700e076-b66f-4715-a716-d67764ffc946","uid":"cd231c15-485c-11e8-b607-00155d380109","resourceVersion":"101976","creationTimestamp":"2018-04-25T07:46:45Z","labels":{"name":"7700e076-b66f-4715-a716-d67764ffc946"}},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}
<-- END HTTP (404-byte body)
--> DELETE https://192.168.1.129:8443/api/v1/namespaces/7700e076-b66f-4715-a716-d67764ffc946?pretty=false HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 75
Accept: application/json
User-Agent: Swagger-Codegen/1.0-SNAPSHOT/java
{"apiVersion":"v1","kind":"DeleteOptions","propagationPolicy":"Background"}
--> END DELETE (75-byte body)
<-- HTTP/1.1 200 OK (9ms)
Content-Type: application/json
Date: Wed, 25 Apr 2018 07:46:46 GMT
Content-Length: 452
OkHttp-Sent-Millis: 1524642405314
OkHttp-Received-Millis: 1524642405321
{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"7700e076-b66f-4715-a716-d67764ffc946","selfLink":"/api/v1/namespaces/7700e076-b66f-4715-a716-d67764ffc946","uid":"cd231c15-485c-11e8-b607-00155d380109","resourceVersion":"101981","creationTimestamp":"2018-04-25T07:46:45Z","deletionTimestamp":"2018-04-25T07:46:46Z","labels":{"name":"7700e076-b66f-4715-a716-d67764ffc946"}},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Terminating"}}
<-- END HTTP (452-byte body)
15:46:45.331 [http-nio-auto-1-exec-4] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 429 path $.status] with root cause
java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 429 path $.status
at com.google.gson.stream.JsonReader.nextString(JsonReader.java:825)
at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:401)
at com.google.gson.internal.bind.TypeAdapters$16.read(TypeAdapters.java:389)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.Gson.fromJson(Gson.java:888)
at com.google.gson.Gson.fromJson(Gson.java:853)
at com.google.gson.Gson.fromJson(Gson.java:802)
at io.kubernetes.client.JSON.deserialize(JSON.java:110)
at io.kubernetes.client.ApiClient.deserialize(ApiClient.java:668)
at io.kubernetes.client.ApiClient.handleResponse(ApiClient.java:871)
at io.kubernetes.client.ApiClient.execute(ApiClient.java:798)
at io.kubernetes.client.apis.CoreV1Api.deleteNamespaceWithHttpInfo(CoreV1Api.java:12133)
at io.kubernetes.client.apis.CoreV1Api.deleteNamespace(CoreV1Api.java:12114)
So is this something that the Kubernetes server team will fix when improving Swagger documentation generation, or something you will (eventually) fix by using a different generator?
Just some example deal-with-it code here for future readers. It's not pretty but meh:
try {
api.deleteNamespace(namespaceString, deleteOptions, PRETTY_PRINT, null, null, null);
LOGGER.debug("Deleted namespace {}", namespaceString);
}
catch (JsonSyntaxException e) {
if (e.getCause() instanceof IllegalStateException) {
IllegalStateException ise = (IllegalStateException) e.getCause();
if (ise.getMessage() != null && ise.getMessage().contains("Expected a string but was BEGIN_OBJECT"))
LOGGER.debug("Catching exception because of issue https://github.com/kubernetes-client/java/issues/86", e);
else throw e;
}
else throw e;
}
+1
This issue is getting dangerously close to its first birthdayβhave there been any developments that might lead to a fix? Or at least an "official" recommendation for a workaround.
@patricklucas unfortunately, there is really very little that we can do here. Until OpenAPI supports multi-type return (or inheritance) the generated client is always going to only be able to return one Java type, while the actual Kubernetes API server will always return two different types, resulting in this exception.
The only 'workaround' is to catch the exception and move on. It's difficult to turn that into a utility method, since it could be any delete call (we'd have to code-generate the exception-catching code)
I'm open to suggestions to improve this behavior, but I have a hard time figuring out the right way to address the issue, without fixing the root cause, which is currently blocked on moving to OpenAPI 3 (kubernetes/kubernetes#51163) and having a codegen that supports OpenAPI 3 (swagger-api/swagger-codegen#6598)
If you have suggestions for temporary workarounds until then, please feel free to add them to the issue, I'm happy to implement them.
Thanks a lot for the reply, I think it makes the situation much clearer for anyone who comes across this thread.
As you hinted, I ended up just catching JsonSyntaxException
and calling delete again to get the expected return type, which is okay in my situation since I expect the delete to be idempotent and a legitimate JsonSyntaxException
should still be thrown on the second invocation. I'm not totally certain that a second delete call immediately after the first will always return a V1Status, or again the resource, but my use-case tolerates that and I'm sure it will become apparent during testing.
fwiw, I think it will return V1Status
only when the delete has finally succeeded, which could take an aribitrary amount of time.
+1
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 66 column 14 path $.status
@brendandburns Is it possible to replace String with Object?
Any progress on this?
+1 fix please!
Please see the detailed comment here
This code is generated from a Swagger spec (and we don't want to stop using a generator) and we have to wait until the Swagger spec is updated to OpenAPI 3.0 to support either (1) multi-return or (2) parent types.
We could in theory munge up the Swagger in the gen repo to monkey patch this ourselves, and perhaps I'll look into doing that eventually. If someone has cycles, I'm happy to send instructions for what that would look like.
Thanks
Deleting Replication Controller via deleteNamespacedReplicationController
gives the same exception complaining about getting object instead of a string.
Hi,
Im getting the same error on deleteNamespacedDeployment
call. Tried catching the IllegalStateException
and proceeding. Not sure if it is the issue or not, but when the Delete gets executed, it only deletes the Deployment & pods get left behind as orphans. I have "Foreground" set as the PropagationPolicy. I saw a mention above about calling delete again on this exception..Since Im not doing that, will that be the reason my pods are getting orphaned ? Any Help ? Thanks, Sreeni
In my experience, there are races in deployment delete in general in k8s, if you want to truly prevent orphaning you need to scale the deployment to zero, wait for that to finish (no pods) and then delete the deployment.
Please file a bug in the main repo if k8s didn't respect the GC / orphan settings.
Since Im not doing that, will that be the reason my pods are getting orphaned ?
@rsreeni actually not. but they're similar. foreground policy will attach a foregroundDeletion
finalizer instead of orphan
which makes you hitting this issue.
Since Im not doing that, will that be the reason my pods are getting orphaned ?
@rsreeni actually not. but they're similar. foreground policy will attach a
foregroundDeletion
finalizer instead oforphan
which makes you hitting this issue.
That means after the delete, the pods should not have been Orphaned , but deleted, am I correct ? That tells me that I need to file a bug as @lavalamp had suggested...
So what can I do now to prevent errors from happening? I need to know if I really deleted the pod. Can I only catch exceptions to handle it?
Yes, for now catching exceptions and retrying the delete is really the only way to make sure the Pod is deleted.
Hi,
In my case I was getting this error when called deleteNamespacedDeployment() method.
As a workaround I replaced the call of deleteNamespacedDeployment() with deleteCollectionNamespacedDeployment() and deleteCollectionNamespacedReplicaSet(), using label selectors to match the desired resources to be deleted.
It's working. No need to catch errors.
Hope it helps.
Hi,
In my case I was getting this error when called deleteNamespacedDeployment() method.
As a workaround I replaced the call of deleteNamespacedDeployment() with deleteCollectionNamespacedDeployment() and deleteCollectionNamespacedReplicaSet(), using label selectors to match the desired resources to be deleted.
It's working. No need to catch errors.
Hope it helps.
you are right
Ok, I am a bit new in the java / Kubernetes business... I am trying to delete pods / workloads when they are finished:
First I list all the pods using:
V1PodList list = api.listPodForAllNamespaces(null, null, null, null, null, null, null, null, null);
Then check if the pod is finished (item from list.getItems())
if(item.getStatus().getPhase().contains("Succeeded")) {
If that is the case I try to delete it:
api.deleteNamespacedPod(item.getMetadata().getName(), "default", null, new V1DeleteOptions(),null, null, null, null);
Which returns the error message:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2066 path $.status
Is there a less cleaner way of removing these pods? I can perform a continous check to see if they are really deleted but they seem not to be deleted. Also the jobs where the pods reside in, is there a way to remove those?
@jjkoehorst if your pod isn't attached w/ any finalizer, then hitting the exception actually means that your deletion works. it's pod deletion is graceful so the kube-apiserver will return a pod as payload in the response (instead of status object as is prescribed in the openapi spec). the deleted pod will be removed in 30s of graceful period. but if the pod has finalizers, you will have to patch and remove them to complete the deletion. note that we're fixing that by support v3 openapi spec targeting 1.16 release, but it's not a required item.
Ok, I figured out the issue here...
When you delete a StatefulSet (and probably a ReplicaSet too) it initially returns a
StatefulSet
object, but eventually it returns aStatus
object.This means that the Swagger should be
oneOf(StatefulSet, Status)
But the Kubernetes Swagger here:
https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json
Only has the
Status
object.Thus, the generated Java code barfs when it tries to parse a
StatefulSet
object into aStatus
object.Unfortunately
go-restful
when generates the swagger spec doesn't supportoneOf
as far as I know, thus we're going to either need to massage the swagger spec before client generation, improve go-restful's swagger generation or switch to a different way of generating swagger...None of these are great options, and none of them will happen very quickly. So for now, I think the best you can do is catch this Exception and move on...
Sorry!
what the meaning of this?
When you delete a StatefulSet (and probably a ReplicaSet too) it initially returns a StatefulSet object, but eventually it returns a Status object.
Can we capture the last state?
Best Wishes
public V1Status deleteNamespacedPod(String name, String namespace, String pretty, V1DeleteOptions body, String dryRun, Integer gracePeriodSeconds, Boolean orphanDependents, String propagationPolicy) throws ApiException {
ApiResponse<V1Status> resp = deleteNamespacedPodWithHttpInfo(name, namespace, pretty, body, dryRun, gracePeriodSeconds, orphanDependents, propagationPolicy);
return resp.getData();
}
replace with, Can it be solved?
public V1Pod deleteNamespacedPod(String name, String namespace, String pretty, V1DeleteOptions body, String dryRun, Integer gracePeriodSeconds, Boolean orphanDependents, String propagationPolicy) throws ApiException {
ApiResponse<V1Pod> resp = deleteNamespacedPodWithHttpInfo(name, namespace, pretty, body, dryRun, gracePeriodSeconds, orphanDependents, propagationPolicy);
return resp.getData();
}
So I'm running into the same issue as @neuromantik33 from 2017 - trying to delete a namespaced job. It's now been two years - can we get an update? Is try catch still the best approach?
I guess you can use AOP to slip the try/catch in where it is needed...
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale
.
Stale issues rot after an additional 30d of inactivity and eventually close.
If this issue is safe to close now please do so with /close
.
Send feedback to sig-testing, kubernetes/test-infra and/or fejta.
/lifecycle stale
Guys, is there any solution for this one? The issue is still valid for:
kubernetes-client-java: 8.0.0
Kubernetes: v1.15.5
@desember see the comment here:
#86 (comment)
about why this problem can't be solved right now.
we're definitely open to clever solutions if anything occurs to you.
/lifecycle frozen
@brendanburns can you add CRUD operations to the Examples, please? It can spare a lot of time and frustration π. Thanks.
A workaround for this issue will be using GenericKubernetesApi. plz refer to the example by #902
@brendanburns is this also related to the same issue?
I am getting exception when trying to replace PVC (existing PVC is not updated).
The same yaml is used to create the PVC.
Yaml.addModelMap("v1", "PersistentVolumeClaim", V1PersistentVolumeClaim.class);
V1PersistentVolumeClaim v1ClaimYaml = (V1PersistentVolumeClaim)Yaml.load(reader);
log.debug("toString-v1ClaimYaml[{}]", v1ClaimYaml.toString());
V1PersistentVolumeClaim v1Claim = api.replaceNamespacedPersistentVolumeClaim(claimName, K8Config.getNamespace(), v1ClaimYaml, null, null, null);
toString-v1ClaimYaml[class V1PersistentVolumeClaim {
apiVersion: v1
kind: PersistentVolumeClaim
metadata: class V1ObjectMeta {
annotations: null
clusterName: null
creationTimestamp: null
deletionGracePeriodSeconds: null
deletionTimestamp: null
finalizers: null
generateName: null
generation: null
initializers: null
labels: null
managedFields: null
name: test-pvc
namespace: null
ownerReferences: null
resourceVersion: null
selfLink: null
uid: null
}
spec: class V1PersistentVolumeClaimSpec {
accessModes: [ReadWriteOnce]
dataSource: null
resources: class V1ResourceRequirements {
limits: null
requests: {storage=Quantity{number=1073741824, format=BINARY_SI}}
}
selector: null
storageClassName: default
volumeMode: null
volumeName: null
}
status: null
}]
Unable to update PersistentVolumeClaim[test-pvc] Exception[Unprocessable Entity]
io.kubernetes.client.openapi.ApiException: Unprocessable Entity
at io.kubernetes.client.openapi.ApiClient.handleResponse(ApiClient.java:979)
at io.kubernetes.client.openapi.ApiClient.execute(ApiClient.java:895)
at io.kubernetes.client.openapi.apis.CoreV1Api.replaceNamespacedPersistentVolumeClaimWithHttpInfo(CoreV1Api.java:28959)
at io.kubernetes.client.openapi.apis.CoreV1Api.replaceNamespacedPersistentVolumeClaim(CoreV1Api.java:28933)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: default
resources:
requests:
storage: 1Gi
@brendanburns is this also related to the same issue?
I am getting exception when trying to replace PVC (existing PVC is not updated).
The same yaml is used to create the PVC.Yaml.addModelMap("v1", "PersistentVolumeClaim", V1PersistentVolumeClaim.class); V1PersistentVolumeClaim v1ClaimYaml = (V1PersistentVolumeClaim)Yaml.load(reader); log.debug("toString-v1ClaimYaml[{}]", v1ClaimYaml.toString()); V1PersistentVolumeClaim v1Claim = api.replaceNamespacedPersistentVolumeClaim(claimName, K8Config.getNamespace(), v1ClaimYaml, null, null, null);toString-v1ClaimYaml[class V1PersistentVolumeClaim { apiVersion: v1 kind: PersistentVolumeClaim metadata: class V1ObjectMeta { annotations: null clusterName: null creationTimestamp: null deletionGracePeriodSeconds: null deletionTimestamp: null finalizers: null generateName: null generation: null initializers: null labels: null managedFields: null name: test-pvc namespace: null ownerReferences: null resourceVersion: null selfLink: null uid: null } spec: class V1PersistentVolumeClaimSpec { accessModes: [ReadWriteOnce] dataSource: null resources: class V1ResourceRequirements { limits: null requests: {storage=Quantity{number=1073741824, format=BINARY_SI}} } selector: null storageClassName: default volumeMode: null volumeName: null } status: null }] Unable to update PersistentVolumeClaim[test-pvc] Exception[Unprocessable Entity] io.kubernetes.client.openapi.ApiException: Unprocessable Entity at io.kubernetes.client.openapi.ApiClient.handleResponse(ApiClient.java:979) at io.kubernetes.client.openapi.ApiClient.execute(ApiClient.java:895) at io.kubernetes.client.openapi.apis.CoreV1Api.replaceNamespacedPersistentVolumeClaimWithHttpInfo(CoreV1Api.java:28959) at io.kubernetes.client.openapi.apis.CoreV1Api.replaceNamespacedPersistentVolumeClaim(CoreV1Api.java:28933)
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-pvc spec: accessModes: - ReadWriteOnce storageClassName: default resources: requests: storage: 1Gi
You can write like this, you can see the detailed error information
try {
Yaml.addModelMap("v1", "PersistentVolumeClaim", V1PersistentVolumeClaim.class);
V1PersistentVolumeClaim v1ClaimYaml = (V1PersistentVolumeClaim)Yaml.load(reader);
log.debug("toString-v1ClaimYaml[{}]", v1ClaimYaml.toString());
V1PersistentVolumeClaim v1Claim = api.replaceNamespacedPersistentVolumeClaim(claimName, K8Config.getNamespace(), v1ClaimYaml, null, null, null);
} catch (ApiException e) {
log.debug(e.getResponseBody());
e.printStackTrace();
}
Guys,
any updates on this issue, i am getting error on deleting the pod.
api.deleteNamespacedPod(pod.getMetadata().getName(), "default", body, null, null, 30, null, null);
The exception is as below,
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2285 path $.status
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:224)
I debugged into this using GCP Kubernetes v1.16.8-gke.15. It seems that the "status" of the "V1Pod" response in the "deleteNamespacedPod" case is parsed as "V1Status" (as implemented in "deleteNamespacedPodWithHttpInfo") instead of "V1PodStatus" as defined in "V1Pod" which obviously fails.
Anyway it looks like the actual response "V1Pod" does not match the expected response "V1Status" in the client.
IMO this is a severe error in the client which should at least be documented. Since this is known for over two year now...
A possible workaround is (iff your Kubernetes cluster is ALWAYS returning V1Pod instead of V1Status) to reimplement some of the client's convenience methods with the "correct" type, e.g. like this:
private V1Pod deleteNamespacedPod(String name, String namespace, String pretty, String dryRun, Integer gracePeriodSeconds, Boolean orphanDependents, String propagationPolicy, V1DeleteOptions body) throws ApiException {
var core = new CoreV1Api(client);
var call = core.deleteNamespacedPodCall(name, namespace, pretty, dryRun, gracePeriodSeconds, orphanDependents, propagationPolicy, body, null);
return client.<V1Pod>execute(call, (new TypeToken<V1Pod>() {}).getType()).getData();
}
Please note that this implementation is not 100% equivalent to the original "deleteNamespacedPod" method as it is missing some of its validation.
@markusheiden Kubernetes returns both V1Status and the specific object depending on if the delete finished in time.
Delete is a semi-asynchronous operation and what is returned depends on the time the operation takes. You can't rely on it always returning a V1Pod
it will sometimes return V1Status
depending on how long the delete takes.
Unfortunately, the Kubernetes Swagger spec here only specifies one of the types (V1Status
) so that's what gets generated in this client.
@brendandburns Thanks for the details.
A possible workaround is to reimplement some of the client's convenience methods with auto detecting the type, e.g. like this:
private Object deleteNamespacedPod(String name, String namespace, String pretty, String dryRun, Integer gracePeriodSeconds, Boolean orphanDependents, String propagationPolicy, V1DeleteOptions body) throws ApiException, IOException {
var core = new CoreV1Api(client);
var call = core.deleteNamespacedPodCall(name, namespace, pretty, dryRun, gracePeriodSeconds, orphanDependents, propagationPolicy, body, null);
var response = call.execute();
try {
return client.handleResponse(response, (new TypeToken<V1Pod>() {}).getType());
} catch (JsonSyntaxException e) {
return client.handleResponse(response, (new TypeToken<V1Status>() {}).getType());
}
}
Please note that this implementation is not 100% equivalent to the original "deleteNamespacedPod" method as it is missing some of its validation.
Hi, is this issue resoved? or is there any way to avoid this error?