add warning about lack of read permissions for user "nobody" to run scapy server. 47/5347/1
authorYaroslav Brustinov <[email protected]>
Mon, 2 Jan 2017 17:10:25 +0000 (19:10 +0200)
committerYaroslav Brustinov <[email protected]>
Mon, 2 Jan 2017 17:10:25 +0000 (19:10 +0200)
add flag to disable scapy server run.

Change-Id: I65ccfb24ed4a5461fe2a13d8be0f07fad8a50bae
Signed-off-by: Yaroslav Brustinov <[email protected]>
scripts/dpdk_setup_ports.py
scripts/scapy_daemon_server
src/main_dpdk.cpp

index 66af699..97484f2 100755 (executable)
@@ -542,13 +542,14 @@ Other network devices
                         sys.exit(1)
                 else:
                        print('WARNING: Some other program is using DPDK driver.\nIf it is TRex and you did not configure it for dual run, current command will fail.')
-        if map_driver.parent_args.stl:
+        if map_driver.parent_args.stl and not map_driver.parent_args.no_scapy_server:
             try:
                 master_core = self.m_cfg_dict[0]['platform']['master_thread_id']
             except:
                 master_core = 0
             ret = os.system('%s scapy_daemon_server restart -c %s' % (sys.executable, master_core))
             if ret:
+                print("Could not start scapy_daemon_server, which is needed by GUI to create packets.\nIf you don't need it, use --no-scapy-server flag.")
                 sys.exit(1)
 
 
@@ -861,6 +862,7 @@ def parse_parent_cfg (parent_cfg):
     parent_parser.add_argument('--cfg', default='')
     parent_parser.add_argument('--dump-interfaces', nargs='*', default=None)
     parent_parser.add_argument('--no-ofed-check', action = 'store_true')
+    parent_parser.add_argument('--no-scapy-server', action = 'store_true')
     parent_parser.add_argument('--no-watchdog', action = 'store_true')
     parent_parser.add_argument('-i', action = 'store_true', dest = 'stl', default = False)
     map_driver.parent_args, _ = parent_parser.parse_known_args(shlex.split(parent_cfg))
index a5e4df0..e19c8b3 100755 (executable)
@@ -6,6 +6,7 @@ import time
 import subprocess, shlex
 from argparse import ArgumentParser, RawTextHelpFormatter
 import errno
+import pwd
 
 def fail(msg):
     print(msg)
@@ -14,8 +15,8 @@ def fail(msg):
 if os.getuid() != 0:
     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')
+cur_dir = os.path.abspath(os.path.dirname(__file__))
+ext_libs_path = os.path.join(cur_dir, 'external_libs')
 if ext_libs_path not in sys.path:
     sys.path.append(ext_libs_path)
 
@@ -30,34 +31,46 @@ 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):
+def progress(success_check, start_msg, success_msg, fail_msg, timeout = 35, poll_rate = 0.5, fail_check = None):
     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
+        if fail_check and fail_check():
+            print(termstyle.red(' ' + fail_msg))
+            return 1
         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))
+    print(termstyle.red(' Timeout'))
     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'
+def demote_func():
+    pw_record = pwd.getpwnam('nobody')
+    os.setgid(pw_record.pw_gid)
+    os.setuid(pw_record.pw_uid)
+
+
+def run_command(command, timeout = 30, poll_rate = 0.1, cwd = None, demote = False, is_daemon = False):
+    if not is_daemon:
+        assert timeout > 0, 'Timeout should be positive'
+        assert poll_rate > 0, 'Poll rate should be positive'
+
+    preexec_fn = demote_func if demote else None
+
+    try: # P2
+        stdout_file = tempfile.TemporaryFile(bufsize = 0)
+    except: # P3
+        stdout_file = tempfile.TemporaryFile(buffering = 0)
+
     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)
+        proc = subprocess.Popen(shlex.split(command), stdout = stdout_file, stderr = subprocess.STDOUT, cwd = cwd,
+                                close_fds = True, universal_newlines = True, preexec_fn = preexec_fn)
+        if is_daemon:
+            return proc, stdout_file
         for i in range(int(timeout/poll_rate)):
             time.sleep(poll_rate)
             if proc.poll() is not None: # process stopped
