Skip to content

Commit 4b8aaa7

Browse files
Merge pull request ntop#947 from hamishcoleman/json_pubsub
Add JSON pubsub framework for edge
2 parents cbad152 + 017f1cf commit 4b8aaa7

24 files changed

+1304
-731
lines changed

.github/workflows/cmake.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,17 @@ jobs:
6666
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more
6767
# detail
6868
run: ctest -C $BUILD_TYPE
69+
70+
- if: ${{ failure() }}
71+
name: Upload test data
72+
uses: actions/upload-artifact@v2
73+
with:
74+
name: tests-out
75+
path: tests
76+
77+
- if: ${{ failure() }}
78+
name: Upload cmake test output
79+
uses: actions/upload-artifact@v2
80+
with:
81+
name: tests-out
82+
path: build/Testing

.github/workflows/tests.yml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,18 +91,18 @@ jobs:
9191
./configure
9292
shell: bash
9393

94-
- name: Run embedded tests
95-
run: make test
94+
- name: Run embedded unit tests
95+
run: make test.units
9696
shell: bash
9797

98-
- if: ${{ always() }}
98+
- if: ${{ failure() }}
9999
name: Move test outputs to an arch specific location
100100
shell: bash
101101
run: |
102102
mkdir -p tests/${{ matrix.os }}
103103
mv tests/*.out tests/${{ matrix.os }}
104104
105-
- if: ${{ always() }}
105+
- if: ${{ failure() }}
106106
name: Upload tests output
107107
uses: actions/upload-artifact@v2
108108
with:
@@ -162,18 +162,18 @@ jobs:
162162
./configure
163163
shell: bash
164164

165-
- name: Run embedded tests
166-
run: make test
165+
- name: Run embedded unit tests
166+
run: make test.units
167167
shell: bash
168168

169-
- if: ${{ always() }}
169+
- if: ${{ failure() }}
170170
name: Move test outputs to an arch specific location
171171
shell: bash
172172
run: |
173173
mkdir -p tests/${{ matrix.os }}
174174
mv tests/*.out tests/${{ matrix.os }}
175175
176-
- if: ${{ always() }}
176+
- if: ${{ failure() }}
177177
name: Upload tests output
178178
uses: actions/upload-artifact@v2
179179
with:
@@ -237,18 +237,18 @@ jobs:
237237
./scripts/hack_fakeautoconf.sh
238238
shell: bash
239239

240-
- name: Run embedded tests
241-
run: make test
240+
- name: Run embedded unit tests
241+
run: make test.units
242242
shell: bash
243243

244-
- if: ${{ always() }}
244+
- if: ${{ failure() }}
245245
name: Move test outputs to an arch specific location
246246
shell: bash
247247
run: |
248248
mkdir -p tests/${{ matrix.os }}
249249
mv tests/*.out tests/${{ matrix.os }}
250250
251-
- if: ${{ always() }}
251+
- if: ${{ failure() }}
252252
name: Upload tests output
253253
uses: actions/upload-artifact@v2
254254
with:

CMakeLists.txt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,10 +309,21 @@ install(FILES ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
309309
DESTINATION /usr/share/man/man1)
310310
install(FILES ${PROJECT_BINARY_DIR}/doc/n2n.7.gz
311311
DESTINATION /usr/share/man/man7)
312+
endif(DEFINED UNIX)
313+
314+
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
312315

313316
# TODO:
314317
# - Add the right dependancy so that the tests binaries get built first
315318
enable_testing()
316-
add_test(tests ${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/tests)
317-
318-
endif(DEFINED UNIX)
319+
add_test(NAME unit
320+
COMMAND ${CMAKE_COMMAND} -E env
321+
TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR}
322+
${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_SOURCE_DIR}/tests/tests_units.list
323+
)
324+
add_test(NAME integration
325+
COMMAND ${CMAKE_COMMAND} -E env
326+
TOPDIR=${PROJECT_SOURCE_DIR} BINDIR=${PROJECT_BINARY_DIR}
327+
${PROJECT_SOURCE_DIR}/scripts/test_harness.sh ${PROJECT_SOURCE_DIR}/tests/tests_integration.list
328+
)
329+
endif()

Makefile.in

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,30 @@ N2N_DEPS=$(wildcard include/*.h) $(wildcard src/*.c) Makefile
8484
# As source files pass the linter, they can be added here (If all the source
8585
# is passing the linter tests, this can be refactored)
8686
LINT_CCODE=\
87+
include/curve25519.h \
8788
include/edge_utils_win32.h \
89+
include/header_encryption.h \
90+
include/hexdump.h \
8891
include/n2n_define.h \
92+
include/n2n_wire.h \
93+
include/network_traffic_filter.h \
8994
include/pearson.h \
95+
include/random_numbers.h \
96+
include/sn_selection.h \
9097
include/speck.h \
98+
include/tf.h \
99+
src/edge_management.c \
91100
src/edge_utils_win32.c \
92101
src/example_edge_embed_quick_edge_init.c \
93102
src/header_encryption.c \
103+
src/sn_management.c \
94104
src/sn_selection.c \
95105
src/transform_cc20.c \
106+
src/transform_null.c \
107+
src/tuntap_freebsd.c \
96108
src/tuntap_linux.c \
109+
src/tuntap_netbsd.c \
110+
src/tuntap_osx.c \
97111
src/wire.c \
98112
tools/tests-auth.c \
99113
tools/tests-compress.c \
@@ -146,9 +160,8 @@ SUBDIRS+=tools
146160
COVERAGEDIR?=coverage
147161

148162
.PHONY: $(SUBDIRS)
149-
.PHONY: steps build push all clean distclean install test cover gcov build-dep
150-
.PHONY: lint lint.python lint.ccode lint.shell lint.yaml
151163

164+
.PHONY: all
152165
all: version $(APPS) $(DOCS) $(SUBDIRS)
153166

154167
# This allows breaking the build if the version.sh script discovers
@@ -188,9 +201,16 @@ $(N2N_LIB): $(N2N_OBJS)
188201

189202
win32/n2n_win32.a: win32
190203

191-
test: tools
192-
scripts/test_harness.sh
204+
.PHONY: test test.units test.integration
205+
test: test.units test.integration
206+
207+
test.units: tools
208+
scripts/test_harness.sh tests/tests_units.list
193209

210+
test.integration: $(APPS)
211+
scripts/test_harness.sh tests/tests_integration.list
212+
213+
.PHONY: lint lint.python lint.ccode lint.shell lint.yaml
194214
lint: lint.python lint.ccode lint.shell lint.yaml
195215

196216
lint.python:
@@ -209,6 +229,7 @@ lint.yaml:
209229
# CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="--coverage"
210230
# and run the desired tests. Ensure that package gcovr is installed
211231
# and then run "make cover"
232+
.PHONY: cover
212233
cover:
213234
mkdir -p $(COVERAGEDIR)
214235
gcovr -s --html --html-details --output=$(COVERAGEDIR)/index.html
@@ -217,11 +238,13 @@ cover:
217238
# Unfortunately, these end up in the wrong directory due to the
218239
# makefile layout
219240
# The steps to use this are similar to the "make cover" above
241+
.PHONY: gcov
220242
gcov:
221243
gcov $(N2N_OBJS)
222244
$(MAKE) -C tools gcov
223245

224246
# This is a convinent target to use during development or from a CI/CD system
247+
.PHONY: build-dep
225248
build-dep:
226249
ifeq ($(CONFIG_TARGET),generic)
227250
sudo apt install $(BUILD_DEP)
@@ -231,11 +254,13 @@ else
231254
echo Not attempting to install dependancies for system $(CONFIG_TARGET)
232255
endif
233256

257+
.PHONY: clean
234258
clean:
235259
rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) $(COVERAGEDIR)/ *.dSYM *~
236260
rm -f tests/*.out src/*.gcno src/*.gcda
237261
for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean; done
238262

263+
.PHONY: distclean
239264
distclean:
240265
rm -f tests/*.out src/*.gcno src/*.gcda src/*.indent src/*.unc-backup*
241266
rm -rf autom4te.cache/
@@ -246,6 +271,7 @@ distclean:
246271
rm -f packages/rpm/config.log packages/rpm/config.status
247272
rm -f $(addprefix src/,$(APPS))
248273

274+
.PHONY: install
249275
install: edge supernode edge.8.gz supernode.1.gz n2n.7.gz
250276
echo "MANDIR=$(MANDIR)"
251277
$(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR)
@@ -261,6 +287,7 @@ DOCKER_IMAGE_NAME=ntop/supernode
261287
DOCKER_IMAGE_VERSION=$N2N_VERSION_SHORT
262288
N2N_COMMIT_HASH=$(shell scripts/version.sh hash)
263289

290+
.PHONY: default steps build push
264291
default: steps
265292

266293
steps:

doc/ManagementAPI.md

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Management API
22

3-
This document is focused on the machine readable API interfaces.
3+
This document is focused on the machine readable API interfaces.
44

55
Both the edge and the supernode provide a management interface UDP port.
66
These interfaces have some documentation on their non machine readable
@@ -48,7 +48,7 @@ but this is intended for debugging.
4848

4949
The request is a single UDP packet containing one line of text with at least
5050
three space separated fields. Any text after the third field is available for
51-
the API method to use for additional parameters
51+
the API method to use for additional parameters
5252

5353
Fields:
5454
- Message Type
@@ -58,15 +58,23 @@ Fields:
5858

5959
The maximum length of the entire line of text is 80 octets.
6060

61+
All request packets should generate a reply. However, this reply may simply
62+
be an error.
63+
6164
### Message Type
6265

63-
This is a single octet that is either "r" for a read (or query) method
64-
call or "w" for a write (or change) method call.
66+
This is a single octet specifying the type:
67+
68+
- "r" for a read-only method (or one that does not need change permissions)
69+
- "w" for a write method (or one that makes changes)
70+
- "s" for a subscribe method to request this socket receive some events
6571

6672
To simplify the interface, the reply from both read and write calls to the
6773
same method is expected to contain the same data. In the case of a write
6874
call, the reply will contain the new state after making the requested change.
6975

76+
The subscribe and events message flow works with a different set of messages.
77+
7078
### Options
7179

7280
The options field is a colon separated set of options for this request. Only
@@ -83,14 +91,16 @@ SubFields:
8391

8492
Each request provides a tag value. Any non error reply associated with this
8593
request will include this tag value, allowing all related messages to be
86-
collected within the client.
94+
collected within the client. The tag will be truncated if needed by the
95+
daemon, but there will be at least 8 octets of space available.
8796

8897
Where possible, the error replies will also include this tag, however some
8998
errors occur before the tag is parsed.
9099

91100
The tag is not interpreted by the daemon, it is simply echoed back in all
92-
the replies. It is expected to be a short string that the client chooses
93-
to be unique amongst all recent or still outstanding requests.
101+
the replies. It is expected to be a short string that the client knows
102+
will be unique amongst all recent, still outstanding or subscription requests
103+
on a given socket.
94104

95105
One possible client implementation is a number between 0 and 999, incremented
96106
for each request and wrapping around to zero when it is greater than 999.
@@ -127,11 +137,14 @@ e.g:
127137
Each UDP packet in the reply is a complete and valid JSON dictionary
128138
containing a fragment of information related to the entire reply.
129139

140+
Reply packets are generated both in response to requests and whenever
141+
an event is published to a subscribed channel.
142+
130143
### Common metadata
131144

132145
There are two keys in each dictionary containing metadata. First
133146
is the `_tag`, containing the Message Tag from the original request.
134-
Second is the `_type` whic identifies the expected contents of this
147+
Second is the `_type` which identifies the expected contents of this
135148
packet.
136149

137150
### `_type: error`
@@ -176,6 +189,47 @@ packets will be required.
176189
e.g:
177190
`{"_tag":"108","_type":"row","mode":"p2p","ip4addr":"10.135.98.84","macaddr":"86:56:21:E4:AA:39","sockaddr":"192.168.7.191:41701","desc":"client4","lastseen":1584682200}`
178191

192+
### `_type: subscribed`
193+
194+
Signals that the subscription request has been successfully completed.
195+
Any future events on the requested channel will be asynchronously sent
196+
as `event` packets using the same tag as the subscribe request.
197+
198+
### `_type: unsubscribed`
199+
200+
Only one management client can be subscribed to any given event topic, so if
201+
another subscribe request arrives, the older client will be sent this message
202+
to let them know that they have been replaced.
203+
204+
(In the future, this may also be sent as a reply to a explicit unsubscribe
205+
request)
206+
207+
### `_type: replacing`
208+
209+
If a new subscription request will replace an existing one, this message is
210+
sent to the new client to inform them that they have replaced an older
211+
connection.
212+
213+
### `_type: event`
214+
215+
Asynchronous events will arrive with this message type, using the same tag as
216+
the original subscribe request. Just like with the `row` packets, the non
217+
metadata contents are entirely defined by the topic and the specific n2n
218+
version.
219+
220+
## Subscribe API
221+
222+
A client can subscribe to events using a request with the type of "s".
223+
Once a subscribe has been successfully completed, any events published
224+
on that channel will be forwarded to the client.
225+
226+
Only one management client can be subscribed to any given event topic,
227+
with newer subscriptions replacing older ones.
228+
229+
The special channel "debug" will receive copies of all events published.
230+
Note that this is for debugging of events and the packets may not have
231+
the same tag as the debug subscription.
232+
179233
## Authentication
180234

181235
Some API requests will make global changes to the running daemon and may

doc/Scripts.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,6 @@ This shell script is a wrapper for the `uncrustify` C code style checker
5151
which checks or applies a set of rules to the code. It is used during
5252
the automated lint checks.
5353

54-
### `test_harness.sh`
55-
56-
This shell script is used to run automated tests during development.
57-
5854
### `n2n-gateway.sh`
5955

6056
A sample script to route all the host traffic towards a remote gateway,
@@ -96,3 +92,26 @@ Manually test fetching and config:
9692
/etc/munin/plugins/n2n_supernode_pkts
9793
/etc/munin/plugins/n2n_supernode_pkts config
9894
```
95+
96+
## Testing scripts
97+
98+
### `test_harness.sh`
99+
100+
This shell script is used to run automated tests during development. It is
101+
run with a testlist filename - pointing at a file containing the list of
102+
tests to run.
103+
104+
Each test needs a file containing the expected output `${TESTNAME}.expected`
105+
which is expected to exist in the same directory as the testlist (this dir is
106+
referred to as `${listdir}` below).
107+
108+
Each test is a program, searched for in several locations, including the
109+
`${listdir}/../scripts` dir.
110+
111+
Each test is run with its output being sent to `*.out` files in the `listdir`
112+
and compared with the expected output.
113+
114+
### `scripts/test_integration_supernode.sh`
115+
116+
This starts a supernode and runs an integration test on the Json API using
117+
the `n2n-ctl` command.

include/n2n.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ int assign_one_ip_subnet (n2n_sn_t *sss, struct sn_community *comm);
285285
const char* compression_str (uint8_t cmpr);
286286
const char* transop_str (enum n2n_transform tr);
287287

288-
void handleMgmtJson (n2n_edge_t *eee, char *udp_buf, const struct sockaddr_in sender_sock);
289-
void handleMgmtJson_sn (n2n_sn_t *sss, char *udp_buf, const struct sockaddr_in sender_sock);
288+
void readFromMgmtSocket (n2n_edge_t *eee);
289+
290+
void mgmt_event_post (enum n2n_event_topic topic, int data0, void *data1);
290291
#endif /* _N2N_H_ */

0 commit comments

Comments
 (0)