Initial VNFTEST fw
Issue-ID: VNFSDK-195

Change-Id: I5abf0dd033e76e5225bb8271c0afaea325d741d9
Signed-off-by: Moshe <moshehoa@amdocs.com>

docker build

Issue-ID: VNFSDK-195

Change-Id: I25eb933504c0201e6c26477b540626fd515d2887

Signed-off-by: Moshe <moshehoa@amdocs.com>

fix requirements

Issue-ID: VNFSDK-195
Change-Id: I5907fa102bfbf9cb81d42e491c133b4fdbb0d6fd
Signed-off-by: Moshe <moshehoa@amdocs.com>

rm netifaces

Issue-ID: VNFSDK-195
Change-Id: I349d0c738442edfef256c90b06cbaeb446c1db13
Signed-off-by: Moshe <moshehoa@amdocs.com>

fix tox config

IssueID: VNFTEST-195

Change-Id: I5c0b0e0ab96cad1bdc56ab63860d794bfd15b5eb
Signed-off-by: Moshe <moshehoa@amdocs.com>

Add unit test

IssueID: VNFTEST-195
Change-Id: I08c9ba53721306aff4b74720181f8c853c4ccabe
Signed-off-by: Moshe <moshehoa@amdocs.com>

fix setup.py

Issue-ID: VNFSDK-195
Change-Id: I72bd93e4977edf5ef0b46c72fe47165b805aab7b
Signed-off-by: Moshe <moshehoa@amdocs.com>

fix test execution

Issue-ID: VNFSDK-195
Change-Id: I488a6226d2562229f0e7fa6c1d20f0c43882bc3b
Signed-off-by: Moshe <moshehoa@amdocs.com>
diff --git a/vnftest/common/process.py b/vnftest/common/process.py
new file mode 100644
index 0000000..21a21ac
--- /dev/null
+++ b/vnftest/common/process.py
@@ -0,0 +1,140 @@
+##############################################################################
+# Copyright 2018 EuropeanSoftwareMarketingLtd.
+# ===================================================================
+#  Licensed under the ApacheLicense, Version2.0 (the"License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# software distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and limitations under
+# the License
+##############################################################################
+# vnftest comment: this is a modified copy of
+# yardstick/common/process.py
+
+import logging
+import multiprocessing
+import signal
+import subprocess
+import time
+
+import os
+from oslo_utils import encodeutils
+
+from vnftest.common import exceptions
+from vnftest.common import utils
+
+
+LOG = logging.getLogger(__name__)
+
+
+def check_if_process_failed(proc, timeout=1):
+    if proc is not None:
+        proc.join(timeout)
+        # Only abort if the process aborted
+        if proc.exitcode is not None and proc.exitcode > 0:
+            raise RuntimeError("{} exited with status {}".format(proc.name, proc.exitcode))
+
+
+def terminate_children(timeout=3):
+    current_proccess = multiprocessing.current_process()
+    active_children = multiprocessing.active_children()
+    if not active_children:
+        LOG.debug("no children to terminate")
+        return
+    for child in active_children:
+        LOG.debug("%s %s %s, child: %s %s", current_proccess.name, current_proccess.pid,
+                  os.getpid(), child, child.pid)
+        LOG.debug("joining %s", child)
+        child.join(timeout)
+        child.terminate()
+    active_children = multiprocessing.active_children()
+    if not active_children:
+        LOG.debug("no children to terminate")
+    for child in active_children:
+        LOG.debug("%s %s %s, after terminate child: %s %s", current_proccess.name,
+                  current_proccess.pid, os.getpid(), child, child.pid)
+
+
+def _additional_env_args(additional_env):
+    """Build arguments for adding additional environment vars with env"""
+    if additional_env is None:
+        return []
+    return ['env'] + ['%s=%s' % pair for pair in additional_env.items()]
+
+
+def _subprocess_setup():
+    # Python installs a SIGPIPE handler by default. This is usually not what
+    # non-Python subprocesses expect.
+    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+
+def subprocess_popen(args, stdin=None, stdout=None, stderr=None, shell=False,
+                     env=None, preexec_fn=_subprocess_setup, close_fds=True):
+    return subprocess.Popen(args, shell=shell, stdin=stdin, stdout=stdout,
+                            stderr=stderr, preexec_fn=preexec_fn,
+                            close_fds=close_fds, env=env)
+
+
+def create_process(cmd, run_as_root=False, additional_env=None):
+    """Create a process object for the given command.
+
+    The return value will be a tuple of the process object and the
+    list of command arguments used to create it.
+    """
+    if not isinstance(cmd, list):
+        cmd = [cmd]
+    cmd = list(map(str, _additional_env_args(additional_env) + cmd))
+    if run_as_root:
+        # NOTE(ralonsoh): to handle a command executed as root, using
+        # a root wrapper, instead of using "sudo".
+        pass
+    LOG.debug("Running command: %s", cmd)
+    obj = subprocess_popen(cmd, shell=False, stdin=subprocess.PIPE,
+                           stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    return obj, cmd
+
+
+def execute(cmd, process_input=None, additional_env=None,
+            check_exit_code=True, return_stderr=False, log_fail_as_error=True,
+            extra_ok_codes=None, run_as_root=False):
+    try:
+        if process_input is not None:
+            _process_input = encodeutils.to_utf8(process_input)
+        else:
+            _process_input = None
+
+        # NOTE(ralonsoh): to handle the execution of a command as root,
+        # using a root wrapper, instead of using "sudo".
+        obj, cmd = create_process(cmd, run_as_root=run_as_root,
+                                  additional_env=additional_env)
+        _stdout, _stderr = obj.communicate(_process_input)
+        returncode = obj.returncode
+        obj.stdin.close()
+        _stdout = utils.safe_decode_utf8(_stdout)
+        _stderr = utils.safe_decode_utf8(_stderr)
+
+        extra_ok_codes = extra_ok_codes or []
+        if returncode and returncode not in extra_ok_codes:
+            msg = ("Exit code: %(returncode)d; "
+                   "Stdin: %(stdin)s; "
+                   "Stdout: %(stdout)s; "
+                   "Stderr: %(stderr)s") % {'returncode': returncode,
+                                            'stdin': process_input or '',
+                                            'stdout': _stdout,
+                                            'stderr': _stderr}
+            if log_fail_as_error:
+                LOG.error(msg)
+            if check_exit_code:
+                raise exceptions.ProcessExecutionError(msg,
+                                                       returncode=returncode)
+
+    finally:
+        # This appears to be necessary in order for the subprocess to clean up
+        # something between call; without it, the second process hangs when two
+        # execute calls are made in a row.
+        time.sleep(0)
+
+    return (_stdout, _stderr) if return_stderr else _stdout