@@ -68,6 +81,9 @@ def run_command(command, timeout = 15, poll_rate = 0.1, cwd = None):
             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())
+    finally:
+        if not is_daemon:
+            stdout_file.close()
 
 
 def get_daemon_pid():
@@ -100,15 +116,37 @@ 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("taskset -c %s su -s /bin/bash -c '%s scapy_zmq_server.py -s %s' nobody" % (args.core, sys.executable, args.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')
+    check_path = cur_dir
+    last_err_path = None
+    ret = -1
+    while ret and check_path != '/':
+        ret, out = run_command("ls %s" % check_path, demote = True)
         if ret:
-            stdout_file.seek(0)
-            print('Output: %s' % stdout_file.read())
-            sys.exit(1)
+            last_err_path = check_path
+            check_path = os.path.abspath(os.path.join(check_path, '..'))
+    if last_err_path:
+        msg = '''
+Error: current path is not readable by user "nobody" (starting at {path}).
+Two possible solutions:
+
+  1. (Recommended)
+     Copy TRex to some public location (/tmp or /scratch, assuming it has proper permissions (chmod 777 etc.))
+
+  2. (Not recommended)
+     Change permissions of current path. (Starting from directory {path}).
+     chmod 777 {path} -R
+'''.format(path = last_err_path)
+        fail(msg)
+
+    server_path = os.path.join(cur_dir, 'automation', 'trex_control_plane', 'stl', 'services', 'scapy_server')
+    cmd = 'taskset -c {core} {python} ./scapy_zmq_server.py -s {port}'.format(core = args.core, python = sys.executable, port = args.port)
+    proc, stdout_file = run_command(cmd, demote = True, is_daemon = True, cwd = server_path)
+    ret = progress(is_running, 'Starting Scapy server', 'Scapy server is started', 'Scapy server failed to run', fail_check = proc.poll)
+    if proc.poll():
+        stdout_file.seek(0)
+        print('Output: %s' % stdout_file.read())
+        stdout_file.close()
+        sys.exit(1)
 
 
 def restart_daemon():
@@ -124,14 +162,15 @@ def kill_daemon():
         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')
+    ret = progress(inv(is_running), 'Killing Scapy server', 'Scapy server is killed', 'failed', timeout = 15)
     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')
+    ret = progress(inv(is_running), 'Killing Scapy server with -9', 'Scapy server is killed', 'failed', timeout = 15)
     if ret:
         fail('Failed to kill Scapy server, even with -9. Please review manually.\nOutput: %s' % out)
 
+
 ### Main ###
 
 if __name__ == '__main__':
index 1f0f993..82ebddd 100644 (file)
@@ -693,6 +693,7 @@ enum { OPT_HELP,
        OPT_CLOSE,
        OPT_ARP_REF_PER,
        OPT_NO_OFED_CHECK,
+       OPT_NO_SCAPY_SERVER,
        OPT_ACTIVE_FLOW
 };
 
@@ -749,11 +750,11 @@ static CSimpleOpt::SOption parser_options[] =
         { OPT_NO_WATCHDOG,            "--no-watchdog",     SO_NONE    },
         { OPT_ALLOW_COREDUMP,         "--allow-coredump",  SO_NONE    },
         { OPT_CHECKSUM_OFFLOAD,       "--checksum-offload", SO_NONE   },
-        { OPT_ACTIVE_FLOW,            "--active-flows",   SO_REQ_SEP    },
+        { OPT_ACTIVE_FLOW,            "--active-flows",   SO_REQ_SEP  },
         { OPT_CLOSE,                  "--close-at-end",    SO_NONE    },
         { OPT_ARP_REF_PER,            "--arp-refresh-period", SO_REQ_SEP },
         { OPT_NO_OFED_CHECK,          "--no-ofed-check",   SO_NONE    },
-        
+        { OPT_NO_SCAPY_SERVER,        "--no-scapy-server", SO_NONE    },
         SO_END_OF_OPTIONS
     };
 
@@ -1090,10 +1091,11 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t
                 break;
             case OPT_NO_OFED_CHECK:
                 break;
+            case OPT_NO_SCAPY_SERVER:
+                break;
 
             default:
                 printf("Error: option %s is not handled.\n\n", args.OptionText());
-                usage();
                 return -1;
                 break;
             } // End of switch