Merge "Refactor: add _get_timestamps()"
[yardstick.git] / yardstick / network_services / utils.py
index d52e27c..9c64fec 100644 (file)
 from __future__ import absolute_import
 import logging
 import os
+import re
 
 from oslo_config import cfg
 from oslo_config.cfg import NoSuchOptError
 from oslo_utils import encodeutils
 
+
 NSB_ROOT = "/opt/nsb_bin"
 
 CONF = cfg.CONF
@@ -34,10 +36,73 @@ OPTS = [
     cfg.StrOpt('trex_client_lib',
                default=os.path.join(NSB_ROOT, 'trex_client/stl'),
                help='trex python library path.'),
+    cfg.StrOpt('jre_path_i386',
+               default='',
+               help='path to installation of 32-bit Java 1.7+.'),
 ]
 CONF.register_opts(OPTS, group="nsb")
 
 
+HEXADECIMAL = "[0-9a-zA-Z]"
+
+
+class PciAddress(object):
+    """Class to handle PCI addresses.
+
+    A PCI address could be written in two ways:
+    - Simple BDF notation:
+        00:00.0 # bus:device.function
+    - With domain extension.
+        0000:00:00.0 # domain:bus:device.function
+
+    Note: in Libvirt, 'device' is called 'slot'.
+
+    Reference: https://wiki.xenproject.org/wiki/
+               Bus:Device.Function_(BDF)_Notation
+    """
+    PCI_PATTERN_STR = (
+        r"((?P<domain>[0-9a-zA-Z]{4}):)?(?P<bus>[0-9a-zA-Z]{2}):"
+        r"(?P<slot>[0-9a-zA-Z]{2})\.(?P<function>[0-9a-zA-Z]{1})")
+
+    def __init__(self, address):
+        pci_pattern = re.compile(self.PCI_PATTERN_STR)
+        match = pci_pattern.search(address)
+        if not match:
+            raise ValueError('Invalid PCI address: {}'.format(address))
+
+        self._domain = (match.group('domain') or '0000').lower()
+        self._bus = match.group('bus').lower()
+        self._slot = match.group('slot').lower()
+        self._function = match.group('function').lower()
+        self.address = '{:0>4}:{:0>2}:{:0>2}.{:1}'.format(self.domain,
+                                                          self.bus,
+                                                          self.slot,
+                                                          self.function)
+        self.match = match
+
+    def __repr__(self):
+        return self.address
+
+    @property
+    def domain(self):
+        return self._domain
+
+    @property
+    def bus(self):
+        return self._bus
+
+    @property
+    def slot(self):
+        return self._slot
+
+    @property
+    def function(self):
+        return self._function
+
+    def values(self):
+        return [self._domain, self._bus, self._slot, self._function]
+
+
 def get_nsb_option(option, default=None):
     """return requested option for yardstick.conf"""
 
@@ -55,15 +120,17 @@ def provision_tool(connection, tool_path, tool_file=None):
 
     :return - Tool path
     """
+    if not tool_path:
+        tool_path = get_nsb_option('tool_path')
     if tool_file:
         tool_path = os.path.join(tool_path, tool_file)
-    bin_path = get_nsb_option("bin_path")
     exit_status = connection.execute("which %s > /dev/null 2>&1" % tool_path)[0]
     if exit_status == 0:
         return encodeutils.safe_decode(tool_path, incoming='utf-8').rstrip()
 
     logging.warning("%s not found on %s, will try to copy from localhost",
                     tool_path, connection.host)
+    bin_path = get_nsb_option("bin_path")
     connection.execute('mkdir -p "%s"' % bin_path)
     connection.put(tool_path, tool_path)
     return tool_path