kubernetes-client / c

Official C client library for Kubernetes
Apache License 2.0
141 stars 45 forks source link

CoreV1API_listPodForAllNamespaces/CoreV1API_listNamespacedPod API return 422 error #209

Closed KagumiRA closed 6 months ago

KagumiRA commented 8 months ago

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!

brendandburns commented 8 months ago

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.

KagumiRA commented 8 months ago

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?

Hgary commented 8 months ago

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 / );

Hgary commented 8 months ago

i only get the response_code 422, No additional information。

ityuhui commented 8 months ago

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: https://github.com/kubernetes-client/c/issues/203

ityuhui commented 8 months ago
(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);
KagumiRA commented 8 months ago

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
ityuhui commented 8 months ago

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

Hgary commented 8 months ago

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)

Hgary commented 8 months ago

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

KagumiRA commented 8 months ago

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!

ityuhui commented 8 months ago

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.

brendandburns commented 8 months ago

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.

ityuhui commented 8 months ago

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

zhemant commented 7 months ago

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

wing328 commented 7 months ago

I prefer int* to solve this issue.

Me too.

michelealbano commented 7 months ago

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 https://github.com/kubernetes-client/c/issues/209#issuecomment-1801995295, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC66LHCC5B6N6XU32P2YM6LYDOI7TAVCNFSM6AAAAAA6QQ25POVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMBRHE4TKMRZGU . You are receiving this because you were mentioned.Message ID: @.***>

ityuhui commented 7 months ago

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 https://github.com/kubernetes-client/c/issues/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.

brendandburns commented 7 months ago

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);