CoreV1API_patchNamespacedPod API returns 422 error,
ReddyArunreddy opened this issue · comments
Hi I'm using CoreV1API_patchNamespacedPod() API to update pod labels but getting 422 error code.
not able to identify the problem. My code is as below.
Pod sample-pod-0 is already present in cluster
#include <kube_config.h>
#include <apiClient.h>
#include <CoreV1API.h>
#include <malloc.h>
#include <stdio.h>
#include <errno.h>
void create_a_pod(apiClient_t * apiClient)
{
char *namespace = "default";
char *body = "[{\"op\": \"replace\", \"path\": \"/metadata/labels/mode\", \"value\": \"stand-by\" }]";
const char *parse_end = NULL;
cJSON *event_json_obj = cJSON_ParseWithOpts(body, &parse_end, 1);
if (!event_json_obj) {
fprintf(stderr, "Cannot create JSON from string: [%s].\n", parse_end);
return;
}
object_t *update_body = object_parseFromJSON(event_json_obj);
printf("obj=%s\n",update_body->temporary);
v1_pod_t *apod = CoreV1API_patchNamespacedPod(apiClient, "sample-pod-0",namespace,update_body , NULL, NULL, NULL,NULL,0);
printf("code=%ld Reci=%s\n", apiClient->response_code,apiClient->dataReceived);
if(apod)
{
printf("Name=%s\n",apod->metadata->name);
printf("Name=%s\n",apod->status->message);
printf("Name=%s\n",apod->status->reason);
printf("Pod_ip=%s\n",apod->status->pod_ip);
printf("kind=%s\n",apod->kind);
}
v1_pod_free(apod);
}
int main(int argc, char *argv[])
{
int rc = 0;
char *baseName = NULL;
sslConfig_t *sslConfig = NULL;
list_t *apiKeys = NULL;
apiClient_t *k8sApiClient = NULL;
rc = load_kube_config(&baseName, &sslConfig, &apiKeys, NULL);
if (0 == rc) {
k8sApiClient = apiClient_create_with_base_path(baseName, sslConfig, apiKeys);
} else {
printf("Cannot load kubernetes configuration.\n");
return -1;
}
if (k8sApiClient) {
create_a_pod(k8sApiClient);
}
free_client_config(baseName, sslConfig, apiKeys);
baseName = NULL;
sslConfig = NULL;
apiKeys = NULL;
apiClient_free(k8sApiClient);
k8sApiClient = NULL;
apiClient_unsetupGlobalEnv();
return 0;
}
I'll check out this issue.
You can enable debugging as follows to check why the request headers/body are invalid (which would give a 422 error):
# If you want to use `gdb` to debug the C client library, add `-DCMAKE_BUILD_TYPE=Debug` to the cmake command line, e.g.
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/local ..
There is a "patch" example that works nicely with a generic client for your reference:
Line 49 in c223563
My guess is that the content-type which is being sent is incorrect. I think that the content-type should be application/merge-patch+json
There's some related info (for the Typescript client) here https://stackoverflow.com/questions/67520468/patch-k8s-custom-resource-with-kubernetes-client-node
Hello,
I tried with generic API and content-type as application/merge-patch+json.
now getting no error but label is not modifying @ityuhui @brendandburns .
it is still showing active only.
const char *patchBody = "{"op": "replace", "path": "/template/spec/metadata/labels/mode", "value": "stand-by" }";
list_t *contentType = list_createList();
// Kubernetes supports multiple content types:
list_addElement(contentType, "application/merge-patch+json");
char *patch = Generic_patchNamespacedResource(genericClient,"default", "sample-pod", patchBody, NULL, NULL, NULL, NULL, contentType);
printf("PATCH=%s\n", patch);
OUTPUT:
OK
PATCH={"kind":"StatefulSet","apiVersion":"apps/v1","metadata":{"name":"sample-pod","namespace":"default","uid":"d74b2293-f87e-4eb9-a964-6ef1af46468f","resourceVersion":"6765553","generation":1,"creationTimestamp":"2023-06-16T06:52:00Z","labels":{"mode":"stand-by"},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{"apiVersion":"apps/v1","kind":"StatefulSet","metadata":{"annotations":{},"name":"sample-pod","namespace":"default"},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"sample-pod"}},"serviceName":"sample-pod","template":{"metadata":{"labels":{"app":"sample-pod","mode":"active"}},"spec":{"containers":[{"image":"k8_docker_server_test_image","imagePullPolicy":"IfNotPresent","name":"sample-pod1"}]}}}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"apps/v1","time":"2023-06-16T06:52:00Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:spec":{"f:podManagementPolicy":{},"f:replicas":{},"f:revisionHistoryLimit":{},"f:selector":{},"f:serviceName":{},"f:template":{"f:metadata":{"f:labels":{".":{},"f:app":{},"f:mode":{}}},"f:spec":{"f:containers":{"k:{"name":"sample-pod1"}":{".":{},"f:image":{},"f:imagePullPolicy":{},"f:name":{},"f:resources":{},"f:terminationMessagePath":{},"f:terminationMessagePolicy":{}}},"f:dnsPolicy":{},"f:restartPolicy":{},"f:schedulerName":{},"f:securityContext":{},"f:terminationGracePeriodSeconds":{}}},"f:updateStrategy":{"f:rollingUpdate":{".":{},"f:partition":{}},"f:type":{}}}}},{"manager":"kube-controller-manager","operation":"Update","apiVersion":"apps/v1","time":"2023-06-16T06:52:02Z","fieldsType":"FieldsV1","fieldsV1":{"f:status":{"f:availableReplicas":{},"f:collisionCount":{},"f:currentReplicas":{},"f:currentRevision":{},"f:observedGeneration":{},"f:readyReplicas":{},"f:replicas":{},"f:updateRevision":{},"f:updatedReplicas":{}}},"subresource":"status"},{"manager":"unknown","operation":"Update","apiVersion":"apps/v1","time":"2023-06-19T05:09:52Z","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:labels":{".":{},"f:mode":{}}}}}]},"spec":{"replicas":1,"selector":{"matchLabels":{"app":"sample-pod"}},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"sample-pod","mode":"active"}},"spec":{"containers":[{"name":"sample-pod1","image":"k8_docker_server_test_image","resources":{},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","securityContext":{},"schedulerName":"default-scheduler"}},"serviceName":"sample-pod","podManagementPolicy":"OrderedReady","updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}},"revisionHistoryLimit":10},"status":{"observedGeneration":1,"replicas":1,"readyReplicas":1,"currentReplicas":1,"updatedReplicas":1,"currentRevision":"sample-pod-948ff7778","updateRevision":"sample-pod-948ff7778","collisionCount":0,"availableReplicas":1}}
I tried using the following code, it works:
genericClient_t *genericClient = genericClient_create(apiClient, NULL, "v1", "pods");
const char *patchBody = "[{\"op\": \"replace\", \"path\": \"/metadata/labels/mode\", \"value\": \"stand-by\" }]";
list_t *contentType = list_createList();
list_addElement(contentType, "application/json-patch+json");
char *patch = Generic_patchNamespacedResource(genericClient, "default", "test-pod-8", patchBody, NULL, NULL, NULL, NULL, contentType);
...
I think application/merge-patch+json
can also work with patchBody in some other formats.
FYI
CoreV1API_patchNamespacedPod
returns 422 because:
A query parameter force
is sent to API server in CoreV1API_patchNamespacedPod
, but this field is forbidden:
{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"PatchOptions.meta.k8s.io \"\" is invalid: force: Forbidden: may not be specified for non-apply patch","reason":"Invalid","details":{"group":"meta.k8s.io","kind":"PatchOptions","causes":[{"reason":"FieldValueForbidden","message":"Forbidden: may not be specified for non-apply patch","field":"force"}]},"code":422}
The C client cannot stop sending because there is a limitation that we have to send "int" type parameter at any time. #176 (comment)
Please use the generic client for patching now.
Yes it working with generic API.
Thank you for support @ityuhui @brendandburns .
closing this as the issue is resolved (at least as resolved as it can be given #176)