Commit 0939f3db authored by Federico Sismondi's avatar Federico Sismondi
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request !44
parents 19bac2ec 08ef6d7f
Pipeline #1491 passed with stage
in 0 seconds
......@@ -8,7 +8,7 @@ data/results/*.pcap
data/results/*.json
data/dumps/*.pcap
data/dumps/*.json
*.pcap
### Python ###
# Byte-compiled / optimized / DLL files
......
[submodule "coap_testing_tool/test_analysis_tool"]
path = coap_testing_tool/test_analysis_tool
url = https://gitlab.distantaccess.com/fsismondi/ttproto.git
url = https://gitlab.f-interop.eu/fsismondi/ttproto.git
branch = master
[submodule "coap_testing_tool/agent"]
path = coap_testing_tool/agent
url = https://gitlab.distantaccess.com/f-interop-contributors/agent.git
url = https://gitlab.f-interop.eu/f-interop-contributors/agent.git
branch = master
[submodule "coap_testing_tool/utils"]
path = coap_testing_tool/utils
url = https://gitlab.f-interop.eu/f-interop-contributors/utils.git
branch = master
[submodule "automated_IUTs/coap_client_coapthon/CoAPthon"]
path = automated_IUTs/coap_client_coapthon/CoAPthon
url = https://github.com/fsismondi/CoAPthon.git
......
......@@ -2,7 +2,7 @@ properties([[$class: 'GitLabConnectionProperty', gitLabConnection: 'figitlab']])
if(env.JOB_NAME =~ 'coap_testing_tool/'){
node('sudo'){
env.AMQP_URL="amqp://paul:iamthewalrus@f-interop.rennes.inria.fr/jenkins.coap_testing_tool"
env.AMQP_URL="amqp://guest:guest@localhost/"
env.AMQP_EXCHANGE="amq.topic"
stage ("Setup dependencies"){
......@@ -20,6 +20,11 @@ if(env.JOB_NAME =~ 'coap_testing_tool/'){
sudo apt-get install --fix-missing -y libssl-dev openssl
sudo apt-get install --fix-missing -y libffi-dev
sudo apt-get install --fix-missing -y curl tree netcat
sudo apt-get install --fix-missing -y rabbitmq-server
echo 'restarting rmq server and app'
sudo rabbitmq-server -detached || true
sudo rabbitmqctl stop_app || true
sudo rabbitmqctl start_app || true
'''
/* Show deployed code */
......@@ -166,7 +171,7 @@ if(env.JOB_NAME =~ 'coap_testing_tool_ansible_container/'){
if(env.JOB_NAME =~ 'coap_testing_tool_docker_build/'){
node('docker'){
env.AMQP_URL = "amqp://paul:iamthewalrus@f-interop.rennes.inria.fr/jenkins.coap_testing_tool_docker_build"
env.AMQP_URL="amqp://guest:guest@localhost/"
env.AMQP_EXCHANGE="amq.topic"
env.DOCKER_CLIENT_TIMEOUT=3000
env.COMPOSE_HTTP_TIMEOUT=3000
......@@ -215,7 +220,7 @@ if(env.JOB_NAME =~ 'coap_testing_tool_docker_build/'){
if(env.JOB_NAME =~ 'coap_automated_iuts_docker_build_and_run/'){
node('docker'){
env.AMQP_URL = "amqp://paul:iamthewalrus@f-interop.rennes.inria.fr/jenkins.coap_automated_iuts"
env.AMQP_URL="amqp://guest:guest@localhost/"
env.AMQP_EXCHANGE="amq.topic"
env.DOCKER_CLIENT_TIMEOUT=3000
env.COMPOSE_HTTP_TIMEOUT=3000
......@@ -309,7 +314,8 @@ if(env.JOB_NAME =~ 'coap_automated_iuts_docker_build_and_run/'){
if(env.JOB_NAME =~ 'full_coap_interop_session/'){
node('docker'){
env.AMQP_URL = "amqp://paul:iamthewalrus@f-interop.rennes.inria.fr/jenkins.full_coap_interop_session"
/* attention, here we use external RMQ server, else we would need to allow docker containers to access host's loopback ports */
env.AMQP_URL="amqp://paul:iamthewalrus@f-interop.rennes.inria.fr/jenkins.full_coap_interop_session"
env.AMQP_EXCHANGE="amq.topic"
env.DOCKER_CLIENT_TIMEOUT=3000
env.COMPOSE_HTTP_TIMEOUT=3000
......
......@@ -25,16 +25,42 @@ For description of components please visit: [f-interop doc](doc.f-interop.eu)
### Clonning the project
```
git clone --recursive https://gitlab.f-interop.eu/fsismondi/coap_testing_tool.git
git clone --recursive https://gitlab.f-interop.eu/f-interop-contributors/coap_testing_tool.git
cd coap_testing_tool
```
### Attention with the git submodules!
remember when cloning a project with submodules to use --recursive flag
```
git clone --recursive ...
```
or else (in case you forgot about the flag), right after cloning you can:
```
git submodule update --init --recursive
```
whenever you find that your utils libraries are not the latests versions
you can 'bring' those last changes from the main utils repo to your project
with:
```
git submodule update --remote --merge
```
after bringing the last changes you can update your project with the last changes by doing:
```
git add <someSubModuleDir>
git commit -m 'updated submodule reference to last commit'
git push
```
### Running CoAP testing tool as standalone mode
(# TODO talk about the CLI, without it you cannot run a session)
First thing needed is to have the rabbit running ;)
You need a server running RabbitMQ message broker for handling the
For this, you need a server running RabbitMQ message broker for handling the
messaging between the components taking part in your test session.
The options for this are:
......@@ -48,7 +74,9 @@ create RMQ vhost, user, pass on local machine
for this contact federico.sismondi@inria.fr or remy.leone@inria.fr
then, export in the machine where the testing tool is running the following vars:
after having a created vhost with its user/password,
export in the machine where the testing tool is running the following
env vars:
```
export AMQP_URL='amqp://someUser:somePassword@server/amqp_vhost'
......@@ -76,7 +104,7 @@ run the testing tool using supervisor.
---
#### Opt 1 - Building & running CoAP testing tool with docker
#### Opt 1 - Building & running CoAP testing tool with docker (recommended)
First, let's install docker. For this just follow this instructions:
......@@ -86,32 +114,71 @@ Don't forget to start it!
Second, **build** the testing tool, from inside coap_testing_tool dir run:
```
docker build -t finterop-coap .
make docker-build-all # build all tools, TT and automated-iuts
```
or run the docker build manually
```
docker build -t testing_tool-interoperability-coap .
```
for running the coap-testing-tool do
```
make run-coap-testing-tool
```
for verifying that TT is actually running:
```
make get-logs
```
Also, if you are running a session alone (no 2nd user) then you may
want to use one of the automated-iut or reference implementations,
for this, if you are testing your coap server:
```
make run-coap-client
```
or (if you are testing your coap client)
```
run-coap-server
```
If build fails due to a "Failed to fetch http://archive.ubuntu ...."
then:
```
docker build -t finterop-coap . --no-cache
docker build -t testing_tool-interoperability-coap . --no-cache
```
Go to FAQ, for known errors.
Finally, **run** it, from inside coap_testing_tool run:
for running coap_testing_tool manually from docker api:
```
docker run -it
--env AMQP_EXCHANGE='default'
--env AMQP_URL='amqp://someUser:somePassword@server/amqp_vhost'
--privileged finterop-coap supervisord
--nodaemon
--configuration supervisor.conf
--env AMQP_EXCHANGE=$AMQP_EXCHANGE
--env AMQP_URL=$AMQP_URL
--sysctl net.ipv6.conf.all.disable_ipv6=0
--privileged
testing_tool-interoperability-coap
```
alternatively, you can:
alternatively, if you are curious and you want to know
what's under the hood:
```
docker run -it --env AMQP_EXCHANGE=default --env AMQP_URL='amqp://someUser:somePassword@server/amqp_vhost' --privileged finterop-coap bash
docker run -it
--env AMQP_EXCHANGE=$AMQP_EXCHANGE
--env AMQP_URL=$AMQP_URL
--sysctl net.ipv6.conf.all.disable_ipv6=0
--privileged
testing_tool-interoperability-coap
bash
root@bab3b2220510:/coap_testing_tool# supervisord -c supervisor.conf
root@bab3b2220510:/coap_testing_tool# supervisorctl -c supervisor.conf
agent RUNNING pid 28, uptime 0:00:02
......
......@@ -13,7 +13,7 @@ import signal
import logging
import threading
from coap_testing_tool.utils.event_bus_messages import *
from coap_testing_tool.utils.messages import *
from coap_testing_tool.utils.amqp_synch_call import publish_message
from coap_testing_tool import AMQP_URL, AMQP_EXCHANGE, INTERACTIVE_SESSION, RESULTS_DIR
......@@ -324,7 +324,7 @@ class UserMock(threading.Thread):
self.channel.stop_consuming()
def exit(self):
publish_message(self.connection.channel(),
publish_message(self.connection,
MsgTestingToolComponentShutdown(component=COMPONENT_ID))
time.sleep(2)
self.connection.close()
......
agent @ accc772f
Subproject commit 591ade863018eada4256898ef18b2acb52b1a876
Subproject commit accc772ff99cc70117cd8beff56b972a4b9b05f7
......@@ -100,7 +100,7 @@
"mandatory": false
},
{
"field_name": "testsuite.reference_iut",
"field_name": "testsuite.additional_session_resource",
"description": "Reference implementation (mandatory)",
"type": "selection",
"value": [
......
......@@ -31,7 +31,7 @@ stderr_logfile_maxbytes=0
[program:agent]
directory= ./coap_testing_tool/agent/
command = sh -c "sleep 1;python -m agent connect --url %(ENV_AMQP_URL)s --exchange %(ENV_AMQP_EXCHANGE)s --name agent_TT"
command = sh -c "sleep 3;python -m agent connect --url %(ENV_AMQP_URL)s --exchange %(ENV_AMQP_EXCHANGE)s --name agent_TT"
user=root
stopsignal=INT
stopasgroup=true
......@@ -49,7 +49,7 @@ stderr_logfile_maxbytes=0
[program:tat]
directory= ./coap_testing_tool/test_analysis_tool
command = sh -c "sleep 2;/usr/bin/python3 -m ttproto --dissector --interface amqp --protocol coap "
command = sh -c "sleep 3;/usr/bin/python3 -m ttproto --dissector --interface amqp --protocol coap "
autorestart=false
stopsignal=INT
stopasgroup=true
......@@ -66,7 +66,7 @@ stderr_logfile_maxbytes=0
[program:bootstrap-agent-TT]
; we auto bootstrap the agent
command = sh -c "sleep 4;/usr/bin/python3 -m coap_testing_tool.agent.utils.bootstrap_agent agent_TT bbbb :3 --no_forwarding"
command = sh -c "sleep 5;/usr/bin/python3 -m coap_testing_tool.agent.utils.bootstrap_agent agent_TT bbbb :3 --no_forwarding"
autorestart=false
stopsignal=INT
stopasgroup=false
......
......@@ -99,7 +99,7 @@
"mandatory": false
},
{
"field_name": "testsuite.automated_iut",
"field_name": "testsuite.additional_session_resource",
"description": "Automated-IUT selection (optional)",
"type": "selection",
"value": [
......
......@@ -2,13 +2,11 @@
# !/usr/bin/env python3
import pika
import threading
import datetime
import signal
import sys
import logging
from coap_testing_tool.utils.rmq_handler import RabbitMQHandler, JsonFormatter
from coap_testing_tool import AMQP_URL, AMQP_EXCHANGE, AGENT_NAMES, AGENT_TT_ID
from coap_testing_tool.utils.event_bus_messages import *
from coap_testing_tool.utils.messages import *
from coap_testing_tool.utils.amqp_synch_call import publish_message
COMPONENT_ID = 'packet_router'
......@@ -43,9 +41,12 @@ class PacketRouter(threading.Thread):
],
}
def __init__(self, conn, routing_table=None):
def __init__(self, amqp_url, amqp_exchange, routing_table=None):
threading.Thread.__init__(self)
self.exchange_name = amqp_exchange
self.url = amqp_url
if routing_table:
self.routing_table = routing_table
else:
......@@ -53,11 +54,8 @@ class PacketRouter(threading.Thread):
logger.info('routing table (rkey_src:[rkey_dst]) : {table}'.format(table=json.dumps(self.routing_table)))
# queues & default exchange declaration
self.message_count = 0
self.connection = conn
self.channel = self.connection.channel()
self.channel.basic_qos(prefetch_count=1)
self.set_up_connection()
self.queues_init()
msg = MsgTestingToolComponentReady(
......@@ -67,6 +65,18 @@ class PacketRouter(threading.Thread):
logger.info('packet router waiting for new messages in the data plane..')
def set_up_connection(self):
try:
logger.info('Setting up AMQP connection..')
# setup AMQP connection
self.connection = pika.BlockingConnection(pika.URLParameters(self.url))
self.channel = self.connection.channel()
self.channel.basic_qos(prefetch_count=1)
except pika.exceptions.ConnectionClosed as cc:
logger.error(' AMQP cannot be established, is message broker up? \n More: %s' % cc)
sys.exit(1)
def queues_init(self):
for src_rkey, dst_rkey_list in self.routing_table.items():
assert type(src_rkey) is str
......@@ -79,7 +89,7 @@ class PacketRouter(threading.Thread):
# start with clean queues
self.channel.queue_purge(src_queue)
self.channel.queue_bind(exchange=AMQP_EXCHANGE,
self.channel.queue_bind(exchange=self.exchange_name,
queue=src_queue,
routing_key=src_rkey)
......@@ -88,6 +98,8 @@ class PacketRouter(threading.Thread):
def stop(self):
self.shutdown_notification()
# delete routing all queues
for src_rkey in self.routing_table.keys():
# convention on queue naming
......@@ -116,7 +128,6 @@ class PacketRouter(threading.Thread):
if src_rkey in self.routing_table.keys():
list_dst_rkey = self.routing_table[src_rkey]
for dst_rkey in list_dst_rkey:
m = MsgPacketInjectRaw(
data=data
)
......@@ -124,7 +135,7 @@ class PacketRouter(threading.Thread):
self.channel.basic_publish(
body=m.to_json(),
routing_key=dst_rkey,
exchange=AMQP_EXCHANGE,
exchange=self.exchange_name,
properties=pika.BasicProperties(
content_type='application/json',
)
......@@ -132,7 +143,6 @@ class PacketRouter(threading.Thread):
logger.info(
"Routing packet (%d) from topic: %s to topic: %s" % (self.message_count, src_rkey, dst_rkey))
elif 'toAgent' in src_rkey:
pass # echo of router message
......@@ -140,39 +150,30 @@ class PacketRouter(threading.Thread):
logger.warning('No known route for r_key source: {r_key}'.format(r_key=src_rkey))
return
def run(self):
self.channel.start_consuming()
logger.info('Bye byes!')
###############################################################################
def shutdown_notification(self):
if __name__ == '__main__':
connection = pika.BlockingConnection(pika.URLParameters(AMQP_URL))
channel = connection.channel()
def signal_int_handler(channel):
# FINISHING... let's send a goodbye message
msg = {
'message': '{component} is out! Bye bye..'.format(component=COMPONENT_ID),
"_type": '{component}.shutdown'.format(component=COMPONENT_ID)
}
channel.basic_publish(
self.channel.basic_publish(
body=json.dumps(msg),
routing_key='control.session.info',
exchange=AMQP_EXCHANGE,
exchange=self.exchange_name,
properties=pika.BasicProperties(
content_type='application/json',
)
)
logger.info('got SIGINT. Bye bye!')
def run(self):
self.channel.start_consuming()
self.shutdown_notification()
sys.exit(0)
###############################################################################
#signal.signal(signal.SIGINT, signal_int_handler)
if __name__ == '__main__':
# routing tables for between agents' TUNs interfaces and also between agents' serial interfaces
iut_routing_table_serial = {
......@@ -198,11 +199,10 @@ if __name__ == '__main__':
routing_table.update(iut_routing_table_tun)
# start amqp router thread
r = PacketRouter(connection, routing_table)
r = PacketRouter(AMQP_URL, AMQP_EXCHANGE, routing_table)
try:
r.start()
r.join()
except (KeyboardInterrupt, SystemExit):
logger.info('got SIGINT. Bye bye!')
r.stop()
......@@ -42,12 +42,11 @@ class PacketRouterTestCase(unittest.TestCase):
}
# start packet router
packet_router = PacketRouter(self.connection, self.routing_table )
packet_router = PacketRouter(AMQP_URL, AMQP_EXCHANGE, self.routing_table)
packet_router.daemon = True
packet_router.start()
def test_packet_routing(self):
assert self.channel.is_open, 'no channel opened for tests'
self._send_packet_fromAgent1()
......@@ -95,9 +94,11 @@ class PacketRouterTestCase(unittest.TestCase):
{
'_type': 'packet.sniffed.raw',
'data': [96, 0, 0, 0, 0, 56, 0, 1, 254, 128, 0, 0, 0, 0, 0, 0, 174, 188, 50, 255, 254, 205, 243,
139, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 58, 0, 1, 0, 5, 2, 0, 0, 143, 0, 166,
127, 0, 0, 0, 2, 4, 0, 0, 0, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 0, 0, 1, 4, 0, 0, 0,
255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 205, 243, 139],
139, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 58, 0, 1, 0, 5, 2, 0, 0, 143, 0,
166,
127, 0, 0, 0, 2, 4, 0, 0, 0, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 0, 0, 1, 4, 0, 0,
0,
255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 205, 243, 139],
'description': 'hello world',
}
),
......@@ -119,9 +120,11 @@ class PacketRouterTestCase(unittest.TestCase):
{
'_type': 'packet.sniffed.raw',
'data': [96, 0, 0, 0, 0, 56, 0, 1, 254, 128, 0, 0, 0, 0, 0, 0, 174, 188, 50, 255, 254, 205, 243,
139, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 58, 0, 1, 0, 5, 2, 0, 0, 143, 0, 166,
127, 0, 0, 0, 2, 4, 0, 0, 0, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 0, 0, 1, 4, 0, 0, 0,
255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 205, 243, 139],
139, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 58, 0, 1, 0, 5, 2, 0, 0, 143, 0,
166,
127, 0, 0, 0, 2, 4, 0, 0, 0, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 0, 0, 1, 4, 0, 0,
0,
255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 255, 205, 243, 139],
'description': 'hello world',
}
),
......
......@@ -12,7 +12,7 @@ import logging
from coap_testing_tool.utils.amqp_synch_call import publish_message
from coap_testing_tool import TMPDIR, DATADIR, LOGDIR, AMQP_EXCHANGE, AMQP_URL
from coap_testing_tool.utils.rmq_handler import RabbitMQHandler, JsonFormatter
from coap_testing_tool.utils.event_bus_messages import *
from coap_testing_tool.utils.messages import *
COMPONENT_ID = 'packet_sniffer'
last_capture_name = None
......@@ -36,11 +36,12 @@ logger.addHandler(rabbitmq_handler)
logger.setLevel(logging.DEBUG)
# in seconds
TIME_WAIT_FOR_TCPDUMP_ON = 5
TIME_WAIT_FOR_TCPDUMP_STARTUP = 5
TIME_WAIT_FOR_COMPONENTS_FINISH_EXECUTION = 2
connection = None
def on_request(ch, method, props, body):
"""
......@@ -90,7 +91,7 @@ def on_request(ch, method, props, body):
except FileNotFoundError as fne:
publish_message(
ch,
connection,
MsgErrorReply(request, error_message=str(fne))
)
logger.error(str(fne))
......@@ -210,8 +211,8 @@ def on_request(ch, method, props, body):
logger.error('Didnt succeed starting the capture')
last_capture_name = capture_id # keep track of the undergoing capture name
time.sleep(TIME_WAIT_FOR_TCPDUMP_ON) # to avoid race conditions
response = MsgReply(request) # by default sends ok = True
time.sleep(TIME_WAIT_FOR_TCPDUMP_STARTUP) # to avoid race conditions
response = MsgReply(request, ok = True)
publish_message(connection, response)
elif isinstance(request, MsgSniffingStop):
......@@ -224,14 +225,14 @@ def on_request(ch, method, props, body):
except:
logger.error('Didnt succeed stopping the sniffer')
response = MsgReply(request) # by default sends ok = True
response = MsgReply(request, ok = True)
publish_message(connection, response)
else:
logger.warning('Ignoring unrecognised service request: %s' % repr(request))
### IMPLEMENTATION OF SERVICES ###
# # # Implementation of tcpdump and OS related calls # # #
def _launch_sniffer(filename, filter_if, filter_proto):
"""
......@@ -294,7 +295,7 @@ def main():
if e.errno != errno.EEXIST:
raise
### SETUPING UP CONNECTION ###
# connection setup
global connection
......@@ -313,13 +314,13 @@ def main():
queue='services_queue@%s' % COMPONENT_ID,
routing_key='control.sniffing.service')
channel.basic_qos(prefetch_count=1)
channel.basic_consume(on_request, queue='services_queue@%s' % COMPONENT_ID)
except pika.exceptions.ConnectionClosed as cc:
logger.error(' AMQP cannot be established, is message broker up? \n More: %s' % traceback.format_exc())
sys.exit(1)
channel.basic_qos(prefetch_count=1)
channel.basic_consume(on_request, queue='services_queue@%s' % COMPONENT_ID)
msg = MsgTestingToolComponentReady(
component='sniffing'
)
......
[unix_http_server]
file=/tmp/supervisor.sock ; (the path to the socket file)
[supervisord]
logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (log level;default info; others: debug,warn,trace)
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
[program:test-coordinator]
command = /usr/bin/python3 -m coap_testing_tool.test_coordinator coap
autorestart=false
stopsignal=INT
stopasgroup=true
loglevel=debug
; for sending logs to docker
;stdout_logfile=/dev/stdout
;stdout_logfile_maxbytes=0
;stderr_logfile=/dev/stderr
;stderr_logfile_maxbytes=0
redirect_stderr=true
stdout_logfile = /var/log/test_coordinator-stdout.log
stdout_logfile_maxbytes = 10MB
stdout_logfile_backups = 5
[program:agent]