1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

tests: fix config tests

This commit is contained in:
Steffen Vogel 2021-09-21 15:22:09 +02:00
parent 8480c7c3b0
commit 23f3cc9ee6
25 changed files with 329 additions and 152 deletions

View file

@ -192,7 +192,6 @@ paths:
formats:
- csv
- gtnet
- gtnet.fake
- iotagent_ul
- json
- json.kafka

View file

@ -1,26 +0,0 @@
nodes = {
ethernet_node = {
type = "socket", # See above.
### The following settings are specific to the socket node-type!! ###
layer = "eth",
in = {
address = "12:34:56:78:90:AB%em1:12002"
},
out = {
address = "12:34:56:78:90:AB%em1:12002"
}
},
unix_domain_node = {
type = "socket",
layer = "unix", # Datagram UNIX domain sockets require two endpoints
in = {
address = "/var/run/villas-node/node.sock"
},
out = {
address = "/var/run/villas-node/client.sock"
}
}
}

View file

@ -0,0 +1,8 @@
nodes = {
example_node = {
type = "example"
setting1 = 1
setting2 = "abc"
}
}

View file

@ -1,23 +0,0 @@
nodes = {
udp_node = { # The dictionary is indexed by the name of the node.
type = "socket", # For a list of available node-types run: 'villas-node -h'
### The following settings are specific to the socket node-type!! ###
in = {
address = "127.0.0.1:12001" # This node only received messages on this IP:Port pair
multicast = { # IGMP multicast is only support for layer = (ip|udp)
enabled = true,
group = "224.1.2.3", # The multicast group. Must be within 224.0.0.0/4
interface = "1.2.3.4", # The IP address of the interface which should receive multicast packets.
ttl = 128, # The time to live for outgoing multicast packets.
loop = false, # Whether or not to loopback outgoing multicast packets to the local host.
}
},
out = {
address = "127.0.0.1:12000", # This node sents outgoing messages to this IP:Port pair
}
}
}

View file

