kubernetes-client / c

Official C client library for Kubernetes

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CoreV1API_listPodForAllNamespaces/CoreV1API_listNamespacedPod API return 422 error

KagumiRA opened this issue · comments

Hello, I have problem when I try to run c/examples/list_pod/main.c , the program return
The return code of HTTP request=422
Cannot get any pod.
My k8s client version is "v1.28.2" and server version is "v1.28.2". Please help me debug these problems!

422 means that the body of the request is malformed.

My guess is that your cluster doesn't have a default namespace, but that's a guess.

You should print the body of the response and you will get a more detailed error message.

422 means that the body of the request is malformed.

My guess is that your cluster doesn't have a default namespace, but that's a guess.

You should print the body of the response and you will get a more detailed error message.

Thanks for helping me!! I try running the code under my cluster having default namespace and return same error. How can I print the body of the response? Where do the response exist?

it works using python, but when i use c language, i have the same error. i just change the namespace to my namespace.
pod_list = CoreV1API_listNamespacedPod(apiClient, "dialogue-dev",
NULL, /* pretty /
0, /
allowWatchBookmarks /
NULL, /
continue /
NULL, /
fieldSelector /
NULL, /
labelSelector /
0, /
limit /
NULL, /
resourceVersion /
NULL, /
resourceVersionMatch /
0, /
sendInitialEvents /
0, /
timeoutSeconds /
0 /
watch */
);

i only get the response_code 422, No additional information。

I can reproduce this issue.
Actually this problem also exists in GitHub Action, but we don't parse the return value 422 as an error.
The cause may be some integer type parameters. I'll check it out.

Maybe it helps:
#203

(gdb) p (char *)apiClient->dataReceived
$3 = 0x5555555b0250 "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"ListOptions.meta.k8s.io \\\"\\\" is invalid: sendInitialEvents: Forbidden: sendInitialEvents is forbidden for list\",\"reason\":\"Invalid\",\"details\":{\"group\":\"meta.k8s.io\",\"kind\":\"ListOptions\",\"causes\":[{\"reason\":\"FieldValueForbidden\",\"message\":\"Forbidden: sendInitialEvents is forbidden for list\",\"field\":\"sendInitialEvents\"}]},\"code\":422}\n"

The parameter sendInitialEvents cannot be passed in the function CoreV1API_listNamespacedPod whether set to 0 or 1.

So this issue cannot be fixed due to the current implementation of the C client.

If you want a workaround, please patch the code:

