summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Douheret <sebastien.douheret@iot.bzh>2018-06-12 17:52:40 +0200
committerSebastien Douheret <sebastien.douheret@iot.bzh>2018-07-10 23:59:54 +0200
commit75eb2161c641f85dded64a99cb862abfab64eff7 (patch)
treec2c6c515e45bba9ca1b2e30fe392342cab643ae0
parent197d9acab4fb5097d3dce56227c2096abdc075bd (diff)
Improved supervisor requests & events recording
Change-Id: I4eb52820d2bec4ca4f2e3e455db7eb79d1a09d12 Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
-rw-r--r--.vscode/c_cpp_properties.json1
-rw-r--r--.vscode/launch.json1
-rw-r--r--.vscode/settings.json22
-rw-r--r--.vscode/tasks.json3
m---------afb-helpers0
-rw-r--r--conf.d/cmake/config.cmake2
-rw-r--r--conf.d/project/etc/xds-supervisor-config.json (renamed from conf.d/project/etc/xds-config.json)16
-rw-r--r--conf.d/project/lua.d/CMakeLists.txt32
-rw-r--r--conf.d/project/lua.d/xds-supervisor.lua119
-rw-r--r--htdocs/d3js-graph.js14
-rw-r--r--htdocs/index.html2
-rw-r--r--htdocs/iotbzh-Binding.js3
-rw-r--r--src/plugins/supervisor-api.c157
-rw-r--r--src/plugins/supervisor-api.h18
-rw-r--r--src/plugins/supervisor.c93
-rw-r--r--src/plugins/supervisor.h2
-rw-r--r--src/xds-apidef.json97
-rw-r--r--src/xds-binding.c202
18 files changed, 579 insertions, 205 deletions
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
-Subproject f9f7e1e3d394024484df41e3d97d6b8505810f3
+Subproject c7cd527a8350f736b8013f65db6f5a52b8cb05d
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-supervisor-config.json
index 3646d3f..39309bb 100644
--- a/conf.d/project/etc/xds-config.json
+++ b/conf.d/project/etc/xds-supervisor-config.json
@@ -9,19 +9,31 @@
"plugins": [{
"uid": "supervisor",
"info": "Plugin to handle interface with supervisor",
- "spath": "lib/plugins",
- "libs": "supervisor.ctlso"
+ "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 <fulup@iot.bzh>
+#
+# 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 <sebastien@iot.bzh>
+
+ 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 @@
<button onclick="graphAGLBindings();">Graph AGL bindings</button>
</li>
- <button onclick="callbinder('xds', 'trace', {'ws': 'unix:ave'});">Trace ws unix:ave</button>
+ <button onclick="callbinder('xds', 'trace', {'ws': 'can_emul'});">Trace ws can_emul</button>
</li>
</div>
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 <fcntl.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#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 <stdbool.h>
-#include "wrap-json.h"
#include "filescan-utils.h"
+#include "wrap-json.h"
+#include <stdbool.h>
#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": {
@@ -137,8 +149,15 @@
},
"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 <signal.h>
-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;
}