summaryrefslogtreecommitdiffstats
path: root/scripts/scapy_daemon_server
diff options
context:
space:
mode:
authorYaroslav Brustinov <ybrustin@cisco.com>2016-12-14 01:19:31 +0200
committerYaroslav Brustinov <ybrustin@cisco.com>2016-12-20 12:08:30 +0200
commit1530b34cabea906fef56f1537cd32aead6103f9d (patch)
treed00746b88c91e68743860a833eb723239a2f8d2c /scripts/scapy_daemon_server
parentde2af4eb20e9f77adfb1ee61e6ae3c82bfb86e92 (diff)
scapy launcher
Change-Id: Iafe0365e82c5386e87dbf7abd0f0982c3ff95d80 Signed-off-by: Yaroslav Brustinov <ybrustin@cisco.com>
Diffstat (limited to 'scripts/scapy_daemon_server')
-rwxr-xr-xscripts/scapy_daemon_server163
1 files changed, 163 insertions, 0 deletions
diff --git a/scripts/scapy_daemon_server b/scripts/scapy_daemon_server
new file mode 100755
index 00000000..490e8033
--- /dev/null
+++ b/scripts/scapy_daemon_server
@@ -0,0 +1,163 @@
+#!/usr/bin/python
+
+import os, sys, getpass
+import tempfile
+import time
+import subprocess, shlex
+from argparse import ArgumentParser, RawTextHelpFormatter
+import errno
+
+def fail(msg):
+ print(msg)
+ sys.exit(-1)
+
+if getpass.getuser() != 'root':
+ fail('Please run this program as root/with sudo')
+
+pwd = os.path.abspath(os.path.dirname(__file__))
+ext_libs_path = os.path.join(pwd, 'external_libs')
+if ext_libs_path not in sys.path:
+ sys.path.append(ext_libs_path)
+
+import netstat
+try:
+ from termstyle import termstyle
+except ImportError:
+ import termstyle
+
+
+def inv(f):
+ return lambda *a, **k: not f(*a, **k)
+
+
+def progress(success_check, start_msg, success_msg, fail_msg, timeout = 10, poll_rate = 0.5):
+ sys.stdout.write('%s...' % start_msg)
+ sys.stdout.flush()
+ for i in range(int(timeout/poll_rate)):
+ if success_check():
+ print(termstyle.green(' ' + success_msg))
+ return 0
+ time.sleep(poll_rate)
+ sys.stdout.write('.')
+ sys.stdout.flush()
+ if success_check():
+ print(termstyle.green(' ' + success_msg))
+ return 0
+ print(termstyle.red(' ' + fail_msg))
+ return 1
+
+
+def run_command(command, timeout = 15, poll_rate = 0.1, cwd = None):
+ assert timeout > 0, 'Timeout should be positive'
+ assert poll_rate > 0, 'Poll rate should be positive'
+ try:
+ tempfile.TemporaryFile(bufsize=0)
+ temp_params = {'bufsize': 0}
+ except:
+ tempfile.TemporaryFile(buffering=0)
+ temp_params = {'buffering': 0}
+ with tempfile.TemporaryFile(**temp_params) as stdout_file:
+ proc = subprocess.Popen(shlex.split(command), stdout = stdout_file, stderr = subprocess.STDOUT, cwd = cwd, close_fds = True, universal_newlines = True)
+ for i in range(int(timeout/poll_rate)):
+ time.sleep(poll_rate)
+ if proc.poll() is not None: # process stopped
+ break
+ if proc.poll() is None:
+ proc.kill() # timeout
+ stdout_file.seek(0)
+ return (errno.ETIMEDOUT, '%s\n\n...Timeout of %s second(s) is reached!' % (stdout_file.read(), timeout))
+ stdout_file.seek(0)
+ return (proc.returncode, stdout_file.read())
+
+
+def get_daemon_pid():
+ pid = None
+ for conn in netstat.netstat():
+ if conn[2] == '0.0.0.0' and int(conn[3]) == args.daemon_port and conn[6] == 'LISTEN':
+ pid = conn[7]
+ if pid is None:
+ raise Exception('Found the connection, but could not determine pid: %s' % conn)
+ break
+ return pid
+
+
+# faster variant of get_daemon_pid
+def is_running():
+ for conn in netstat.netstat(with_pid = False):
+ if conn[2] == '0.0.0.0' and int(conn[3]) == args.daemon_port and conn[6] == 'LISTEN':
+ return True
+ return False
+
+
+def show_daemon_status():
+ if is_running():
+ print(termstyle.green('Scapy server is running'))
+ else:
+ print(termstyle.red('Scapy server is NOT running'))
+
+
+def start_daemon():
+ if is_running():
+ print(termstyle.red('Scapy server is already running'))
+ return
+ server_path = os.path.join(pwd, 'automation', 'trex_control_plane', 'stl', 'services', 'scapy_server')
+ with tempfile.TemporaryFile() as stdout_file:
+ subprocess.Popen(shlex.split('sudo -u nobody %s scapy_zmq_server.py -s %s' % (sys.executable, args.daemon_port)), stdout = stdout_file,
+ stderr = subprocess.STDOUT, cwd = server_path, close_fds = True, universal_newlines = True)
+ ret = progress(is_running, 'Starting Scapy server', 'Scapy server is started', 'Scapy server failed to run')
+ if ret:
+ stdout_file.seek(0)
+ print('Output: %s' % stdout_file.read())
+ sys.exit(1)
+
+
+def restart_daemon():
+ if is_running():
+ kill_daemon()
+ time.sleep(0.5)
+ start_daemon()
+
+
+def kill_daemon():
+ pid = get_daemon_pid()
+ if not pid:
+ print(termstyle.red('Scapy server is NOT running'))
+ return True
+ run_command('kill %s' % pid) # usual kill
+ ret = progress(inv(is_running), 'Killing Scapy server', 'Scapy server is killed', 'failed')
+ if not ret:
+ return
+ _, out = run_command('kill -9 %s' % pid) # unconditional kill
+ ret = progress(inv(is_running), 'Killing Scapy server with -9', 'Scapy server is killed', 'failed')
+ if ret:
+ fail('Failed to kill Scapy server, even with -9. Please review manually.\nOutput: %s' % out)
+
+### Main ###
+
+if __name__ == '__main__':
+ actions_help = '''Specify action command to be applied on server.
+ (*) start : start the application in as a daemon process.
+ (*) show : prompt an updated status of daemon process (running/ not running).
+ (*) stop : exit Scapy server daemon process.
+ (*) restart : stop, then start again the application as daemon process
+ '''
+ action_funcs = {'start': start_daemon,
+ 'show': show_daemon_status,
+ 'stop': kill_daemon,
+ 'restart': restart_daemon,
+ }
+
+ parser = ArgumentParser(description = 'Runs Scapy server application.',
+ formatter_class = RawTextHelpFormatter,
+ )
+
+ parser.add_argument('-p', '--port', type = int, default = 4507, metavar="PORT", dest="daemon_port",
+ help="Select tcp port on which Scapy server listens.\nDefault port is 4507.", action="store")
+ parser.add_argument('action', choices=action_funcs.keys(),
+ action='store', help=actions_help)
+ parser.usage = None
+ args = parser.parse_args()
+
+ action_funcs[args.action]()
+
+