From 9afb677d1d1d89c950775958dd1fb2f8cc14315a Mon Sep 17 00:00:00 2001 From: Matthias Gatto Date: Thu, 7 Mar 2024 15:35:29 +0100 Subject: [PATCH 1/3] add variable support Signed-off-by: Matthias Gatto --- cognac_gen.sh | 29 +++++++++++++++++++--- main_tpl.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/cognac_gen.sh b/cognac_gen.sh index 315b16a..d405dac 100755 --- a/cognac_gen.sh +++ b/cognac_gen.sh @@ -346,7 +346,7 @@ EOF goto ${snake_l}_arg; } - if (i + 1 < ac && av[i + 1][0] == '-' && av[i + 1][1] == '-') { + if (i + 1 < ac && av[i + 1][0] == '-' && av[i + 1][1] == '-' && strcmp(av[i + 1] + 2, "SetVar")) { char *next_a = &av[i + 1][2]; char *str = next_a; char *aa = i + 2 < ac ? av[i + 2] : 0; @@ -365,7 +365,18 @@ EOF ++incr; aa = read_file(files_cnt, av[i + 3], 1); STRY(!aa); - + } else if (!strcmp(aa, "--var")) { + TRY(i + 3 >= ac, "var name require"); + int var_found = 0; + for (int j = 0; j < nb_cli_vars; ++j) { + if (!strcmp(cli_vars[j].name, av[i + 3])) { + var_found = 1; + aa = cli_vars[j].val; + } + } + TRY(!var_found, "--var could not find osc variable '%s'", av[i + 3]); + ++incr; + STRY(!aa); } else { aa = 0; incr = 1; @@ -399,6 +410,7 @@ EOF cret = osc_$snake_l(&e, &r, &a); TRY(cret, "fail to call $l: %s\n", curl_easy_strerror(cret)); CHK_BAD_RET(!r.buf, "connection sucessful, but empty responce\n"); + jobj = NULL; if (program_flag & OAPI_RAW_OUTPUT) puts(r.buf); else { @@ -406,8 +418,19 @@ EOF puts(json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE | color_flag)); - json_object_put(jobj); + } + if (i + 1 < ac && !strcmp(av[i + 1], "--SetVar")) { + ++i; + TRY(i + 1 >= ac, "--SetVar require an argument"); + if (!jobj) + jobj = json_tokener_parse(r.buf); + if (parse_variable(jobj, av, ac, i)) + return -1; + ++i; } + + if (jobj) + json_object_put(jobj); osc_deinit_str(&r); } else EOF diff --git a/main_tpl.c b/main_tpl.c index 2bd1efa..5feaba1 100644 --- a/main_tpl.c +++ b/main_tpl.c @@ -58,10 +58,24 @@ #define TRY(f, args...) \ do { \ - if (f) {fprintf(stderr, args); return 1;} \ + if (f) {fprintf(stderr, args); return -1;} \ } while(0) +#define VAR_NAME_SIZE 128 +#define VAR_VAL_SIZE 512 +#define VAR_ARRAY_SIZE 128 + +static int nb_cli_vars; + +struct cli_var { + char name[VAR_NAME_SIZE]; + char val[VAR_VAL_SIZE]; +} cli_vars[VAR_ARRAY_SIZE]; + +static void *cascade_struct; +static int (*cascade_parser)(void *, char *, char *, struct ptr_array *); + static int argcmp2(const char *s1, const char *s2, char dst) { while (*s1 == *s2 && *s1 && *s2) { @@ -111,6 +125,55 @@ char *string_to_jsonstr(char **file_str_p) return *file_str_p; } +static int parse_variable(json_object *jobj, char **av, int ac, int i) +{ + const char *tmp = av[i + 1]; + const char *tmp2; + TRY(nb_cli_vars >= VAR_ARRAY_SIZE, "variable asignement fail: too much variables"); + struct cli_var *var = &cli_vars[nb_cli_vars++]; + json_object *j = jobj; + char buf[512]; + + tmp2 = strchr(tmp, '='); + TRY(!tmp2, "variable asignement fail (missing '='))\n"); + TRY((uintptr_t)(tmp2 - tmp) >= VAR_NAME_SIZE, "var name too long"); + strncpy(var->name, tmp, tmp2 - tmp); + var->name[tmp2 - tmp] = 0; + tmp = tmp2 + 1; + + while ((tmp2 = strchr(tmp, '.')) != NULL) { + char *end = NULL; + // get json + int idx = strtoul(tmp, &end, 0); + if (end != tmp) { + j = json_object_array_get_idx(j, idx); + } else { + TRY((uintptr_t)(tmp2 - tmp) >= sizeof buf - 1, + "variable asignement fail"); + strncpy(buf, tmp, tmp2 - tmp); + buf[tmp2 - tmp] = 0; + j = json_object_object_get(j, buf); + } + TRY(!j, "variable asignement fail (not found)"); + tmp = tmp2 + 1; + } + tmp2 = tmp + strlen(tmp); + TRY((uintptr_t)(tmp2 - tmp) >= sizeof buf - 1, + "variable asignement fail"); + strncpy(buf, tmp, tmp2 - tmp); + buf[tmp2 - tmp] = 0; + j = json_object_object_get(j, buf); + if (json_object_is_type(j, json_type_string)) { + tmp = json_object_get_string(j); + } else { + tmp = json_object_to_json_string_ext(j, JSON_C_TO_STRING_PLAIN); + } + TRY(strlen(tmp) >= VAR_VAL_SIZE, "variable asignement fail: value too big"); + strcpy(var->val, tmp); + return 0; + +} + char *read_file(char *files_cnt[static MAX_FILES_PER_CMD], char *file_name, int is_json) { @@ -161,10 +224,6 @@ char *read_file(char *files_cnt[static MAX_FILES_PER_CMD], char *file_name, return NULL; } - -static void *cascade_struct; -static int (*cascade_parser)(void *, char *, char *, struct ptr_array *); - ____complex_struct_func_parser____ From 781c1a77cdb24a36a96a13b465e22593e23903a5 Mon Sep 17 00:00:00 2001 From: Matthias Gatto Date: Thu, 21 Mar 2024 17:47:16 +0100 Subject: [PATCH 2/3] autofree json_c structs Signed-off-by: Matthias Gatto --- cognac_gen.sh | 6 ++++-- function.c | 2 +- lib.c | 24 ++++++++++-------------- lib.h | 11 +++++++++++ 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/cognac_gen.sh b/cognac_gen.sh index d405dac..0d870d5 100755 --- a/cognac_gen.sh +++ b/cognac_gen.sh @@ -314,7 +314,7 @@ EOF cat <c, CURLOPT_POSTFIELDS, r ? data.buf : ""); curl_easy_setopt(e->c, CURLOPT_WRITEDATA, out); if (e->flag & OSC_VERBOSE_MODE) { - printf("\n%s\n\n", data.buf); + printf("\n%s\n\n", data.buf); } res = curl_easy_perform(e->c); out: diff --git a/lib.c b/lib.c index 551b9d1..15110d2 100644 --- a/lib.c +++ b/lib.c @@ -129,16 +129,6 @@ const char **osc_calls_name(void) #define THREAD_LOCAL #endif -static void osc_json_c_obj_put(json_object **js) -{ - if (!*js) - return; - json_object_put(*js); -} - -#define auto_osc_json_c_obj_put __attribute__((cleanup(osc_json_c_obj_put))) - - static THREAD_LOCAL const char *cfg_path; void osc_set_cfg_path(const char *cfg) @@ -294,7 +284,7 @@ int osc_load_ak_sk_from_conf(const char *profile, char **ak, char **sk) char buf[1024]; const char *cfg = cfg_path; struct json_object *js, *ak_js, *sk_js; - auto_osc_json_c_obj_put struct json_object *to_free = NULL; + auto_osc_json_c struct json_object *to_free = NULL; if (!ak && !sk) return 0; @@ -330,7 +320,7 @@ int osc_load_loging_password_from_conf(const char *profile, { char buf[1024]; const char *cfg = cfg_path; - auto_osc_json_c_obj_put struct json_object *to_free = NULL; + auto_osc_json_c struct json_object *to_free = NULL; struct json_object *js, *login_js, *pass_js; if (!email && !password) @@ -370,7 +360,7 @@ int osc_load_region_from_conf(const char *profile, char **region) const char *cfg = cfg_path; char buf[1024]; struct json_object *js; - auto_osc_json_c_obj_put struct json_object *to_free = NULL; + auto_osc_json_c struct json_object *to_free = NULL; if (!cfg) { LOAD_CFG_GET_HOME(buf); @@ -395,7 +385,7 @@ int osc_load_cert_from_conf(const char *profile, char **cert, char **key) { struct json_object *cert_obj, *key_obj, *js; const char *cfg = cfg_path; - auto_osc_json_c_obj_put struct json_object *to_free = NULL; + auto_osc_json_c struct json_object *to_free = NULL; char buf[1024]; int ret = 0; @@ -447,6 +437,12 @@ void osc_init_str(struct osc_str *r) r->buf = NULL; } +void osc_deinit_json_c(json_object **j) +{ + if (j && *j) + json_object_put(*j); +} + void osc_deinit_str(struct osc_str *r) { free(r->buf); diff --git a/lib.h b/lib.h index 962194d..95cd4d9 100644 --- a/lib.h +++ b/lib.h @@ -53,6 +53,11 @@ extern "C" { #define auto_osc_str __attribute__((cleanup(osc_deinit_str))) #define auto_osc_env __attribute__((cleanup(osc_deinit_sdk))) +/* + * Helper for json C + */ +#define auto_osc_json_c __attribute__((cleanup(osc_deinit_json_c))) + #endif struct osc_str { @@ -141,6 +146,12 @@ int osc_init_sdk_ext(struct osc_env *e, const char *profile, unsigned int flag, struct osc_env_conf *cfg); void osc_deinit_sdk(struct osc_env *e); +struct json_object; + +typedef struct json_object json_object; + +void osc_deinit_json_c(json_object **j); + int osc_str_append_string(struct osc_str *osc_str, const char *str); int osc_str_append_n_string(struct osc_str *osc_str, const char *str, int l); From 131727a1f1c02fc2f4b124ac0b31bf47b7da53d2 Mon Sep 17 00:00:00 2001 From: Matthias Gatto Date: Mon, 25 Mar 2024 16:07:54 +0100 Subject: [PATCH 3/3] add help for -set-var/-var Signed-off-by: Matthias Gatto --- cognac_gen.sh | 6 +++--- main_tpl.c | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cognac_gen.sh b/cognac_gen.sh index 0d870d5..5efa7de 100755 --- a/cognac_gen.sh +++ b/cognac_gen.sh @@ -346,7 +346,7 @@ EOF goto ${snake_l}_arg; } - if (i + 1 < ac && av[i + 1][0] == '-' && av[i + 1][1] == '-' && strcmp(av[i + 1] + 2, "SetVar")) { + if (i + 1 < ac && av[i + 1][0] == '-' && av[i + 1][1] == '-' && strcmp(av[i + 1] + 2, "set-var")) { char *next_a = &av[i + 1][2]; char *str = next_a; char *aa = i + 2 < ac ? av[i + 2] : 0; @@ -419,9 +419,9 @@ EOF JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE | color_flag)); } - if (i + 1 < ac && !strcmp(av[i + 1], "--SetVar")) { + if (i + 1 < ac && !strcmp(av[i + 1], "--set-var")) { ++i; - TRY(i + 1 >= ac, "--SetVar require an argument"); + TRY(i + 1 >= ac, "--set-var require an argument"); if (!jobj) jobj = json_tokener_parse(r.buf); if (parse_variable(jobj, av, ac, i)) diff --git a/main_tpl.c b/main_tpl.c index 5feaba1..699fb6f 100644 --- a/main_tpl.c +++ b/main_tpl.c @@ -365,7 +365,7 @@ int main(int ac, char **av) if (ac < 2 || (ac == 2 && !strcmp(av[1], "--help"))) { show_help: - printf("Usage: %s [--help] CallName [options] [--Params >]\n" + printf("Usage: %s [--help] CallName [options] [--Params >] | --var \n" "options:\n" "\t --auth-method=METHODE set authentification method, password|accesskey|none\n" "\t --color try to colorize json if json-c support it\n" @@ -373,6 +373,10 @@ int main(int ac, char **av) "\t --file PATH use content of PATH as an agrument for a call, example:\n" "\t\t\t\toapi-cli CreateCa --CaPem --file /$CA_DIR/cert.pem\n" "\t --jsonstr-file PATH same as --file, except the content is surrounded by \"\n" + "\t --set-var ID=VARIABLE_PATH Create an oapi-cli variable, that can be use with --var\n" + "\t\t\t\tExamples: ./oapi-cli ReadVms --Filters.TagValues[] VM_NAME --set-var id=Vms.0.VmId ReadVms --Filters.VmIds[] --var id\n" + "\t\t\t\twill find the vm with VM_NAME as it's tag, and read it again, but using it's VmId as filter this time\n" + "\t --var use variabble content created by --set-var\n" "\t\t\t\tand \" inside the file are escape with a \\, this option is useful for CreatePolicy\n" "\t-h, --help [CallName] this, can be used with call name, example:\n\t\t\t\t%s --help ReadVms\n" "\t --list-calls list all calls\n"