From 75eb2161c641f85dded64a99cb862abfab64eff7 Mon Sep 17 00:00:00 2001 From: Sebastien Douheret Date: Tue, 12 Jun 2018 17:52:40 +0200 Subject: Improved supervisor requests & events recording Change-Id: I4eb52820d2bec4ca4f2e3e455db7eb79d1a09d12 Signed-off-by: Sebastien Douheret --- .vscode/c_cpp_properties.json | 1 + .vscode/launch.json | 1 + .vscode/settings.json | 22 ++- .vscode/tasks.json | 3 +- afb-helpers | 2 +- conf.d/cmake/config.cmake | 2 +- conf.d/project/etc/xds-config.json | 27 ---- conf.d/project/etc/xds-supervisor-config.json | 39 +++++ conf.d/project/lua.d/CMakeLists.txt | 32 ++++ conf.d/project/lua.d/xds-supervisor.lua | 119 +++++++++++++++ htdocs/d3js-graph.js | 14 +- htdocs/index.html | 2 +- htdocs/iotbzh-Binding.js | 3 +- src/plugins/supervisor-api.c | 157 ++++++++++++++++---- src/plugins/supervisor-api.h | 18 ++- src/plugins/supervisor.c | 93 +++++++++--- src/plugins/supervisor.h | 2 +- src/xds-apidef.json | 97 ++++++++----- src/xds-binding.c | 202 ++++++++++++++------------ 19 files changed, 605 insertions(+), 231 deletions(-) delete mode 100644 conf.d/project/etc/xds-config.json create mode 100644 conf.d/project/etc/xds-supervisor-config.json create mode 100644 conf.d/project/lua.d/CMakeLists.txt create mode 100644 conf.d/project/lua.d/xds-supervisor.lua diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index f7487f5..cf04612 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -17,6 +17,7 @@ "/usr/include" ], "defines": [ + "CONTROL_SUPPORT_LUA", "AFB_BINDING_PREV3", "USE_API_DYN" ], diff --git a/.vscode/launch.json b/.vscode/launch.json index b163338..a2162c2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,6 +13,7 @@ "--port=5678", "--name=afb-xds", "--ws-client=unix:/tmp/supervisor", + "--ws-client=unix:/tmp/harvester", "--workdir=${workspaceRoot}/build/package/", "--ldpaths=lib", "--roothttp=htdocs", diff --git a/.vscode/settings.json b/.vscode/settings.json index 2777e9f..d41869a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,11 @@ { + "files.exclude": { + ".vscode": true, + "nbproject": true, + "build": true, + "**/.git": true, + "**/node_modules": true + }, "[json]": { "editor.quickSuggestions": { "strings": true @@ -42,12 +49,22 @@ "unistd.h": "c", "supervisor.h": "c", "sstream": "c", - "stat.h": "c" + "stat.h": "c", + "filescan-utils.h": "c", + "optional": "cpp", + "ostream": "cpp", + "system_error": "cpp", + "supervisor-api.h": "c", + "string_view": "c", + "initializer_list": "c", + "valarray": "c" }, // Words to add to dictionary for a workspace. "cSpell.words": [ "CTLP", + "SPVR", "callbinder", + "ctlso", "gotevent", "ldpaths", "lightgreen", @@ -58,7 +75,8 @@ "replyerr", "replyok", "reqid", - "roothttp" + "roothttp", + "spath" ], "C_Cpp.intelliSenseEngineFallback": "Enabled" } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index d1709f7..fc33950 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -17,7 +17,8 @@ "command": "clear && cd build && make", "presentation": { "echo": true, - "reveal": "always", + //"reveal": "always", + "reveal": "silent", "focus": false, "panel": "shared" }, diff --git a/afb-helpers b/afb-helpers index f9f7e1e..c7cd527 160000 --- a/afb-helpers +++ b/afb-helpers @@ -1 +1 @@ -Subproject commit f9f7e1e3d394024484df41e3d97d6b8505810f36 +Subproject commit c7cd527a8350f736b8013f65db6f5a52b8cb05dd diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index 8ffa90d..3c17187 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -197,7 +197,7 @@ set(AFB_REMPORT "5678" CACHE PATH "Default binder listening port") # Print a helper message when every thing is finished # ---------------------------------------------------- -set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --port=${AFB_REMPORT} --name=afb-xds --workdir=${CMAKE_BINARY_DIR}/package --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --verbose --ws-client=unix:/tmp/supervisor --ws-client=unix:/tmp/harvester") +set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --port=${AFB_REMPORT} --name=afb-xds --workdir=${CMAKE_BINARY_DIR}/package --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --ws-client=unix:/tmp/supervisor --ws-client=unix:/tmp/harvester -vv ") set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt") # Optional schema validator about now only XML, LUA and JSON diff --git a/conf.d/project/etc/xds-config.json b/conf.d/project/etc/xds-config.json deleted file mode 100644 index 3646d3f..0000000 --- a/conf.d/project/etc/xds-config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "http://iot.bzh/download/public/schema/json/ctl-schema.json", - "metadata": { - "uid": "XDS", - "version": "1.0", - "api": "xds", - "info": "XDS Data collection binding" - }, - "plugins": [{ - "uid": "supervisor", - "info": "Plugin to handle interface with supervisor", - "spath": "lib/plugins", - "libs": "supervisor.ctlso" - }], - - "onload": [], - - "controls": [{ - "uid": "list", - "action": "plugin://supervisor#list" - }, - { - "uid": "trace", - "action": "plugin://supervisor#trace" - } - ] -} diff --git a/conf.d/project/etc/xds-supervisor-config.json b/conf.d/project/etc/xds-supervisor-config.json new file mode 100644 index 0000000..39309bb --- /dev/null +++ b/conf.d/project/etc/xds-supervisor-config.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://iot.bzh/download/public/schema/json/ctl-schema.json", + "metadata": { + "uid": "XDS", + "version": "1.0", + "api": "xds", + "info": "XDS Data collection binding" + }, + "plugins": [{ + "uid": "supervisor", + "info": "Plugin to handle interface with supervisor", + "spath": "./lib/plugins:./var", + "libs": [ + "supervisor.ctlso", + "xds-supervisor.lua" + ] + }], + + "onload": [], + + "controls": [{ + "uid": "list", + "privileges": "urn:AGL:permission::platform:can:list ", + "action": "plugin://supervisor#list" + }, + { + "uid": "trace", + "privileges": "urn:AGL:permission::platform:can:trace ", + "action": "plugin://supervisor#trace" + } + ], + + "events": [{ + "uid": "supervisor/xds-trace", + "action": "lua://supervisor#_trace_events_" + } + ] + +} diff --git a/conf.d/project/lua.d/CMakeLists.txt b/conf.d/project/lua.d/CMakeLists.txt new file mode 100644 index 0000000..1e64cf2 --- /dev/null +++ b/conf.d/project/lua.d/CMakeLists.txt @@ -0,0 +1,32 @@ +########################################################################### +# Copyright 2018 IoT.bzh +# +# author: Fulup Ar Foll +# +# 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. +########################################################################### + + +################################################## +# XDS Lua Scripts +################################################## +PROJECT_TARGET_ADD(xds-lua) + + file(GLOB LUA_FILES "*.lua") + + add_input_files("${LUA_FILES}") + + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "DATA" + OUTPUT_NAME ${TARGET_NAME} + ) diff --git a/conf.d/project/lua.d/xds-supervisor.lua b/conf.d/project/lua.d/xds-supervisor.lua new file mode 100644 index 0000000..747d33d --- /dev/null +++ b/conf.d/project/lua.d/xds-supervisor.lua @@ -0,0 +1,119 @@ +--[[ + Copyright (C) 2018 "IoT.bzh" + Author Sebastien Douheret + + 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. + + + NOTE: strict mode: every global variables should be prefixed by '_' +--]] + +-- return serialised version of printable table +function ToJson(o) + if type(o) == "table" then + local s = "{" + local i = 0 + for k, v in pairs(o) do + if (i > 0) then + s = s .. "," + end + i = i + 1 + if type(k) ~= "number" then + k = '"' .. k .. '"' + end + s = s .. k .. ":" .. ToJson(v) + end + return s .. "}" + else + return '"' .. tostring(o) .. '"' + end +end + +function _trace_hello_events_(source, args, event) + -- TODO nothing for now +end + +function _trace_Async_CB(source, response, context) + --AFB:debug(source, "--InLua-- _trace_Async_CB response=%s context=%s\n", Dump_Table(response), Dump_Table(context)) + + if (response["request"]["status"] ~= "success") then + AFB:error(source, "--InLua-- _trace_Async_CB response=%s context=%s", Dump_Table(response), Dump_Table(context)) + return + end +end + +function _trace_events_(source, args, event) + --AFB:notice(source, "--InLua-- ENTER _trace_events_ event=%s\n", Dump_Table(event)) + + local query = { + ["host"] = "localhost", + ["port"] = 8086, + ["metric"] = { + { + ["name"] = "supervisor/trace", + ["metadata"] = { + ["identity"] = "xds supervisor", + ["tag"] = event["tag"], + }, + ["values"] = { + ["id"] = event["id"] + }, + ["timestamp"] = event["time"] + } + } + } + + if event.request then + local request = event.request + -- Filter out some traces + -- if (request.action == "begin" and request.action == "end" and request.action == "json") then + -- AFB:debug(source, "--InLua-- _trace_events_ IGNORED event=%s\n", Dump_Table(event)) + -- return + -- end + AFB:notice(source, ">>> PROCESS request %s", request) + query.metric[1].metadata.api = request.api + query.metric[1].metadata.verb = request.verb + query.metric[1].metadata.action = request.action + query.metric[1].metadata.session = request.session + query.metric[1].metadata.req_index = tostring(request.index) + if event.data then + query.metric[1].values.data = ToJson(event.data) + end + + elseif event.event then + local evt = event.event + AFB:notice(source, ">>> PROCESS event %s", evt) + query.metric[1].metadata.id = evt.id + query.metric[1].metadata.name = evt.name + query.metric[1].metadata.action = evt.action + if event.data then + query.metric[1].values.data = ToJson(event.data) + end + + else + AFB:warning(source, "--InLua-- UNKNOWN _trace_events_ event type: %s\n", Dump_Table(event)) + return + end + + AFB:debug(source, "CALL harvester write query=%s", Dump_Table(query)) + local err, response = AFB:service(source, "harvester", "write", query, "_trace_Async_CB", query) + + -- FIXME SEB : still true ? + -- Note: in current version controls only return a status. Also we may safely ignore API response + if (err) then + AFB:error(source, "--LUA:_trace_events_ harvester write refuse response=%s", response) + return 1 + end + + return 0 +end diff --git a/htdocs/d3js-graph.js b/htdocs/d3js-graph.js index 16b8939..ab826b8 100644 --- a/htdocs/d3js-graph.js +++ b/htdocs/d3js-graph.js @@ -86,8 +86,6 @@ function graphAGLBindings() { }); } -console.log("SEB d3", d3); - // http://bl.ocks.org/mbostock/1153292 // Compute the distinct nodes from the links. @@ -188,8 +186,9 @@ function graph_mobile_patent_suits() { } } +/* +Just a test of http://bl.ocks.org/d3noob/8375092 -// http://bl.ocks.org/d3noob/8375092 function interactive_tree() { var treeData = [{ @@ -404,6 +403,10 @@ function interactive_tree() { } } +*/ + +/* +Just a test of https://bl.ocks.org/mbostock/1044242 var flare = [ {"name":"flare.analytics.cluster.AgglomerativeCluster","size":3938,"imports":["flare.animate.Transitioner","flare.vis.data.DataList","flare.util.math.IMatrix","flare.analytics.cluster.MergeEdge","flare.analytics.cluster.HierarchicalCluster","flare.vis.data.Data"]}, @@ -628,7 +631,6 @@ var flare = [ {"name":"flare.vis.Visualization","size":16540,"imports":["flare.animate.Transitioner","flare.vis.operator.IOperator","flare.animate.Scheduler","flare.vis.events.VisualizationEvent","flare.vis.data.Tree","flare.vis.events.DataEvent","flare.vis.axis.Axes","flare.vis.axis.CartesianAxes","flare.util.Displays","flare.vis.operator.OperatorList","flare.vis.controls.ControlList","flare.animate.ISchedulable","flare.vis.data.Data"]} ]; -// https://bl.ocks.org/mbostock/1044242 function hierarchy_edge_bundling() { var diameter = 960, @@ -740,7 +742,7 @@ function hierarchy_edge_bundling() { } } - +// Load a graph on startup //$("#graph").ready(function(){ setTimeout(function () { //graph_mobile_patent_suits(); @@ -748,3 +750,5 @@ setTimeout(function () { //hierarchy_edge_bundling(); }, 500); //}); + +*/ diff --git a/htdocs/index.html b/htdocs/index.html index 7a3f4a8..2fdccd4 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -34,7 +34,7 @@ - + diff --git a/htdocs/iotbzh-Binding.js b/htdocs/iotbzh-Binding.js index 1d28658..a64461b 100644 --- a/htdocs/iotbzh-Binding.js +++ b/htdocs/iotbzh-Binding.js @@ -85,6 +85,7 @@ function callbinder(api, verb, query) { //********************************************** // //********************************************** +/* var topo = null; function getTopo() { @@ -119,7 +120,7 @@ function getTopo() { console.log() }); }; - +*/ diff --git a/src/plugins/supervisor-api.c b/src/plugins/supervisor-api.c index 0c1a5bc..c21cd8d 100644 --- a/src/plugins/supervisor-api.c +++ b/src/plugins/supervisor-api.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "ctl-plugin.h" @@ -44,6 +45,7 @@ CTLP_CAPI(list, source, argsJ, eventJ) return ERROR; } + AFB_ApiInfo(source->api, "Build response (nb daemons %d)", daemons->count); result = json_object_new_array(); for (int i = 0; i < daemons->count; i++) { @@ -58,31 +60,43 @@ CTLP_CAPI(list, source, argsJ, eventJ) //, "config", daemons->daemons[i]->config); json_object_array_add(result, item); } - AFB_ReqSucess(source->request, result, NULL); + + AFB_ApiInfo(source->api, "Send response"); + AFB_ReqSuccess(source->request, result, NULL); return 0; } -CTLP_CAPI(trace, source, argsJ, eventJ) +CTLP_CAPI(trace, source, argsJ, queryJ) { int rc; json_object* result = NULL; DAEMONS_T* daemons = NULL; - const char* ws_name; - const char* wsn; + const char* ws_name = ""; + const char* level = NULL; + pid_t pid = -1; - if (wrap_json_unpack(argsJ, "{s:?s}", "ws", &ws_name)) { + if (wrap_json_unpack(queryJ, "{s:?i s:?s s:?s}", + "pid", &pid, "ws", &ws_name, "level", &level)) { AFB_ReqFail(source->request, "Failed", "Error processing arguments."); return ERROR; } - AFB_ApiNotice(source->api, "Trace ws: %s", ws_name); + + if (pid == -1 && strlen(ws_name) == 0) { + AFB_ReqFail(source->request, "failed", "one of pid or ws parameter must be set"); + return ERROR; + } + + AFB_ApiDebug(source->api, "Trace pid: %d ws: %s", pid, ws_name); getDaemons(source->api, &daemons); if (daemons == NULL || daemons->count <= 0) { AFB_ReqFail(source->request, "failed", "No daemon found"); + return ERROR; } // search server and client pid DAEMON_T *pid_s = NULL, *pid_c = NULL; + const char* wsn; for (int i = 0; i < daemons->count; i++) { AFB_ApiDebug(source->api, "_DEBUG_ svr %s", json_object_to_json_string(daemons->daemons[i]->ws_servers)); @@ -109,7 +123,7 @@ CTLP_CAPI(trace, source, argsJ, eventJ) } if (pid_s != NULL && pid_c != NULL) { - if ((rc = trace_exchange(source->api, pid_s, pid_c)) < 0) { + if ((rc = trace_exchange(source->api, pid_s, pid_c, level)) < 0) { AFB_ReqFailF(source->request, "failed", "Trace error %d", rc); } break; @@ -121,44 +135,127 @@ CTLP_CAPI(trace, source, argsJ, eventJ) return ERROR; } - AFB_ReqSucessF(source->request, result, "Tracing Server pid=%d <-> Client pid=%d", pid_s->pid, pid_c->pid); + AFB_ReqSuccessF(source->request, result, "Tracing Server pid=%d <-> Client pid=%d", pid_s->pid, pid_c->pid); + + return 0; +} + +uint64_t get_ts() +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + return (uint64_t)(ts.tv_sec) * (uint64_t)1000000000 + (uint64_t)(ts.tv_nsec); +} + +static void cb_harvester_write(void* closure, int status, struct json_object* result, struct afb_dynapi* dynapi) +{ + AFB_ApiDebug(dynapi, "SEB cb_harvester_write"); +} + +/* SEB Cleanup if move in lua */ +static int harvester_post_data(CtlSourceT* source, METRIC_T* metric) +{ + int rc; + json_object *j_res, *j_query, *j_metric; + + if (!metric->timestamp) { + metric->timestamp = get_ts(); + } + + // To be REWORK + if (metric->dataType == SPVR_DATA_STRING) { + rc = wrap_json_pack(&j_metric, "{s:s s:{s:s s:s} s:{s:s} s:I }", + "name", metric->name, + "metadata", "source", "my_source", "identity", source->uid, + "values", "value", metric->data, + "timestamp", metric->timestamp); + } else if (metric->dataType == SPVR_DATA_INT) { + rc = wrap_json_pack(&j_metric, "{s:s s:{s:s s:s} s:{s:i} s:I }", + "name", metric->name, + "metadata", "source", "my_source", "identity", source->uid, + "values", "value", metric->data, + "timestamp", metric->timestamp); + } else { + AFB_ApiError(source->api, "Unsupported dataType"); + return ERROR; + } + + if (rc < 0) { + AFB_ApiError(source->api, "Error packing metric, rc=%d", rc); + return rc; + } + + rc = wrap_json_pack(&j_query, "{s:s s:i s:o }", "host", + "localhost", "port", 8086, "metric", j_metric); + if (rc < 0) { + AFB_ApiError(source->api, "Error packing query, rc=%d", rc); + return rc; + } + + AFB_ApiDebug(source->api, "%s write: %s", SRV_HARVESTER_NAME, + json_object_to_json_string(j_query)); + + /* SEB + rc = AFB_ServiceSync(source->api, SRV_HARVESTER_NAME, "write", j_query, &j_res); + if (rc < 0) { + AFB_ApiError(source->api, "Error %s write : rc=%d, j_res=%s", SRV_HARVESTER_NAME, rc, + json_object_to_json_string(j_res)); + return rc; + } +*/ + AFB_ServiceCall(source->api, SRV_HARVESTER_NAME, "write", j_query, cb_harvester_write, &j_res); return 0; } -/* SEB TODO -void xds_event_cb(const char* evtname, json_object* j_event) +CTLP_CAPI(tracing_events, source, argsJ, eventJ) { int rc; - METRIC_T metric; + METRIC_T metric = { 0 }; const char* type = NULL; struct json_object* request = NULL; - AFB_NOTICE("RECV Event %s : %s", evtname, - json_object_to_json_string(j_event)); + //struct signalCBT* ctx = (struct signalCBT*)source->context; + + AFB_ApiDebug(source->api, ">>> RECV Event uid %s : %s", source->uid, + json_object_to_json_string(eventJ)); - if (strcmp(evtname, "supervisor/trace") != 0) { - return; + if (strcmp(source->uid, "supervisor/trace") != 0) { + AFB_ApiNotice(source->api, "WARNING: un-handle uid '%s'", source->uid); + return 0; } - if ((rc = wrap_json_unpack(j_event, "{s:?s}", "type", &type)) < 0) { - AFB_ERROR("Cannot decode event type"); - return; + if ((rc = wrap_json_unpack(eventJ, "{s:?s}", "type", &type)) < 0) { + AFB_ApiError(source->api, "Cannot decode event type"); + return ERROR; } - if (strcmp(type, "request") == 0) { + if (strcmp(type, "request") != 0) { + AFB_ApiError(source->api, "Cannot retrieve request"); + return ERROR; + } + if (!json_object_object_get_ex(eventJ, "request", &request)) { + AFB_ApiError(source->api, "Cannot decode event request"); + return ERROR; + } - if (!json_object_object_get_ex(j_event, "request", &request)) { - AFB_ERROR("Cannot decode event request"); - return; - } - metric.name = "trace"; - metric.data = request; + // TODO: decode request and build trace - rc = harvester_post_data(&metric); - if (rc < 0) { - AFB_ERROR("ERROR harvester_post_data: rc %d", rc); - } + metric.name = "trace"; + /* FIXME string KO + metric.dataType = SPVR_DATA_STRING; + metric.data = "test1234"; + */ + metric.dataType = SPVR_DATA_INT; + int val = 54321; + metric.data = &val; + + rc = harvester_post_data(source, &metric); + if (rc < 0) { + AFB_ApiError(source->api, "ERROR harvester_post_data: rc %d", rc); + return rc; } + + return 0; } -*/ diff --git a/src/plugins/supervisor-api.h b/src/plugins/supervisor-api.h index beadeca..fddaf98 100644 --- a/src/plugins/supervisor-api.h +++ b/src/plugins/supervisor-api.h @@ -16,9 +16,9 @@ */ #pragma once -#include -#include "wrap-json.h" #include "filescan-utils.h" +#include "wrap-json.h" +#include #define SRV_HARVESTER_NAME "harvester" @@ -26,11 +26,19 @@ #define META_IDENTITY "" // FIXME #ifndef ERROR - #define ERROR -1 +#define ERROR -1 #endif +typedef enum { + SPVR_DATA_STRING = 0, + SPVR_DATA_INT, + SPVR_DATA_BOOL, + SPVR_DATA_FLOAT, +} SpvrDataTypeT; + typedef struct metric_t { char* name; - json_object* data; - struct timespec timestamp; + SpvrDataTypeT dataType; + void* data; + uint64_t timestamp; } METRIC_T; diff --git a/src/plugins/supervisor.c b/src/plugins/supervisor.c index 649713e..503609a 100644 --- a/src/plugins/supervisor.c +++ b/src/plugins/supervisor.c @@ -39,6 +39,7 @@ struct decode_daemon_str { DAEMONS_T* daemons; AFB_ApiT api; const char* ignored_daemon; + int* ret_code; }; static void decode_daemons_cb(void* closure, json_object* obj, const char* fName) @@ -61,7 +62,7 @@ static void decode_daemons_cb(void* closure, json_object* obj, const char* fName return; } - AFB_ApiInfo(clStr->api, "Get config of pid %d", cred.pid); + AFB_ApiInfo(clStr->api, "Get supervisor/config - pid %d", cred.pid); daemon->pid = cred.pid; // Get config @@ -69,6 +70,7 @@ static void decode_daemons_cb(void* closure, json_object* obj, const char* fName rc = AFB_ServiceSync(clStr->api, SRV_SUPERVISOR_NAME, "config", j_query, &j_response); if (rc < 0) { AFB_ApiError(clStr->api, "Cannot get config of pid %d", cred.pid); + *clStr->ret_code = rc; return; } @@ -103,6 +105,8 @@ static void decode_daemons_cb(void* closure, json_object* obj, const char* fName } // Get apis + AFB_ApiInfo(clStr->api, "Get supervisor/do monitor get apis - pid %d", cred.pid); + // '{"pid":6262,"api":"monitor","verb":"get","args":{"apis":true}} wrap_json_pack(&j_query, "{si ss ss s {sb}}", "pid", cred.pid, @@ -117,6 +121,8 @@ static void decode_daemons_cb(void* closure, json_object* obj, const char* fName AFB_ApiDebug(clStr->api, "%s do ...get apis result, res=%s", SRV_SUPERVISOR_NAME, json_object_to_json_string(j_response)); if (json_object_object_get_ex(j_response, "response", &j_config) && json_object_object_get_ex(j_config, "apis", &j_apis)) { + // Don't forward monitor config details + json_object_object_del(j_apis, "monitor"); daemon->apis = j_apis; } } @@ -131,59 +137,104 @@ int getDaemons(AFB_ApiT apiHandle, DAEMONS_T** daemons) *daemons = calloc(sizeof(DAEMONS_T), 1); + AFB_ApiInfo(apiHandle, "Call supervisor/discover"); if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "discover", NULL, &j_response)) < 0) { return rc; } + AFB_ApiInfo(apiHandle, "Call supervisor/list"); if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "list", NULL, &j_response)) < 0) { return rc; } + AFB_ApiInfo(apiHandle, "Get details info for each daemon"); AFB_ApiDebug(apiHandle, "%s list result, res=%s", SRV_SUPERVISOR_NAME, json_object_to_json_string(j_response)); - if (json_object_object_get_ex(j_response, "response", &j_daemons)) { - struct decode_daemon_str str = { - *daemons, - apiHandle, - GetBinderName() - }; - wrap_json_object_for_all(j_daemons, decode_daemons_cb, &str); + if (!json_object_object_get_ex(j_response, "response", &j_daemons)) { } - - return 0; + struct decode_daemon_str cls = { + *daemons, + apiHandle, + apiHandle->apiname, + &rc + }; + wrap_json_object_for_all(j_daemons, decode_daemons_cb, &cls); + + return rc; } -int trace_exchange(AFB_ApiT apiHandle, DAEMON_T* svr, DAEMON_T* cli) +#define XDS_TAG_REQUEST "xds:*/request" +#define XDS_TAG_EVENT "xds:*/event" +#define XDS_TRACE_NAME "xds-trace" + +int trace_exchange(AFB_ApiT apiHandle, DAEMON_T* svr, DAEMON_T* cli, const char* level) { int rc; - json_object *j_response, *j_query; + json_object *j_response, *j_query, *j_tracereq, *j_traceevt; if (svr == NULL || cli == NULL) { return -1; } - wrap_json_pack(&j_query, "{s:i, s:{s:s}}", "pid", svr->pid, "add", - "request", "common"); - if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "trace", j_query, - &j_response)) - < 0) { + // First drop previous traces + // monitor/trace({ "drop": { "tag": "*/request" } }) + // Note: ignored error (expected 1st time/when no trace exist) + wrap_json_pack(&j_query, "{s:i s:{s:[s s]}}", "pid", svr->pid, + "drop", "tag", XDS_TAG_REQUEST, XDS_TAG_EVENT); + AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "trace", j_query, &j_response); + + wrap_json_pack(&j_query, "{s:i s:{s:[s s]}}", "pid", cli->pid, + "drop", "tag", XDS_TAG_REQUEST, XDS_TAG_EVENT); + AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "trace", j_query, &j_response); + + j_tracereq = json_object_new_array(); + if (level && !strncmp(level, "all", 3)) { + json_object_array_add(j_tracereq, json_object_new_string("all")); + } else { + json_object_array_add(j_tracereq, json_object_new_string("life")); + json_object_array_add(j_tracereq, json_object_new_string("result")); + } + json_object_get(j_tracereq); // because use 2 times to configure both server and client + + j_traceevt = json_object_new_array(); + if (level && !strncmp(level, "all", 3)) { + json_object_array_add(j_traceevt, json_object_new_string("all")); + } else { + json_object_array_add(j_traceevt, json_object_new_string("common")); + } + json_object_get(j_traceevt); // because use 2 times to configure both server and client + + // Configure trace for server daemon + // request: monitor/trace({ "add": { "tag": "xds:*/request", "name": "trace", "request": "all" } }) + wrap_json_pack(&j_query, "{s:i, s: [{s:s s:s s:o}, {s:s s:s s:o}] }", + "pid", svr->pid, "add", + "tag", XDS_TAG_REQUEST, "name", XDS_TRACE_NAME, "request", j_tracereq, + "tag", XDS_TAG_EVENT, "name", XDS_TRACE_NAME, "event", j_traceevt); + + if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "trace", j_query, &j_response)) < 0) { AFB_ApiError(apiHandle, "ERROR trace %d result: %s", svr->pid, json_object_to_json_string(j_response)); return rc; } - wrap_json_pack(&j_query, "{s:i}", "pid", cli->pid); - if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "trace", j_query, - &j_response)) - < 0) { + // Configure trace for client daemon(s) + // request: monitor/trace({ "pid": 1234, "add": { "event": "all" } }) +#if 1 // SEB + wrap_json_pack(&j_query, "{s:i, s: [{s:s s:s s:o}, {s:s s:s s:o}] }", + "pid", cli->pid, "add", + "tag", XDS_TAG_REQUEST, "name", XDS_TRACE_NAME, "request", j_tracereq, + "tag", XDS_TAG_EVENT, "name", XDS_TRACE_NAME, "event", j_traceevt); + + if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "trace", j_query, &j_response)) < 0) { AFB_ApiError(apiHandle, "ERROR trace %d result: %s", cli->pid, json_object_to_json_string(j_response)); return rc; } +#endif return 0; } diff --git a/src/plugins/supervisor.h b/src/plugins/supervisor.h index 3311734..6d33151 100644 --- a/src/plugins/supervisor.h +++ b/src/plugins/supervisor.h @@ -49,5 +49,5 @@ typedef struct daemons_result_ extern int getDaemons(AFB_ApiT apiHandle, DAEMONS_T **daemons); -extern int trace_exchange(AFB_ApiT apiHandle, DAEMON_T *svr, DAEMON_T *cli); +extern int trace_exchange(AFB_ApiT apiHandle, DAEMON_T *svr, DAEMON_T *cli, const char *level); extern int supervisor_init(void); diff --git a/src/xds-apidef.json b/src/xds-apidef.json index 949e3e8..9ed5843 100644 --- a/src/xds-apidef.json +++ b/src/xds-apidef.json @@ -10,32 +10,28 @@ "version": 2, "prefix": "afv_", "postfix": "", - "start": null , + "start": null, "onevent": null, "init": "init", "scope": "", "private": false } }, - "servers": [ - { - "url": "ws://{host}:{port}/api/monitor", - "description": "TS caching binding", - "variables": { - "host": { - "default": "localhost" - }, - "port": { - "default": "1234" - } + "servers": [{ + "url": "ws://{host}:{port}/api/monitor", + "description": "TS caching binding", + "variables": { + "host": { + "default": "localhost" }, - "x-afb-events": [ - { - "$ref": "#/components/schemas/afb-event" - } - ] - } - ], + "port": { + "default": "1234" + } + }, + "x-afb-events": [{ + "$ref": "#/components/schemas/afb-event" + }] + }], "components": { "schemas": { "afb-reply": { @@ -47,7 +43,7 @@ "afb-reply-v2": { "title": "Generic response.", "type": "object", - "required": [ "jtype", "request" ], + "required": ["jtype", "request"], "properties": { "jtype": { "type": "string", @@ -55,28 +51,44 @@ }, "request": { "type": "object", - "required": [ "status" ], + "required": ["status"], "properties": { - "status": { "type": "string" }, - "info": { "type": "string" }, - "token": { "type": "string" }, - "uuid": { "type": "string" }, - "reqid": { "type": "string" } + "status": { + "type": "string" + }, + "info": { + "type": "string" + }, + "token": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "reqid": { + "type": "string" + } } }, - "response": { "type": "object" } + "response": { + "type": "object" + } } }, "afb-event-v2": { "type": "object", - "required": [ "jtype", "event" ], + "required": ["jtype", "event"], "properties": { "jtype": { "type": "string", "const": "afb-event" }, - "event": { "type": "string" }, - "data": { "type": "object" } + "event": { + "type": "string" + }, + "data": { + "type": "object" + } } } }, @@ -89,16 +101,16 @@ } }, "responses": { - "200": { - "description": "A complex object array response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/afb-reply" - } - } + "200": { + "description": "A complex object array response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/afb-reply" } } + } + } } }, "paths": { @@ -136,9 +148,16 @@ "LOA": 1 }, "parameters": [{ + "in": "query", + "name": "pid", + "required": false, + "schema": { + "type": "integer" + } + }, { "in": "query", "name": "ws", - "required": true, + "required": false, "schema": { "type": "string" } diff --git a/src/xds-binding.c b/src/xds-binding.c index 4f7971f..3d9839b 100644 --- a/src/xds-binding.c +++ b/src/xds-binding.c @@ -23,135 +23,145 @@ #include "xds-binding.h" - -// default api to print log when apihandle not avaliable -afb_dynapi *AFB_default; +afb_dynapi* AFB_default; // Config Section definition (note: controls section index should match handle // retrieval in HalConfigExec) static CtlSectionT ctrlSections[] = { - {.key = "plugins" , .loadCB = PluginConfig}, - {.key = "onload" , .loadCB = OnloadConfig}, - {.key = "controls", .loadCB = ControlConfig}, - {.key = "events" , .loadCB = EventConfig}, - {.key = NULL} + { .key = "plugins", .loadCB = PluginConfig }, + { .key = "onload", .loadCB = OnloadConfig }, + { .key = "controls", .loadCB = ControlConfig }, + { .key = "events", .loadCB = EventConfig }, + { .key = NULL } }; -static void ctrlapi_ping(AFB_ReqT request) { - static int count = 0; - - count++; - AFB_ReqNotice(request, "Controller:ping count=%d", count); - AFB_ReqSucess(request, json_object_new_int(count), NULL); - - return; +static void ctrlapi_ping(AFB_ReqT request) +{ + static int count = 0; + json_object* resJ; + int rc; + count++; + AFB_ReqNotice(request, "Controller:ping count=%d", count); + rc = wrap_json_pack(&resJ, "{ss si}", "status", "pong", "count", count); + if (rc < 0) { + AFB_ReqFailF(request, "ERROR", "wrap_json_pack rc=%d", rc); + return; + } + AFB_ReqSuccess(request, resJ, NULL); + + return; } void ctrlapi_auth(AFB_ReqT request) { - AFB_ReqSetLOA(request, 1); - AFB_ReqSucess(request, NULL, NULL); + AFB_ReqSetLOA(request, 1); + AFB_ReqSuccess(request, NULL, NULL); } static AFB_ApiVerbs CtrlApiVerbs[] = { - /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ - {.verb = "ping", .callback = ctrlapi_ping, .info = "ping test for API"}, - {.verb = "auth", .callback = ctrlapi_auth, .info = "Authenticate session to raise Level Of Assurance of the session"}, - {.verb = NULL} /* marker for end of the array */ + /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ + { .verb = "ping", .callback = ctrlapi_ping, .info = "ping test for API" }, + { .verb = "auth", .callback = ctrlapi_auth, .info = "Authenticate session to raise Level Of Assurance of the session" }, + { .verb = NULL } /* marker for end of the array */ }; -static int CtrlLoadStaticVerbs(afb_dynapi *apiHandle, AFB_ApiVerbs *verbs) { - int errcount = 0; +static int CtrlLoadStaticVerbs(afb_dynapi* apiHandle, AFB_ApiVerbs* verbs) +{ + int errcount = 0; - for (int idx = 0; verbs[idx].verb; idx++) { - errcount += afb_dynapi_add_verb( - apiHandle, CtrlApiVerbs[idx].verb, NULL, CtrlApiVerbs[idx].callback, - (void *)&CtrlApiVerbs[idx], CtrlApiVerbs[idx].auth, 0); - } + for (int idx = 0; verbs[idx].verb; idx++) { + errcount += afb_dynapi_add_verb( + apiHandle, CtrlApiVerbs[idx].verb, NULL, CtrlApiVerbs[idx].callback, + (void*)&CtrlApiVerbs[idx], CtrlApiVerbs[idx].auth, 0); + } - return errcount; + return errcount; }; -static int CtrlInitOneApi(AFB_ApiT apiHandle) { - int err = 0; - AFB_default = apiHandle; // hugely hack to make all V2 AFB_DEBUG to work in fileutils +static int CtrlInitOneApi(AFB_ApiT apiHandle) +{ + int err = 0; + + AFB_default = apiHandle; // hugely hack to make all V2 AFB_DEBUG to work in fileutils - // retrieve section config from api handle - CtlConfigT *ctrlConfig = (CtlConfigT *)afb_dynapi_get_userdata(apiHandle); - err = CtlConfigExec(apiHandle, ctrlConfig); - if(err) { - AFB_ApiError(apiHandle, "Error at CtlConfigExec step"); - return err; - } + // retrieve section config from api handle + CtlConfigT* ctrlConfig = (CtlConfigT*)afb_dynapi_get_userdata(apiHandle); + err = CtlConfigExec(apiHandle, ctrlConfig); + if (err) { + AFB_ApiError(apiHandle, "Error at CtlConfigExec step"); + return err; + } - return err; + return err; } // next generation dynamic API-V3 mode #include -static int CtrlLoadOneApi(void *cbdata, AFB_ApiT apiHandle) { - CtlConfigT *ctrlConfig = (CtlConfigT *)cbdata; +static int CtrlLoadOneApi(void* cbdata, AFB_ApiT apiHandle) +{ + CtlConfigT* ctrlConfig = (CtlConfigT*)cbdata; - // save closure as api's data context - afb_dynapi_set_userdata(apiHandle, ctrlConfig); + // save closure as api's data context + afb_dynapi_set_userdata(apiHandle, ctrlConfig); - // add static controls verbs - int err = CtrlLoadStaticVerbs(apiHandle, CtrlApiVerbs); - if (err) { - AFB_ApiError(apiHandle, "CtrlLoadSection fail to register static V2 verbs"); - return ERROR; - } + // add static controls verbs + int err = CtrlLoadStaticVerbs(apiHandle, CtrlApiVerbs); + if (err) { + AFB_ApiError(apiHandle, "CtrlLoadSection fail to register static V2 verbs"); + return ERROR; + } - // load section for corresponding API - err = CtlLoadSections(apiHandle, ctrlConfig, ctrlSections); + // load section for corresponding API + err = CtlLoadSections(apiHandle, ctrlConfig, ctrlSections); - // declare an event event manager for this API; - afb_dynapi_on_event(apiHandle, CtrlDispatchApiEvent); + // declare an event event manager for this API; + afb_dynapi_on_event(apiHandle, CtrlDispatchApiEvent); - // init API function (does not receive user closure ??? - afb_dynapi_on_init(apiHandle, CtrlInitOneApi); + // init API function (does not receive user closure ??? + afb_dynapi_on_init(apiHandle, CtrlInitOneApi); - afb_dynapi_seal(apiHandle); - return err; + afb_dynapi_seal(apiHandle); + return err; } -int afbBindingVdyn(afb_dynapi *apiHandle) { - - AFB_default = apiHandle; - AFB_ApiNotice(apiHandle, "Controller in afbBindingVdyn"); - - const char *dirList = getenv("CONTROL_CONFIG_PATH"); - if (!dirList) - dirList = CONTROL_CONFIG_PATH; - - const char *configPath = CtlConfigSearch(apiHandle, dirList, ""); - if (!configPath) { - AFB_ApiError(apiHandle, "CtlPreInit: No %s* config found in %s ", GetBinderName(), dirList); - return ERROR; - } - - // load config file and create API - CtlConfigT *ctrlConfig = CtlLoadMetaData(apiHandle, configPath); - if (!ctrlConfig) { - AFB_ApiError(apiHandle, - "CtrlBindingDyn No valid control config file in:\n-- %s", - configPath); - return ERROR; - } - - if (!ctrlConfig->api) { - AFB_ApiError(apiHandle, - "CtrlBindingDyn API Missing from metadata in:\n-- %s", - configPath); - return ERROR; - } - - AFB_ApiNotice(apiHandle, "Controller API='%s' info='%s'", ctrlConfig->api, - ctrlConfig->info); - - // create one API per config file (Pre-V3 return code ToBeChanged) - int status = afb_dynapi_new_api(apiHandle, ctrlConfig->api, ctrlConfig->info, 1, CtrlLoadOneApi, ctrlConfig); +int afbBindingVdyn(afb_dynapi* apiHandle) +{ - return status; + AFB_default = apiHandle; + AFB_ApiNotice(apiHandle, "Controller in afbBindingVdyn"); + + const char* dirList = getenv("CONTROL_CONFIG_PATH"); + if (!dirList) + dirList = CONTROL_CONFIG_PATH; + + const char* configPath = CtlConfigSearch(apiHandle, dirList, ""); + if (!configPath) { + AFB_ApiError(apiHandle, "CtlPreInit: No %s* config found in %s ", GetBinderName(), dirList); + return ERROR; + } + + // load config file and create API + CtlConfigT* ctrlConfig = CtlLoadMetaData(apiHandle, configPath); + if (!ctrlConfig) { + AFB_ApiError(apiHandle, + "CtrlBindingDyn No valid control config file in:\n-- %s", + configPath); + return ERROR; + } + + if (!ctrlConfig->api) { + AFB_ApiError(apiHandle, + "CtrlBindingDyn API Missing from metadata in:\n-- %s", + configPath); + return ERROR; + } + + AFB_ApiNotice(apiHandle, "Controller API='%s' info='%s'", ctrlConfig->api, + ctrlConfig->info); + + // create one API per config file (Pre-V3 return code ToBeChanged) + int status = afb_dynapi_new_api(apiHandle, ctrlConfig->api, ctrlConfig->info, 1, CtrlLoadOneApi, ctrlConfig); + + return status; } -- cgit 1.2.3-korg