예제 #1
0
    def instantiate(self, scenario_cfg, context_cfg):
        vnf_cfg = scenario_cfg['vnf_options']['vpe']['cfg']

        mgmt_interface = self.vnfd["mgmt-interface"]
        self.connection = ssh.SSH.from_node(mgmt_interface)

        self.tc_file_name = '{0}.yaml'.format(scenario_cfg['tc'])

        self.setup_vnf_environment(self.connection)

        cores = self._get_cpu_sibling_list()
        self.resource = ResourceProfile(self.vnfd, cores)

        self.connection.execute("pkill vPE_vnf")
        dpdk_nic_bind = \
            provision_tool(self.connection,
                           os.path.join(self.bin_path, "dpdk_nic_bind.py"))

        interfaces = self.vnfd["vdu"][0]['external-interface']
        self.socket = \
            next((0 for v in interfaces
                  if v['virtual-interface']["vpci"][5] == "0"), 1)

        bound_pci = [v['virtual-interface']["vpci"] for v in interfaces]
        for vpci in bound_pci:
            self.connection.execute("%s --force -b igb_uio %s" %
                                    (dpdk_nic_bind, vpci))
        queue_wrapper = \
            QueueFileWrapper(self.q_in, self.q_out, "pipeline>")
        self._vnf_process = multiprocessing.Process(target=self._run_vpe,
                                                    args=(
                                                        queue_wrapper,
                                                        vnf_cfg,
                                                    ))
        self._vnf_process.start()
        buf = []
        time.sleep(WAIT_TIME)  # Give some time for config to load
        while True:
            message = ''
            while self.q_out.qsize() > 0:
                buf.append(self.q_out.get())
                message = ''.join(buf)
                if "pipeline>" in message:
                    LOG.info("VPE VNF is up and running.")
                    queue_wrapper.clear()
                    self._resource_collect_start()
                    return self._vnf_process.exitcode
                if "PANIC" in message:
                    raise RuntimeError("Error starting vPE VNF.")

            LOG.info("Waiting for VNF to start.. ")
            time.sleep(3)
            if not self._vnf_process.is_alive():
                raise RuntimeError("vPE VNF process died.")
예제 #2
0
 def test_clear(self):
     queue_file_wrapper = \
         QueueFileWrapper(self.q_in, self.q_out, self.prompt)
     queue_file_wrapper.bufsize = 5
     queue_file_wrapper.write("pipeline>")
     queue_file_wrapper.close()
     self.assertIsNone(queue_file_wrapper.clear())
     self.assertIsNotNone(queue_file_wrapper.q_out.empty())
예제 #3
0
 def test_run_vpe(self):
     with mock.patch("yardstick.ssh.SSH") as ssh:
         ssh_mock = mock.Mock(autospec=ssh.SSH)
         ssh_mock.execute = \
             mock.Mock(return_value=(0, "", ""))
         ssh_mock.run = \
             mock.Mock(return_value=(0, "", ""))
         ssh.from_node.return_value = ssh_mock
         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
         vpe_approx_vnf = VpeApproxVnf(vnfd)
         curr_path = os.path.dirname(os.path.abspath(__file__))
         vpe_vnf = os.path.join(curr_path, "vpe_config")
         queue_wrapper = \
             QueueFileWrapper(vpe_approx_vnf.q_in,
                              vpe_approx_vnf.q_out, "pipeline>")
         self.assertEqual(None,
                          vpe_approx_vnf._run_vpe(queue_wrapper, vpe_vnf))
예제 #4
0
    def instantiate(self, scenario_cfg, context_cfg):
        LOG.info("printing .........prox instantiate ")

        self.scenario_helper.scenario_cfg = scenario_cfg

        # this won't work we need 1GB hugepages at boot
        self.setup_helper.setup_vnf_environment()

        # self.connection.run("cat /proc/cpuinfo")

        prox_args, prox_path, remote_path = self.resource_helper.get_process_args(
        )

        self.q_in = multiprocessing.Queue()
        self.q_out = multiprocessing.Queue()
        self.queue_wrapper = QueueFileWrapper(self.q_in, self.q_out,
                                              "PROX started")
        self._vnf_process = multiprocessing.Process(target=self._run_prox,
                                                    args=(remote_path,
                                                          prox_path,
                                                          prox_args))
        self._vnf_process.start()
