From dc590fb0d38037782d467f67120c4a24456f5502 Mon Sep 17 00:00:00 2001 From: Hui Yu Date: Sun, 26 Apr 2020 20:48:18 +0800 Subject: [PATCH] [Configuration] Support exec for kubeconfig --- examples/Makefile | 2 + examples/exec_provider/.gitignore | 4 + examples/exec_provider/Makefile | 14 + .../config_with_exec_provider_sample | 29 ++ .../exec_provider/list_pod_by_exec_provider.c | 66 ++++ examples/exec_provider/my_exec_provider.c | 44 +++ kubernetes/CMakeLists.txt | 3 + kubernetes/config/exec_provider.c | 98 ++++++ kubernetes/config/exec_provider.h | 46 +++ kubernetes/config/incluster_config.c | 4 +- kubernetes/config/kube_config.c | 183 ++++++++-- kubernetes/config/kube_config.h | 4 +- kubernetes/config/kube_config_common.h | 15 + kubernetes/config/kube_config_model.c | 194 ++++++---- kubernetes/config/kube_config_model.h | 157 +++++---- kubernetes/config/kube_config_yaml.c | 331 ++++++++++++++++-- kubernetes/config/kube_config_yaml.h | 27 +- 17 files changed, 1038 insertions(+), 183 deletions(-) create mode 100644 examples/exec_provider/.gitignore create mode 100644 examples/exec_provider/Makefile create mode 100644 examples/exec_provider/config_with_exec_provider_sample 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 kubernetes/config/exec_provider.c create mode 100644 kubernetes/config/exec_provider.h create mode 100644 kubernetes/config/kube_config_common.h diff --git a/examples/Makefile b/examples/Makefile index e2ca28f..6cb5afe 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -2,8 +2,10 @@ all: cd create_pod; make cd list_pod; make cd list_pod_incluster; make + cd exec_provider; make clean: cd create_pod; make clean cd list_pod; make clean cd list_pod_incluster; make clean + cd exec_provider; make clean diff --git a/examples/exec_provider/.gitignore b/examples/exec_provider/.gitignore new file mode 100644 index 0000000..0bc4eb6 --- /dev/null +++ b/examples/exec_provider/.gitignore @@ -0,0 +1,4 @@ +my_exec_provider_bin +list_pod_by_exec_provider_bin +config_with_exec_provider +config_with_exec_provider.* diff --git a/examples/exec_provider/Makefile b/examples/exec_provider/Makefile new file mode 100644 index 0000000..5851042 --- /dev/null +++ b/examples/exec_provider/Makefile @@ -0,0 +1,14 @@ +INCLUDE:=-I../../kubernetes/include -I../../kubernetes/model -I../../kubernetes/api -I../../kubernetes/config +LIBS:=-L../../kubernetes/build -lkubernetes -lcurl -lyaml -lpthread -lssl -lz +CFLAGS:=-g + +all: my_exec_provider_bin list_pod_by_exec_provider_bin + +list_pod_by_exec_provider_bin: + gcc list_pod_by_exec_provider.c $(CFLAGS) $(INCLUDE) $(LIBS) -o list_pod_by_exec_provider_bin + +my_exec_provider_bin: + gcc my_exec_provider.c $(CFLAGS) -o my_exec_provider_bin + +clean: + rm ./my_exec_provider_bin ./list_pod_by_exec_provider_bin diff --git a/examples/exec_provider/config_with_exec_provider_sample b/examples/exec_provider/config_with_exec_provider_sample new file mode 100644 index 0000000..45e0281 --- /dev/null +++ b/examples/exec_provider/config_with_exec_provider_sample @@ -0,0 +1,29 @@ +apiVersion: v1 +clusters: +- cluster: + certificate-authority-data: + server: + name: kubernetes +contexts: +- context: + cluster: kubernetes + user: kubernetes-admin + name: kubernetes-admin@kubernetes +current-context: kubernetes-admin@kubernetes +kind: Config +preferences: {} +users: +- name: kubernetes-admin + user: + exec: + command: "./my_exec_provider_bin" + apiVersion: "client.authentication.k8s.io/v1beta1" + env: + - name: "exec_client_certificate_data" + value: "-----BEGIN CERTIFICATE-----\n\n-----END CERTIFICATE-----" + - name: "exec_client_private_key" + value: "-----BEGIN RSA PRIVATE KEY-----\n\n-----END RSA PRIVATE KEY-----" + args: + - "arg1" + - "arg2" + - "token_value" 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 0000000..5a4e7d2 --- /dev/null +++ b/examples/exec_provider/list_pod_by_exec_provider.c @@ -0,0 +1,66 @@ +#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 */ + 0, /* allowWatchBookmarks */ + NULL, /* continue */ + NULL, /* fieldSelector */ + NULL, /* labelSelector */ + 0, /* limit */ + NULL, /* resourceVersion */ + 0, /* timeoutSeconds */ + 0 /* 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); + } + } 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; + + 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 0000000..b0d4844 --- /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/kubernetes/CMakeLists.txt b/kubernetes/CMakeLists.txt index 7750c50..2ded034 100644 --- a/kubernetes/CMakeLists.txt +++ b/kubernetes/CMakeLists.txt @@ -25,6 +25,7 @@ set(SRCS config/kube_config_yaml.c config/kube_config.c config/incluster_config.c + config/exec_provider.c src/list.c src/apiKey.c src/apiClient.c @@ -776,10 +777,12 @@ set(SRCS ) set(HDRS + config/kube_config_common.h config/kube_config_model.h config/kube_config_yaml.h config/kube_config.h config/incluster_config.h + config/exec_provider.h include/apiClient.h include/list.h include/keyValuePair.h diff --git a/kubernetes/config/exec_provider.c b/kubernetes/config/exec_provider.c new file mode 100644 index 0000000..564c15d --- /dev/null +++ b/kubernetes/config/exec_provider.c @@ -0,0 +1,98 @@ +#include "exec_provider.h" +#include "kube_config_yaml.h" +#include +#include +#include + +#define ARGS_DELIM " " +#define KUBECONFIG_EXEC_ARGS_BUFFER_SIZE 1024 +#define KUBECONFIG_EXEC_COMMAND_BUFFER_SIZE 1024 +#define KUBECONFIG_STRING_BUFFER_SIZE 1024 +#define KUBECONFIG_EXEC_RESULT_BUFFER_SIZE 4096 + +int kube_exec_and_get_result(ExecCredential_t * exec_credential, const kubeconfig_property_t * exec) +{ + static char fname[] = "kube_exec_and_get_result()"; + int rc = 0; + + if (!exec || exec->type != KUBECONFIG_PROPERTY_TYPE_USER_EXEC) { + fprintf(stderr, "%s: This is not a valid kubeconfig exec configuration.\n", fname); + return -1; + } + if (!exec->command) { + fprintf(stderr, "%s: The kubeconfig exec command is not specified.\n", fname); + return -1; + } + + if (exec->envs_count > 0 && exec->envs != NULL) { + for (int i = 0; i < exec->envs_count; i++) { + keyValuePair_t *pair = exec->envs[i]; + if (pair && pair->key && pair->value) { + rc = setenv(pair->key, (char *) (pair->value), 1); /* 1 means to overwrite the existing environment variable */ + if (0 != rc) { + fprintf(stderr, "%s: Cannot set environment variable %s=%s.[%s]\n", fname, pair->key, (char *) (pair->value), strerror(errno)); + return -1; + } + } else { + fprintf(stderr, "%s: The environment variable does not exist in exec->envs[%d].\n", fname, i); + return -1; + } + } + } + + char args_string[KUBECONFIG_EXEC_ARGS_BUFFER_SIZE]; + memset(args_string, 0, sizeof(args_string)); + int args_string_remaining_size = sizeof(args_string) - 1; /* 1 for the end of string ('\n') */ + if (exec->args_count > 0 && exec->args != NULL) { + for (int i = 0; i < exec->args_count; i++) { + args_string_remaining_size -= (strlen(ARGS_DELIM) + strlen(exec->args[i])); + if (args_string_remaining_size <= 0) { + fprintf(stderr, "%s: The buffer for exec args is not sufficient.\n", fname); + return -1; + } + strncat(args_string, ARGS_DELIM, strlen(ARGS_DELIM)); + strncat(args_string, exec->args[i], strlen(exec->args[i])); + } + } + + char command_string[KUBECONFIG_EXEC_COMMAND_BUFFER_SIZE]; + memset(command_string, 0, sizeof(command_string)); + snprintf(command_string, sizeof(command_string), "%s%s", exec->command, args_string); + + char *result_string = NULL; + FILE *fp = NULL; + fp = popen(command_string, "r"); /* r means read from stdout */ + if (fp) { + result_string = calloc(1, KUBECONFIG_EXEC_RESULT_BUFFER_SIZE); + if (!result_string) { + fprintf(stderr, "%s: Cannot allocate memory for command result.[%s]\n", fname, strerror(errno)); + return -1; + } + int result_string_remaining_size = KUBECONFIG_EXEC_RESULT_BUFFER_SIZE - 1; + char string_buf[KUBECONFIG_STRING_BUFFER_SIZE]; + memset(string_buf, 0, sizeof(string_buf)); + while (fgets(string_buf, sizeof(string_buf), fp) != NULL) { + result_string_remaining_size -= strlen(string_buf); + if (result_string_remaining_size <= 0) { + fprintf(stderr, "%s: The buffer for exec result is not sufficient.\n", fname); + rc = -1; + goto end; + } + strncat(result_string, string_buf, strlen(string_buf)); + memset(string_buf, 0, sizeof(string_buf)); + } + pclose(fp); + } else { + fprintf(stderr, "%s: Cannot open pipe to run command.[%s]\n", fname, strerror(errno)); + return -1; + } + + rc = kubeyaml_parse_exec_crendential(exec_credential, result_string); + + end: + if (result_string) { + free(result_string); + } + + return rc; +} diff --git a/kubernetes/config/exec_provider.h b/kubernetes/config/exec_provider.h new file mode 100644 index 0000000..c140c07 --- /dev/null +++ b/kubernetes/config/exec_provider.h @@ -0,0 +1,46 @@ +#ifndef _EXEC_PROVIDER_H +#define _EXEC_PROVIDER_H + +#include "kube_config_model.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * kube_exec_and_get_result + * + * + * Description: + * + * + * run exec command and get result of authentication + * + * + * + * Return: + * + * 0 Success + * -1 Failed + * + * + * Parameter: + * + * + * IN: + * + * exec: kubeconfig exec configuration + * + * OUT: + * + * exec_credential: result of exec + * + * + */ + + int kube_exec_and_get_result(ExecCredential_t * exec_credential, const kubeconfig_property_t * exec); + +#ifdef __cplusplus +} +#endif +#endif /* _EXEC_PROVIDER_H */ diff --git a/kubernetes/config/incluster_config.c b/kubernetes/config/incluster_config.c index 50236b6..95000d2 100644 --- a/kubernetes/config/incluster_config.c +++ b/kubernetes/config/incluster_config.c @@ -4,15 +4,13 @@ #include #include #include "incluster_config.h" +#include "kube_config_common.h" #define SERVICE_HOST_ENV_NAME "KUBERNETES_SERVICE_HOST" #define SERVICE_PORT_ENV_NAME "KUBERNETES_SERVICE_PORT" #define SERVICE_HTTPS_PREFIX "https://" #define SERVICE_TOKEN_FILENAME "/var/run/secrets/kubernetes.io/serviceaccount/token" #define SERVICE_CERT_FILENAME "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -#define AUTH_TOKEN_KEY "Authorization" -#define BEARER_TOKEN_TEMPLATE "Bearer %s" -#define BEARER_TOKEN_BUFFER_SIZE 1024 static int checkServiceAccountFile(const char *fileName) { diff --git a/kubernetes/config/kube_config.c b/kubernetes/config/kube_config.c index 2c7c394..5566a14 100644 --- a/kubernetes/config/kube_config.c +++ b/kubernetes/config/kube_config.c @@ -3,8 +3,12 @@ #include #include #include +#include +#include #include "kube_config.h" #include "kube_config_yaml.h" +#include "kube_config_common.h" +#include "exec_provider.h" #define ENV_KUBECONFIG "KUBECONFIG" #define ENV_HOME "HOME" @@ -21,15 +25,35 @@ static int setBasePath(char **pBasePath, char *basePath) return -1; } -static char *kubeconfig_mk_cert_key_tempfile(const char *b64data) +static bool is_cert_or_key_base64_encoded(const char *data) +{ + if (NULL == strstr(data, "BEGIN")) { + return true; + } else { + return false; // e.g. "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----" + } +} + +static char *kubeconfig_mk_cert_key_tempfile(const char *data) { static char fname[] = "kubeconfig_mk_tempfile()"; - int decoded_bytes = 0; - char *b64decode = base64decode(b64data, strlen(b64data), &decoded_bytes); - if (!b64decode || 0 == decoded_bytes) { - fprintf(stderr, "%s: Base64 decodes failed.\n", fname); - return NULL; + const char *cert_key_data = NULL; + int cert_key_data_bytes = 0; + + bool is_data_base64_encoded = is_cert_or_key_base64_encoded(data); + if (true == is_data_base64_encoded) { + int decoded_bytes = 0; + char *b64decode = base64decode(data, strlen(data), &decoded_bytes); + if (!b64decode || 0 == decoded_bytes) { + fprintf(stderr, "%s: Base64 decodes failed.\n", fname); + return NULL; + } + cert_key_data = b64decode; + cert_key_data_bytes = decoded_bytes; + } else { // plain text, no need base64 decode + cert_key_data = data; + cert_key_data_bytes = strlen(cert_key_data); } char tempfile_name_template[] = KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE; @@ -39,8 +63,12 @@ static char *kubeconfig_mk_cert_key_tempfile(const char *b64data) return NULL; } - int rc = write(fd, b64decode, decoded_bytes); + int rc = write(fd, cert_key_data, cert_key_data_bytes); close(fd); + if (true == is_data_base64_encoded && cert_key_data) { + free((char *) cert_key_data); // cast "const char *" to "char *" + cert_key_data = NULL; + } if (-1 == rc) { fprintf(stderr, "%s: Writing temp file failed with error [%s]\n", fname, strerror(errno)); return NULL; @@ -117,17 +145,24 @@ static int setSslConfig(sslConfig_t ** pSslConfig, const kubeconfig_property_t * return rc; } -static int setApiKeys(list_t ** pApiKeys, const kubeconfig_property_t * user) +static int setApiKeys(list_t ** pApiKeys, const char *token) { + static char fname[] = "setApiKeys()"; + list_t *apiKeys = list_create(); - if (apiKeys) { - - /* under development for the token based authentication */ - - *pApiKeys = apiKeys; - return 0; + if (!apiKeys) { + fprintf(stderr, "%s: Cannot allocate the memory for api key list for kubernetes service.\n", fname); + return -1; } - return -1; + + char tokenValue[BEARER_TOKEN_BUFFER_SIZE]; + memset(tokenValue, 0, sizeof(tokenValue)); + snprintf(tokenValue, BEARER_TOKEN_BUFFER_SIZE, BEARER_TOKEN_TEMPLATE, token); + keyValuePair_t *keyPairToken = keyValuePair_create(strdup(AUTH_TOKEN_KEY), strdup(tokenValue)); + list_addElement(apiKeys, keyPairToken); + + *pApiKeys = apiKeys; + return 0; } static char *getWorkingConfigFile(const char *configFileNamePassedIn) @@ -157,9 +192,9 @@ static char *getWorkingConfigFile(const char *configFileNamePassedIn) return configFileName; } -static const kubeconfig_property_t *kubeconfig_get_current_property(kubeconfig_property_t ** properties, int properties_count, const char *property_name) +static kubeconfig_property_t *kubeconfig_get_current_property(kubeconfig_property_t ** properties, int properties_count, const char *property_name) { - const kubeconfig_property_t *current_property = NULL; + kubeconfig_property_t *current_property = NULL; if (NULL == properties || NULL == property_name) { return NULL; @@ -175,15 +210,93 @@ static const kubeconfig_property_t *kubeconfig_get_current_property(kubeconfig_p return current_property; } +static int kubeconfig_exec(kubeconfig_property_t * current_user) +{ + static char fname[] = "kubeconfig_exec()"; + int rc = 0; + + ExecCredential_t *exec_output = exec_credential_create(); + if (!exec_output) { + fprintf(stderr, "%s: Cannot allocate memory for exec credential.[%s]\n", fname, strerror(errno)); + return -1; + } + + rc = kube_exec_and_get_result(exec_output, current_user->exec); + if (0 != rc) { + fprintf(stderr, "%s: The kubeconfig exec failed.\n", fname); + goto end; + } + if (!exec_output->status) { + rc = -1; + fprintf(stderr, "%s: The kubeconfig exec result is not valid.\n", fname); + goto end; + } + if (EXEC_CREDENTIAL_TYPE_TOKEN == exec_output->status->type && exec_output->status->token) { + current_user->token = strdup(exec_output->status->token); + } else if (exec_output->status->clientCertificateData && exec_output->status->clientKeyData) { + current_user->client_certificate_data = strdup(exec_output->status->clientCertificateData); + current_user->client_key_data = strdup(exec_output->status->clientKeyData); + } else { + rc = -1; + fprintf(stderr, "%s: Cannot get the authentication infomation from the kubeconfig exec result.\n", fname); + goto end; + } + + end: + exec_credential_free(exec_output); + exec_output = NULL; + return rc; +} + +static int kubeconfig_update_exec_command_path(kubeconfig_property_t * exec, const char *kube_config_file) +{ + static char fname[] = "kubeconfig_update_exec_command_path()"; + int rc = 0; + + if (!exec->command || 0 == strlen(exec->command)) { + return 0; + } + + char *kube_config_file_copy = NULL; + char *original_command = NULL; + if ('/' != exec->command[0]) { // relative path e.g. "./bin/" or "bin/" + kube_config_file_copy = strdup(kube_config_file); + if (NULL == kube_config_file_copy) { + fprintf(stderr, "%s: Cannot allocate memory for temp kube config file name.[%s]\n", fname, strerror(errno)); + return -1; + } + const char *kube_config_dirname = dirname(kube_config_file_copy); + original_command = exec->command; + int new_command_length = strlen(kube_config_dirname) + strlen("/") + strlen(original_command) + 1 /* 1 for the terminal of string */ ; + exec->command = calloc(1, new_command_length); + if (!exec->command) { + fprintf(stderr, "%s: Cannot allocate memory for exec new command.[%s]\n", fname, strerror(errno)); + exec->command = original_command; //restore original exec->command, its memory will be freed outside + rc = -1; + goto end; + } + snprintf(exec->command, new_command_length, "%s/%s", kube_config_dirname, original_command); + if (original_command) { + free(original_command); + } + } + + end: + if (kube_config_file_copy) { + free(kube_config_file_copy); + kube_config_file_copy = NULL; + } + + 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; - const kubeconfig_property_t *current_context = NULL; const kubeconfig_property_t *current_cluster = NULL; - const kubeconfig_property_t *current_user = NULL; + kubeconfig_property_t *current_user = NULL; kubeconfig_t *kubeconfig = kubeconfig_create(); if (!kubeconfig) { @@ -220,6 +333,19 @@ int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApi goto end; } + if (current_user && current_user->exec) { + rc = kubeconfig_update_exec_command_path(current_user->exec, kubeconfig->fileName); + if (0 != rc) { + fprintf(stderr, "%s: Cannot update exec command path.\n", fname); + goto end; + } + rc = kubeconfig_exec(current_user); + if (0 != rc) { + fprintf(stderr, "%s: Cannot exec command in kubeconfig.\n", fname); + goto end; + } + } + if (current_cluster && current_cluster->server) { rc = setBasePath(pBasePath, current_cluster->server); if (0 != rc) { @@ -236,10 +362,10 @@ int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApi } } - if (current_user) { - rc = setApiKeys(pApiKeys, current_user); + if (current_user && current_user->token) { + rc = setApiKeys(pApiKeys, current_user->token); if (0 != rc) { - fprintf(stderr, "%s: Cannot set the tokens for the client.\n", fname); + fprintf(stderr, "%s: Cannot set token for the client.\n", fname); goto end; } } @@ -262,6 +388,17 @@ void free_client_config(char *basePath, sslConfig_t * sslConfig, list_t * apiKey } if (apiKeys) { + listEntry_t *listEntry = NULL; + list_ForEach(listEntry, apiKeys) { + keyValuePair_t *pair = listEntry->data; + if (pair->key) { + free(pair->key); + } + if (pair->value) { + free(pair->value); + } + keyValuePair_free(pair); + } list_free(apiKeys); } } diff --git a/kubernetes/config/kube_config.h b/kubernetes/config/kube_config.h index 96a9fb5..9d29f72 100644 --- a/kubernetes/config/kube_config.h +++ b/kubernetes/config/kube_config.h @@ -44,7 +44,7 @@ extern "C" { * */ -int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, const char *configFileName); + int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, const char *configFileName); /* * free_client_config @@ -74,7 +74,7 @@ int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApi * */ -void free_client_config(char *basePath, sslConfig_t * sslConfig, list_t * apiKeys); + void free_client_config(char *basePath, sslConfig_t * sslConfig, list_t * apiKeys); #ifdef __cplusplus } diff --git a/kubernetes/config/kube_config_common.h b/kubernetes/config/kube_config_common.h new file mode 100644 index 0000000..d3b66b7 --- /dev/null +++ b/kubernetes/config/kube_config_common.h @@ -0,0 +1,15 @@ +#ifndef _KUBE_CONFIG_COMMON_H +#define _KUBE_CONFIG_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define AUTH_TOKEN_KEY "Authorization" +#define BEARER_TOKEN_TEMPLATE "Bearer %s" +#define BEARER_TOKEN_BUFFER_SIZE 1024 + +#ifdef __cplusplus +} +#endif +#endif /* _KUBE_CONFIG_COMMON_H */ diff --git a/kubernetes/config/kube_config_model.c b/kubernetes/config/kube_config_model.c index 9d4518c..10e392c 100644 --- a/kubernetes/config/kube_config_model.c +++ b/kubernetes/config/kube_config_model.c @@ -1,68 +1,40 @@ #include "kube_config_model.h" #include -kubeconfig_auth_provider_t *kubeconfig_auth_provider_create() +void kubeconfig_free_string_list(char **string_list, int count) { - kubeconfig_auth_provider_t *provider = calloc(1, sizeof(kubeconfig_auth_provider_t)); - return provider; + if (string_list && count > 0) { + for (int i = 0; i < count; i++) { + if (string_list[i]) { + free(string_list[i]); + string_list[i] = NULL; + } + } + free(string_list); + } } -void kubeconfig_auth_provider_free(kubeconfig_auth_provider_t * provider) +void kubeconfig_free_string_map_list(keyValuePair_t ** map_list, int count) { - if (!provider) { - return; + if (map_list && count > 0) { + keyValuePair_t *pair = NULL; + for (int i = 0; i < count; i++) { + pair = map_list[i]; + if (pair) { + if (pair->key) { + free(pair->key); + pair->key = NULL; + } + if (pair->value) { + free(pair->value); + pair->value = NULL; + } + free(pair); + pair = NULL; + } + } + free(map_list); } - - if (provider->name) { - free(provider->name); - provider->name = NULL; - } - if (provider->id_token) { - free(provider->id_token); - provider->id_token = NULL; - } - if (provider->cmd_path) { - free(provider->cmd_path); - provider->cmd_path = NULL; - } - if (provider->access_token) { - free(provider->access_token); - provider->access_token = NULL; - } - if (provider->expires_on) { - free(provider->expires_on); - provider->expires_on = NULL; - } - if (provider->expiry) { - free(provider->expiry); - provider->expiry = NULL; - } - if (provider->idp_certificate_authority_data) { - free(provider->idp_certificate_authority_data); - provider->idp_certificate_authority_data = NULL; - } - - free(provider); -} - -kubeconfig_exec_t *kubeconfig_exec_create() -{ - kubeconfig_exec_t *exec = calloc(1, sizeof(kubeconfig_exec_t)); - return exec; -} - -void kubeconfig_exec_free(kubeconfig_exec_t * exec) -{ - if (!exec) { - return; - } - - if (exec->command) { - free(exec->command); - exec->command = NULL; - } - - free(exec); } kubeconfig_property_t *kubeconfig_property_create(kubeconfig_property_type_t type) @@ -112,11 +84,11 @@ void kubeconfig_property_free(kubeconfig_property_t * property) property->password = NULL; } if (property->auth_provider) { - kubeconfig_auth_provider_free(property->auth_provider); + kubeconfig_property_free(property->auth_provider); property->auth_provider = NULL; } if (property->exec) { - kubeconfig_exec_free(property->exec); + kubeconfig_property_free(property->exec); property->exec = NULL; } } @@ -132,6 +104,54 @@ void kubeconfig_property_free(kubeconfig_property_t * property) } } + if (KUBECONFIG_PROPERTY_TYPE_USER_EXEC == property->type) { + if (property->command) { + free(property->command); + property->command = NULL; + } + if (property->apiVersion) { + free(property->apiVersion); + property->apiVersion = NULL; + } + if (property->envs && property->envs_count > 0) { + kubeconfig_free_string_map_list(property->envs, property->envs_count); + property->envs = NULL; + property->envs_count = 0; + } + if (property->args && property->args_count > 0) { + kubeconfig_free_string_list(property->args, property->args_count); + property->args = NULL; + property->args_count = 0; + } + } + + if (KUBECONFIG_PROPERTY_TYPE_USER_AUTH_PROVIDER == property->type) { + if (property->id_token) { + free(property->id_token); + property->id_token = NULL; + } + if (property->cmd_path) { + free(property->cmd_path); + property->cmd_path = NULL; + } + if (property->access_token) { + free(property->access_token); + property->access_token = NULL; + } + if (property->expires_on) { + free(property->expires_on); + property->expires_on = NULL; + } + if (property->expiry) { + free(property->expiry); + property->expiry = NULL; + } + if (property->idp_certificate_authority_data) { + free(property->idp_certificate_authority_data); + property->idp_certificate_authority_data = NULL; + } + } + free(property); } @@ -207,3 +227,59 @@ void kubeconfig_free(kubeconfig_t * kubeconfig) free(kubeconfig); } + +ExecCredential_status_t *exec_credential_status_create() +{ + ExecCredential_status_t *exec_credential_status = calloc(1, sizeof(ExecCredential_status_t)); + return exec_credential_status; +} + +void exec_credential_status_free(ExecCredential_status_t * exec_credential_status) +{ + if (!exec_credential_status) { + return; + } + + if (exec_credential_status->token) { + free(exec_credential_status->token); + exec_credential_status->token = NULL; + } + if (exec_credential_status->clientCertificateData) { + free(exec_credential_status->clientCertificateData); + exec_credential_status->clientCertificateData = NULL; + } + if (exec_credential_status->clientKeyData) { + free(exec_credential_status->clientKeyData); + exec_credential_status->clientKeyData = NULL; + } + + free(exec_credential_status); +} + +ExecCredential_t *exec_credential_create() +{ + ExecCredential_t *exec_credential = calloc(1, sizeof(ExecCredential_t)); + return exec_credential; +} + +void exec_credential_free(ExecCredential_t * exec_credential) +{ + if (!exec_credential) { + return; + } + + if (exec_credential->apiVersion) { + free(exec_credential->apiVersion); + exec_credential->apiVersion = NULL; + } + if (exec_credential->kind) { + free(exec_credential->kind); + exec_credential->kind = NULL; + } + if (exec_credential->status) { + exec_credential_status_free(exec_credential->status); + exec_credential->status = NULL; + } + + free(exec_credential); +} diff --git a/kubernetes/config/kube_config_model.h b/kubernetes/config/kube_config_model.h index bdbcc7e..6df703f 100644 --- a/kubernetes/config/kube_config_model.h +++ b/kubernetes/config/kube_config_model.h @@ -1,82 +1,113 @@ #ifndef _KUBE_CONFIG_MODEL_H #define _KUBE_CONFIG_MODEL_H +#include "../include/keyValuePair.h" + #ifdef __cplusplus extern "C" { #endif -typedef struct kubeconfig_auth_provider_t { - char *name; - char *id_token; - char *cmd_path; - char *access_token; - char *expires_on; - char *expiry; - char *idp_certificate_authority_data; -} kubeconfig_auth_provider_t; + typedef enum ExecCredential_type_t { + EXEC_CREDENTIAL_TYPE_TOKEN = 1, + EXEC_CREDENTIAL_TYPE_CLIENT_CERT + } ExecCredential_type_t; -typedef struct kubeconfig_exec_t { - char *command; -} kubeconfig_exec_t; - -typedef enum kubeconfig_property_type_t { - KUBECONFIG_PROPERTY_TYPE_CONTEXT = 1, - KUBECONFIG_PROPERTY_TYPE_CLUSTER, - KUBECONFIG_PROPERTY_TYPE_USER -} kubeconfig_property_type_t; - -typedef struct kubeconfig_property_t { - kubeconfig_property_type_t type; - char *name; - union { - struct { /* context */ - char *cluster; - char *user; + typedef struct ExecCredential_status_t { + ExecCredential_type_t type; + union { + struct { + char *token; + }; + struct { + char *clientCertificateData; + char *clientKeyData; + }; }; - struct { /* cluster */ - char *server; - char *certificate_authority_data; + } ExecCredential_status_t; + + typedef struct ExecCredential_t { + char *apiVersion; + char *kind; + ExecCredential_status_t *status; + } ExecCredential_t; + + typedef enum kubeconfig_property_type_t { + KUBECONFIG_PROPERTY_TYPE_CONTEXT = 1, + KUBECONFIG_PROPERTY_TYPE_CLUSTER, + KUBECONFIG_PROPERTY_TYPE_USER, + KUBECONFIG_PROPERTY_TYPE_USER_EXEC, + KUBECONFIG_PROPERTY_TYPE_USER_AUTH_PROVIDER + } kubeconfig_property_type_t; + + typedef struct kubeconfig_property_t { + kubeconfig_property_type_t type; + char *name; + union { + struct { /* context */ + char *cluster; + char *user; + }; + struct { /* cluster */ + char *server; + char *certificate_authority_data; + }; + struct { /* user */ + char *token; + char *client_certificate_data; + char *client_key_data; + struct kubeconfig_property_t *auth_provider; + struct kubeconfig_property_t *exec; + int insecure_skip_tls_verify; + char *username; + char *password; + }; + struct { /* user exec */ + char *command; + char *apiVersion; + keyValuePair_t **envs; + int envs_count; + char **args; + int args_count; + }; + struct { /* user auth provider */ + char *id_token; + char *cmd_path; + char *access_token; + char *expires_on; + char *expiry; + char *idp_certificate_authority_data; + }; }; - struct { /* user */ - char *client_certificate_data; - char *client_key_data; - kubeconfig_auth_provider_t *auth_provider; - kubeconfig_exec_t *exec; - int insecure_skip_tls_verify; - char *username; - char *password; - }; - }; -} kubeconfig_property_t; + } kubeconfig_property_t; -typedef struct kubeconfig_t { - char *fileName; - char *apiVersion; - char *preferences; - char *kind; - char *current_context; - kubeconfig_property_t **contexts; - int contexts_count; - kubeconfig_property_t **clusters; - int clusters_count; - kubeconfig_property_t **users; - int users_count; -} kubeconfig_t; + typedef struct kubeconfig_t { + char *fileName; + char *apiVersion; + char *preferences; + char *kind; + char *current_context; + kubeconfig_property_t **contexts; + int contexts_count; + kubeconfig_property_t **clusters; + int clusters_count; + kubeconfig_property_t **users; + int users_count; + } kubeconfig_t; -kubeconfig_auth_provider_t *kubeconfig_auth_provider_create(); -void kubeconfig_auth_provider_free(kubeconfig_auth_provider_t * provider); + ExecCredential_t *exec_credential_create(); + void exec_credential_free(ExecCredential_t *); -kubeconfig_exec_t *kubeconfig_exec_create(); -void kubeconfig_exec_free(kubeconfig_exec_t * exec); + ExecCredential_status_t *exec_credential_status_create(); + void exec_credential_status_free(ExecCredential_status_t *); -kubeconfig_property_t *kubeconfig_property_create(kubeconfig_property_type_t type); -void kubeconfig_property_free(kubeconfig_property_t * property); + kubeconfig_property_t *kubeconfig_property_create(kubeconfig_property_type_t type); + void kubeconfig_property_free(kubeconfig_property_t * property); -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); + 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); -kubeconfig_t *kubeconfig_create(); -void kubeconfig_free(kubeconfig_t * kubeconfig); + kubeconfig_t *kubeconfig_create(); + void kubeconfig_free(kubeconfig_t * kubeconfig); #ifdef __cplusplus } diff --git a/kubernetes/config/kube_config_yaml.c b/kubernetes/config/kube_config_yaml.c index 1ce1097..949ec5e 100644 --- a/kubernetes/config/kube_config_yaml.c +++ b/kubernetes/config/kube_config_yaml.c @@ -21,14 +21,56 @@ mapping :: = MAPPING - START(node node) * MAPPING - END #define KEY_USERS "users" #define KEY_USER "user" #define KEY_NAME "name" +#define KEY_USER_EXEC "exec" +#define KEY_USER_EXEC_COMMAND "command" +#define KEY_USER_EXEC_ENV "env" +#define KEY_USER_EXEC_ENV_KEY "name" +#define KEY_USER_EXEC_ENV_VALUE "value" +#define KEY_USER_EXEC_ARGS "args" #define KEY_CERTIFICATE_AUTHORITY_DATA "certificate-authority-data" #define KEY_SERVER "server" #define KEY_CLIENT_CERTIFICATE_DATA "client-certificate-data" #define KEY_CLIENT_KEY_DATA "client-key-data" +#define KEY_STAUTS "status" +#define KEY_TOKEN "token" +#define KEY_CLIENT_CERTIFICATE_DATA2 "clientCertificateData" +#define KEY_CLIENT_KEY_DATA2 "clientKeyData" -static int parse_kubeconfig_yaml_property_info_mapping(kubeconfig_property_t * property, yaml_document_t * document, yaml_node_t * node) +static int parse_kubeconfig_yaml_string_sequence(char ***p_strings, int *p_strings_count, yaml_document_t * document, yaml_node_t * node) { - static char fname[] = "parse_kubeconfig_yaml_property_info_mapping()"; + static char fname[] = "parse_kubeconfig_yaml_string_sequence()"; + + yaml_node_item_t *item = NULL; + yaml_node_t *value = NULL; + int item_count = 0; + int i = 0; + int rc = 0; + + for (item = node->data.sequence.items.start, item_count = 0; item < node->data.sequence.items.top; item++, item_count++) { + ; + } + + int strings_count = item_count; + char **strings = (char **) calloc(strings_count, sizeof(char *)); + if (!strings) { + fprintf(stderr, "%s: Cannot allocate memory for string sequence.\n", fname); + return -1; + } + + for (item = node->data.sequence.items.start, i = 0; item < node->data.sequence.items.top; item++, i++) { + value = yaml_document_get_node(document, *item); + strings[i] = strdup(value->data.scalar.value); + } + + *p_strings = strings; + *p_strings_count = strings_count; + + return 0; +} + +static int parse_kubeconfig_yaml_string_mapping(keyValuePair_t * string_mapping, yaml_document_t * document, yaml_node_t * node) +{ + static char fname[] = "parse_kubeconfig_yaml_string_mapping()"; yaml_node_pair_t *pair = NULL; yaml_node_t *key = NULL; @@ -44,24 +86,13 @@ static int parse_kubeconfig_yaml_property_info_mapping(kubeconfig_property_t * p } if (value->type == YAML_SCALAR_NODE) { - if (KUBECONFIG_PROPERTY_TYPE_CLUSTER == property->type) { - if (0 == strcmp(key->data.scalar.value, KEY_CERTIFICATE_AUTHORITY_DATA)) { - property->certificate_authority_data = strdup(value->data.scalar.value); - } else if (0 == strcmp(key->data.scalar.value, KEY_SERVER)) { - property->server = strdup(value->data.scalar.value); - } - } else if (KUBECONFIG_PROPERTY_TYPE_USER == property->type) { - if (0 == strcmp(key->data.scalar.value, KEY_CLIENT_CERTIFICATE_DATA)) { - property->client_certificate_data = strdup(value->data.scalar.value); - } else if (0 == strcmp(key->data.scalar.value, KEY_CLIENT_KEY_DATA)) { - property->client_key_data = strdup(value->data.scalar.value); - } - } else if (KUBECONFIG_PROPERTY_TYPE_CONTEXT == property->type) { - if (0 == strcmp(key->data.scalar.value, KEY_CLUSTER)) { - property->cluster = strdup(value->data.scalar.value); - } else if (0 == strcmp(key->data.scalar.value, KEY_USER)) { - property->user = strdup(value->data.scalar.value); - } + if (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC_ENV_KEY)) { + string_mapping->key = strdup(value->data.scalar.value); + } else if (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC_ENV_VALUE)) { + string_mapping->value = strdup(value->data.scalar.value); + } else { + fprintf(stderr, "%s: The key of node is invalid: %s\n", fname, key->data.scalar.value); + return -1; } } } @@ -69,10 +100,53 @@ static int parse_kubeconfig_yaml_property_info_mapping(kubeconfig_property_t * p return 0; } +static int parse_kubeconfig_yaml_string_mapping_sequence(keyValuePair_t *** p_string_mappings, int *p_mappings_count, yaml_document_t * document, yaml_node_t * node) +{ + static char fname[] = "parse_kubeconfig_yaml_string_mapping_sequence()"; + + yaml_node_item_t *item = NULL; + yaml_node_t *value = NULL; + int item_count = 0; + int i = 0; + int rc = 0; + + for (item = node->data.sequence.items.start, item_count = 0; item < node->data.sequence.items.top; item++, item_count++) { + ; + } + + int mappings_count = item_count; + keyValuePair_t **string_mappings = (keyValuePair_t **) calloc(mappings_count, sizeof(keyValuePair_t *)); + if (!string_mappings) { + fprintf(stderr, "%s: Cannot allocate memory for string mappings.\n", fname); + return -1; + } + for (int j = 0; j < mappings_count; j++) { + string_mappings[j] = calloc(1, sizeof(keyValuePair_t)); + if (!string_mappings[j]) { + fprintf(stderr, "%s: Cannot allocate memory for string mapping.\n", fname); + return -1; + } + } + + for (item = node->data.sequence.items.start, i = 0; item < node->data.sequence.items.top; item++, i++) { + value = yaml_document_get_node(document, *item); + + rc = parse_kubeconfig_yaml_string_mapping(string_mappings[i], document, value); + if (0 != rc) { + fprintf(stderr, "%s: Cannot parse kubeconfig string mapping.\n", fname); + return -1; + } + } + + *p_string_mappings = string_mappings; + *p_mappings_count = mappings_count; + + return 0; +} + static int parse_kubeconfig_yaml_property_mapping(kubeconfig_property_t * property, yaml_document_t * document, yaml_node_t * node) { - static char fname[] = "parse_kubeconfig_yaml_property_mapping()"; - int rc = 0; + static char fname[] = "parse_kubeconfig_yaml_property_info_mapping()"; yaml_node_pair_t *pair = NULL; yaml_node_t *key = NULL; @@ -91,15 +165,62 @@ static int parse_kubeconfig_yaml_property_mapping(kubeconfig_property_t * proper if (0 == strcmp(key->data.scalar.value, KEY_NAME)) { property->name = strdup(value->data.scalar.value); } + if (KUBECONFIG_PROPERTY_TYPE_CLUSTER == property->type) { + if (0 == strcmp(key->data.scalar.value, KEY_CERTIFICATE_AUTHORITY_DATA)) { + property->certificate_authority_data = strdup(value->data.scalar.value); + } else if (0 == strcmp(key->data.scalar.value, KEY_SERVER)) { + property->server = strdup(value->data.scalar.value); + } + } else if (KUBECONFIG_PROPERTY_TYPE_USER == property->type) { + if (0 == strcmp(key->data.scalar.value, KEY_CLIENT_CERTIFICATE_DATA)) { + property->client_certificate_data = strdup(value->data.scalar.value); + } else if (0 == strcmp(key->data.scalar.value, KEY_CLIENT_KEY_DATA)) { + property->client_key_data = strdup(value->data.scalar.value); + } + } else if (KUBECONFIG_PROPERTY_TYPE_CONTEXT == property->type) { + if (0 == strcmp(key->data.scalar.value, KEY_CLUSTER)) { + property->cluster = strdup(value->data.scalar.value); + } else if (0 == strcmp(key->data.scalar.value, KEY_USER)) { + property->user = strdup(value->data.scalar.value); + } + } else if (KUBECONFIG_PROPERTY_TYPE_USER_EXEC == property->type) { + if (0 == strcmp(key->data.scalar.value, KEY_APIVERSION)) { + property->apiVersion = strdup(value->data.scalar.value); + } else if (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC_COMMAND)) { + property->command = strdup(value->data.scalar.value); + } + } } else if (value->type == YAML_MAPPING_NODE) { - rc = parse_kubeconfig_yaml_property_info_mapping(property, document, value); + if ((KUBECONFIG_PROPERTY_TYPE_USER == property->type) && (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC))) { + property->exec = kubeconfig_property_create(KUBECONFIG_PROPERTY_TYPE_USER_EXEC); + if (property->exec) { + int rc = parse_kubeconfig_yaml_property_mapping(property->exec, document, value); + if (0 != rc) { + fprintf(stderr, "Cannot parse kubeconfig exec for user %s.\n", property->name); + return -1; + } + } else { + fprintf(stderr, "Cannot allocate memory for kubeconfig exec for user %s.\n", property->name); + return -1; + } + } else { + parse_kubeconfig_yaml_property_mapping(property, document, value); + } + } else if (value->type == YAML_SEQUENCE_NODE) { + if (KUBECONFIG_PROPERTY_TYPE_USER_EXEC == property->type) { + if (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC_ENV)) { + parse_kubeconfig_yaml_string_mapping_sequence(&(property->envs), &(property->envs_count), document, value); + } else if (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC_ARGS)) { + parse_kubeconfig_yaml_string_sequence(&(property->args), &(property->args_count), document, value); + } + } } } - return rc; + return 0; } -static int parse_kubeconfig_yaml_sequence(kubeconfig_property_t *** p_properties, int *p_properties_count, kubeconfig_property_type_t type, yaml_document_t * document, yaml_node_t * node) +static int parse_kubeconfig_yaml_property_sequence(kubeconfig_property_t *** p_properties, int *p_properties_count, kubeconfig_property_type_t type, yaml_document_t * document, yaml_node_t * node) { yaml_node_item_t *item = NULL; yaml_node_t *value = NULL; @@ -107,7 +228,7 @@ static int parse_kubeconfig_yaml_sequence(kubeconfig_property_t *** p_properties int i = 0; int rc = 0; - // Get the count of data (e.g. cluster, context, user) + // Get the count of data (e.g. cluster, context, user, user_exec ) for (item = node->data.sequence.items.start, item_count = 0; item < node->data.sequence.items.top; item++, item_count++) { ; } @@ -123,7 +244,7 @@ static int parse_kubeconfig_yaml_sequence(kubeconfig_property_t *** p_properties value = yaml_document_get_node(document, *item); rc = parse_kubeconfig_yaml_property_mapping(properties[i], document, value); if (0 != rc) { - fprintf(stderr, "Cannot parse kubeconfi properties.\n"); + fprintf(stderr, "Cannot parse kubeconfig properties.\n"); return -1; } } @@ -163,17 +284,16 @@ static int parse_kubeconfig_yaml_top_mapping(kubeconfig_t * kubeconfig, yaml_doc } } else { if (0 == strcmp(key->data.scalar.value, KEY_CLUSTERS)) { - rc = parse_kubeconfig_yaml_sequence(&(kubeconfig->clusters), &(kubeconfig->clusters_count), KUBECONFIG_PROPERTY_TYPE_CLUSTER, document, value); + rc = parse_kubeconfig_yaml_property_sequence(&(kubeconfig->clusters), &(kubeconfig->clusters_count), KUBECONFIG_PROPERTY_TYPE_CLUSTER, document, value); } else if (0 == strcmp(key->data.scalar.value, KEY_CONTEXTS)) { - rc = parse_kubeconfig_yaml_sequence(&(kubeconfig->contexts), &(kubeconfig->contexts_count), KUBECONFIG_PROPERTY_TYPE_CONTEXT, document, value); + rc = parse_kubeconfig_yaml_property_sequence(&(kubeconfig->contexts), &(kubeconfig->contexts_count), KUBECONFIG_PROPERTY_TYPE_CONTEXT, document, value); } else if (0 == strcmp(key->data.scalar.value, KEY_USERS)) { - rc = parse_kubeconfig_yaml_sequence(&(kubeconfig->users), &(kubeconfig->users_count), KUBECONFIG_PROPERTY_TYPE_USER, document, value); + rc = parse_kubeconfig_yaml_property_sequence(&(kubeconfig->users), &(kubeconfig->users_count), KUBECONFIG_PROPERTY_TYPE_USER, document, value); } } } return rc; - } static int parse_kubeconfig_yaml_node(kubeconfig_t * kubeconfig, yaml_document_t * document, yaml_node_t * node) @@ -261,3 +381,152 @@ int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig) fclose(input); return -1; } + +static int parse_exec_credential_yaml_status_mapping(ExecCredential_status_t ** p_status, yaml_document_t * document, yaml_node_t * node) +{ + static char fname[] = "parse_exec_credential_yaml_status_mapping()"; + int rc = 0; + + yaml_node_pair_t *pair = NULL; + yaml_node_t *key = NULL; + yaml_node_t *value = NULL; + + ExecCredential_status_t *status = exec_credential_status_create(); + if (!status) { + fprintf(stderr, "Cannot allocate memory for kubeconfig exec credentail status.\n"); + return -1; + } + + for (pair = node->data.mapping.pairs.start; pair < node->data.mapping.pairs.top; pair++) { + key = yaml_document_get_node(document, pair->key); + value = yaml_document_get_node(document, pair->value); + + if (key->type != YAML_SCALAR_NODE) { + fprintf(stderr, "%s: The key node is not YAML_SCALAR_NODE.\n", fname); + return -1; + } + + if (value->type == YAML_SCALAR_NODE) { + if (0 == strcmp(key->data.scalar.value, KEY_TOKEN)) { + status->token = strdup(value->data.scalar.value); + status->type = EXEC_CREDENTIAL_TYPE_TOKEN; + } else if (0 == strcmp(key->data.scalar.value, KEY_CLIENT_CERTIFICATE_DATA2)) { + status->clientCertificateData = strdup(value->data.scalar.value); + status->type = EXEC_CREDENTIAL_TYPE_CLIENT_CERT; + } else if (0 == strcmp(key->data.scalar.value, KEY_CLIENT_KEY_DATA2)) { + status->clientKeyData = strdup(value->data.scalar.value); + status->type = EXEC_CREDENTIAL_TYPE_CLIENT_CERT; + } + } + } + + *p_status = status; + + return rc; +} + +static int parse_exec_credential_yaml_top_mapping(ExecCredential_t * exec_credential, yaml_document_t * document, yaml_node_t * node) +{ + static char fname[] = "parse_exec_credential_yaml_top_mapping()"; + int rc = 0; + + yaml_node_pair_t *pair = NULL; + yaml_node_t *key = NULL; + yaml_node_t *value = NULL; + + for (pair = node->data.mapping.pairs.start; pair < node->data.mapping.pairs.top; pair++) { + key = yaml_document_get_node(document, pair->key); + value = yaml_document_get_node(document, pair->value); + + if (key->type != YAML_SCALAR_NODE) { + fprintf(stderr, "%s: The key node is not YAML_SCALAR_NODE.\n", fname); + return -1; + } + + if (value->type == YAML_SCALAR_NODE) { + if (0 == strcmp(key->data.scalar.value, KEY_APIVERSION)) { + exec_credential->apiVersion = strdup(value->data.scalar.value); + } else if (0 == strcmp(key->data.scalar.value, KEY_KIND)) { + exec_credential->kind = strdup(value->data.scalar.value); + } + } else { + if (0 == strcmp(key->data.scalar.value, KEY_STAUTS)) { + rc = parse_exec_credential_yaml_status_mapping(&(exec_credential->status), document, value); + } + } + } + + return rc; +} + +static int parse_exec_credential_yaml_node(ExecCredential_t * exec_credential, yaml_document_t * document, yaml_node_t * node) +{ + static char fname[] = "parse_exec_credential_yaml_node()"; + int rc = 0; + + if (YAML_MAPPING_NODE == node->type) { + rc = parse_exec_credential_yaml_top_mapping(exec_credential, document, node); + } else { + fprintf(stderr, "%s: This is not a valid exec credential string.\n", fname); + rc = -1; + } + + return rc; +} + +static int parse_exec_credential_yaml_document(ExecCredential_t * exec_credential, yaml_document_t * document) +{ + static char fname[] = "parse_exec_credential_yaml_document()"; + int rc = 0; + + yaml_node_t *root; + root = yaml_document_get_root_node(document); + if (NULL == root) { + fprintf(stderr, "%s: The document is null\n", fname); + return -1; + } + + rc = parse_exec_credential_yaml_node(exec_credential, document, root); + + return rc; +} + +int kubeyaml_parse_exec_crendential(ExecCredential_t * exec_credential, const char *exec_credential_string) +{ + static char fname[] = "kubeyaml_parse_ExecCrendentail()"; + + yaml_parser_t parser; + yaml_document_t document; + + int done = 0; + + /* Create the Parser object. */ + yaml_parser_initialize(&parser); + + /* Set a string input. */ + yaml_parser_set_input_string(&parser, exec_credential_string, strlen(exec_credential_string)); + + while (!done) { + + if (!yaml_parser_load(&parser, &document)) { + goto error; + } + + done = (!yaml_document_get_root_node(&document)); + + if (!done) { + parse_exec_credential_yaml_document(exec_credential, &document); + } + + yaml_document_delete(&document); + + } + + /* Cleanup */ + yaml_parser_delete(&parser); + return 0; + + error: + yaml_parser_delete(&parser); + return -1; +} diff --git a/kubernetes/config/kube_config_yaml.h b/kubernetes/config/kube_config_yaml.h index 49b62a3..4621873 100644 --- a/kubernetes/config/kube_config_yaml.h +++ b/kubernetes/config/kube_config_yaml.h @@ -5,7 +5,6 @@ #ifdef __cplusplus extern "C" { - #endif /* __cplusplus */ /* @@ -28,8 +27,32 @@ extern "C" { * * OUT: * kubeconfig: kubernetes cluster configuration + * */ -int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig); + int kubeyaml_load_kubeconfig(kubeconfig_t * kubeconfig); + +/* + * kubeyaml_parse_exec_crendential + * + * Description: + * + * Parse the exec result string to get the kubeconfig exec credential. + * + * Return: + * + * 0 Success + * -1 Failed + * + * Parameter: + * + * IN: + * exec_credential_string: text string of kubeconfig exec result + * + * OUT: + * exec_credential: data structure of kubeconfig exec credential + * + */ + int kubeyaml_parse_exec_crendential(ExecCredential_t * exec_credential, const char *exec_credential_string); #ifdef __cplusplus }