From 6d3bd661215f3f2c575eca4247bbd4d5a3a30c24 Mon Sep 17 00:00:00 2001 From: DanyT Date: Mon, 1 Jul 2024 18:55:51 +0300 Subject: [PATCH 01/10] add support to load kubernetes configuration for memory buffer - existing api is not changed - load_kube_config works as before - extend kubeconfig_t to hold in memory buffer - make a common flow for file/buffer code - set fileName/buffer members accordingly - provide new api: load_kube_config_buffer --- kubernetes/config/kube_config.c | 51 ++++++++++++++++++++++----- kubernetes/config/kube_config.h | 38 ++++++++++++++++++++ kubernetes/config/kube_config_model.c | 4 +++ kubernetes/config/kube_config_model.h | 1 + kubernetes/config/kube_config_yaml.c | 14 ++++++-- kubernetes/config/kube_config_yaml.h | 4 ++- 6 files changed, 99 insertions(+), 13 deletions(-) diff --git a/kubernetes/config/kube_config.c b/kubernetes/config/kube_config.c index 115f2088..5383c650 100644 --- a/kubernetes/config/kube_config.c +++ b/kubernetes/config/kube_config.c @@ -304,21 +304,14 @@ static int kuberconfig_auth_provider(kubeconfig_property_t * current_user, kubec return rc; } -int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, const char *configFileName) +int load_kube_config_common(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, kubeconfig_t *kubeconfig) { - static char fname[] = "load_kube_config()"; + static char fname[] = "load_kube_config_common()"; int rc = 0; const kubeconfig_property_t *current_context = NULL; const kubeconfig_property_t *current_cluster = NULL; kubeconfig_property_t *current_user = NULL; - kubeconfig_t *kubeconfig = kubeconfig_create(); - if (!kubeconfig) { - fprintf(stderr, "%s: Cannot create kubeconfig.[%s]\n", fname, strerror(errno)); - return -1; - } - - kubeconfig->fileName = getWorkingConfigFile(configFileName); rc = kubeyaml_load_kubeconfig(kubeconfig); if (0 != rc) { fprintf(stderr, "%s: Cannot load the kubeconfig %s\n", fname, kubeconfig->fileName); @@ -393,8 +386,48 @@ int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApi } end: + return rc; +} + +int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, const char *configFileName) +{ + static char fname[] = "load_kube_config()"; + int rc = 0; + + kubeconfig_t *kubeconfig = kubeconfig_create(); + if (!kubeconfig) { + fprintf(stderr, "%s: Cannot create kubeconfig.[%s]\n", fname, strerror(errno)); + return -1; + } + + kubeconfig->fileName = getWorkingConfigFile(configFileName); + + rc = load_kube_config_common(pBasePath, pSslConfig, pApiKeys, kubeconfig); + + kubeconfig_free(kubeconfig); + kubeconfig = NULL; + + return rc; +} + +int load_kube_config_buffer(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, const char *buffer) +{ + static char fname[] = "load_kube_config_buffer()"; + int rc = 0; + + kubeconfig_t *kubeconfig = kubeconfig_create(); + if (!kubeconfig) { + fprintf(stderr, "%s: Cannot create kubeconfig.[%s]\n", fname, strerror(errno)); + return -1; + } + + kubeconfig->buffer = strdup(buffer); + + rc = load_kube_config_common(pBasePath, pSslConfig, pApiKeys, kubeconfig); + kubeconfig_free(kubeconfig); kubeconfig = NULL; + return rc; } diff --git a/kubernetes/config/kube_config.h b/kubernetes/config/kube_config.h index 9d29f729..31d06054 100644 --- a/kubernetes/config/kube_config.h +++ b/kubernetes/config/kube_config.h @@ -46,6 +46,44 @@ extern "C" { int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, const char *configFileName); +/* + * load_kube_config_buffer + * + * + * Description: + * + * + * Load kubernetes cluster configuration from specfied buffer + * + * + * Return: + * + * 0 Success + * -1 Failed + * + * + * Parameter: + * + * + * IN: + + * buffer : kubernetes cluster configuration data + * + * + * OUT: + * + * pBasePath: The pointer to API server address + * pSslConfig: The pointer to SSL configuration for client + * pApiKeys: The pointer to API tokens for client + * + * The memory will be allocated inside this function. User + * should call free_client_config to free the memory after + * these parameters are not used. + * + */ + + int load_kube_config_buffer(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, const char *buffer); + /* * free_client_config * diff --git a/kubernetes/config/kube_config_model.c b/kubernetes/config/kube_config_model.c index 8076c596..e162c09b 100644 --- a/kubernetes/config/kube_config_model.c +++ b/kubernetes/config/kube_config_model.c @@ -224,6 +224,10 @@ void kubeconfig_free(kubeconfig_t * kubeconfig) free(kubeconfig->fileName); kubeconfig->fileName = NULL; } + if (kubeconfig->buffer) { + free(kubeconfig->buffer); + kubeconfig->buffer = NULL; + } if (kubeconfig->apiVersion) { free(kubeconfig->apiVersion); kubeconfig->apiVersion = NULL; diff --git a/kubernetes/config/kube_config_model.h b/kubernetes/config/kube_config_model.h index 45833a21..6bae4ada 100644 --- a/kubernetes/config/kube_config_model.h +++ b/kubernetes/config/kube_config_model.h @@ -88,6 +88,7 @@ extern "C" { typedef struct kubeconfig_t { char *fileName; + char *buffer; char *apiVersion; char *preferences; char *kind; diff --git a/kubernetes/config/kube_config_yaml.c b/kubernetes/config/kube_config_yaml.c index 3007f6eb..21ffe293 100644 --- a/kubernetes/config/kube_config_yaml.c +++ b/kubernetes/config/kube_config_yaml.c @@ -430,7 +430,7 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) { static char fname[] = "kubeyaml_load_kubeconfig()"; - /* Set a file input. */ + /* Set a file input or use the provided buffer. */ FILE *input = NULL; if (kubeconfig->fileName) { input = fopen(kubeconfig->fileName, "rb"); @@ -438,17 +438,25 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) fprintf(stderr, "%s: Cannot open the file %s.[%s]\n", fname, kubeconfig->fileName, strerror(errno)); return -1; } + else if (kubeconfig->buffer) { + // Nothing to do here for now. + } } else { fprintf(stderr, "%s: The kubeconf file name needs be set by kubeconfig->fileName .\n", fname); return -1; } + /* Create the Parser object. */ yaml_parser_t parser; yaml_document_t document; - /* Create the Parser object. */ yaml_parser_initialize(&parser); - yaml_parser_set_input_file(&parser, input); + if (input) { + yaml_parser_set_input_file(&parser, input); + } + else { + yaml_parser_set_input_string(&parser, (const unsigned char*)kubeconfig->buffer, strlen(kubeconfig->buffer)); + } int done = 0; while (!done) { diff --git a/kubernetes/config/kube_config_yaml.h b/kubernetes/config/kube_config_yaml.h index b162b5cf..eb093556 100644 --- a/kubernetes/config/kube_config_yaml.h +++ b/kubernetes/config/kube_config_yaml.h @@ -24,13 +24,15 @@ extern "C" { * * IN: * kubeconfig->fileName: kubernetes cluster configuration file name - * + * kubeconfig->buffer: kubernetes cluster configuration data; this is considered only if kubeconfig->fileName is set to NULL + * * OUT: * kubeconfig: kubernetes cluster configuration * */ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig); + /* * kubeyaml_parse_exec_crendential * From 8f759fcfb7a41f3993331ad1d4c68237430828be Mon Sep 17 00:00:00 2001 From: DanyT Date: Tue, 2 Jul 2024 11:58:32 +0300 Subject: [PATCH 02/10] fix typo close filehandle only if we opened one --- kubernetes/config/kube_config.c | 2 +- kubernetes/config/kube_config_yaml.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/kubernetes/config/kube_config.c b/kubernetes/config/kube_config.c index 5383c650..c32ce1a4 100644 --- a/kubernetes/config/kube_config.c +++ b/kubernetes/config/kube_config.c @@ -314,7 +314,7 @@ int load_kube_config_common(char **pBasePath, sslConfig_t ** pSslConfig, list_t rc = kubeyaml_load_kubeconfig(kubeconfig); if (0 != rc) { - fprintf(stderr, "%s: Cannot load the kubeconfig %s\n", fname, kubeconfig->fileName); + fprintf(stderr, "%s: Cannot load the kubeconfig %s\n", fname, kubeconfig->fileName?kubeconfig->fileName:kubeconfig->buffer); rc = -1; goto end; } diff --git a/kubernetes/config/kube_config_yaml.c b/kubernetes/config/kube_config_yaml.c index 21ffe293..94421f97 100644 --- a/kubernetes/config/kube_config_yaml.c +++ b/kubernetes/config/kube_config_yaml.c @@ -438,10 +438,11 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) fprintf(stderr, "%s: Cannot open the file %s.[%s]\n", fname, kubeconfig->fileName, strerror(errno)); return -1; } + } else if (kubeconfig->buffer) { // Nothing to do here for now. } - } else { + else { fprintf(stderr, "%s: The kubeconf file name needs be set by kubeconfig->fileName .\n", fname); return -1; } @@ -477,12 +478,16 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) /* Cleanup */ yaml_parser_delete(&parser); - fclose(input); + if (input) { + fclose(input); + } return 0; error: yaml_parser_delete(&parser); - fclose(input); + if (input) { + fclose(input); + } return -1; } From 34d1b13efe0d9d1d31db8ed2ba2a782a0f833fb9 Mon Sep 17 00:00:00 2001 From: DanyT Date: Wed, 3 Jul 2024 09:18:24 +0300 Subject: [PATCH 03/10] Check that only one of the kubeconfig_t::fileName and kubeconfig_t::buffer is set Add documentation note stating that only of the kubeconfig_t::fileName and kubeconfig_t::buffer may be set --- kubernetes/config/kube_config_yaml.c | 7 ++++++- kubernetes/config/kube_config_yaml.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/kubernetes/config/kube_config_yaml.c b/kubernetes/config/kube_config_yaml.c index 94421f97..fbd229af 100644 --- a/kubernetes/config/kube_config_yaml.c +++ b/kubernetes/config/kube_config_yaml.c @@ -430,6 +430,11 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) { static char fname[] = "kubeyaml_load_kubeconfig()"; + if (kubeconfig->fileName && kubeconfig->buffer) { + fprintf(stderr, "%s: Cannot use both kubeconfig->fileName and kubeconfig->buffer.\n", fname); + return -1; + } + /* Set a file input or use the provided buffer. */ FILE *input = NULL; if (kubeconfig->fileName) { @@ -443,7 +448,7 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) // Nothing to do here for now. } else { - fprintf(stderr, "%s: The kubeconf file name needs be set by kubeconfig->fileName .\n", fname); + fprintf(stderr, "%s: One of the kubeconfig->fileName or kubeconfig->buffer needs to be set.\n", fname); return -1; } diff --git a/kubernetes/config/kube_config_yaml.h b/kubernetes/config/kube_config_yaml.h index eb093556..325deb9e 100644 --- a/kubernetes/config/kube_config_yaml.h +++ b/kubernetes/config/kube_config_yaml.h @@ -26,6 +26,8 @@ extern "C" { * kubeconfig->fileName: kubernetes cluster configuration file name * kubeconfig->buffer: kubernetes cluster configuration data; this is considered only if kubeconfig->fileName is set to NULL * + * Note: One may use either kubeconfig->fileName or kubeconfig->buffer but not both at the same time. + * * OUT: * kubeconfig: kubernetes cluster configuration * From 4a19bc2a5f153bfdb01bffe38b3021120d2842ef Mon Sep 17 00:00:00 2001 From: DanyT Date: Wed, 3 Jul 2024 18:48:51 +0300 Subject: [PATCH 04/10] add support to free a stack based allocated kubeconfig_t --- kubernetes/config/kube_config.c | 28 ++++++++++----------------- kubernetes/config/kube_config_model.c | 11 ++++++++++- kubernetes/config/kube_config_model.h | 8 ++++++++ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/kubernetes/config/kube_config.c b/kubernetes/config/kube_config.c index c32ce1a4..d8732d7b 100644 --- a/kubernetes/config/kube_config.c +++ b/kubernetes/config/kube_config.c @@ -394,18 +394,14 @@ int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApi static char fname[] = "load_kube_config()"; int rc = 0; - kubeconfig_t *kubeconfig = kubeconfig_create(); - if (!kubeconfig) { - fprintf(stderr, "%s: Cannot create kubeconfig.[%s]\n", fname, strerror(errno)); - return -1; - } + kubeconfig_t kubeconfig; + memset(&kubeconfig, 0, sizeof(kubeconfig_t)); - kubeconfig->fileName = getWorkingConfigFile(configFileName); + kubeconfig.fileName = getWorkingConfigFile(configFileName); - rc = load_kube_config_common(pBasePath, pSslConfig, pApiKeys, kubeconfig); + rc = load_kube_config_common(pBasePath, pSslConfig, pApiKeys, &kubeconfig); - kubeconfig_free(kubeconfig); - kubeconfig = NULL; + kubeconfig_free_members(&kubeconfig); return rc; } @@ -415,18 +411,14 @@ int load_kube_config_buffer(char **pBasePath, sslConfig_t ** pSslConfig, list_t static char fname[] = "load_kube_config_buffer()"; int rc = 0; - kubeconfig_t *kubeconfig = kubeconfig_create(); - if (!kubeconfig) { - fprintf(stderr, "%s: Cannot create kubeconfig.[%s]\n", fname, strerror(errno)); - return -1; - } + kubeconfig_t kubeconfig; + memset(&kubeconfig, 0, sizeof(kubeconfig_t)); - kubeconfig->buffer = strdup(buffer); + kubeconfig.buffer = strdup(buffer); - rc = load_kube_config_common(pBasePath, pSslConfig, pApiKeys, kubeconfig); + rc = load_kube_config_common(pBasePath, pSslConfig, pApiKeys, &kubeconfig); - kubeconfig_free(kubeconfig); - kubeconfig = NULL; + kubeconfig_free_members(&kubeconfig); return rc; } diff --git a/kubernetes/config/kube_config_model.c b/kubernetes/config/kube_config_model.c index e162c09b..bcf54094 100644 --- a/kubernetes/config/kube_config_model.c +++ b/kubernetes/config/kube_config_model.c @@ -214,7 +214,7 @@ kubeconfig_t *kubeconfig_create() return config; } -void kubeconfig_free(kubeconfig_t * kubeconfig) +void kubeconfig_free_members(kubeconfig_t * kubeconfig) { if (!kubeconfig) { return; @@ -256,6 +256,15 @@ void kubeconfig_free(kubeconfig_t * kubeconfig) kubeconfig_properties_free(kubeconfig->contexts, kubeconfig->contexts_count); kubeconfig->contexts = NULL; } +} + +void kubeconfig_free(kubeconfig_t * kubeconfig) +{ + if (!kubeconfig) { + return; + } + + kubeconfig_free_members(kubeconfig); free(kubeconfig); } diff --git a/kubernetes/config/kube_config_model.h b/kubernetes/config/kube_config_model.h index 6bae4ada..8915f5c7 100644 --- a/kubernetes/config/kube_config_model.h +++ b/kubernetes/config/kube_config_model.h @@ -113,9 +113,17 @@ extern "C" { kubeconfig_property_t **kubeconfig_properties_create(int contexts_count, kubeconfig_property_type_t type); void kubeconfig_properties_free(kubeconfig_property_t ** properties, int properties_count); + // allocate kubeconfig_t structure on heap kubeconfig_t *kubeconfig_create(); + + // free a kubeconfig_t structure allocated on heap by a call to kubeconfig_create void kubeconfig_free(kubeconfig_t * kubeconfig); + // free internal members of a kubeconfig_t structure. + // used when releasing resources for a kubeconfig_t that was not allocated using kubeconfig_create + // for example a kubeconfig_t allocated on stack + void kubeconfig_free_members(kubeconfig_t * kubeconfig); + #ifdef __cplusplus } #endif From 70f05e512c2be86109c5bbe8ad2d58cbb3061395 Mon Sep 17 00:00:00 2001 From: DanyT Date: Fri, 5 Jul 2024 07:55:42 +0300 Subject: [PATCH 05/10] resolve code-sytle-check issues --- kubernetes/config/kube_config.c | 4 ++-- kubernetes/config/kube_config_yaml.c | 11 ++++------- kubernetes/config/kube_config_yaml.h | 1 - 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/kubernetes/config/kube_config.c b/kubernetes/config/kube_config.c index d8732d7b..f6085820 100644 --- a/kubernetes/config/kube_config.c +++ b/kubernetes/config/kube_config.c @@ -304,7 +304,7 @@ static int kuberconfig_auth_provider(kubeconfig_property_t * current_user, kubec return rc; } -int load_kube_config_common(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, kubeconfig_t *kubeconfig) +int load_kube_config_common(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, kubeconfig_t * kubeconfig) { static char fname[] = "load_kube_config_common()"; int rc = 0; @@ -314,7 +314,7 @@ int load_kube_config_common(char **pBasePath, sslConfig_t ** pSslConfig, list_t rc = kubeyaml_load_kubeconfig(kubeconfig); if (0 != rc) { - fprintf(stderr, "%s: Cannot load the kubeconfig %s\n", fname, kubeconfig->fileName?kubeconfig->fileName:kubeconfig->buffer); + fprintf(stderr, "%s: Cannot load the kubeconfig %s\n", fname, kubeconfig->fileName ? kubeconfig->fileName : kubeconfig->buffer); rc = -1; goto end; } diff --git a/kubernetes/config/kube_config_yaml.c b/kubernetes/config/kube_config_yaml.c index fbd229af..33ac0276 100644 --- a/kubernetes/config/kube_config_yaml.c +++ b/kubernetes/config/kube_config_yaml.c @@ -443,11 +443,9 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) fprintf(stderr, "%s: Cannot open the file %s.[%s]\n", fname, kubeconfig->fileName, strerror(errno)); return -1; } - } - else if (kubeconfig->buffer) { + } else if (kubeconfig->buffer) { // Nothing to do here for now. - } - else { + } else { fprintf(stderr, "%s: One of the kubeconfig->fileName or kubeconfig->buffer needs to be set.\n", fname); return -1; } @@ -459,9 +457,8 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) yaml_parser_initialize(&parser); if (input) { yaml_parser_set_input_file(&parser, input); - } - else { - yaml_parser_set_input_string(&parser, (const unsigned char*)kubeconfig->buffer, strlen(kubeconfig->buffer)); + } else { + yaml_parser_set_input_string(&parser, (const unsigned char *) kubeconfig->buffer, strlen(kubeconfig->buffer)); } int done = 0; diff --git a/kubernetes/config/kube_config_yaml.h b/kubernetes/config/kube_config_yaml.h index 325deb9e..82bb73ee 100644 --- a/kubernetes/config/kube_config_yaml.h +++ b/kubernetes/config/kube_config_yaml.h @@ -34,7 +34,6 @@ extern "C" { */ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig); - /* * kubeyaml_parse_exec_crendential * From 1d79e0f4f6b98f97f47233c8720b6f63d65a1d43 Mon Sep 17 00:00:00 2001 From: DanyT Date: Fri, 5 Jul 2024 09:25:16 +0300 Subject: [PATCH 06/10] add example for load_kube_config_buffer --- examples/Makefile | 3 + .../list_pod_by_exec_provider.c~ | 71 +++++++++ examples/exec_provider/my_exec_provider.c~ | 44 ++++++ examples/list_pod_buffer/.gitignore | 1 + examples/list_pod_buffer/CMakeLists.txt | 4 + examples/list_pod_buffer/Makefile | 17 +++ examples/list_pod_buffer/main.c | 141 ++++++++++++++++++ 7 files changed, 281 insertions(+) create mode 100644 examples/exec_provider/list_pod_by_exec_provider.c~ create mode 100644 examples/exec_provider/my_exec_provider.c~ create mode 100644 examples/list_pod_buffer/.gitignore create mode 100644 examples/list_pod_buffer/CMakeLists.txt create mode 100644 examples/list_pod_buffer/Makefile create mode 100644 examples/list_pod_buffer/main.c diff --git a/examples/Makefile b/examples/Makefile index 65fcf94f..b2c6eefc 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,6 +2,7 @@ all: cd create_pod; make cd list_pod_with_invalid_kubeconfig; make cd list_pod; make + cd list_pod_buffer; make cd list_pod_incluster; make cd delete_pod; make cd exec_provider; make @@ -18,6 +19,7 @@ clean: cd create_pod; make clean cd list_pod_with_invalid_kubeconfig; make clean cd list_pod; make clean + cd list_pod_buffer; make clean cd list_pod_incluster; make clean cd delete_pod; make clean cd exec_provider; make clean @@ -35,6 +37,7 @@ test: kubectl wait --for=condition=ready --all pod -n default --timeout=60s cd list_pod_with_invalid_kubeconfig; make test cd list_pod; make test + cd list_pod_buffer; make test cd delete_pod; make test kubectl wait --for=delete pod/test-pod-6 -n default --timeout=120s cd list_secret; make test diff --git a/examples/exec_provider/list_pod_by_exec_provider.c~ b/examples/exec_provider/list_pod_by_exec_provider.c~ new file mode 100644 index 00000000..721b2a02 --- /dev/null +++ b/examples/exec_provider/list_pod_by_exec_provider.c~ @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include + +void list_pod(apiClient_t * apiClient) +{ + v1_pod_list_t *pod_list = NULL; + pod_list = CoreV1API_listNamespacedPod(apiClient, "default", /*namespace */ + NULL, /* pretty */ + NULL, /* allowWatchBookmarks */ + NULL, /* continue */ + NULL, /* fieldSelector */ + NULL, /* labelSelector */ + NULL, /* limit */ + NULL, /* resourceVersion */ + NULL, /* resourceVersionMatch */ + NULL, /* sendInitialEvents */ + NULL, /* timeoutSeconds */ + NULL /* watch */ + ); + printf("The return code of HTTP request=%ld\n", apiClient->response_code); + if (pod_list) { + printf("Get pod list:\n"); + listEntry_t *listEntry = NULL; + v1_pod_t *pod = NULL; + list_ForEach(listEntry, pod_list->items) { + pod = listEntry->data; + printf("\tThe pod name: %s\n", pod->metadata->name); + } + v1_pod_list_free(pod_list); + pod_list = NULL; + } else { + printf("Cannot get any pod.\n"); + } +} + +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, "./config_with_exec_provider"); + if (0 == rc) { + k8sApiClient = apiClient_create_with_base_path(baseName, sslConfig, apiKeys); + } else { + printf("Cannot load kubernetes configuration.\n"); + return -1; + } + + if (k8sApiClient) { + list_pod(k8sApiClient); + } + + free_client_config(baseName, sslConfig, apiKeys); + baseName = NULL; + sslConfig = NULL; + apiKeys = NULL; + + apiClient_free(k8sApiClient); + k8sApiClient = NULL; + apiClient_unsetupGlobalEnv(); + + return rc; +} diff --git a/examples/exec_provider/my_exec_provider.c~ b/examples/exec_provider/my_exec_provider.c~ new file mode 100644 index 00000000..b0d48448 --- /dev/null +++ b/examples/exec_provider/my_exec_provider.c~ @@ -0,0 +1,44 @@ +#define _GNU_SOURCE +#include +#include +#include + +#define ENV_EXEC_CLIENT_CERTIFICATE_DATA "exec_client_certificate_data" +#define ENV_EXEC_CLIENT_PRIVATE_KEY "exec_client_private_key" + +char token_template[] = "\ +{\ + \"apiVersion\": \"client.authentication.k8s.io/v1beta1\",\ + \"kind\": \"ExecCredential\",\ + \"status\": {\ + \"token\": \"%s\"\ + }\ +}"; + +char certificate_template[] = "\ +{\ + \"apiVersion\": \"client.authentication.k8s.io/v1beta1\",\ + \"kind\": \"ExecCredential\",\ + \"status\": {\ + \"clientCertificateData\": \"%s\",\ + \"clientKeyData\": \"%s\"\ + }\ +}"; + +int main(int argc, char *argv[]) +{ + const char *client_certificate_data = secure_getenv(ENV_EXEC_CLIENT_CERTIFICATE_DATA); + const char *client_private_key = secure_getenv(ENV_EXEC_CLIENT_PRIVATE_KEY); + + if ((4 == argc) && argv[3]) { + // token is passed by command line argument + printf(token_template, argv[3]); + } else if ((client_certificate_data) && strlen(client_certificate_data) > 0 && (client_private_key) && strlen(client_private_key) > 0) { + // client certificate and private key are passed by environment variables + printf(certificate_template, client_certificate_data, client_private_key); + } else { + printf("Cannot get authentication data\n"); + } + + return 0; +} diff --git a/examples/list_pod_buffer/.gitignore b/examples/list_pod_buffer/.gitignore new file mode 100644 index 00000000..48417105 --- /dev/null +++ b/examples/list_pod_buffer/.gitignore @@ -0,0 +1 @@ +list_pod_buffer_bin diff --git a/examples/list_pod_buffer/CMakeLists.txt b/examples/list_pod_buffer/CMakeLists.txt new file mode 100644 index 00000000..46a76bab --- /dev/null +++ b/examples/list_pod_buffer/CMakeLists.txt @@ -0,0 +1,4 @@ +find_package(${pkgName} CONFIG REQUIRED COMPONENTS ${pkgName}) + +add_executable(list_pod_buffer main.c) +target_link_libraries(list_pod_buffer PRIVATE ${pkgName}::${pkgName}) \ No newline at end of file diff --git a/examples/list_pod_buffer/Makefile b/examples/list_pod_buffer/Makefile new file mode 100644 index 00000000..efaafc58 --- /dev/null +++ b/examples/list_pod_buffer/Makefile @@ -0,0 +1,17 @@ +INCLUDE:=-I../../kubernetes/ -I/usr/local/include/kubernetes/ +LIBS:=-L../../kubernetes/build -lyaml -lwebsockets -lkubernetes -L/usr/local/lib +CFLAGS:=-g +BIN:=list_pod_buffer_bin + +.PHONY : all clean test memcheck +all: + gcc main.c $(CFLAGS) $(INCLUDE) $(LIBS) -o $(BIN) + +test: + ./$(BIN) + +memcheck: + valgrind --tool=memcheck --leak-check=full ./$(BIN) + +clean: + rm ./$(BIN) diff --git a/examples/list_pod_buffer/main.c b/examples/list_pod_buffer/main.c new file mode 100644 index 00000000..b1475c0b --- /dev/null +++ b/examples/list_pod_buffer/main.c @@ -0,0 +1,141 @@ +#include +#include +#include + +#define ENV_KUBECONFIG "KUBECONFIG" +#ifndef _WIN32 +#define ENV_HOME "HOME" +#else +#define ENV_HOME "USERPROFILE" +#endif + +#define KUBE_CONFIG_DEFAULT_LOCATION "%s/.kube/config" + +static char *getWorkingConfigFile(const char *configFileNamePassedIn) +{ + char *configFileName = NULL; + const char *kubeconfig_env = NULL; + const char *homedir_env = NULL; + + if (configFileNamePassedIn) { + configFileName = strdup(configFileNamePassedIn); + } else { +#if defined(HAVE_SECURE_GETENV) + kubeconfig_env = secure_getenv(ENV_KUBECONFIG); +#elif defined(HAVE_GETENV) + kubeconfig_env = getenv(ENV_KUBECONFIG); +#endif + if (kubeconfig_env) { + configFileName = strdup(kubeconfig_env); + } else { +#if defined(HAVE_SECURE_GETENV) + homedir_env = secure_getenv(ENV_HOME); +#elif defined(HAVE_GETENV) + homedir_env = getenv(ENV_HOME); +#endif + if (homedir_env) { + int configFileNameSize = strlen(homedir_env) + strlen(KUBE_CONFIG_DEFAULT_LOCATION) + 1; + configFileName = calloc(configFileNameSize, sizeof(char)); + if (configFileName) { + snprintf(configFileName, configFileNameSize, KUBE_CONFIG_DEFAULT_LOCATION, homedir_env); + } + } + } + } + + return configFileName; +} + +static char *getFileData(const char *filePath) +{ + char *data = NULL; + char *kubeConfigFile = getWorkingConfigFile(filePath); + if (kubeConfigFile) { + FILE *kubeFile = fopen(kubeConfigFile, "r"); + if (kubeFile) { + fseek(kubeFile, 0, SEEK_END); + long fsize = ftell(kubeFile); + fseek(kubeFile, 0, SEEK_SET); + + data = calloc(1, fsize + 1); + if (data) { + fread(data, 1, fsize, kubeFile); + } + + fclose(kubeFile); + } + free(kubeConfigFile); + } + + return data; +} + +void list_pod(apiClient_t * apiClient) +{ + v1_pod_list_t *pod_list = NULL; + pod_list = CoreV1API_listNamespacedPod(apiClient, "default", /*namespace */ + NULL, /* pretty */ + NULL, /* allowWatchBookmarks */ + NULL, /* continue */ + NULL, /* fieldSelector */ + NULL, /* labelSelector */ + NULL, /* limit */ + NULL, /* resourceVersion */ + NULL, /* resourceVersionMatch */ + NULL, /* sendInitialEvents */ + NULL, /* timeoutSeconds */ + NULL /* watch */ + ); + printf("The return code of HTTP request=%ld\n", apiClient->response_code); + if (pod_list) { + printf("Get pod list:\n"); + listEntry_t *listEntry = NULL; + v1_pod_t *pod = NULL; + list_ForEach(listEntry, pod_list->items) { + pod = listEntry->data; + printf("\tThe pod name: %s\n", pod->metadata->name); + } + v1_pod_list_free(pod_list); + pod_list = NULL; + } else { + printf("Cannot get any pod.\n"); + } +} + +int main() +{ + char *basePath = NULL; + sslConfig_t *sslConfig = NULL; + list_t *apiKeys = NULL; + + char *dataBuffer = getFileData(NULL); /* NULL means loading configuration from $HOME/.kube/config */ + if (dataBuffer == NULL) { + printf("Cannot get kubernetes configuration from file.\n"); + return -1; + } + + int rc = load_kube_config_buffer(&basePath, &sslConfig, &apiKeys, dataBuffer); + if (rc != 0) { + printf("Cannot load kubernetes configuration.\n"); + return -1; + } + apiClient_t *apiClient = apiClient_create_with_base_path(basePath, sslConfig, apiKeys); + if (!apiClient) { + printf("Cannot create a kubernetes client.\n"); + return -1; + } + + list_pod(apiClient); + + apiClient_free(apiClient); + apiClient = NULL; + free_client_config(basePath, sslConfig, apiKeys); + basePath = NULL; + sslConfig = NULL; + apiKeys = NULL; + apiClient_unsetupGlobalEnv(); + free(dataBuffer); + dataBuffer = NULL; + + return 0; +} From 25252711e74cbb805e24a9bf861765e0b5fcbd3d Mon Sep 17 00:00:00 2001 From: DanyT Date: Fri, 5 Jul 2024 17:05:20 +0300 Subject: [PATCH 07/10] remove files that are not needed --- .../list_pod_by_exec_provider.c~ | 71 ------------------- examples/exec_provider/my_exec_provider.c~ | 44 ------------ 2 files changed, 115 deletions(-) delete mode 100644 examples/exec_provider/list_pod_by_exec_provider.c~ delete mode 100644 examples/exec_provider/my_exec_provider.c~ diff --git a/examples/exec_provider/list_pod_by_exec_provider.c~ b/examples/exec_provider/list_pod_by_exec_provider.c~ deleted file mode 100644 index 721b2a02..00000000 --- a/examples/exec_provider/list_pod_by_exec_provider.c~ +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void list_pod(apiClient_t * apiClient) -{ - v1_pod_list_t *pod_list = NULL; - pod_list = CoreV1API_listNamespacedPod(apiClient, "default", /*namespace */ - NULL, /* pretty */ - NULL, /* allowWatchBookmarks */ - NULL, /* continue */ - NULL, /* fieldSelector */ - NULL, /* labelSelector */ - NULL, /* limit */ - NULL, /* resourceVersion */ - NULL, /* resourceVersionMatch */ - NULL, /* sendInitialEvents */ - NULL, /* timeoutSeconds */ - NULL /* watch */ - ); - printf("The return code of HTTP request=%ld\n", apiClient->response_code); - if (pod_list) { - printf("Get pod list:\n"); - listEntry_t *listEntry = NULL; - v1_pod_t *pod = NULL; - list_ForEach(listEntry, pod_list->items) { - pod = listEntry->data; - printf("\tThe pod name: %s\n", pod->metadata->name); - } - v1_pod_list_free(pod_list); - pod_list = NULL; - } else { - printf("Cannot get any pod.\n"); - } -} - -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, "./config_with_exec_provider"); - if (0 == rc) { - k8sApiClient = apiClient_create_with_base_path(baseName, sslConfig, apiKeys); - } else { - printf("Cannot load kubernetes configuration.\n"); - return -1; - } - - if (k8sApiClient) { - list_pod(k8sApiClient); - } - - free_client_config(baseName, sslConfig, apiKeys); - baseName = NULL; - sslConfig = NULL; - apiKeys = NULL; - - apiClient_free(k8sApiClient); - k8sApiClient = NULL; - apiClient_unsetupGlobalEnv(); - - return rc; -} diff --git a/examples/exec_provider/my_exec_provider.c~ b/examples/exec_provider/my_exec_provider.c~ deleted file mode 100644 index b0d48448..00000000 --- a/examples/exec_provider/my_exec_provider.c~ +++ /dev/null @@ -1,44 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include - -#define ENV_EXEC_CLIENT_CERTIFICATE_DATA "exec_client_certificate_data" -#define ENV_EXEC_CLIENT_PRIVATE_KEY "exec_client_private_key" - -char token_template[] = "\ -{\ - \"apiVersion\": \"client.authentication.k8s.io/v1beta1\",\ - \"kind\": \"ExecCredential\",\ - \"status\": {\ - \"token\": \"%s\"\ - }\ -}"; - -char certificate_template[] = "\ -{\ - \"apiVersion\": \"client.authentication.k8s.io/v1beta1\",\ - \"kind\": \"ExecCredential\",\ - \"status\": {\ - \"clientCertificateData\": \"%s\",\ - \"clientKeyData\": \"%s\"\ - }\ -}"; - -int main(int argc, char *argv[]) -{ - const char *client_certificate_data = secure_getenv(ENV_EXEC_CLIENT_CERTIFICATE_DATA); - const char *client_private_key = secure_getenv(ENV_EXEC_CLIENT_PRIVATE_KEY); - - if ((4 == argc) && argv[3]) { - // token is passed by command line argument - printf(token_template, argv[3]); - } else if ((client_certificate_data) && strlen(client_certificate_data) > 0 && (client_private_key) && strlen(client_private_key) > 0) { - // client certificate and private key are passed by environment variables - printf(certificate_template, client_certificate_data, client_private_key); - } else { - printf("Cannot get authentication data\n"); - } - - return 0; -} From fb4170b235fb6303ea9a747b5fd2cac25255012d Mon Sep 17 00:00:00 2001 From: DanyT Date: Fri, 5 Jul 2024 17:59:15 +0300 Subject: [PATCH 08/10] log attempts to load kube data --- examples/list_pod_buffer/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/list_pod_buffer/main.c b/examples/list_pod_buffer/main.c index b1475c0b..c257ba66 100644 --- a/examples/list_pod_buffer/main.c +++ b/examples/list_pod_buffer/main.c @@ -63,9 +63,16 @@ static char *getFileData(const char *filePath) } fclose(kubeFile); + } else { + printf("Could not open %s!\n", kubeConfigFile); } + free(kubeConfigFile); + } else { + printf("Could not determine the path to kubernetes configuration file! Tried: ENV_KUBECONFIG = %s and ENV_HOME = %s\n", + getenv(ENV_KUBECONFIG), getenv(ENV_HOME) ); } + return data; } From 45f6073fd0c4cd590f2e8553a7347fcc1977b392 Mon Sep 17 00:00:00 2001 From: DanyT Date: Mon, 22 Jul 2024 14:42:48 +0300 Subject: [PATCH 09/10] fix example --- examples/list_pod_buffer/main.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/examples/list_pod_buffer/main.c b/examples/list_pod_buffer/main.c index c257ba66..0906f946 100644 --- a/examples/list_pod_buffer/main.c +++ b/examples/list_pod_buffer/main.c @@ -20,25 +20,12 @@ static char *getWorkingConfigFile(const char *configFileNamePassedIn) if (configFileNamePassedIn) { configFileName = strdup(configFileNamePassedIn); } else { -#if defined(HAVE_SECURE_GETENV) - kubeconfig_env = secure_getenv(ENV_KUBECONFIG); -#elif defined(HAVE_GETENV) - kubeconfig_env = getenv(ENV_KUBECONFIG); -#endif - if (kubeconfig_env) { - configFileName = strdup(kubeconfig_env); - } else { -#if defined(HAVE_SECURE_GETENV) - homedir_env = secure_getenv(ENV_HOME); -#elif defined(HAVE_GETENV) - homedir_env = getenv(ENV_HOME); -#endif - if (homedir_env) { - int configFileNameSize = strlen(homedir_env) + strlen(KUBE_CONFIG_DEFAULT_LOCATION) + 1; - configFileName = calloc(configFileNameSize, sizeof(char)); - if (configFileName) { - snprintf(configFileName, configFileNameSize, KUBE_CONFIG_DEFAULT_LOCATION, homedir_env); - } + homedir_env = getenv(ENV_HOME); + if (homedir_env) { + int configFileNameSize = strlen(homedir_env) + strlen(KUBE_CONFIG_DEFAULT_LOCATION) + 1; + configFileName = calloc(configFileNameSize, sizeof(char)); + if (configFileName) { + snprintf(configFileName, configFileNameSize, KUBE_CONFIG_DEFAULT_LOCATION, homedir_env); } } } From 65bcd15fc0f3f1bfc8c2e76b739c5b682002b297 Mon Sep 17 00:00:00 2001 From: DanyT Date: Mon, 22 Jul 2024 16:04:16 +0300 Subject: [PATCH 10/10] add example to memcheck target --- examples/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/Makefile b/examples/Makefile index b2c6eefc..c3a0eafe 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -54,6 +54,7 @@ memcheck: kubectl wait --for=condition=ready --all pod -n default --timeout=60s cd list_pod_with_invalid_kubeconfig; make memcheck cd list_pod; make memcheck + cd list_pod_buffer; make memcheck cd delete_pod; make memcheck kubectl wait --for=delete pod/test-pod-6 -n default --timeout=120s cd list_secret; make memcheck