예제 #5
0
 def _start_vnf(self):
     self.queue_wrapper = QueueFileWrapper(self.q_in, self.q_out, self.VNF_PROMPT)
     name = "{}-{}-{}".format(self.name, self.APP_NAME, os.getpid())
     self._vnf_process = Process(name=name, target=self._run)
     self._vnf_process.start()
예제 #6
0
class SampleVNF(GenericVNF):
    """ Class providing file-like API for generic VNF implementation """

    VNF_PROMPT = "pipeline>"
    WAIT_TIME = 1
    WAIT_TIME_FOR_SCRIPT = 10
    APP_NAME = "SampleVNF"
    # we run the VNF interactively, so the ssh command will timeout after this long

    def __init__(self, name, vnfd, task_id, setup_env_helper_type=None,
                 resource_helper_type=None):
        super(SampleVNF, self).__init__(name, vnfd, task_id)
        self.bin_path = get_nsb_option('bin_path', '')

        self.scenario_helper = ScenarioHelper(self.name)
        self.ssh_helper = VnfSshHelper(self.vnfd_helper.mgmt_interface, self.bin_path)

        if setup_env_helper_type is None:
            setup_env_helper_type = SetupEnvHelper

        self.setup_helper = setup_env_helper_type(self.vnfd_helper,
                                                  self.ssh_helper,
                                                  self.scenario_helper)

        self.deploy_helper = SampleVNFDeployHelper(vnfd, self.ssh_helper)

        if resource_helper_type is None:
            resource_helper_type = ResourceHelper

        self.resource_helper = resource_helper_type(self.setup_helper)

        self.context_cfg = None
        self.pipeline_kwargs = {}
        self.uplink_ports = None
        self.downlink_ports = None
        # NOTE(esm): make QueueFileWrapper invert-able so that we
        #            never have to manage the queues
        self.q_in = Queue()
        self.q_out = Queue()
        self.queue_wrapper = None
        self.run_kwargs = {}
        self.used_drivers = {}
        self.vnf_port_pairs = None
        self._vnf_process = None

    def _start_vnf(self):
        self.queue_wrapper = QueueFileWrapper(self.q_in, self.q_out, self.VNF_PROMPT)
        name = "{}-{}-{}".format(self.name, self.APP_NAME, os.getpid())
        self._vnf_process = Process(name=name, target=self._run)
        self._vnf_process.start()

    def _vnf_up_post(self):
        pass

    def instantiate(self, scenario_cfg, context_cfg):
        self._update_collectd_options(scenario_cfg, context_cfg)
        self.scenario_helper.scenario_cfg = scenario_cfg
        self.context_cfg = context_cfg
        self.resource_helper.update_from_context(
            Context.get_context_from_server(self.scenario_helper.nodes[self.name]),
            self.scenario_helper.nodes[self.name]
        )

        # vnf deploy is unsupported, use ansible playbooks
        if self.scenario_helper.options.get("vnf_deploy", False):
            self.deploy_helper.deploy_vnfs(self.APP_NAME)
        self.resource_helper.setup()
        self._start_vnf()

    def _update_collectd_options(self, scenario_cfg, context_cfg):
        """Update collectd configuration options
        This function retrieves all collectd options contained in the test case

        definition builds a single dictionary combining them. The following fragment
        represents a test case with the collectd options and priorities (1 highest, 3 lowest):
        ---
        schema: yardstick:task:0.1
        scenarios:
        - type: NSPerf
          nodes:
            tg__0: trafficgen_1.yardstick
            vnf__0: vnf.yardstick
          options:
            collectd:
              <options>  # COLLECTD priority 3
            vnf__0:
              collectd:
                plugins:
                    load
                <options> # COLLECTD priority 2
        context:
          type: Node
          name: yardstick
          nfvi_type: baremetal
          file: /etc/yardstick/nodes/pod_ixia.yaml  # COLLECTD priority 1
        """
        scenario_options = scenario_cfg.get('options', {})
        generic_options = scenario_options.get('collectd', {})
        scenario_node_options = scenario_options.get(self.name, {})\
            .get('collectd', {})
        context_node_options = context_cfg.get('nodes', {})\
            .get(self.name, {}).get('collectd', {})

        options = generic_options
        self._update_options(options, scenario_node_options)
        self._update_options(options, context_node_options)

        self.setup_helper.collectd_options = options

    def _update_options(self, options, additional_options):
        """Update collectd options and plugins dictionary"""
        for k, v in additional_options.items():
            if isinstance(v, dict) and k in options:
                options[k].update(v)
            else:
                options[k] = v

    def wait_for_instantiate(self):
        buf = []
        time.sleep(self.WAIT_TIME)  # Give some time for config to load
        while True:
            if not self._vnf_process.is_alive():
                raise RuntimeError("%s VNF process died." % self.APP_NAME)

            # NOTE(esm): move to QueueFileWrapper
            while self.q_out.qsize() > 0:
                buf.append(self.q_out.get())
                message = ''.join(buf)
                if self.VNF_PROMPT in message:
                    LOG.info("%s VNF is up and running.", self.APP_NAME)
                    self._vnf_up_post()
                    self.queue_wrapper.clear()
                    return self._vnf_process.exitcode

                if "PANIC" in message:
                    raise RuntimeError("Error starting %s VNF." %
                                       self.APP_NAME)

            LOG.info("Waiting for %s VNF to start.. ", self.APP_NAME)
            time.sleep(self.WAIT_TIME_FOR_SCRIPT)
            # Send ENTER to display a new prompt in case the prompt text was corrupted
            # by other VNF output
            self.q_in.put('\r\n')

    def start_collect(self):
        self.resource_helper.start_collect()

    def stop_collect(self):
        self.resource_helper.stop_collect()

    def _build_run_kwargs(self):
        self.run_kwargs = {
            'stdin': self.queue_wrapper,
            'stdout': self.queue_wrapper,
            'keep_stdin_open': True,
            'pty': True,
            'timeout': self.scenario_helper.timeout,
        }

    def _build_config(self):
        return self.setup_helper.build_config()

    def _run(self):
        # we can't share ssh paramiko objects to force new connection
        self.ssh_helper.drop_connection()
        cmd = self._build_config()
        # kill before starting
        self.setup_helper.kill_vnf()

        LOG.debug(cmd)
        self._build_run_kwargs()
        self.ssh_helper.run(cmd, **self.run_kwargs)

    def vnf_execute(self, cmd, wait_time=2):
        """ send cmd to vnf process """

        LOG.info("%s command: %s", self.APP_NAME, cmd)
        self.q_in.put("{}\r\n".format(cmd))
        time.sleep(wait_time)
        output = []
        while self.q_out.qsize() > 0:
            output.append(self.q_out.get())
        return "".join(output)

    def _tear_down(self):
        pass

    def terminate(self):
        self.vnf_execute("quit")
        self.setup_helper.kill_vnf()
        self._tear_down()
        self.resource_helper.stop_collect()
        if self._vnf_process is not None:
            # be proper and join first before we kill
            LOG.debug("joining before terminate %s", self._vnf_process.name)
            self._vnf_process.join(constants.PROCESS_JOIN_TIMEOUT)
            self._vnf_process.terminate()
        # no terminate children here because we share processes with tg

    def get_stats(self, *args, **kwargs):  # pylint: disable=unused-argument
        """Method for checking the statistics

        This method could be overridden in children classes.

        :return: VNF statistics
        """
        cmd = 'p {0} stats'.format(self.APP_WORD)
        out = self.vnf_execute(cmd)
        return out

    def collect_kpi(self):
        # we can't get KPIs if the VNF is down
        check_if_process_failed(self._vnf_process, 0.01)
        stats = self.get_stats()
        m = re.search(self.COLLECT_KPI, stats, re.MULTILINE)
        physical_node = Context.get_physical_node_from_server(
            self.scenario_helper.nodes[self.name])

        result = {"physical_node": physical_node}
        if m:
            result.update({k: int(m.group(v)) for k, v in self.COLLECT_MAP.items()})
            result["collect_stats"] = self.resource_helper.collect_kpi()
        else:
            result.update({"packets_in": 0,
                           "packets_fwd": 0,
                           "packets_dropped": 0})

        LOG.debug("%s collect KPIs %s", self.APP_NAME, result)
        return result

    def scale(self, flavor=""):
        """The SampleVNF base class doesn't provide the 'scale' feature"""
        raise y_exceptions.FunctionNotImplemented(
            function_name='scale', class_name='SampleVNFTrafficGen')