@ -4,7 +4,7 @@ nodes = {
### The following settings are specific to the socket node-type!! ###
format = "gtnet.fake", # For a list of available node-types run: 'villas-node -h'
format = "gtnet", # For a list of available node-types run: 'villas-node -h'
in = {
address = "127.0.0.1:12001" # This node only received messages on this IP:Port pair

View file

@ -0,0 +1,76 @@
nodes = {
udp_node = { # The dictionary is indexed by the name of the node.
type = "socket", # For a list of available node-types run: 'villas-node -h'
vectorize = 30, # Receive and sent 30 samples per message (combining).
samplelen = 10 # The maximum number of samples this node can receive
builtin = false, # By default, all nodes will have a few builtin hooks attached to them.
# When collecting statistics or measurements these are undesired.
### The following settings are specific to the socket node-type!! ###
layer = "udp", # Layer can be one of:
# - udp Send / receive L4 UDP packets
# - ip Send / receive L3 IP packets
# - eth Send / receive L2 Ethernet frames (IEEE802.3)
format = "gtnet", # For a list of available node-types run: 'villas-node -h'
in = {
address = "127.0.0.1:12001" # This node only received messages on this IP:Port pair
verify_source = true # Check if source address of incoming packets matches the remote address.
},
out = {
address = "127.0.0.1:12000", # This node sents outgoing messages to this IP:Port pair
}
}
ethernet_node = {
type = "socket", # See above.
### The following settings are specific to the socket node-type!! ###
layer = "eth",
in = {
address = "12:34:56:78:90:AB%em1:12002"
},
out = {
address = "12:34:56:78:90:AB%em1:12002"
}
},
unix_domain_node = {
type = "socket",
layer = "unix", # Datagram UNIX domain sockets require two endpoints
in = {
address = "/var/run/villas-node/node.sock"
},
out = {
address = "/var/run/villas-node/client.sock"
}
}
udp_multicast_node = { # The dictionary is indexed by the name of the node.
type = "socket", # For a list of available node-types run: 'villas-node -h'
### The following settings are specific to the socket node-type!! ###
in = {
address = "127.0.0.1:12001" # This node only received messages on this IP:Port pair
multicast = { # IGMP multicast is only support for layer = (ip|udp)
enabled = true,
group = "224.1.2.3", # The multicast group. Must be within 224.0.0.0/4
interface = "1.2.3.4", # The IP address of the interface which should receive multicast packets.
ttl = 128, # The time to live for outgoing multicast packets.
loop = false, # Whether or not to loopback outgoing multicast packets to the local host.
}
},
out = {
address = "127.0.0.1:12000", # This node sents outgoing messages to this IP:Port pair
}
}
}

View file

@ -0,0 +1,13 @@
nodes = {
temper_node = {
type = "temper"
calibration = {
scale = 1.0
offset = 0.0
}
bus = 0x1
port = 0x1
}
}

View file

@ -1,28 +0,0 @@
nodes = {
udp_node = { # The dictionary is indexed by the name of the node.
type = "socket", # For a list of available node-types run: 'villas-node -h'
vectorize = 30, # Receive and sent 30 samples per message (combining).
samplelen = 10 # The maximum number of samples this node can receive
builtin = false, # By default, all nodes will have a few builtin hooks attached to them.
# When collecting statistics or measurements these are undesired.
### The following settings are specific to the socket node-type!! ###
layer = "udp", # Layer can be one of:
# - udp Send / receive L4 UDP packets
# - ip Send / receive L3 IP packets
# - eth Send / receive L2 Ethernet frames (IEEE802.3)
format = "gtnet.fake", # For a list of available node-types run: 'villas-node -h'
in = {
address = "127.0.0.1:12001" # This node only received messages on this IP:Port pair
verify_source = true # Check if source address of incoming packets matches the remote address.
},
out = {
address = "127.0.0.1:12000", # This node sents outgoing messages to this IP:Port pair
}
}
}

View file

@ -32,7 +32,10 @@ nodes = {
node1 = {
type = "socket"
format = "gtnet.fake"
format = {
type = "gtnet"
fake = true
}
in = {
address = "134.130.169.31:12002" # Local ip:port, use '*' for random port

View file

@ -32,7 +32,10 @@ logging = {
nodes = {
node1 = {
type = "socket",
format = "gtnet.fake"
format = {
type = "gtnet"
fake = true
}
in = {
address = "134.130.169.31:12002" # Local ip:port, use '*' for random port
@ -50,7 +53,10 @@ nodes = {
},
node2 = {
type = "socket",
format = "gtnet.fake"
format = {
type = "gtnet"
fake = true
}
in = {
address = "134.130.169.31:12004", # Local ip:port, use '*' for random port

View file

@ -3,7 +3,10 @@ nodes = {
rtds_ss1 = {
type = "socket",
layer = "udp",
format = "gtnet.fake"
format = {
type = "gtnet"
fake = true
}
in = { # Local address, i.e. address of villas instance
address = "134.130.169.31:12000"
@ -45,7 +48,10 @@ nodes = {
rtds_ss2 = {
type = "socket",
layer = "udp",
format = "gtnet.fake"
format = {
type = "gtnet"
fake = true
}
in = {
# Local address, i.e. address of villas instance
@ -90,7 +96,10 @@ nodes = {
rtds_ss1_monitoring = {
type = "socket"
layer = "udp"
format = "gtnet.fake"
format = {
type = "gtnet"
fake = true
}
in = { # Local address, i.e. address of villas instance
address = "134.130.169.31:12002"

View file

@ -1,12 +1,10 @@
nodes = {
sig = {
type = "signal1"
type = "signal"
signal = "sine"
}
dpsim = {
enabled = false,
type = "shmem",

View file

@ -0,0 +1,33 @@
/** Capabilities
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#include <jansson.h>
namespace villas {
namespace node {
json_t * getCapabilities();
} /* namespace node */
} /* namepace vilals */

View file

@ -64,7 +64,7 @@ struct kafka {
} ssl;
struct {
char *mechanism; /**< SASL mechanism. */
char *mechanisms; /**< SASL mechanisms. */
char *username; /**< SSL CA path. */
char *password; /**< SSL certificate. */
} sasl;

View file

@ -41,6 +41,7 @@ if(UNIX AND NOT APPLE)
endif()
set(LIB_SRC
capabilities.cpp
config_helper.cpp
config.cpp
dumper.cpp

View file

@ -20,11 +20,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/config.h>
#include <villas/hook.hpp>
#include <villas/format.hpp>
#include <villas/api/request.hpp>
#include <villas/api/response.hpp>
#include <villas/capabilities.hpp>
namespace villas {
namespace node {
@ -37,52 +35,13 @@ public:
virtual Response * execute()
{
json_t *json_hooks = json_array();
json_t *json_apis = json_array();
json_t *json_nodes = json_array();
json_t *json_formats = json_array();
json_t *json_name;
if (method != Session::Method::GET)
throw InvalidMethod(this);
if (body != nullptr)
throw BadRequest("Capabilities endpoint does not accept any body data");
for (auto p : plugin::Registry::lookup<RequestFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_apis, json_name);
}
for (auto p : plugin::Registry::lookup<HookFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_hooks, json_name);
}
for (auto p : plugin::Registry::lookup<FormatFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_formats, json_name);
}
#if 0 /* @todo Port to C++ */
for (auto f : NodeFactory::lookup()) {
json_name = json_string(f->getName().c_str());
json_array_append_new(json_nodes, json_name);
}
#else
for (auto *vt : *node_types)
json_array_append_new(json_nodes, json_string(vt->name));
#endif
auto *json_capabilities = json_pack("{ s: o, s: o, s: o, s: o }",
"hooks", json_hooks,
"node-types", json_nodes,
"apis", json_apis,
"formats", json_formats);
auto *json_capabilities = getCapabilities();
return new JsonResponse(session, HTTP_STATUS_OK, json_capabilities);
}

75
lib/capabilities.cpp Normal file
View file

@ -0,0 +1,75 @@
/** Capabilities
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <villas/capabilities.hpp>
#include <villas/plugin.hpp>
#include <villas/hook.hpp>
#include <villas/format.hpp>
#include <villas/api/request.hpp>
using namespace villas;
using namespace villas::node;
json_t * villas::node::getCapabilities()
{
json_t *json_hooks = json_array();
json_t *json_apis = json_array();
json_t *json_nodes = json_array();
json_t *json_formats = json_array();
json_t *json_name;
for (auto p : plugin::Registry::lookup<api::RequestFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_apis, json_name);
}
for (auto p : plugin::Registry::lookup<HookFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_hooks, json_name);
}
for (auto p : plugin::Registry::lookup<FormatFactory>()) {
json_name = json_string(p->getName().c_str());
json_array_append_new(json_formats, json_name);
}
#if 0 /* @todo Port to C++ */
for (auto f : NodeFactory::lookup()) {
json_name = json_string(f->getName().c_str());
json_array_append_new(json_nodes, json_name);
}
#else
for (auto *vt : *node_types)
json_array_append_new(json_nodes, json_string(vt->name));
#endif
return json_pack("{ s: o, s: o, s: o, s: o }",
"hooks", json_hooks,
"nodes", json_nodes,
"apis", json_apis,
"formats", json_formats);
}

View file

@ -263,7 +263,7 @@ public:
"window_size_factor", &windowSizeFactor,
"window_type", &windowTypeC,
"padding_type", &paddingTypeC,
"freq_estimate_type", &freqEstimateTypeC,
"frequency_estimate_type", &freqEstimateTypeC,
"sync", &sync,
"pps_index", &ppsIndex,
"angle_unit", &angleUnitC

View file

@ -153,7 +153,7 @@ int kafka_init(struct vnode *n)
k->producer.client = nullptr;
k->producer.topic = nullptr;
k->sasl.mechanism = nullptr;
k->sasl.mechanisms = nullptr;
k->sasl.username = nullptr;
k->sasl.password = nullptr;
@ -227,19 +227,19 @@ int kafka_parse(struct vnode *n, json_t *json)
}
if (json_sasl) {
const char *mechanism;
const char *mechanisms;
const char *username;
const char *password;
ret = json_unpack_ex(json_ssl, &err, 0, "{ s: s, s: s, s: s }",
"mechanism", &mechanism,
ret = json_unpack_ex(json_sasl, &err, 0, "{ s: s, s: s, s: s }",
"mechanisms", &mechanisms,
"username", &username,
"password", &password
);
if (ret)
throw ConfigError(json_sasl, err, "node-config-node-kafka-sasl", "Failed to parse SASL configuration of node {}", *n);
throw ConfigError(json_sasl, err, "node-config-node-kafka-sasl", "Failed to parse SASL configuration");
k->sasl.mechanism = strdup(mechanism);
k->sasl.mechanisms = strdup(mechanisms);
k->sasl.username = strdup(username);
k->sasl.password = strdup(password);
}
@ -362,7 +362,7 @@ int kafka_start(struct vnode *n)
}
if (!strcmp(k->protocol, "SASL_PLAINTEXT") || !strcmp(k->protocol, "SASL_SSL")) {
ret = rd_kafka_conf_set(rdkconf, "sasl.mechanisms", k->sasl.mechanism, errstr, sizeof(errstr));
ret = rd_kafka_conf_set(rdkconf, "sasl.mechanisms", k->sasl.mechanisms, errstr, sizeof(errstr));
if (ret != RD_KAFKA_CONF_OK)
goto kafka_config_error;

View file

@ -346,16 +346,6 @@ int path_prepare(struct vpath *p, NodeList &nodes)
if (p->original_sequence_no == -1)
p->original_sequence_no = vlist_length(&p->sources) == 1;
/* Autodetect whether to use poll() for this path or not */
if (p->poll == -1) {
if (p->rate > 0)
p->poll = 1;
else if (vlist_length(&p->sources) > 1)
p->poll = 1;
else
p->poll = 0;
}
/* Prepare poll() */
if (p->poll) {
ret = path_prepare_poll(p);
@ -487,6 +477,16 @@ int path_parse(struct vpath *p, json_t *json, NodeList &nodes, const uuid_t sn_u
if (ret)
return ret;
/* Autodetect whether to use poll() for this path or not */
if (p->poll == -1) {
if (p->rate > 0)
p->poll = 1;
else if (vlist_length(&p->sources) > 1)
p->poll = 1;
else
p->poll = 0;
}
p->config = json;
p->state = State::PARSED;

View file

@ -47,6 +47,7 @@
#include <villas/exceptions.hpp>
#include <villas/kernel/kernel.hpp>
#include <villas/kernel/rt.hpp>
#include <villas/capabilities.hpp>
#ifdef WITH_NODE_OPAL
#include <villas/nodes/opal.hpp>
@ -71,6 +72,7 @@ protected:
SuperNode sn;
std::string uri;
bool showCapabilities = false;
void handler(int signal, siginfo_t *sinfo, void *ctx)
{
@ -92,6 +94,7 @@ protected:
<< " OPTIONS is one or more of the following options:" << std::endl
<< " -h show this usage information" << std::endl
<< " -d LVL set logging level" << std::endl
<< " -C show capabilities in JSON format" << std::endl
<< " -V show the version of the tool" << std::endl << std::endl
<< " CONFIG is the path to an optional configuration file" << std::endl
<< " if omitted, VILLASnode will start without a configuration" << std::endl
@ -145,7 +148,7 @@ protected:
/* Parse optional command line arguments */
int c;
while ((c = getopt(argc, argv, "hVd:")) != -1) {
while ((c = getopt(argc, argv, "hCVd:")) != -1) {
switch (c) {
case 'V':
printVersion();
@ -155,6 +158,10 @@ protected:
logging.setLevel(optarg);
break;
case 'C':
showCapabilities = true;
break;
case 'h':
case '?':
usage();
@ -175,6 +182,20 @@ protected:
int main()
{
return showCapabilities
? capabilities()
: daemon();
}
int capabilities() {
auto *json_caps = getCapabilities();
json_dumpf(json_caps, stdout, JSON_INDENT(4));
return 0;
}
int daemon() {
if (!uri.empty())
sn.parse(uri);
else

View file

@ -0,0 +1,51 @@
#!/bin/bash
#
# Test example configurations
#
# @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
# @copyright 2014-2020, Institute for Automation of Complex Power Systems, EONERC
# @license GNU General Public License (version 3)
#
# VILLASnode
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
##################################################################################
NODE_TYPES=$(villas-node -C | jq -r '.nodes | join(" ")')
HOOKS_TYPES=$(villas-node -C | jq -r '.["hooks"] | join(" ")')
CONFIGS=$(find -name '*.conf' -o -name '*.json')
MISSING=0
for NODE in ${NODE_TYPES}; do
[ ${NODE} == "loopback_internal" ] && continue
if [ ! -f "${SRCDIR}/etc/examples/nodes/${NODE}.conf" ]; then
echo "Missing example config for node-type: ${NODE}"
((MISSING++))
fi
done
for HOOK in ${HOOK_TYPES}; do
[ ${NODE} == "loopback_internal" ] && continue
if [ ! -f "${SRCDIR}/etc/examples/hooks/${HOOK}.conf" ]; then
echo "Missing example config for hook-type: ${HOOK}"
((MISSING++))
fi
done
(( ${MISSING} == 0 ))

View file

@ -30,8 +30,10 @@ CONFIGS=$(find ${SRCDIR}/etc/ -name '*.conf' -o -name '*.json')
for CONFIG in ${CONFIGS}; do
if [ "$(basename ${CONFIG})" == "opal.conf" ] ||
[ "$(basename ${CONFIG})" == "paths.conf" ] ||
[ "$(basename ${CONFIG})" == "tricks.json" ] ||
[ "$(basename ${CONFIG})" == "tricks.conf" ] ||
[ "$(basename ${CONFIG})" == "vc707_ips.conf" ] ||
[ "$(basename ${CONFIG})" == "uldaq.conf" ] ||
[ "$(basename ${CONFIG})" == "infiniband.conf" ] ||
[ "$(basename ${CONFIG})" == "global.conf" ]; then
echo "=== Skipping config: ${CONFIG}"
continue