diff --git a/kubernetes/api/CoreV1API.c b/kubernetes/api/CoreV1API.c
index 53cb60a..ddd2fcd 100644
--- a/kubernetes/api/CoreV1API.c
+++ b/kubernetes/api/CoreV1API.c
@@ -22381,7 +22381,7 @@ CoreV1API_listNamespacedPod(apiClient_t *apiClient, char * _namespace , char * p
     char *keyQuery_sendInitialEvents = NULL;
     char * valueQuery_sendInitialEvents = NULL;
     keyValuePair_t *keyPairQuery_sendInitialEvents = 0;
-    if (1) // Always send boolean parameters to the API server
+    if (0) // Always ignore sendInitialEvents
     {
         keyQuery_sendInitialEvents = strdup("sendInitialEvents");
         valueQuery_sendInitialEvents = calloc(1,MAX_NUMBER_LENGTH);

Thanks for helping me. I try to ignore sendInitialEvents, but it still returns 422. I try to print the apiClient->dataReceived in gdb, but it has nothing.

(gdb) p (char *)apiClient->dataReceived 
$1 = 0x0

You have to add a breakpoint at this line:

b CoreV1API.c:22442

to debug the C client library and then print apiClient->dataReceived

https://github.com/kubernetes-client/c/blob/b02e6e5d5865f822d0b19a9be2c306897ae761c1/kubernetes/api/CoreV1API.c#L22442

i ignore sendInitialEvents, it works. thanks for help from ityuhui .

error:
Breakpoint 2, CoreV1API_listNamespacedPod (apiClient=0x555555586390, _namespace=0x555555556008 "dialogue-dev", pretty=0x0, allowWatchBookmarks=0, _continue=0x0, fieldSelector=0x0, labelSelector=0x0, limit=0, resourceVersion=0x0,
resourceVersionMatch=0x0, sendInitialEvents=0, timeoutSeconds=0, watch=0) at /root/k8s-study/c/kubernetes/api/CoreV1API.c:22442
22442 cJSON *CoreV1APIlocalVarJSON = cJSON_Parse(apiClient->dataReceived);
(gdb) n
22443 v1_pod_list_t *elementToReturn = v1_pod_list_parseFromJSON(CoreV1APIlocalVarJSON);
(gdb) p apiClient
$1 = (apiClient_t *) 0x555555586390
(gdb) p *apiClient
$2 = {basePath = 0x55555558ade0 "https://10.150.148.26:6443", sslConfig = 0x555555588090, dataReceived = 0x5555555b9ae0, dataReceivedLen = 412, data_callback_func = 0x0, progress_func = 0x0, progress_data = 0x0, response_code = 422,
apiKeys_BearerToken = 0x5555555700e0}
(gdb) p apiClient->dataReceived
$3 = (void *) 0x5555555b9ae0
(gdb) p *apiClient->dataReceived
Attempt to dereference a generic pointer.
(gdb) p (char *)apiClient->dataReceived
$4 = 0x5555555b9ae0 "{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"ListOptions.meta.k8s.io \"\" is invalid: sendInitialEvents: Forbidden: sendInitialEvents is forbidden for list","reason":"...
(gdb)

it seems all api need ignore sendInitialEvents(for example, CoreV1API_listNamespacedEndpoints)? Is there an official upgrade to address this issue?

Thanks for helping!
I try to print apiClient->dataReceived after adding a breakpoint b CoreV1API.c:22442 with ignoring sendInitialEvents in CoreV1API.c:22381 and CoreV1API.c:20988.
I still get the same result:

(gdb) p (char*)apiClient->dataReceived
$2 = 0x555555669f10 "{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"ListOptions.meta.k8s.io \\\"\\\" is invalid: sendInitialEvents: Forbidden: sendInitialEvents is forbidden for list\",\"reason\":\"Invalid\",\"details\":{\"group\":\"meta.k8s.io\",\"kind\":\"ListOptions\",\"causes\":[{\"reason\":\"FieldValueForbidden\",\"message\":\"Forbidden: sendInitialEvents is forbidden for list\",\"field\":\"sendInitialEvents\"}]},\"code\":422}\n"

At least, we know what problem lead to return 422 in my environment. How can I fix the problem? Thanks!

This problem (whether to send int/boolean type parameters to the API server when their value is 0) has been around for a while and we need to find a solution to fix it.

I have some ideas:

Option 1: Add a flag sendXxx for every int/boolean type parameter xxx to control whether to send xxx to the API server.

e.g.

v1_pod_list_t* CoreV1API_listPodForAllNamespaces(apiClient_t *apiClient, 
                    int sendAllowWatchBookmarks, int allowWatchBookmarks, 
                    char * _continue, char * fieldSelector, char * labelSelector, 
                    int sendLimit, int limit, 
                    char * pretty,  char * resourceVersion, char * resourceVersionMatch, 
                    int sendSendInitialEvents, int sendInitialEvents, 
                    int sendTimeoutSeconds, int timeoutSeconds, 
                    int sendWatch, int watch);

Option 2: Use int *foo for the int/boolean type parameters, if foo == NULL, ignore sending.

e.g.

v1_pod_list_t* CoreV1API_listPodForAllNamespaces(apiClient_t *apiClient,
                    int *pAllowWatchBookmarks, 
                    char * _continue, char * fieldSelector, char * labelSelector, 
                    int *pLimit, 
                    char * pretty, char * resourceVersion, char * resourceVersionMatch, 
                    int *pSendInitialEvents, 
                    int *pTimeoutSeconds, 
                    int *pWatch);

Option 3: Add a parameter alwaysSendIntParameter in apiClient_t

if (apiClilent->alwaysSendIntParameter) {
    always send int/boolean type parameters
} else {
    send the int/boolean type parameters whose value is not `NULL/0`
}

Users need to set apiClilent->alwaysSendIntParameter before calling the API such as CoreV1API_listPodForAllNamespaces

Hi @brendandburns
What do you think of these solutions ?

cc @wing328 @zhemant @michelealbano for early discussion as this change will eventually be made in OpenAPI-Generator/c-libcurl.

I would vote for either

typedef struct {
   bool is_none,
   int value
} optional_int_t;

or using int* with NULL meaning "don't send"

int* is probably easier for clients to deal with the change.

I prefer int* to solve this issue.
What do you think ? @wing328 @zhemant @michelealbano

I would say int * and possibly similar for boolean/any other primitive which is not pointer. Then it is also easy to handle from code generator as it will possibly remove the need of individual type separation

I prefer int* to solve this issue.

Me too.

Thank you for your votes and suggestions !Based on the result of discussion, I'm going to implement the int* solution.

So far, we have been discussing the case in the API function parameter list, but in fact the same problem exists with OpenAPI's model. The detail is in #193

In short, the int/boolean members/fields in a model should also be changed to int* to support the required check:

https://github.com/kubernetes-client/c/blob/b02e6e5d5865f822d0b19a9be2c306897ae761c1/kubernetes/model/v1_daemon_set_status.c#L112C22-L112C22

I'll make this the next phase of work once I resolve this issue.

I also prefer using int*. I am a little worried for all the heap fragmentation it will cause, but it's still the best option. Michele

On Wed, Nov 8, 2023 at 3:26 PM William Cheng @.> wrote: I prefer int to solve this issue. Me too. — Reply to this email directly, view it on GitHub <#209 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC66LHCC5B6N6XU32P2YM6LYDOI7TAVCNFSM6AAAAAA6QQ25POVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMBRHE4TKMRZGU . You are receiving this because you were mentioned.Message ID: @.*>

fwiw, it doesn't have to cause heap fragementation if people use & to pass pointers to stack allocated variables when they make the client calls.

e.g.

int foo;
someApiCall(&foo);