예제 #7
0
class SampleVNF(GenericVNF):
    """ Class providing file-like API for generic VNF implementation """

    VNF_PROMPT = "pipeline>"
    WAIT_TIME = 1
    WAIT_TIME_FOR_SCRIPT = 10
    APP_NAME = "SampleVNF"
    # we run the VNF interactively, so the ssh command will timeout after this long

    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
        super(SampleVNF, self).__init__(name, vnfd)
        self.bin_path = get_nsb_option('bin_path', '')

        self.scenario_helper = ScenarioHelper(self.name)
        self.ssh_helper = VnfSshHelper(self.vnfd_helper.mgmt_interface, self.bin_path)

        if setup_env_helper_type is None:
            setup_env_helper_type = SetupEnvHelper

        self.setup_helper = setup_env_helper_type(self.vnfd_helper,
                                                  self.ssh_helper,
                                                  self.scenario_helper)

        self.deploy_helper = SampleVNFDeployHelper(vnfd, self.ssh_helper)

        if resource_helper_type is None:
            resource_helper_type = ResourceHelper

        self.resource_helper = resource_helper_type(self.setup_helper)

        self.context_cfg = None
        self.nfvi_context = None
        self.pipeline_kwargs = {}
        self.uplink_ports = None
        self.downlink_ports = None
        # NOTE(esm): make QueueFileWrapper invert-able so that we
        #            never have to manage the queues
        self.q_in = Queue()
        self.q_out = Queue()
        self.queue_wrapper = None
        self.run_kwargs = {}
        self.used_drivers = {}
        self.vnf_port_pairs = None
        self._vnf_process = None

    def _build_ports(self):
        self._port_pairs = PortPairs(self.vnfd_helper.interfaces)
        self.networks = self._port_pairs.networks
        self.uplink_ports = self.vnfd_helper.port_nums(self._port_pairs.uplink_ports)
        self.downlink_ports = self.vnfd_helper.port_nums(self._port_pairs.downlink_ports)
        self.my_ports = self.vnfd_helper.port_nums(self._port_pairs.all_ports)

    def _get_route_data(self, route_index, route_type):
        route_iter = iter(self.vnfd_helper.vdu0.get('nd_route_tbl', []))
        for _ in range(route_index):
            next(route_iter, '')
        return next(route_iter, {}).get(route_type, '')

    def _get_port0localip6(self):
        return_value = self._get_route_data(0, 'network')
        LOG.info("_get_port0localip6 : %s", return_value)
        return return_value

    def _get_port1localip6(self):
        return_value = self._get_route_data(1, 'network')
        LOG.info("_get_port1localip6 : %s", return_value)
        return return_value

    def _get_port0prefixlen6(self):
        return_value = self._get_route_data(0, 'netmask')
        LOG.info("_get_port0prefixlen6 : %s", return_value)
        return return_value

    def _get_port1prefixlen6(self):
        return_value = self._get_route_data(1, 'netmask')
        LOG.info("_get_port1prefixlen6 : %s", return_value)
        return return_value

    def _get_port0gateway6(self):
        return_value = self._get_route_data(0, 'network')
        LOG.info("_get_port0gateway6 : %s", return_value)
        return return_value

    def _get_port1gateway6(self):
        return_value = self._get_route_data(1, 'network')
        LOG.info("_get_port1gateway6 : %s", return_value)
        return return_value

    def _start_vnf(self):
        self.queue_wrapper = QueueFileWrapper(self.q_in, self.q_out, self.VNF_PROMPT)
        name = "{}-{}-{}".format(self.name, self.APP_NAME, os.getpid())
        self._vnf_process = Process(name=name, target=self._run)
        self._vnf_process.start()

    def _vnf_up_post(self):
        pass

    def instantiate(self, scenario_cfg, context_cfg):
        self.scenario_helper.scenario_cfg = scenario_cfg
        self.context_cfg = context_cfg
        self.nfvi_context = Context.get_context_from_server(self.scenario_helper.nodes[self.name])
        # self.nfvi_context = None

        # vnf deploy is unsupported, use ansible playbooks
        if self.scenario_helper.options.get("vnf_deploy", False):
            self.deploy_helper.deploy_vnfs(self.APP_NAME)
        self.resource_helper.setup()
        self._start_vnf()

    def wait_for_instantiate(self):
        buf = []
        time.sleep(self.WAIT_TIME)  # Give some time for config to load
        while True:
            if not self._vnf_process.is_alive():
                raise RuntimeError("%s VNF process died." % self.APP_NAME)

            # NOTE(esm): move to QueueFileWrapper
            while self.q_out.qsize() > 0:
                buf.append(self.q_out.get())
                message = ''.join(buf)
                if self.VNF_PROMPT in message:
                    LOG.info("%s VNF is up and running.", self.APP_NAME)
                    self._vnf_up_post()
                    self.queue_wrapper.clear()
                    self.resource_helper.start_collect()
                    return self._vnf_process.exitcode

                if "PANIC" in message:
                    raise RuntimeError("Error starting %s VNF." %
                                       self.APP_NAME)

            LOG.info("Waiting for %s VNF to start.. ", self.APP_NAME)
            time.sleep(self.WAIT_TIME_FOR_SCRIPT)
            # Send ENTER to display a new prompt in case the prompt text was corrupted
            # by other VNF output
            self.q_in.put('\r\n')

    def _build_run_kwargs(self):
        self.run_kwargs = {
            'stdin': self.queue_wrapper,
            'stdout': self.queue_wrapper,
            'keep_stdin_open': True,
            'pty': True,
            'timeout': self.scenario_helper.timeout,
        }

    def _build_config(self):
        return self.setup_helper.build_config()

    def _run(self):
        # we can't share ssh paramiko objects to force new connection
        self.ssh_helper.drop_connection()
        cmd = self._build_config()
        # kill before starting
        self.setup_helper.kill_vnf()

        LOG.debug(cmd)
        self._build_run_kwargs()
        self.ssh_helper.run(cmd, **self.run_kwargs)

    def vnf_execute(self, cmd, wait_time=2):
        """ send cmd to vnf process """

        LOG.info("%s command: %s", self.APP_NAME, cmd)
        self.q_in.put("{}\r\n".format(cmd))
        time.sleep(wait_time)
        output = []
        while self.q_out.qsize() > 0:
            output.append(self.q_out.get())
        return "".join(output)

    def _tear_down(self):
        pass

    def terminate(self):
        self.vnf_execute("quit")
        self.setup_helper.kill_vnf()
        self._tear_down()
        self.resource_helper.stop_collect()
        if self._vnf_process is not None:
            # be proper and join first before we kill
            LOG.debug("joining before terminate %s", self._vnf_process.name)
            self._vnf_process.join(constants.PROCESS_JOIN_TIMEOUT)
            self._vnf_process.terminate()
        # no terminate children here because we share processes with tg

    def get_stats(self, *args, **kwargs):  # pylint: disable=unused-argument
        """Method for checking the statistics

        This method could be overridden in children classes.

        :return: VNF statistics
        """
        cmd = 'p {0} stats'.format(self.APP_WORD)
        out = self.vnf_execute(cmd)
        return out

    def collect_kpi(self):
        # we can't get KPIs if the VNF is down
        check_if_process_failed(self._vnf_process)
        stats = self.get_stats()
        m = re.search(self.COLLECT_KPI, stats, re.MULTILINE)
        if m:
            result = {k: int(m.group(v)) for k, v in self.COLLECT_MAP.items()}
            result["collect_stats"] = self.resource_helper.collect_kpi()
        else:
            result = {
                "packets_in": 0,
                "packets_fwd": 0,
                "packets_dropped": 0,
            }
        LOG.debug("%s collect KPIs %s", self.APP_NAME, result)
        return result

    def scale(self, flavor=""):
        """The SampleVNF base class doesn't provide the 'scale' feature"""
        raise y_exceptions.FunctionNotImplemented(
            function_name='scale', class_name='SampleVNFTrafficGen')
