From d3729fb1999f555581d809ee3d34eff0da5797d3 Mon Sep 17 00:00:00 2001 From: kwangsuk Date: Thu, 5 Nov 2020 10:50:00 -0800 Subject: [PATCH] add the built-in methods to ehhance Klish performance --- .../patches/klish-2.1.4/configure.ac.diff | 3 + .../plugins/clish/builtin_init.c.diff | 8 + .../klish-2.1.4/plugins/clish/call_pyobj.c | 260 +++++++++++++ .../klish-2.1.4/plugins/clish/hook_log.c.diff | 16 + .../klish-2.1.4/plugins/clish/logging.h | 18 + .../klish-2.1.4/plugins/clish/module.am.diff | 4 + .../klish-2.1.4/plugins/clish/nos_extn.c | 125 ++++++ .../klish-2.1.4/plugins/clish/nos_extn.h | 24 ++ .../klish-2.1.4/plugins/clish/private.h.diff | 4 + .../klish-2.1.4/plugins/clish/rest_cl.cpp | 364 ++++++++++++++++++ .../plugins/clish/sym_script.c.diff | 28 ++ 11 files changed, 854 insertions(+) create mode 100644 CLI/klish/patches/klish-2.1.4/configure.ac.diff create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/builtin_init.c.diff create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/call_pyobj.c create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/hook_log.c.diff create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/logging.h create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/module.am.diff create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/nos_extn.c create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/nos_extn.h create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/private.h.diff create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/rest_cl.cpp create mode 100644 CLI/klish/patches/klish-2.1.4/plugins/clish/sym_script.c.diff diff --git a/CLI/klish/patches/klish-2.1.4/configure.ac.diff b/CLI/klish/patches/klish-2.1.4/configure.ac.diff new file mode 100644 index 0000000000..417bc44bc4 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/configure.ac.diff @@ -0,0 +1,3 @@ +27a28,29 +> AC_PROG_CXX +> diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/builtin_init.c.diff b/CLI/klish/patches/klish-2.1.4/plugins/clish/builtin_init.c.diff new file mode 100644 index 0000000000..16a3055732 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/builtin_init.c.diff @@ -0,0 +1,8 @@ +9a10 +> #include "nos_extn.h" +32a34,38 +> clish_plugin_add_psym(plugin, clish_restcl, "clish_restcl"); +> clish_plugin_add_psym(plugin, clish_pyobj, "clish_pyobj"); +> clish_plugin_add_psym(plugin, clish_setenv, "clish_setenv"); +> +> nos_extn_init(); diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/call_pyobj.c b/CLI/klish/patches/klish-2.1.4/plugins/clish/call_pyobj.c new file mode 100644 index 0000000000..47bc419a96 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/call_pyobj.c @@ -0,0 +1,260 @@ +/* +########################################################################### +# +# Copyright 2019 Dell, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +########################################################################### +*/ +#include "lub/dump.h" +#include "private.h" +#include "logging.h" + +#include +#include +#include +#include + +void pyobj_init() { + Py_Initialize(); +} + +static void pyobj_handle_error() { + PyObject *type, *value, *traceback; + PyObject *pystr, *py_module, *py_func; + char *str; + + if (!PyErr_Occurred()) { + return; + } + + PyErr_Fetch(&type, &value, &traceback); + PyErr_NormalizeException(&type, &value, &traceback); + + if (!PyErr_GivenExceptionMatches(type, PyExc_SystemExit)) { + lub_dump_printf("%%Error: Internal error.\n"); + } + + py_module = PyImport_ImportModule("traceback"); + if (py_module) { + py_func = PyObject_GetAttrString(py_module, "format_exception"); + + if (py_func && PyCallable_Check(py_func)) { + PyObject *py_val; + py_val = PyObject_CallFunctionObjArgs(py_func, + type, value, traceback, NULL); + + pystr = PyObject_Str(py_val); + if (pystr) { + str = PyString_AsString(pystr); + syslog(LOG_WARNING, "clish_pyobj: Traceback: %s", str); + } + + Py_XDECREF(pystr); + Py_XDECREF(py_func); + Py_XDECREF(py_val); + } + } + + pystr = PyObject_Str(value); + if (pystr) { + str = PyString_AsString(pystr); + syslog(LOG_WARNING, "clish_pyobj: Error: %s", str); + } + + Py_XDECREF(pystr); + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + Py_XDECREF(py_module); +} + +int pyobj_update_environ(const char *key, const char *val) { + + PyObject *module = PyImport_ImportModule("os"); + if (module == NULL) { + pyobj_handle_error(); + return -1; + } + + PyObject *dict = PyModule_GetDict(module); + PyObject *env_obj = PyDict_GetItemString(dict, "environ"); + + PyObject *func = PyObject_GetAttrString(env_obj, "update"); + + PyObject *pMap = PyDict_New(); + PyObject *v_obj = PyString_FromString(val); + PyDict_SetItemString(pMap, key, v_obj); + + PyObject *args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pMap); + + PyObject_CallObject(func, args); + + if (PyErr_Occurred()) { + pyobj_handle_error(); + return 1; + } + + Py_XDECREF(module); + Py_XDECREF(func); + Py_XDECREF(v_obj); + Py_XDECREF(pMap); + Py_XDECREF(args); + + return 0; +} + +static int pyobj_set_user_cmd(const char *cmd) { + return pyobj_update_environ("USER_COMMAND", cmd); +} + +int pyobj_set_rest_token(const char *token) { + return pyobj_update_environ("REST_API_TOKEN", token); +} + +int call_pyobj(char *cmd, const char *arg, char **out) { + int ret_code = 0; + char *token[128]; + char *buf; + int i; + + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + + pyobj_set_user_cmd(cmd); + syslog(LOG_DEBUG, "clish_pyobj: cmd=%s", cmd); + + buf = strdup(arg); + if (!buf) { + syslog(LOG_WARNING, "clish_pyobj: Failed to allocate memory"); + return -1; + } + + // trim leading and trailing whtespace + char *p = buf; + int len = strlen(buf); + while (isspace(p[len-1])) p[--len] = '\0'; + while (*p && isspace(*p)) ++p, --len; + + char *saved_ptr = '\0'; + size_t idx = 0; + bool quoted = false; + + while (*p) { + if (!saved_ptr) saved_ptr = p; + if (*p == ' ' && quoted == false) { + while (*(p+1) && *(p+1)==' ') { + memmove(p, p+1, strlen(p)-1); + *(p+strlen(p)-1) = '\0'; + } + *p = '\0'; + token[idx++] = saved_ptr; + saved_ptr = '\0'; + } else if (*p == '\"') { + if (!quoted && strchr((p+1), '\"')) { + // open quote + if (*saved_ptr == '\"') { + saved_ptr++; + quoted = true; + } + } else if (quoted) { + // close quote + quoted = false; + *p = '\0'; + } + } + // escape chars + if (*p == '\\') { + if (*(p+1) == '\\' || *(p+1) == '\"') { + memmove(p, p+1, strlen(p)-1); + *(p+strlen(p)-1) = '\0'; + } + } + if (*++p == '\0' && saved_ptr) + token[idx++] = saved_ptr; + } + + PyObject *module, *name, *func, *args, *value; + + name = PyBytes_FromString(token[0]); + module = PyImport_Import(name); + if (module == NULL) { + syslog(LOG_WARNING, "clish_pyobj: Failed to load module %s", token[0]); + pyobj_handle_error(); + free(buf); + Py_XDECREF(name); + PyGILState_Release(gstate); + return -1; + } + + func = PyObject_GetAttrString(module, "run"); + + if (!func || !PyCallable_Check(func)) { + lub_dump_printf("%%Error: Internal error.\n"); + syslog(LOG_WARNING, "clish_pyobj: Function run not found in module %s", token[0]); + Py_XDECREF(module); + Py_XDECREF(name); + free(buf); + PyGILState_Release(gstate); + return -1; + } + + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, PyBytes_FromString(token[1])); + + PyObject *args_list = PyList_New(0); + for (i=1; i< idx-1; i++) { + PyList_Append(args_list, PyBytes_FromString(token[i+1])); + } + PyTuple_SetItem(args, 1, args_list); + + value = PyObject_CallObject(func, args); + if (value == NULL) { + pyobj_handle_error(); + syslog(LOG_WARNING, "clish_pyobj: Failed [cmd=%s][args:%s]", cmd, arg); + ret_code = 1; + } else { + if (PyInt_Check(value)) { + ret_code = PyInt_AsLong(value); + } else if (PyString_Check(value)) { + if (!*out) *out = (char *)calloc((PyString_Size(value)+1), sizeof(char)); // dealloc higher up in call hierarchy + if (*out == NULL) { + lub_dump_printf("%%Error: Internal error.\n"); + syslog(LOG_WARNING, "clish_pyobj: Failed to allocate memory"); + ret_code = -1; + } else { + strncpy(*out,PyString_AsString(value),PyString_Size(value)); + } + } + + if (ret_code) { + syslog(LOG_WARNING, "clish_pyobj: [cmd=%s][args:%s] ret_code:%d", cmd, arg, ret_code); + } + } + + Py_XDECREF(module); + Py_XDECREF(name); + Py_XDECREF(func); + Py_XDECREF(args); + Py_XDECREF(value); + + free(buf); + + PyGC_Collect(); + malloc_trim(0); + + PyGILState_Release(gstate); + return ret_code; +} diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/hook_log.c.diff b/CLI/klish/patches/klish-2.1.4/plugins/clish/hook_log.c.diff new file mode 100644 index 0000000000..61b56a8345 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/hook_log.c.diff @@ -0,0 +1,16 @@ +diff --git a/plugins/clish/hook_log.c b/plugins/clish/hook_log.c +index cafd29e..da59419 100644 +--- a/plugins/clish/hook_log.c ++++ b/plugins/clish/hook_log.c +@@ -37,8 +37,9 @@ CLISH_HOOK_LOG(clish_hook_log) + if (!(uname = getenv("LOGNAME"))) + uname = user ? user->pw_name : "unknown"; + } +- syslog(LOG_INFO, "%u(%s) %s : %d", +- user ? user->pw_uid : getuid(), uname, line, retcode); ++ ++ int facility = LOG_LOCAL4; ++ syslog(LOG_INFO|facility, "User \"%s\" command \"%s\" status - %s", uname, line, retcode ? "failure" : "success"); + + return 0; + } diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/logging.h b/CLI/klish/patches/klish-2.1.4/plugins/clish/logging.h new file mode 100644 index 0000000000..2f5f84b65e --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/logging.h @@ -0,0 +1,18 @@ +#ifndef __LOGGING_H__ +#define __LOGGING_H__ + +#include +#include + +#ifdef SYSLOG_TO_STDOUT + +#define syslog(LEVEL, FMT, ARGS...) \ + do { \ + if (LEVEL < LOG_DEBUG || getenv("DEBUG")) { \ + printf("[%s] " FMT "\n", #LEVEL, ##ARGS); \ + } \ + } while(0) + +#endif + +#endif // __LOGGING_H__ diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/module.am.diff b/CLI/klish/patches/klish-2.1.4/plugins/clish/module.am.diff new file mode 100644 index 0000000000..002f7df516 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/module.am.diff @@ -0,0 +1,4 @@ +20a21,23 +> plugins/clish/rest_cl.cpp \ +> plugins/clish/call_pyobj.c \ +> plugins/clish/nos_extn.c \ diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/nos_extn.c b/CLI/klish/patches/klish-2.1.4/plugins/clish/nos_extn.c new file mode 100644 index 0000000000..e0686c7fa1 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/nos_extn.c @@ -0,0 +1,125 @@ +/* +########################################################################### +# +# Copyright 2019 Dell, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +########################################################################### +*/ + +#include "private.h" +#include "nos_extn.h" +#include "lub/string.h" + +#include +#include +#include +#include +#include +#include +#include + +pthread_mutex_t lock; + +void *rest_token_refresh(void *vargp){ + int expiry = (intptr_t)vargp; + int interval; + while(1) { + interval = 0.8 * expiry; + syslog(LOG_DEBUG, "Token update - sleeping for %d of %d", interval, expiry); + + /* Sleep for 80% of the interval */ + sleep(interval); + + pthread_mutex_lock(&lock); + + rest_token_fetch(&expiry); + + pthread_mutex_unlock(&lock); + } +} + +int clish_rest_thread_init() { + pthread_t thread_id; + + + int expiry = 30; + rest_token_fetch(&expiry); + + pthread_create(&thread_id, NULL, rest_token_refresh, (void*)(long)expiry); + return 0; +} + +CLISH_PLUGIN_SYM(clish_restcl) +{ + char *cmd = clish_shell__get_full_line(clish_context); + + pthread_mutex_lock(&lock); + + int ret = rest_cl(cmd, script); + + pthread_mutex_unlock(&lock); + + lub_string_free(cmd); + + return ret; +} + +CLISH_PLUGIN_SYM(clish_pyobj) +{ + char *cmd = clish_shell__get_full_line(clish_context); + + sigset_t sigs; + sigemptyset(&sigs); + sigaddset(&sigs, SIGINT); + sigprocmask(SIG_UNBLOCK, &sigs, NULL); + + pthread_mutex_lock(&lock); + int ret = call_pyobj(cmd, script, out); + pthread_mutex_unlock(&lock); + + return ret; +} + +CLISH_PLUGIN_SYM(clish_setenv) +{ + char *key, *value; + key = strtok_r((char*)script, "=", &value); + + if (key) { + pyobj_update_environ(key,value); + + setenv(key, value, 1); + } + + return 0; +} + +void nos_extn_init() { + + pthread_mutex_init(&lock, NULL); + + int auth_ena = (getenv("CLISH_NOAUTH") == NULL); + + rest_client_init(); + pyobj_init(); + + if (auth_ena) { + clish_rest_thread_init(); + } + + if (!auth_ena) { + syslog(LOG_WARNING, "CLISH running with auth disabled"); + } +} diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/nos_extn.h b/CLI/klish/patches/klish-2.1.4/plugins/clish/nos_extn.h new file mode 100644 index 0000000000..d7cb2353a8 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/nos_extn.h @@ -0,0 +1,24 @@ + +#ifndef __NOS_EXTN_H__ +#define __NOS_EXTN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void pyobj_init(); +extern void nos_extn_init(); + +extern int call_pyobj(char *cmd, const char *buff, char **out); +extern int pyobj_set_rest_token(const char*); +extern int pyobj_update_environ(const char *key, const char *val); + +extern void rest_client_init(); +extern int rest_token_fetch(int *interval); +extern int rest_cl(char *cmd, const char *buff); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/private.h.diff b/CLI/klish/patches/klish-2.1.4/plugins/clish/private.h.diff new file mode 100644 index 0000000000..73dbea3b80 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/private.h.diff @@ -0,0 +1,4 @@ +23a24,26 +> CLISH_PLUGIN_SYM(clish_restcl); +> CLISH_PLUGIN_SYM(clish_pyobj); +> CLISH_PLUGIN_SYM(clish_setenv); diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/rest_cl.cpp b/CLI/klish/patches/klish-2.1.4/plugins/clish/rest_cl.cpp new file mode 100644 index 0000000000..1690f74aec --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/rest_cl.cpp @@ -0,0 +1,364 @@ +/* +########################################################################### +# +# Copyright 2019 Dell, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +########################################################################### +*/ + +extern "C" { +#include "private.h" +#include "lub/dump.h" +#include "nos_extn.h" +#include "logging.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +} + +#include + +std::string REST_API_ROOT; + +typedef struct { + int size; + std::string body; +} RestResponse; + +typedef struct { + const char* data; + size_t length; +} PayloadData; + +static ssize_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp) +{ + PayloadData *upload = reinterpret_cast(userp); + size_t max = size*nmemb; + + size_t copy_size = max; + if (upload->length < max) { + copy_size = upload->length; + } + + memcpy(ptr, upload->data, copy_size); + + upload->length -= copy_size; + upload->data += copy_size; + + return copy_size; +} + +static size_t write_callback(void *data, size_t size, + size_t nmemb, void *userdata) { + size_t realsize = size * nmemb; + RestResponse *mem = reinterpret_cast(userdata); + + mem->body.append(reinterpret_cast(data), realsize); + mem->size += realsize; + + return realsize; + +} + +int print_error(const char *str) { + + cJSON *ret_json = cJSON_Parse(str); + if (!ret_json) { + syslog(LOG_DEBUG, "clish_restcl: Failed parsing error string\r\n"); + return 0; + } + + cJSON *ietf_err = cJSON_GetObjectItemCaseSensitive(ret_json, "ietf-restconf:errors"); + if (!ietf_err) { + syslog(LOG_DEBUG, "clish_restcl: No errors\r\n"); + return 0; + } + + cJSON *errors = cJSON_GetObjectItemCaseSensitive(ietf_err, "error"); + if (!errors) { + syslog(LOG_DEBUG, "clish_restcl: No error\r\n"); + return 0; + } + + cJSON *error; + cJSON_ArrayForEach(error, errors) { + cJSON *err_msg = cJSON_GetObjectItemCaseSensitive(error, "error-message"); + if (err_msg) { + lub_dump_printf("%% Error: %s\r\n", err_msg->valuestring); + /* Since error-message is an optional attribute, we need to check for "error-tag" + and print the error-message accordingly */ + } else { + std::string err_msg = "operation failed"; + + cJSON* err_tag = cJSON_GetObjectItemCaseSensitive(error, "error-tag"); + if(err_tag == NULL) { + lub_dump_printf("%% Error: %s\r\n", err_msg.c_str()); + return 1; + } + std::string err_tag_str = std::string {err_tag->valuestring}; + + if(err_tag_str == "invalid-value") { + err_msg = "validation failed"; + } else if (err_tag_str == "operation-not-supported") { + err_msg = "not supported"; + } else if (err_tag_str == "access-denied") { + err_msg = "not authorized"; + } else { + err_msg = "operation failed"; + } + lub_dump_printf("%% Error: %s\r\n", err_msg.c_str()); + } + return 1; + } + return 0; +} + + +std::string rest_token; + +CURL *curl = NULL; + +static int rest_set_curl_headers(bool use_token) { + struct curl_slist* headerList = NULL; + headerList = curl_slist_append(headerList, "accept: application/yang-data+json"); + headerList = curl_slist_append(headerList, "Content-Type: application/yang-data+json"); + + if (rest_token.size() && use_token) { + std::string auth_hdr = "Authorization: Bearer "; + auth_hdr += rest_token; + headerList = curl_slist_append(headerList, auth_hdr.c_str()); + } + + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList); + + return 0; +} + +static int _init_curl() { + + curl_global_init(CURL_GLOBAL_ALL); + + curl = curl_easy_init(); + if (!curl) { + return 1; + } + + curl_easy_setopt(curl, CURLOPT_USERAGENT, "CLI"); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + + if (REST_API_ROOT.find("https://") == 0) { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + } else { + curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, "/var/run/rest-local.sock"); + } + + return 0; +} + +void rest_client_init() { + char *root = getenv("REST_API_ROOT"); + + REST_API_ROOT.assign(root ? root : "http://localhost"); + + _init_curl(); + + rest_set_curl_headers(true); +} + +int rest_token_fetch(int *interval) { + + CURLcode res; + std::string url; + + if (!curl) { + syslog(LOG_WARNING, "curl handle is not yet initialized."); + return 1; + } + + url = REST_API_ROOT; + url.append("/authenticate"); + + rest_set_curl_headers(false); + + RestResponse ret = {}; + ret.size = 0; + + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + + curl_easy_setopt(curl, CURLOPT_UPLOAD, 0L); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); + + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); + + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) { + syslog(LOG_WARNING, "curl_easy_perform() for rest_token_fetch failed: %s\n", + curl_easy_strerror(res)); + } else { + if (ret.size) { + cJSON *ret_json = cJSON_Parse(ret.body.c_str()); + if (ret_json) { + cJSON *token = cJSON_GetObjectItemCaseSensitive(ret_json, "access_token"); + if (token) { + rest_token.assign(token->valuestring); + + setenv("REST_API_TOKEN", rest_token.c_str(), 1); + + pyobj_set_rest_token(rest_token.c_str()); + + rest_set_curl_headers(true); + + cJSON *expiry = cJSON_GetObjectItemCaseSensitive(ret_json, "expires_in"); + if (expiry) { + *interval = expiry->valueint; + } + } else { + syslog(LOG_DEBUG, "rest_token_fetch: No access_token"); + } + } else { + syslog(LOG_DEBUG, "rest_token_fetch: Failed parsing return string"); + } + } else { + syslog(LOG_DEBUG, "rest_token_fetch: No response received"); + } + } + } + return 0; +} + +std::string& rtrim(std::string& str, const std::string& chars = "\t\n\v\f\r ") +{ + str.erase(str.find_last_not_of(chars) + 1); + return str; +} + +int _parse_args (std::string &input, std::string &oper_s, std::string &url_s, std::string &body_s){ + + size_t oper_pos = input.find("oper="); + if (oper_pos != std::string::npos) { + oper_pos += strlen("oper="); + } + + size_t url_pos = input.find("url="); + if (url_pos == std::string::npos) { + syslog(LOG_ERR, "url= missing in %s\r\n", input.c_str()); + return 1; + } else { + /* 'oper' terminates just before 'url=' */ + oper_s = input.substr(oper_pos, url_pos - oper_pos); + rtrim(oper_s); + + url_pos += strlen("url="); + } + + url_s = REST_API_ROOT; + + size_t body_pos = input.find("body="); + + /* If "body=" doesnt exist, 'url' extends till end of string */ + if (body_pos == std::string::npos) { + url_s += input.substr(url_pos); + } else { + /* 'url' terminates just before 'body=' */ + url_s += input.substr(url_pos, body_pos - url_pos); + + body_pos += strlen("body="); + body_s = input.substr(body_pos); + + rtrim(body_s); + } + + rtrim(url_s); + + return 0; +} + +int rest_cl(char *cmd, const char *buff) +{ + CURLcode res; + + int ret_code = 1; + std::string url, body, oper; + std::string arg = buff; + + setenv("USER_COMMAND", cmd, 1); + syslog(LOG_DEBUG, "clish_restcl: cmd=%s", cmd); + + _parse_args(arg, oper, url, body); + syslog(LOG_DEBUG, "clish_restcl: [oper:%s][path:%s][body:%s]", oper.c_str(), url.c_str(), body.c_str()); + + RestResponse ret = {}; + ret.size = 0; + + if(curl) { + + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, oper.c_str()); + + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + + PayloadData up_obj = {}; + if (body.size()) { + + up_obj.data = body.c_str(); + up_obj.length = body.size(); + curl_easy_setopt(curl, CURLOPT_READDATA, &up_obj); + + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, + (curl_off_t)up_obj.length); + + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + } else { + curl_easy_setopt(curl, CURLOPT_UPLOAD, 0L); + } + + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); + + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) { + lub_dump_printf("%%Error: Could not connect to Management REST Server\n"); + syslog(LOG_WARNING, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + } else { + int64_t http_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); + if (ret.size) { + syslog(LOG_DEBUG, "clish_restcl: http_code:%ld [%d:%s]", http_code, ret.size, ret.body.c_str()); + print_error(ret.body.c_str()); + } else { + ret_code = 0; + } + } + } else { + lub_dump_printf("%%Error: Could not connect to Management REST Server\n"); + syslog(LOG_WARNING, "Couldn't initialize curl handle"); + } + + return ret_code; +} diff --git a/CLI/klish/patches/klish-2.1.4/plugins/clish/sym_script.c.diff b/CLI/klish/patches/klish-2.1.4/plugins/clish/sym_script.c.diff new file mode 100644 index 0000000000..b2b8ac1529 --- /dev/null +++ b/CLI/klish/patches/klish-2.1.4/plugins/clish/sym_script.c.diff @@ -0,0 +1,28 @@ +diff --git a/plugins/clish/sym_script.c b/plugins/clish/sym_script.c +index 93cc88f..7dee09b 100644 +--- a/plugins/clish/sym_script.c ++++ b/plugins/clish/sym_script.c +@@ -37,6 +37,10 @@ CLISH_PLUGIN_OSYM(clish_script) + if (!script) /* Nothing to do */ + return 0; + ++ char *cmd = clish_shell__get_full_line(clish_context); ++ setenv("USER_COMMAND", cmd, 1); ++ lub_string_free(cmd); ++ + /* Find out shebang */ + if (action) + shebang = clish_action__get_shebang(action); +@@ -80,6 +84,12 @@ CLISH_PLUGIN_OSYM(clish_script) + lub_string_cat(&command, shebang); + lub_string_cat(&command, " "); + lub_string_cat(&command, fifo_name); ++ lub_string_cat(&command, " 2> /dev/null"); ++ ++ sigset_t sigs; ++ sigemptyset(&sigs); ++ sigaddset(&sigs, SIGINT); ++ sigprocmask(SIG_UNBLOCK, &sigs, NULL); + + res = system(command); +