예제 #8
0
 def test_read(self):
     queue_file_wrapper = \
         QueueFileWrapper(self.q_in, self.q_out, self.prompt)
     queue_file_wrapper.q_in.put("pipeline>")
     self.assertEqual("pipeline>", queue_file_wrapper.read(20))
예제 #9
0
 def test_close(self):
     queue_file_wrapper = \
         QueueFileWrapper(self.q_in, self.q_out, self.prompt)
     self.assertEqual(None, queue_file_wrapper.close())
예제 #10
0
 def test___init__(self):
     queue_file_wrapper = \
         QueueFileWrapper(self.q_in, self.q_out, self.prompt)
     self.assertEqual(queue_file_wrapper.prompt, self.prompt)
예제 #11
0
 def test_write(self):
     queue_file_wrapper = \
         QueueFileWrapper(self.q_in, self.q_out, self.prompt)
     queue_file_wrapper.write("pipeline>")
     self.assertIsNotNone(queue_file_wrapper.q_out.empty())
예제 #12
0
 def _start_vnf(self):
     self.queue_wrapper = QueueFileWrapper(self.q_in, self.q_out, self.VNF_PROMPT)
     self._vnf_process = Process(target=self._run)
     self._vnf_process.start()
예제 #13
0
class SampleVNF(GenericVNF):
    """ Class providing file-like API for generic VNF implementation """

    VNF_PROMPT = "pipeline>"
    WAIT_TIME = 1

    def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
        super(SampleVNF, self).__init__(name, vnfd)
        self.bin_path = get_nsb_option('bin_path', '')

        self.scenario_helper = ScenarioHelper(self.name)
        self.ssh_helper = VnfSshHelper(self.vnfd_helper.mgmt_interface, self.bin_path)

        if setup_env_helper_type is None:
            setup_env_helper_type = SetupEnvHelper

        self.setup_helper = setup_env_helper_type(self.vnfd_helper,
                                                  self.ssh_helper,
                                                  self.scenario_helper)

        self.deploy_helper = SampleVNFDeployHelper(vnfd, self.ssh_helper)

        if resource_helper_type is None:
            resource_helper_type = ResourceHelper

        self.resource_helper = resource_helper_type(self.setup_helper)

        self.context_cfg = None
        self.nfvi_context = None
        self.pipeline_kwargs = {}
        self.uplink_ports = None
        self.downlink_ports = None
        # TODO(esm): make QueueFileWrapper invert-able so that we
        #            never have to manage the queues
        self.q_in = Queue()
        self.q_out = Queue()
        self.queue_wrapper = None
        self.run_kwargs = {}
        self.used_drivers = {}
        self.vnf_port_pairs = None
        self._vnf_process = None

    def _build_ports(self):
        self._port_pairs = PortPairs(self.vnfd_helper.interfaces)
        self.networks = self._port_pairs.networks
        self.uplink_ports = self.vnfd_helper.port_nums(self._port_pairs.uplink_ports)
        self.downlink_ports = self.vnfd_helper.port_nums(self._port_pairs.downlink_ports)
        self.my_ports = self.vnfd_helper.port_nums(self._port_pairs.all_ports)

    def _get_route_data(self, route_index, route_type):
        route_iter = iter(self.vnfd_helper.vdu0.get('nd_route_tbl', []))
        for _ in range(route_index):
            next(route_iter, '')
        return next(route_iter, {}).get(route_type, '')

    def _get_port0localip6(self):
        return_value = self._get_route_data(0, 'network')
        LOG.info("_get_port0localip6 : %s", return_value)
        return return_value

    def _get_port1localip6(self):
        return_value = self._get_route_data(1, 'network')
        LOG.info("_get_port1localip6 : %s", return_value)
        return return_value

    def _get_port0prefixlen6(self):
        return_value = self._get_route_data(0, 'netmask')
        LOG.info("_get_port0prefixlen6 : %s", return_value)
        return return_value

    def _get_port1prefixlen6(self):
        return_value = self._get_route_data(1, 'netmask')
        LOG.info("_get_port1prefixlen6 : %s", return_value)
        return return_value

    def _get_port0gateway6(self):
        return_value = self._get_route_data(0, 'network')
        LOG.info("_get_port0gateway6 : %s", return_value)
        return return_value

    def _get_port1gateway6(self):
        return_value = self._get_route_data(1, 'network')
        LOG.info("_get_port1gateway6 : %s", return_value)
        return return_value

    def _start_vnf(self):
        self.queue_wrapper = QueueFileWrapper(self.q_in, self.q_out, self.VNF_PROMPT)
        self._vnf_process = Process(target=self._run)
        self._vnf_process.start()

    def _vnf_up_post(self):
        pass

    def instantiate(self, scenario_cfg, context_cfg):
        self.scenario_helper.scenario_cfg = scenario_cfg
        self.context_cfg = context_cfg
        self.nfvi_context = Context.get_context_from_server(self.scenario_helper.nodes[self.name])
        # self.nfvi_context = None

        self.deploy_helper.deploy_vnfs(self.APP_NAME)
        self.resource_helper.setup()
        self._start_vnf()

    def wait_for_instantiate(self):
        buf = []
        time.sleep(self.WAIT_TIME)  # Give some time for config to load
        while True:
            if not self._vnf_process.is_alive():
                raise RuntimeError("%s VNF process died." % self.APP_NAME)

            # TODO(esm): move to QueueFileWrapper
            while self.q_out.qsize() > 0:
                buf.append(self.q_out.get())
                message = ''.join(buf)
                if self.VNF_PROMPT in message:
                    LOG.info("%s VNF is up and running.", self.APP_NAME)
                    self._vnf_up_post()
                    self.queue_wrapper.clear()
                    self.resource_helper.start_collect()
                    return self._vnf_process.exitcode

                if "PANIC" in message:
                    raise RuntimeError("Error starting %s VNF." %
                                       self.APP_NAME)

            LOG.info("Waiting for %s VNF to start.. ", self.APP_NAME)
            time.sleep(1)
            # Send ENTER to display a new prompt in case the prompt text was corrupted
            # by other VNF output
            self.q_in.put('\r\n')

    def _build_run_kwargs(self):
        self.run_kwargs = {
            'stdin': self.queue_wrapper,
            'stdout': self.queue_wrapper,
            'keep_stdin_open': True,
            'pty': True,
        }

    def _build_config(self):
        return self.setup_helper.build_config()

    def _run(self):
        # we can't share ssh paramiko objects to force new connection
        self.ssh_helper.drop_connection()
        cmd = self._build_config()
        # kill before starting
        self.setup_helper.kill_vnf()

        LOG.debug(cmd)
        self._build_run_kwargs()
        self.ssh_helper.run(cmd, **self.run_kwargs)

    def vnf_execute(self, cmd, wait_time=2):
        """ send cmd to vnf process """

        LOG.info("%s command: %s", self.APP_NAME, cmd)
        self.q_in.put("{}\r\n".format(cmd))
        time.sleep(wait_time)
        output = []
        while self.q_out.qsize() > 0:
            output.append(self.q_out.get())
        return "".join(output)

    def _tear_down(self):
        pass

    def terminate(self):
        self.vnf_execute("quit")
        if self._vnf_process:
            self._vnf_process.terminate()
        self.setup_helper.kill_vnf()
        self._tear_down()
        self.resource_helper.stop_collect()

    def get_stats(self, *args, **kwargs):
        """
        Method for checking the statistics

        :return:
           VNF statistics
        """
        cmd = 'p {0} stats'.format(self.APP_WORD)
        out = self.vnf_execute(cmd)
        return out

    def collect_kpi(self):
        stats = self.get_stats()
        m = re.search(self.COLLECT_KPI, stats, re.MULTILINE)
        if m:
            result = {k: int(m.group(v)) for k, v in self.COLLECT_MAP.items()}
            result["collect_stats"] = self.resource_helper.collect_kpi()
        else:
            result = {
                "packets_in": 0,
                "packets_fwd": 0,
                "packets_dropped": 0,
            }
        LOG.debug("%s collect KPIs %s", self.APP_NAME, result)
        return result