diff options
-rw-r--r-- | dashboard/opnfv_yardstick_tc056.json | 301 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/standalone/model.py | 52 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/standalone/ovs_dpdk.py | 206 | ||||
-rw-r--r-- | yardstick/benchmark/contexts/standalone/sriov.py | 56 | ||||
-rw-r--r-- | yardstick/common/exceptions.py | 30 | ||||
-rw-r--r-- | yardstick/tests/unit/benchmark/contexts/standalone/test_model.py | 337 | ||||
-rw-r--r-- | yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py | 238 | ||||
-rw-r--r-- | yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py | 80 |
8 files changed, 912 insertions, 388 deletions
diff --git a/dashboard/opnfv_yardstick_tc056.json b/dashboard/opnfv_yardstick_tc056.json new file mode 100644 index 000000000..5d7f2b013 --- /dev/null +++ b/dashboard/opnfv_yardstick_tc056.json @@ -0,0 +1,301 @@ +{ + "__inputs": [ + { + "name": "DS_YARDSTICK", + "label": "yardstick", + "description": "", + "type": "datasource", + "pluginId": "influxdb", + "pluginName": "InfluxDB" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "4.4.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "influxdb", + "name": "InfluxDB", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "" + } + ], + "annotations": { + "list": [] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [], + "refresh": "1m", + "rows": [ + { + "collapse": false, + "height": 340, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "yardstick", + "description": "", + "fill": 1, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "span": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "", + "dsType": "influxdb", + "groupBy": [], + "measurement": "opnfv_yardstick_tc056", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"openstack-user-list_outage_time\" FROM \"opnfv_yardstick_tc056\" WHERE $timeFilter", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "openstack-volume-list_outage_time" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 5 + }, + { + "colorMode": "ok", + "fill": true, + "line": true, + "op": "lt", + "value": 5 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "command monitor (outage time)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": true, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "yardstick", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "alias": "", + "dsType": "influxdb", + "groupBy": [], + "measurement": "opnfv_yardstick_tc056", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"sla_pass\" FROM \"opnfv_yardstick_tc056\" WHERE $timeFilter", + "rawQuery": false, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "sla_pass" + ], + "type": "field" + } + ] + ], + "tags": [] + } + ], + "thresholds": "0.5,1", + "title": "SLA PASS/FAIL", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "HA" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now/d", + "to": "now/d" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "opnfv_yardstick_tc056", + "version": 2 +} diff --git a/yardstick/benchmark/contexts/standalone/model.py b/yardstick/benchmark/contexts/standalone/model.py index 14738da8a..f18d090d8 100644 --- a/yardstick/benchmark/contexts/standalone/model.py +++ b/yardstick/benchmark/contexts/standalone/model.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import import os import re import time @@ -25,11 +24,12 @@ from netaddr import IPNetwork import xml.etree.ElementTree as ET from yardstick import ssh -from yardstick.common.constants import YARDSTICK_ROOT_PATH +from yardstick.common import constants +from yardstick.common import exceptions from yardstick.common.yaml_loader import yaml_load from yardstick.network_services.utils import PciAddress from yardstick.network_services.helpers.cpu import CpuSysCores -from yardstick.common.utils import write_file + LOG = logging.getLogger(__name__) @@ -106,12 +106,17 @@ class Libvirt(object): @staticmethod def virsh_create_vm(connection, cfg): - err = connection.execute("virsh create %s" % cfg)[0] - LOG.info("VM create status: %s", err) + LOG.info('VM create, XML config: %s', cfg) + status, _, error = connection.execute('virsh create %s' % cfg) + if status: + raise exceptions.LibvirtCreateError(error=error) @staticmethod def virsh_destroy_vm(vm_name, connection): - connection.execute("virsh destroy %s" % vm_name) + LOG.info('VM destroy, VM name: %s', vm_name) + status, _, error = connection.execute('virsh destroy %s' % vm_name) + if status: + LOG.warning('Error destroying VM %s. Error: %s', vm_name, error) @staticmethod def _add_interface_address(interface, pci_address): @@ -132,7 +137,7 @@ class Libvirt(object): return vm_pci @classmethod - def add_ovs_interface(cls, vpath, port_num, vpci, vports_mac, xml): + def add_ovs_interface(cls, vpath, port_num, vpci, vports_mac, xml_str): """Add a DPDK OVS 'interface' XML node in 'devices' node <devices> @@ -156,7 +161,7 @@ class Libvirt(object): vhost_path = ('{0}/var/run/openvswitch/dpdkvhostuser{1}'. format(vpath, port_num)) - root = ET.parse(xml) + root = ET.fromstring(xml_str) pci_address = PciAddress(vpci.strip()) device = root.find('devices') @@ -181,10 +186,10 @@ class Libvirt(object): cls._add_interface_address(interface, pci_address) - root.write(xml) + return ET.tostring(root) @classmethod - def add_sriov_interfaces(cls, vm_pci, vf_pci, vf_mac, xml): + def add_sriov_interfaces(cls, vm_pci, vf_pci, vf_mac, xml_str): """Add a SR-IOV 'interface' XML node in 'devices' node <devices> @@ -207,7 +212,7 @@ class Libvirt(object): -sr_iov-how_sr_iov_libvirt_works """ - root = ET.parse(xml) + root = ET.fromstring(xml_str) device = root.find('devices') interface = ET.SubElement(device, 'interface') @@ -224,7 +229,7 @@ class Libvirt(object): pci_vm_address = PciAddress(vm_pci.strip()) cls._add_interface_address(interface, pci_vm_address) - root.write(xml) + return ET.tostring(root) @staticmethod def create_snapshot_qemu(connection, index, vm_image): @@ -237,7 +242,8 @@ class Libvirt(object): return image @classmethod - def build_vm_xml(cls, connection, flavor, cfg, vm_name, index): + def build_vm_xml(cls, connection, flavor, vm_name, index): + """Build the XML from the configuration parameters""" memory = flavor.get('ram', '4096') extra_spec = flavor.get('extra_specs', {}) cpu = extra_spec.get('hw:cpu_cores', '2') @@ -261,9 +267,7 @@ class Libvirt(object): socket=socket, threads=threads, vm_image=image, cpuset=cpuset, cputune=cputune) - write_file(cfg, vm_xml) - - return [vcpu, mac] + return vm_xml, mac @staticmethod def update_interrupts_hugepages_perf(connection): @@ -283,6 +287,13 @@ class Libvirt(object): cpuset = "%s,%s" % (cores, threads) return cpuset + @classmethod + def write_file(cls, file_name, xml_str): + """Dump a XML string to a file""" + root = ET.fromstring(xml_str) + et = ET.ElementTree(element=root) + et.write(file_name, encoding='utf-8', method='xml') + class StandaloneContextHelper(object): """ This class handles all the common code for standalone @@ -374,7 +385,8 @@ class StandaloneContextHelper(object): except IOError as io_error: if io_error.errno != errno.ENOENT: raise - self.file_path = os.path.join(YARDSTICK_ROOT_PATH, file_path) + self.file_path = os.path.join(constants.YARDSTICK_ROOT_PATH, + file_path) cfg = self.read_config_file() nodes.extend([node for node in cfg["nodes"] if str(node["role"]) != nfvi_role]) @@ -506,7 +518,7 @@ class OvsDeploy(object): StandaloneContextHelper.install_req_libs(self.connection, pkgs) def ovs_deploy(self): - ovs_deploy = os.path.join(YARDSTICK_ROOT_PATH, + ovs_deploy = os.path.join(constants.YARDSTICK_ROOT_PATH, "yardstick/resources/scripts/install/", self.OVS_DEPLOY_SCRIPT) if os.path.isfile(ovs_deploy): @@ -522,4 +534,6 @@ class OvsDeploy(object): cmd = "sudo -E %s --ovs='%s' --dpdk='%s' -p='%s'" % (remote_ovs_deploy, ovs, dpdk, http_proxy) - self.connection.execute(cmd) + exit_status, _, stderr = self.connection.execute(cmd) + if exit_status: + raise exceptions.OVSDeployError(stderr=stderr) diff --git a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py index a18b42ea5..30b685eec 100644 --- a/yardstick/benchmark/contexts/standalone/ovs_dpdk.py +++ b/yardstick/benchmark/contexts/standalone/ovs_dpdk.py @@ -12,26 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import -import os -import logging +import io import collections +import logging +import os +import re import time -from collections import OrderedDict - from yardstick import ssh -from yardstick.network_services.utils import get_nsb_option -from yardstick.network_services.utils import provision_tool from yardstick.benchmark.contexts.base import Context -from yardstick.benchmark.contexts.standalone.model import Libvirt -from yardstick.benchmark.contexts.standalone.model import StandaloneContextHelper -from yardstick.benchmark.contexts.standalone.model import Server -from yardstick.benchmark.contexts.standalone.model import OvsDeploy -from yardstick.network_services.utils import PciAddress +from yardstick.benchmark.contexts.standalone import model +from yardstick.common import exceptions +from yardstick.network_services import utils + LOG = logging.getLogger(__name__) +MAIN_BRIDGE = 'br0' + class OvsDpdkContext(Context): """ This class handles OVS standalone nodes - VM running on Non-Managed NFVi @@ -50,8 +48,8 @@ class OvsDpdkContext(Context): } DEFAULT_OVS = '2.6.0' - - PKILL_TEMPLATE = "pkill %s %s" + CMD_TIMEOUT = 30 + DEFAULT_USER_PATH = '/usr/local' def __init__(self): self.file_path = None @@ -65,8 +63,8 @@ class OvsDpdkContext(Context): self.attrs = {} self.vm_flavor = None self.servers = None - self.helper = StandaloneContextHelper() - self.vnf_node = Server() + self.helper = model.StandaloneContextHelper() + self.vnf_node = model.Server() self.ovs_properties = {} self.wait_for_vswitchd = 10 super(OvsDpdkContext, self).__init__() @@ -93,34 +91,32 @@ class OvsDpdkContext(Context): LOG.debug("Networks: %r", self.networks) def setup_ovs(self): - vpath = self.ovs_properties.get("vpath", "/usr/local") - xargs_kill_cmd = self.PKILL_TEMPLATE % ('-9', 'ovs') - + """Initialize OVS-DPDK""" + vpath = self.ovs_properties.get('vpath', self.DEFAULT_USER_PATH) create_from = os.path.join(vpath, 'etc/openvswitch/conf.db') create_to = os.path.join(vpath, 'share/openvswitch/vswitch.ovsschema') cmd_list = [ - "chmod 0666 /dev/vfio/*", - "chmod a+x /dev/vfio", - "pkill -9 ovs", - xargs_kill_cmd, - "killall -r 'ovs*'", - "mkdir -p {0}/etc/openvswitch".format(vpath), - "mkdir -p {0}/var/run/openvswitch".format(vpath), - "rm {0}/etc/openvswitch/conf.db".format(vpath), - "ovsdb-tool create {0} {1}".format(create_from, create_to), - "modprobe vfio-pci", - "chmod a+x /dev/vfio", - "chmod 0666 /dev/vfio/*", + 'killall -r "ovs.*" -q | true', + 'mkdir -p {0}/etc/openvswitch'.format(vpath), + 'mkdir -p {0}/var/run/openvswitch'.format(vpath), + 'rm {0}/etc/openvswitch/conf.db | true'.format(vpath), + 'ovsdb-tool create {0} {1}'.format(create_from, create_to), + 'modprobe vfio-pci', + 'chmod a+x /dev/vfio', + 'chmod 0666 /dev/vfio/*', ] - for cmd in cmd_list: - self.connection.execute(cmd) - bind_cmd = "{dpdk_devbind} --force -b {driver} {port}" - phy_driver = "vfio-pci" + + bind_cmd = '%s --force -b vfio-pci {port}' % self.dpdk_devbind for port in self.networks.values(): - vpci = port.get("phy_port") - self.connection.execute(bind_cmd.format( - dpdk_devbind=self.dpdk_devbind, driver=phy_driver, port=vpci)) + cmd_list.append(bind_cmd.format(port=port.get('phy_port'))) + + for cmd in cmd_list: + LOG.info(cmd) + exit_status, _, stderr = self.connection.execute( + cmd, timeout=self.CMD_TIMEOUT) + if exit_status: + raise exceptions.OVSSetupError(command=cmd, error=stderr) def start_ovs_serverswitch(self): vpath = self.ovs_properties.get("vpath") @@ -166,56 +162,78 @@ class OvsDpdkContext(Context): vpath = self.ovs_properties.get("vpath", "/usr/local") version = self.ovs_properties.get('version', {}) ovs_ver = [int(x) for x in version.get('ovs', self.DEFAULT_OVS).split('.')] - ovs_add_port = \ - "ovs-vsctl add-port {br} {port} -- set Interface {port} type={type_}{dpdk_args}" - ovs_add_queue = "ovs-vsctl set Interface {port} options:n_rxq={queue}" - chmod_vpath = "chmod 0777 {0}/var/run/openvswitch/dpdkvhostuser*" - - cmd_dpdk_list = [ - "ovs-vsctl del-br br0", - "rm -rf {0}/var/run/openvswitch/dpdkvhostuser*".format(vpath), - "ovs-vsctl add-br br0 -- set bridge br0 datapath_type=netdev", + ovs_add_port = ('ovs-vsctl add-port {br} {port} -- ' + 'set Interface {port} type={type_}{dpdk_args}') + ovs_add_queue = 'ovs-vsctl set Interface {port} options:n_rxq={queue}' + chmod_vpath = 'chmod 0777 {0}/var/run/openvswitch/dpdkvhostuser*' + + cmd_list = [ + 'ovs-vsctl --if-exists del-br {0}'.format(MAIN_BRIDGE), + 'rm -rf {0}/var/run/openvswitch/dpdkvhostuser*'.format(vpath), + 'ovs-vsctl add-br {0} -- set bridge {0} datapath_type=netdev'. + format(MAIN_BRIDGE) ] - ordered_network = OrderedDict(self.networks) + ordered_network = collections.OrderedDict(self.networks) for index, vnf in enumerate(ordered_network.values()): if ovs_ver >= [2, 7, 0]: dpdk_args = " options:dpdk-devargs=%s" % vnf.get("phy_port") - dpdk_list.append(ovs_add_port.format(br='br0', port='dpdk%s' % vnf.get("port_num", 0), - type_='dpdk', dpdk_args=dpdk_args)) - dpdk_list.append(ovs_add_queue.format(port='dpdk%s' % vnf.get("port_num", 0), - queue=self.ovs_properties.get("queues", 1))) + dpdk_list.append(ovs_add_port.format( + br=MAIN_BRIDGE, port='dpdk%s' % vnf.get("port_num", 0), + type_='dpdk', dpdk_args=dpdk_args)) + dpdk_list.append(ovs_add_queue.format( + port='dpdk%s' % vnf.get("port_num", 0), + queue=self.ovs_properties.get("queues", 1))) # Sorting the array to make sure we execute dpdk0... in the order list.sort(dpdk_list) - cmd_dpdk_list.extend(dpdk_list) + cmd_list.extend(dpdk_list) # Need to do two for loop to maintain the dpdk/vhost ports. for index, _ in enumerate(ordered_network): - cmd_dpdk_list.append(ovs_add_port.format(br='br0', port='dpdkvhostuser%s' % index, - type_='dpdkvhostuser', dpdk_args="")) - - for cmd in cmd_dpdk_list: - LOG.info(cmd) - self.connection.execute(cmd) - - # Fixme: add flows code - ovs_flow = "ovs-ofctl add-flow br0 in_port=%s,action=output:%s" + cmd_list.append(ovs_add_port.format( + br=MAIN_BRIDGE, port='dpdkvhostuser%s' % index, + type_='dpdkvhostuser', dpdk_args="")) + ovs_flow = ("ovs-ofctl add-flow {0} in_port=%s,action=output:%s". + format(MAIN_BRIDGE)) network_count = len(ordered_network) + 1 for in_port, out_port in zip(range(1, network_count), range(network_count, network_count * 2)): - self.connection.execute(ovs_flow % (in_port, out_port)) - self.connection.execute(ovs_flow % (out_port, in_port)) + cmd_list.append(ovs_flow % (in_port, out_port)) + cmd_list.append(ovs_flow % (out_port, in_port)) - self.connection.execute(chmod_vpath.format(vpath)) + cmd_list.append(chmod_vpath.format(vpath)) + + for cmd in cmd_list: + LOG.info(cmd) + exit_status, _, stderr = self.connection.execute( + cmd, timeout=self.CMD_TIMEOUT) + if exit_status: + raise exceptions.OVSSetupError(command=cmd, error=stderr) + + def _check_hugepages(self): + meminfo = io.BytesIO() + self.connection.get_file_obj('/proc/meminfo', meminfo) + regex = re.compile(r"HugePages_Total:\s+(?P<hp_total>\d+)[\n\r]" + r"HugePages_Free:\s+(?P<hp_free>\d+)") + match = regex.search(meminfo.getvalue().decode('utf-8')) + if not match: + raise exceptions.OVSHugepagesInfoError() + if int(match.group('hp_total')) == 0: + raise exceptions.OVSHugepagesNotConfigured() + if int(match.group('hp_free')) == 0: + raise exceptions.OVSHugepagesZeroFree( + total_hugepages=int(match.group('hp_total'))) def cleanup_ovs_dpdk_env(self): - self.connection.execute("ovs-vsctl del-br br0") + self.connection.execute( + 'ovs-vsctl --if-exists del-br {0}'.format(MAIN_BRIDGE)) self.connection.execute("pkill -9 ovs") def check_ovs_dpdk_env(self): self.cleanup_ovs_dpdk_env() + self._check_hugepages() version = self.ovs_properties.get("version", {}) ovs_ver = version.get("ovs", self.DEFAULT_OVS) @@ -223,13 +241,15 @@ class OvsDpdkContext(Context): supported_version = self.SUPPORTED_OVS_TO_DPDK_MAP.get(ovs_ver, None) if supported_version is None or supported_version.split('.')[:2] != dpdk_ver[:2]: - raise Exception("Unsupported ovs '{}'. Please check the config...".format(ovs_ver)) + raise exceptions.OVSUnsupportedVersion( + ovs_version=ovs_ver, + ovs_to_dpdk_map=self.SUPPORTED_OVS_TO_DPDK_MAP) status = self.connection.execute("ovs-vsctl -V | grep -i '%s'" % ovs_ver)[0] if status: - deploy = OvsDeploy(self.connection, - get_nsb_option("bin_path"), - self.ovs_properties) + deploy = model.OvsDeploy(self.connection, + utils.get_nsb_option("bin_path"), + self.ovs_properties) deploy.ovs_deploy() def deploy(self): @@ -240,15 +260,15 @@ class OvsDpdkContext(Context): return self.connection = ssh.SSH.from_node(self.host_mgmt) - self.dpdk_devbind = provision_tool( + self.dpdk_devbind = utils.provision_tool( self.connection, - os.path.join(get_nsb_option("bin_path"), "dpdk-devbind.py")) + os.path.join(utils.get_nsb_option('bin_path'), 'dpdk-devbind.py')) # Check dpdk/ovs version, if not present install self.check_ovs_dpdk_env() # Todo: NFVi deploy (sriov, vswitch, ovs etc) based on the config. - StandaloneContextHelper.install_req_libs(self.connection) - self.networks = StandaloneContextHelper.get_nic_details( + model.StandaloneContextHelper.install_req_libs(self.connection) + self.networks = model.StandaloneContextHelper.get_nic_details( self.connection, self.networks, self.dpdk_devbind) self.setup_ovs() @@ -256,9 +276,8 @@ class OvsDpdkContext(Context): self.setup_ovs_bridge_add_flows() self.nodes = self.setup_ovs_dpdk_context() LOG.debug("Waiting for VM to come up...") - self.nodes = StandaloneContextHelper.wait_for_vnfs_to_start(self.connection, - self.servers, - self.nodes) + self.nodes = model.StandaloneContextHelper.wait_for_vnfs_to_start( + self.connection, self.servers, self.nodes) def undeploy(self): @@ -278,7 +297,7 @@ class OvsDpdkContext(Context): # Todo: NFVi undeploy (sriov, vswitch, ovs etc) based on the config. for vm in self.vm_names: - Libvirt.check_if_vm_exists_and_delete(vm, self.connection) + model.Libvirt.check_if_vm_exists_and_delete(vm, self.connection) def _get_server(self, attr_name): """lookup server info by name from context @@ -333,50 +352,53 @@ class OvsDpdkContext(Context): return result def configure_nics_for_ovs_dpdk(self): - portlist = OrderedDict(self.networks) + portlist = collections.OrderedDict(self.networks) for key in portlist: - mac = StandaloneContextHelper.get_mac_address() + mac = model.StandaloneContextHelper.get_mac_address() portlist[key].update({'mac': mac}) self.networks = portlist LOG.info("Ports %s", self.networks) - def _enable_interfaces(self, index, vfs, cfg): + def _enable_interfaces(self, index, vfs, xml_str): vpath = self.ovs_properties.get("vpath", "/usr/local") vf = self.networks[vfs[0]] port_num = vf.get('port_num', 0) - vpci = PciAddress(vf['vpci'].strip()) + vpci = utils.PciAddress(vf['vpci'].strip()) # Generate the vpci for the interfaces slot = index + port_num + 10 vf['vpci'] = \ "{}:{}:{:02x}.{}".format(vpci.domain, vpci.bus, slot, vpci.function) - Libvirt.add_ovs_interface(vpath, port_num, vf['vpci'], vf['mac'], str(cfg)) + return model.Libvirt.add_ovs_interface( + vpath, port_num, vf['vpci'], vf['mac'], xml_str) def setup_ovs_dpdk_context(self): nodes = [] self.configure_nics_for_ovs_dpdk() - for index, (key, vnf) in enumerate(OrderedDict(self.servers).items()): + for index, (key, vnf) in enumerate(collections.OrderedDict( + self.servers).items()): cfg = '/tmp/vm_ovs_%d.xml' % index vm_name = "vm_%d" % index # 1. Check and delete VM if already exists - Libvirt.check_if_vm_exists_and_delete(vm_name, self.connection) + model.Libvirt.check_if_vm_exists_and_delete(vm_name, + self.connection) + xml_str, mac = model.Libvirt.build_vm_xml( + self.connection, self.vm_flavor, vm_name, index) - _, mac = Libvirt.build_vm_xml(self.connection, self.vm_flavor, - cfg, vm_name, index) # 2: Cleanup already available VMs - for vkey, vfs in OrderedDict(vnf["network_ports"]).items(): - if vkey == "mgmt": - continue - self._enable_interfaces(index, vfs, cfg) + for vfs in [vfs for vfs_name, vfs in vnf["network_ports"].items() + if vfs_name != 'mgmt']: + xml_str = self._enable_interfaces(index, vfs, xml_str) # copy xml to target... + model.Libvirt.write_file(cfg, xml_str) self.connection.put(cfg, cfg) # NOTE: launch through libvirt LOG.info("virsh create ...") - Libvirt.virsh_create_vm(self.connection, cfg) + model.Libvirt.virsh_create_vm(self.connection, cfg) self.vm_names.append(vm_name) diff --git a/yardstick/benchmark/contexts/standalone/sriov.py b/yardstick/benchmark/contexts/standalone/sriov.py index d7620552b..5db419e6a 100644 --- a/yardstick/benchmark/contexts/standalone/sriov.py +++ b/yardstick/benchmark/contexts/standalone/sriov.py @@ -16,15 +16,12 @@ from __future__ import absolute_import import os import logging import collections -from collections import OrderedDict from yardstick import ssh from yardstick.network_services.utils import get_nsb_option from yardstick.network_services.utils import provision_tool from yardstick.benchmark.contexts.base import Context -from yardstick.benchmark.contexts.standalone.model import Libvirt -from yardstick.benchmark.contexts.standalone.model import StandaloneContextHelper -from yardstick.benchmark.contexts.standalone.model import Server +from yardstick.benchmark.contexts.standalone import model from yardstick.network_services.utils import PciAddress LOG = logging.getLogger(__name__) @@ -49,8 +46,8 @@ class SriovContext(Context): self.attrs = {} self.vm_flavor = None self.servers = None - self.helper = StandaloneContextHelper() - self.vnf_node = Server() + self.helper = model.StandaloneContextHelper() + self.vnf_node = model.Server() self.drivers = [] super(SriovContext, self).__init__() @@ -87,15 +84,14 @@ class SriovContext(Context): os.path.join(get_nsb_option("bin_path"), "dpdk-devbind.py")) # Todo: NFVi deploy (sriov, vswitch, ovs etc) based on the config. - StandaloneContextHelper.install_req_libs(self.connection) - self.networks = StandaloneContextHelper.get_nic_details( + model.StandaloneContextHelper.install_req_libs(self.connection) + self.networks = model.StandaloneContextHelper.get_nic_details( self.connection, self.networks, self.dpdk_devbind) self.nodes = self.setup_sriov_context() LOG.debug("Waiting for VM to come up...") - self.nodes = StandaloneContextHelper.wait_for_vnfs_to_start(self.connection, - self.servers, - self.nodes) + self.nodes = model.StandaloneContextHelper.wait_for_vnfs_to_start( + self.connection, self.servers, self.nodes) def undeploy(self): """don't need to undeploy""" @@ -105,7 +101,7 @@ class SriovContext(Context): # Todo: NFVi undeploy (sriov, vswitch, ovs etc) based on the config. for vm in self.vm_names: - Libvirt.check_if_vm_exists_and_delete(vm, self.connection) + model.Libvirt.check_if_vm_exists_and_delete(vm, self.connection) # Bind nics back to kernel for ports in self.networks.values(): @@ -136,8 +132,8 @@ class SriovContext(Context): except StopIteration: pass else: - raise ValueError("Duplicate nodes!!! Nodes: %s %s" % - (node, duplicate)) + raise ValueError("Duplicate nodes!!! Nodes: %s %s" + % (node, duplicate)) node["name"] = attr_name return node @@ -179,7 +175,7 @@ class SriovContext(Context): self.connection.execute(build_vfs.format(ports.get('phy_port'))) # configure VFs... - mac = StandaloneContextHelper.get_mac_address() + mac = model.StandaloneContextHelper.get_mac_address() interface = ports.get('interface') if interface is not None: self.connection.execute(vf_cmd.format(interface, mac)) @@ -201,7 +197,7 @@ class SriovContext(Context): slot = index + idx + 10 vf['vpci'] = \ "{}:{}:{:02x}.{}".format(vpci.domain, vpci.bus, slot, vpci.function) - Libvirt.add_sriov_interfaces( + model.Libvirt.add_sriov_interfaces( vf['vpci'], vf['vf_pci']['vf_pci'], vf['mac'], str(cfg)) self.connection.execute("ifconfig %s up" % vf['interface']) self.connection.execute(vf_spoofchk.format(vf['interface'])) @@ -212,34 +208,37 @@ class SriovContext(Context): # 1 : modprobe host_driver with num_vfs self.configure_nics_for_sriov() - for index, (key, vnf) in enumerate(OrderedDict(self.servers).items()): + for index, (key, vnf) in enumerate(collections.OrderedDict( + self.servers).items()): cfg = '/tmp/vm_sriov_%s.xml' % str(index) vm_name = "vm_%s" % str(index) # 1. Check and delete VM if already exists - Libvirt.check_if_vm_exists_and_delete(vm_name, self.connection) + model.Libvirt.check_if_vm_exists_and_delete(vm_name, + self.connection) + xml_str, mac = model.Libvirt.build_vm_xml( + self.connection, self.vm_flavor, vm_name, index) - _, mac = Libvirt.build_vm_xml(self.connection, self.vm_flavor, cfg, vm_name, index) # 2: Cleanup already available VMs - for idx, (vkey, vfs) in enumerate(OrderedDict(vnf["network_ports"]).items()): - if vkey == "mgmt": - continue + network_ports = collections.OrderedDict( + {k: v for k, v in vnf["network_ports"].items() if k != 'mgmt'}) + for idx, vfs in enumerate(network_ports.values()): self._enable_interfaces(index, idx, vfs, cfg) # copy xml to target... + model.Libvirt.write_file(cfg, xml_str) self.connection.put(cfg, cfg) # NOTE: launch through libvirt LOG.info("virsh create ...") - Libvirt.virsh_create_vm(self.connection, cfg) + model.Libvirt.virsh_create_vm(self.connection, cfg) self.vm_names.append(vm_name) # build vnf node details - nodes.append(self.vnf_node.generate_vnf_instance(self.vm_flavor, - self.networks, - self.host_mgmt.get('ip'), - key, vnf, mac)) + nodes.append(self.vnf_node.generate_vnf_instance( + self.vm_flavor, self.networks, self.host_mgmt.get('ip'), + key, vnf, mac)) return nodes @@ -248,7 +247,8 @@ class SriovContext(Context): "mac": vfmac, "pf_if": pfif } - vfs = StandaloneContextHelper.get_virtual_devices(self.connection, value) + vfs = model.StandaloneContextHelper.get_virtual_devices( + self.connection, value) for k, v in vfs.items(): m = PciAddress(k.strip()) m1 = PciAddress(value.strip()) diff --git a/yardstick/common/exceptions.py b/yardstick/common/exceptions.py index 43d1eb598..439b9cb1b 100644 --- a/yardstick/common/exceptions.py +++ b/yardstick/common/exceptions.py @@ -82,6 +82,36 @@ class DPDKSetupDriverError(YardstickException): message = '"igb_uio" driver is not loaded' +class OVSUnsupportedVersion(YardstickException): + message = ('Unsupported OVS version "%(ovs_version)s". Please check the ' + 'config. OVS to DPDK version map: %(ovs_to_dpdk_map)s.') + + +class OVSHugepagesInfoError(YardstickException): + message = 'MemInfo cannnot be retrieved.' + + +class OVSHugepagesNotConfigured(YardstickException): + message = 'HugePages are not configured in this system.' + + +class OVSHugepagesZeroFree(YardstickException): + message = ('There are no HugePages free in this system. Total HugePages ' + 'configured: %(total_hugepages)s') + + +class OVSDeployError(YardstickException): + message = 'OVS deploy tool failed with error: %(stderr)s.' + + +class OVSSetupError(YardstickException): + message = 'OVS setup error. Command: %(command)s. Error: %(error)s.' + + +class LibvirtCreateError(YardstickException): + message = 'Error creating the virtual machine. Error: %(error)s.' + + class ScenarioConfigContextNameNotFound(YardstickException): message = 'Context name "%(context_name)s" not found' diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py index 18ea3c4e6..b1dcee209 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_model.py @@ -13,12 +13,17 @@ # limitations under the License. import copy +import mock import os import unittest -import mock +import uuid from xml.etree import ElementTree + +from yardstick import ssh from yardstick.benchmark.contexts.standalone import model +from yardstick.common import exceptions +from yardstick import constants from yardstick.network_services import utils @@ -38,22 +43,19 @@ XML_SAMPLE_INTERFACE = """<?xml version="1.0"?> </domain> """ + class ModelLibvirtTestCase(unittest.TestCase): def setUp(self): - self.xml = ElementTree.ElementTree( - element=ElementTree.fromstring(XML_SAMPLE)) self.pci_address_str = '0001:04:03.2' self.pci_address = utils.PciAddress(self.pci_address_str) self.mac = '00:00:00:00:00:01' - self._mock_write_xml = mock.patch.object(ElementTree.ElementTree, - 'write') - self.mock_write_xml = self._mock_write_xml.start() - + self._mock_ssh = mock.Mock() + self.mock_ssh = self._mock_ssh.start() self.addCleanup(self._cleanup) def _cleanup(self): - self._mock_write_xml.stop() + self._mock_ssh.stop() # TODO: Remove mocking of yardstick.ssh.SSH (here and elsewhere) # In this case, we are mocking a param to be passed into other methods @@ -67,20 +69,31 @@ class ModelLibvirtTestCase(unittest.TestCase): model.Libvirt.check_if_vm_exists_and_delete("vm_0", ssh_mock) def test_virsh_create_vm(self): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = mock.Mock(return_value=(0, "a", "")) - ssh.return_value = ssh_mock - # NOTE(ralonsoh): this test doesn't cover function execution. - model.Libvirt.virsh_create_vm(ssh_mock, "vm_0") + self.mock_ssh.execute = mock.Mock(return_value=(0, 0, 0)) + model.Libvirt.virsh_create_vm(self.mock_ssh, 'vm_0') + self.mock_ssh.execute.assert_called_once_with('virsh create vm_0') + + def test_virsh_create_vm_error(self): + self.mock_ssh.execute = mock.Mock(return_value=(1, 0, 'error_create')) + with self.assertRaises(exceptions.LibvirtCreateError) as exc: + model.Libvirt.virsh_create_vm(self.mock_ssh, 'vm_0') + self.assertEqual('Error creating the virtual machine. Error: ' + 'error_create.', str(exc.exception)) + self.mock_ssh.execute.assert_called_once_with('virsh create vm_0') def test_virsh_destroy_vm(self): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = mock.Mock(return_value=(0, "a", "")) - ssh.return_value = ssh_mock - # NOTE(ralonsoh): this test doesn't cover function execution. - model.Libvirt.virsh_destroy_vm("vm_0", ssh_mock) + self.mock_ssh.execute = mock.Mock(return_value=(0, 0, 0)) + model.Libvirt.virsh_destroy_vm('vm_0', self.mock_ssh) + self.mock_ssh.execute.assert_called_once_with('virsh destroy vm_0') + + @mock.patch.object(model, 'LOG') + def test_virsh_destroy_vm_error(self, mock_logger): + self.mock_ssh.execute = mock.Mock(return_value=(1, 0, 'error_destroy')) + mock_logger.warning = mock.Mock() + model.Libvirt.virsh_destroy_vm('vm_0', self.mock_ssh) + mock_logger.warning.assert_called_once_with( + 'Error destroying VM %s. Error: %s', 'vm_0', 'error_destroy') + self.mock_ssh.execute.assert_called_once_with('virsh destroy vm_0') def test_add_interface_address(self): xml = ElementTree.ElementTree( @@ -98,72 +111,65 @@ class ModelLibvirtTestCase(unittest.TestCase): result.get('function')) def test_add_ovs_interfaces(self): - xml_input = mock.Mock() - with mock.patch.object(ElementTree, 'parse', return_value=self.xml) \ - as mock_parse: - xml = copy.deepcopy(self.xml) - mock_parse.return_value = xml - model.Libvirt.add_ovs_interface( - '/usr/local', 0, self.pci_address_str, self.mac, xml_input) - mock_parse.assert_called_once_with(xml_input) - self.mock_write_xml.assert_called_once_with(xml_input) - interface = xml.find('devices').find('interface') - self.assertEqual('vhostuser', interface.get('type')) - mac = interface.find('mac') - self.assertEqual(self.mac, mac.get('address')) - source = interface.find('source') - self.assertEqual('unix', source.get('type')) - self.assertEqual('/usr/local/var/run/openvswitch/dpdkvhostuser0', - source.get('path')) - self.assertEqual('client', source.get('mode')) - _model = interface.find('model') - self.assertEqual('virtio', _model.get('type')) - driver = interface.find('driver') - self.assertEqual('4', driver.get('queues')) - host = driver.find('host') - self.assertEqual('off', host.get('mrg_rxbuf')) - self.assertIsNotNone(interface.find('address')) + xml_input = copy.deepcopy(XML_SAMPLE) + xml_output = model.Libvirt.add_ovs_interface( + '/usr/local', 0, self.pci_address_str, self.mac, xml_input) + + root = ElementTree.fromstring(xml_output) + et_out = ElementTree.ElementTree(element=root) + interface = et_out.find('devices').find('interface') + self.assertEqual('vhostuser', interface.get('type')) + mac = interface.find('mac') + self.assertEqual(self.mac, mac.get('address')) + source = interface.find('source') + self.assertEqual('unix', source.get('type')) + self.assertEqual('/usr/local/var/run/openvswitch/dpdkvhostuser0', + source.get('path')) + self.assertEqual('client', source.get('mode')) + _model = interface.find('model') + self.assertEqual('virtio', _model.get('type')) + driver = interface.find('driver') + self.assertEqual('4', driver.get('queues')) + host = driver.find('host') + self.assertEqual('off', host.get('mrg_rxbuf')) + self.assertIsNotNone(interface.find('address')) def test_add_sriov_interfaces(self): - xml_input = mock.Mock() - with mock.patch.object(ElementTree, 'parse', return_value=self.xml) \ - as mock_parse: - xml = copy.deepcopy(self.xml) - mock_parse.return_value = xml - vm_pci = '0001:05:04.2' - model.Libvirt.add_sriov_interfaces( - vm_pci, self.pci_address_str, self.mac, xml_input) - mock_parse.assert_called_once_with(xml_input) - self.mock_write_xml.assert_called_once_with(xml_input) - interface = xml.find('devices').find('interface') - self.assertEqual('yes', interface.get('managed')) - self.assertEqual('hostdev', interface.get('type')) - mac = interface.find('mac') - self.assertEqual(self.mac, mac.get('address')) - source = interface.find('source') - source_address = source.find('address') - self.assertIsNotNone(source.find('address')) - - self.assertEqual('pci', source_address.get('type')) - self.assertEqual('0x' + self.pci_address_str.split(':')[0], - source_address.get('domain')) - self.assertEqual('0x' + self.pci_address_str.split(':')[1], - source_address.get('bus')) - self.assertEqual('0x' + self.pci_address_str.split(':')[2].split('.')[0], - source_address.get('slot')) - self.assertEqual('0x' + self.pci_address_str.split(':')[2].split('.')[1], - source_address.get('function')) - - interface_address = interface.find('address') - self.assertEqual('pci', interface_address.get('type')) - self.assertEqual('0x' + vm_pci.split(':')[0], - interface_address.get('domain')) - self.assertEqual('0x' + vm_pci.split(':')[1], - interface_address.get('bus')) - self.assertEqual('0x' + vm_pci.split(':')[2].split('.')[0], - interface_address.get('slot')) - self.assertEqual('0x' + vm_pci.split(':')[2].split('.')[1], - interface_address.get('function')) + xml_input = copy.deepcopy(XML_SAMPLE) + vm_pci = '0001:05:04.2' + xml_output = model.Libvirt.add_sriov_interfaces( + vm_pci, self.pci_address_str, self.mac, xml_input) + root = ElementTree.fromstring(xml_output) + et_out = ElementTree.ElementTree(element=root) + interface = et_out.find('devices').find('interface') + self.assertEqual('yes', interface.get('managed')) + self.assertEqual('hostdev', interface.get('type')) + mac = interface.find('mac') + self.assertEqual(self.mac, mac.get('address')) + source = interface.find('source') + source_address = source.find('address') + self.assertIsNotNone(source.find('address')) + + self.assertEqual('pci', source_address.get('type')) + self.assertEqual('0x' + self.pci_address_str.split(':')[0], + source_address.get('domain')) + self.assertEqual('0x' + self.pci_address_str.split(':')[1], + source_address.get('bus')) + self.assertEqual('0x' + self.pci_address_str.split(':')[2].split('.')[0], + source_address.get('slot')) + self.assertEqual('0x' + self.pci_address_str.split(':')[2].split('.')[1], + source_address.get('function')) + + interface_address = interface.find('address') + self.assertEqual('pci', interface_address.get('type')) + self.assertEqual('0x' + vm_pci.split(':')[0], + interface_address.get('domain')) + self.assertEqual('0x' + vm_pci.split(':')[1], + interface_address.get('bus')) + self.assertEqual('0x' + vm_pci.split(':')[2].split('.')[0], + interface_address.get('slot')) + self.assertEqual('0x' + vm_pci.split(':')[2].split('.')[1], + interface_address.get('function')) def test_create_snapshot_qemu(self): result = "/var/lib/libvirt/images/0.qcow2" @@ -175,24 +181,38 @@ class ModelLibvirtTestCase(unittest.TestCase): image = model.Libvirt.create_snapshot_qemu(ssh_mock, "0", "ubuntu.img") self.assertEqual(image, result) - @mock.patch.object(model.Libvirt, 'pin_vcpu_for_perf') - @mock.patch.object(model.Libvirt, 'create_snapshot_qemu') + @mock.patch.object(model.Libvirt, 'pin_vcpu_for_perf', return_value='4,5') + @mock.patch.object(model.Libvirt, 'create_snapshot_qemu', + return_value='qemu_image') def test_build_vm_xml(self, mock_create_snapshot_qemu, - *args): - # NOTE(ralonsoh): this test doesn't cover function execution. This test - # should also check mocked function calls. - cfg_file = 'test_config_file.cfg' - self.addCleanup(os.remove, cfg_file) - result = [4] - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "a", "")) - ssh.return_value = ssh_mock - mock_create_snapshot_qemu.return_value = "0.img" - - status = model.Libvirt.build_vm_xml(ssh_mock, {}, cfg_file, 'vm_0', 0) - self.assertEqual(status[0], result[0]) + mock_pin_vcpu_for_perf): + extra_specs = {'hw:cpu_cores': '4', + 'hw:cpu_sockets': '3', + 'hw:cpu_threads': '2', + 'cputune': 'cool'} + flavor = {'ram': '1024', + 'extra_specs': extra_specs, + 'hw_socket': '1', + 'images': 'images'} + mac = model.StandaloneContextHelper.get_mac_address(0x00) + _uuid = uuid.uuid4() + connection = mock.Mock() + with mock.patch.object(model.StandaloneContextHelper, + 'get_mac_address', return_value=mac) as \ + mock_get_mac_address, \ + mock.patch.object(uuid, 'uuid4', return_value=_uuid): + xml_out, mac = model.Libvirt.build_vm_xml( + connection, flavor, 'vm_name', 100) + + xml_ref = model.VM_TEMPLATE.format(vm_name='vm_name', + random_uuid=_uuid, mac_addr=mac, memory='1024', vcpu='8', cpu='4', + numa_cpus='0-7', socket='3', threads='2', + vm_image='qemu_image', cpuset='4,5', cputune='cool') + self.assertEqual(xml_ref, xml_out) + mock_get_mac_address.assert_called_once_with(0x00) + mock_create_snapshot_qemu.assert_called_once_with( + connection, 100, 'images') + mock_pin_vcpu_for_perf.assert_called_once_with(connection, '1') # TODO: Edit this test to test state instead of output # update_interrupts_hugepages_perf does not return anything @@ -398,43 +418,80 @@ class ServerTestCase(unittest.TestCase): class OvsDeployTestCase(unittest.TestCase): - NETWORKS = { - 'mgmt': {'cidr': '152.16.100.10/24'}, - 'private_0': { - 'phy_port': "0000:05:00.0", - 'vpci': "0000:00:07.0", - 'driver': 'i40e', - 'mac': '', - 'cidr': '152.16.100.10/24', - 'gateway_ip': '152.16.100.20'}, - 'public_0': { - 'phy_port': "0000:05:00.1", - 'vpci': "0000:00:08.0", - 'driver': 'i40e', - 'mac': '', - 'cidr': '152.16.40.10/24', - 'gateway_ip': '152.16.100.20'} - } - - @mock.patch('yardstick.ssh.SSH') - def setUp(self, mock_ssh): - self.ovs_deploy = model.OvsDeploy(mock_ssh, '/tmp/dpdk-devbind.py', {}) + OVS_DETAILS = {'version': {'ovs': 'ovs_version', 'dpdk': 'dpdk_version'}} - def test___init__(self): - self.assertIsNotNone(self.ovs_deploy.connection) - - @mock.patch('yardstick.benchmark.contexts.standalone.model.os') - def test_prerequisite(self, *args): - # NOTE(ralonsoh): this test should check mocked function calls. - self.ovs_deploy.helper = mock.Mock() - self.assertIsNone(self.ovs_deploy.prerequisite()) - - @mock.patch('yardstick.benchmark.contexts.standalone.model.os') - def test_prerequisite_2(self, *args): - # NOTE(ralonsoh): this test should check mocked function calls. Rename - # this test properly. - self.ovs_deploy.helper = mock.Mock() - self.ovs_deploy.connection.execute = mock.Mock( - return_value=(1, '1.2.3.4 00:00:00:00:00:01', '')) - self.ovs_deploy.prerequisite = mock.Mock() - self.assertIsNone(self.ovs_deploy.ovs_deploy()) + def setUp(self): + self._mock_ssh = mock.patch.object(ssh, 'SSH') + self.mock_ssh = self._mock_ssh .start() + self.ovs_deploy = model.OvsDeploy(self.mock_ssh, + '/tmp/dpdk-devbind.py', + self.OVS_DETAILS) + self._mock_path_isfile = mock.patch.object(os.path, 'isfile') + self._mock_path_join = mock.patch.object(os.path, 'join') + self.mock_path_isfile = self._mock_path_isfile.start() + self.mock_path_join = self._mock_path_join.start() + + self.addCleanup(self._stop_mock) + + def _stop_mock(self): + self._mock_ssh.stop() + self._mock_path_isfile.stop() + self._mock_path_join.stop() + + @mock.patch.object(model.StandaloneContextHelper, 'install_req_libs') + def test_prerequisite(self, mock_install_req_libs): + pkgs = ["git", "build-essential", "pkg-config", "automake", + "autotools-dev", "libltdl-dev", "cmake", "libnuma-dev", + "libpcap-dev"] + self.ovs_deploy.prerequisite() + mock_install_req_libs.assert_called_once_with( + self.ovs_deploy.connection, pkgs) + + def test_ovs_deploy_no_file(self): + self.mock_path_isfile.return_value = False + mock_file = mock.Mock() + self.mock_path_join.return_value = mock_file + + self.ovs_deploy.ovs_deploy() + self.mock_path_isfile.assert_called_once_with(mock_file) + self.mock_path_join.assert_called_once_with( + constants.YARDSTICK_ROOT_PATH, + 'yardstick/resources/scripts/install/', + self.ovs_deploy.OVS_DEPLOY_SCRIPT) + + @mock.patch.object(os.environ, 'get', return_value='test_proxy') + def test_ovs_deploy(self, mock_env_get): + self.mock_path_isfile.return_value = True + mock_deploy_file = mock.Mock() + mock_remove_ovs_deploy = mock.Mock() + self.mock_path_join.side_effect = [mock_deploy_file, + mock_remove_ovs_deploy] + dpdk_version = self.OVS_DETAILS['version']['dpdk'] + ovs_version = self.OVS_DETAILS['version']['ovs'] + + with mock.patch.object(self.ovs_deploy.connection, 'put') as \ + mock_put, \ + mock.patch.object(self.ovs_deploy.connection, 'execute') as \ + mock_execute, \ + mock.patch.object(self.ovs_deploy, 'prerequisite'): + mock_execute.return_value = (0, 0, 0) + self.ovs_deploy.ovs_deploy() + + self.mock_path_isfile.assert_called_once_with(mock_deploy_file) + self.mock_path_join.assert_has_calls([ + mock.call(constants.YARDSTICK_ROOT_PATH, + 'yardstick/resources/scripts/install/', + self.ovs_deploy.OVS_DEPLOY_SCRIPT), + mock.call(self.ovs_deploy.bin_path, + self.ovs_deploy.OVS_DEPLOY_SCRIPT) + ]) + mock_put.assert_called_once_with(mock_deploy_file, + mock_remove_ovs_deploy) + cmd = ("sudo -E %(remote_ovs_deploy)s --ovs='%(ovs_version)s' " + "--dpdk='%(dpdk_version)s' -p='%(proxy)s'" % + {'remote_ovs_deploy': mock_remove_ovs_deploy, + 'ovs_version': ovs_version, + 'dpdk_version': dpdk_version, + 'proxy': 'test_proxy'}) + mock_execute.assert_called_once_with(cmd) + mock_env_get.assert_called_once_with('http_proxy', '') diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py index 0223fd3ff..bc3bb73cd 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_ovs_dpdk.py @@ -12,12 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +import io import os import mock +import six import unittest +from yardstick.benchmark.contexts.standalone import model from yardstick.benchmark.contexts.standalone import ovs_dpdk +from yardstick.common import exceptions +from yardstick.network_services import utils class OvsDpdkContextTestCase(unittest.TestCase): @@ -27,7 +32,6 @@ class OvsDpdkContextTestCase(unittest.TestCase): NODES_DUPLICATE_SAMPLE = "nodes_duplicate_sample.yaml" NETWORKS = { - 'mgmt': {'cidr': '152.16.100.10/24'}, 'private_0': { 'phy_port': "0000:05:00.0", 'vpci': "0000:00:07.0", @@ -82,15 +86,43 @@ class OvsDpdkContextTestCase(unittest.TestCase): self.assertIsNone(self.ovs_dpdk.init(ATTRS)) def test_setup_ovs(self): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "a", "")) - ssh.return_value = ssh_mock - self.ovs_dpdk.connection = ssh_mock - self.ovs_dpdk.networks = self.NETWORKS - self.ovs_dpdk.ovs_properties = {} - self.assertIsNone(self.ovs_dpdk.setup_ovs()) + fake_path = '/fake_path' + fake_dpdk_nic_bind = 'dpdk_tool.py' + self.ovs_dpdk.ovs_properties = {'vpath': fake_path} + self.ovs_dpdk.dpdk_devbind = fake_dpdk_nic_bind + self.ovs_dpdk.networks = self.NETWORKS + self.ovs_dpdk.connection = mock.Mock() + self.ovs_dpdk.connection.execute = mock.Mock(return_value=(0, 0, 0)) + create_from = fake_path + '/etc/openvswitch/conf.db' + create_to = fake_path + '/share/openvswitch/vswitch.ovsschema' + cmd_list = [ + 'killall -r "ovs.*" -q | true', + 'mkdir -p {0}/etc/openvswitch'.format(fake_path), + 'mkdir -p {0}/var/run/openvswitch'.format(fake_path), + 'rm {0}/etc/openvswitch/conf.db | true'.format(fake_path), + 'ovsdb-tool create {0} {1}'.format(create_from, create_to), + 'modprobe vfio-pci', + 'chmod a+x /dev/vfio', + 'chmod 0666 /dev/vfio/*', + '{0} --force -b vfio-pci {1}'.format(fake_dpdk_nic_bind, + self.ovs_dpdk.networks['private_0']['phy_port']), + '{0} --force -b vfio-pci {1}'.format(fake_dpdk_nic_bind, + self.ovs_dpdk.networks['public_0']['phy_port']) + ] + calls = [mock.call(cmd, timeout=self.ovs_dpdk.CMD_TIMEOUT) + for cmd in cmd_list] + + self.ovs_dpdk.setup_ovs() + self.ovs_dpdk.connection.execute.assert_has_calls(calls, + any_order=True) + + def test_setup_ovs_exception(self): + self.ovs_dpdk.networks = self.NETWORKS + self.ovs_dpdk.connection = mock.Mock() + self.ovs_dpdk.connection.execute = mock.Mock(return_value=(1, 0, 0)) + + with self.assertRaises(exceptions.OVSSetupError): + self.ovs_dpdk.setup_ovs() def test_start_ovs_serverswitch(self): with mock.patch("yardstick.ssh.SSH") as ssh: @@ -129,34 +161,45 @@ class OvsDpdkContextTestCase(unittest.TestCase): self.ovs_dpdk.wait_for_vswitchd = 0 self.assertIsNone(self.ovs_dpdk.cleanup_ovs_dpdk_env()) - @mock.patch('yardstick.benchmark.contexts.standalone.model.OvsDeploy') - def test_check_ovs_dpdk_env(self, mock_ovs): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(1, "a", "")) - ssh.return_value = ssh_mock - self.ovs_dpdk.connection = ssh_mock - self.ovs_dpdk.networks = self.NETWORKS - self.ovs_dpdk.ovs_properties = { - 'version': {'ovs': '2.7.0', 'dpdk': '16.11.1'} - } - self.ovs_dpdk.wait_for_vswitchd = 0 - self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock() - self.assertIsNone(self.ovs_dpdk.check_ovs_dpdk_env()) - self.ovs_dpdk.ovs_properties = { - 'version': {'ovs': '2.0.0'} - } - self.ovs_dpdk.wait_for_vswitchd = 0 - self.cleanup_ovs_dpdk_env = mock.Mock() - mock_ovs.deploy = mock.Mock() - # NOTE(elfoley): Check for a specific Exception - self.assertRaises(Exception, self.ovs_dpdk.check_ovs_dpdk_env) + @mock.patch.object(ovs_dpdk.OvsDpdkContext, '_check_hugepages') + @mock.patch.object(utils, 'get_nsb_option') + @mock.patch.object(model.OvsDeploy, 'ovs_deploy') + def test_check_ovs_dpdk_env(self, mock_ovs_deploy, mock_get_nsb_option, + mock_check_hugepages): + self.ovs_dpdk.connection = mock.Mock() + self.ovs_dpdk.connection.execute = mock.Mock( + return_value=(1, 0, 0)) + self.ovs_dpdk.networks = self.NETWORKS + self.ovs_dpdk.ovs_properties = { + 'version': {'ovs': '2.7.0', 'dpdk': '16.11.1'} + } + self.ovs_dpdk.wait_for_vswitchd = 0 + self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock() + mock_get_nsb_option.return_value = 'fake_path' + + self.ovs_dpdk.check_ovs_dpdk_env() + mock_ovs_deploy.assert_called_once() + mock_check_hugepages.assert_called_once() + mock_get_nsb_option.assert_called_once_with('bin_path') + + @mock.patch.object(ovs_dpdk.OvsDpdkContext, '_check_hugepages') + def test_check_ovs_dpdk_env_wrong_version(self, mock_check_hugepages): + self.ovs_dpdk.connection = mock.Mock() + self.ovs_dpdk.connection.execute = mock.Mock( + return_value=(1, 0, 0)) + self.ovs_dpdk.networks = self.NETWORKS + self.ovs_dpdk.ovs_properties = { + 'version': {'ovs': '0.0.1', 'dpdk': '9.8.7'} + } + self.ovs_dpdk.wait_for_vswitchd = 0 + self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock() - @mock.patch('yardstick.ssh.SSH') - def test_deploy(self, mock_ssh): - mock_ssh.execute.return_value = 0, "a", "" + with self.assertRaises(exceptions.OVSUnsupportedVersion): + self.ovs_dpdk.check_ovs_dpdk_env() + mock_check_hugepages.assert_called_once() + @mock.patch('yardstick.ssh.SSH') + def test_deploy(self, *args): self.ovs_dpdk.vm_deploy = False self.assertIsNone(self.ovs_dpdk.deploy()) @@ -174,21 +217,19 @@ class OvsDpdkContextTestCase(unittest.TestCase): # output. self.assertIsNone(self.ovs_dpdk.deploy()) - @mock.patch('yardstick.benchmark.contexts.standalone.model.Libvirt') - @mock.patch('yardstick.ssh.SSH') - def test_undeploy(self, mock_ssh, *args): - mock_ssh.execute.return_value = 0, "a", "" - - self.ovs_dpdk.vm_deploy = False - self.assertIsNone(self.ovs_dpdk.undeploy()) - + @mock.patch.object(model.Libvirt, 'check_if_vm_exists_and_delete') + def test_undeploy(self, mock_libvirt): self.ovs_dpdk.vm_deploy = True - self.ovs_dpdk.connection = mock_ssh + self.ovs_dpdk.connection = mock.Mock() self.ovs_dpdk.vm_names = ['vm_0', 'vm_1'] self.ovs_dpdk.drivers = ['vm_0', 'vm_1'] self.ovs_dpdk.cleanup_ovs_dpdk_env = mock.Mock() self.ovs_dpdk.networks = self.NETWORKS - self.assertIsNone(self.ovs_dpdk.undeploy()) + self.ovs_dpdk.undeploy() + mock_libvirt.assert_has_calls([ + mock.call(self.ovs_dpdk.vm_names[0], self.ovs_dpdk.connection), + mock.call(self.ovs_dpdk.vm_names[1], self.ovs_dpdk.connection) + ]) def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) @@ -310,34 +351,28 @@ class OvsDpdkContextTestCase(unittest.TestCase): self.ovs_dpdk.get_vf_datas = mock.Mock(return_value="") self.assertIsNone(self.ovs_dpdk.configure_nics_for_ovs_dpdk()) - @mock.patch('yardstick.benchmark.contexts.standalone.ovs_dpdk.Libvirt') - def test__enable_interfaces(self, *args): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "a", "")) - ssh.return_value = ssh_mock + @mock.patch.object(model.Libvirt, 'add_ovs_interface') + def test__enable_interfaces(self, mock_add_ovs_interface): self.ovs_dpdk.vm_deploy = True - self.ovs_dpdk.connection = ssh_mock + self.ovs_dpdk.connection = mock.Mock() self.ovs_dpdk.vm_names = ['vm_0', 'vm_1'] self.ovs_dpdk.drivers = [] self.ovs_dpdk.networks = self.NETWORKS + self.ovs_dpdk.ovs_properties = {'vpath': 'fake_path'} self.ovs_dpdk.get_vf_datas = mock.Mock(return_value="") - self.assertIsNone(self.ovs_dpdk._enable_interfaces( - 0, ["private_0"], 'test')) - - @mock.patch('yardstick.benchmark.contexts.standalone.model.Server') - @mock.patch('yardstick.benchmark.contexts.standalone.ovs_dpdk.Libvirt') - def test_setup_ovs_dpdk_context(self, mock_libvirt, *args): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "a", "")) - ssh_mock.put = \ - mock.Mock(return_value=(0, "a", "")) - ssh.return_value = ssh_mock + self.ovs_dpdk._enable_interfaces(0, ["private_0"], 'test') + mock_add_ovs_interface.assert_called_once_with( + 'fake_path', 0, self.NETWORKS['private_0']['vpci'], + self.NETWORKS['private_0']['mac'], 'test') + + @mock.patch.object(model.Libvirt, 'write_file') + @mock.patch.object(model.Libvirt, 'build_vm_xml') + @mock.patch.object(model.Libvirt, 'check_if_vm_exists_and_delete') + @mock.patch.object(model.Libvirt, 'virsh_create_vm') + def test_setup_ovs_dpdk_context(self, mock_create_vm, mock_check_if_exists, + mock_build_xml, mock_write_file): self.ovs_dpdk.vm_deploy = True - self.ovs_dpdk.connection = ssh_mock + self.ovs_dpdk.connection = mock.Mock() self.ovs_dpdk.vm_names = ['vm_0', 'vm_1'] self.ovs_dpdk.drivers = [] self.ovs_dpdk.servers = { @@ -353,11 +388,64 @@ class OvsDpdkContextTestCase(unittest.TestCase): self.ovs_dpdk.host_mgmt = {} self.ovs_dpdk.flavor = {} self.ovs_dpdk.configure_nics_for_ovs_dpdk = mock.Mock(return_value="") - mock_libvirt.build_vm_xml.return_value = [6, "00:00:00:00:00:01"] - self.ovs_dpdk._enable_interfaces = mock.Mock(return_value="") - mock_libvirt.virsh_create_vm.return_value = "" - mock_libvirt.pin_vcpu_for_perf.return_value = "" + xml_str = mock.Mock() + mock_build_xml.return_value = (xml_str, '00:00:00:00:00:01') + self.ovs_dpdk._enable_interfaces = mock.Mock(return_value=xml_str) + vnf_instance = mock.Mock() self.ovs_dpdk.vnf_node.generate_vnf_instance = mock.Mock( - return_value={}) - - self.assertIsNotNone(self.ovs_dpdk.setup_ovs_dpdk_context()) + return_value=vnf_instance) + + self.assertEqual([vnf_instance], + self.ovs_dpdk.setup_ovs_dpdk_context()) + mock_create_vm.assert_called_once_with( + self.ovs_dpdk.connection, '/tmp/vm_ovs_0.xml') + mock_check_if_exists.assert_called_once_with( + 'vm_0', self.ovs_dpdk.connection) + mock_build_xml.assert_called_once_with( + self.ovs_dpdk.connection, self.ovs_dpdk.vm_flavor, 'vm_0', 0) + mock_write_file.assert_called_once_with('/tmp/vm_ovs_0.xml', xml_str) + + @mock.patch.object(io, 'BytesIO') + def test__check_hugepages(self, mock_bytesio): + data = six.BytesIO('HugePages_Total: 20\n' + 'HugePages_Free: 20\n' + 'HugePages_Rsvd: 0\n' + 'HugePages_Surp: 0\n' + 'Hugepagesize: 1048576 kB'.encode()) + mock_bytesio.return_value = data + self.ovs_dpdk.connection = mock.Mock() + self.ovs_dpdk._check_hugepages() + + @mock.patch.object(io, 'BytesIO') + def test__check_hugepages_no_info(self, mock_bytesio): + data = six.BytesIO(''.encode()) + mock_bytesio.return_value = data + self.ovs_dpdk.connection = mock.Mock() + with self.assertRaises(exceptions.OVSHugepagesInfoError): + self.ovs_dpdk._check_hugepages() + + @mock.patch.object(io, 'BytesIO') + def test__check_hugepages_no_total_hp(self, mock_bytesio): + data = six.BytesIO('HugePages_Total: 0\n' + 'HugePages_Free: 0\n' + 'HugePages_Rsvd: 0\n' + 'HugePages_Surp: 0\n' + 'Hugepagesize: 1048576 kB'.encode()) + mock_bytesio.return_value = data + self.ovs_dpdk.connection = mock.Mock() + with self.assertRaises(exceptions.OVSHugepagesNotConfigured): + self.ovs_dpdk._check_hugepages() + + @mock.patch.object(io, 'BytesIO') + def test__check_hugepages_no_free_hp(self, mock_bytesio): + data = six.BytesIO('HugePages_Total: 20\n' + 'HugePages_Free: 0\n' + 'HugePages_Rsvd: 0\n' + 'HugePages_Surp: 0\n' + 'Hugepagesize: 1048576 kB'.encode()) + mock_bytesio.return_value = data + self.ovs_dpdk.connection = mock.Mock() + with self.assertRaises(exceptions.OVSHugepagesZeroFree) as exc: + self.ovs_dpdk._check_hugepages() + self.assertEqual('There are no HugePages free in this system. Total ' + 'HugePages configured: 20', exc.exception.msg) diff --git a/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py b/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py index f0953ef55..e70ab0ae8 100644 --- a/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py +++ b/yardstick/tests/unit/benchmark/contexts/standalone/test_sriov.py @@ -18,6 +18,7 @@ import mock import unittest from yardstick import ssh +from yardstick.benchmark.contexts.standalone import model from yardstick.benchmark.contexts.standalone import sriov @@ -69,10 +70,11 @@ class SriovContextTestCase(unittest.TestCase): if self.sriov in self.sriov.list: self.sriov._delete_context() - @mock.patch('yardstick.benchmark.contexts.standalone.sriov.Libvirt') - @mock.patch('yardstick.benchmark.contexts.standalone.model.StandaloneContextHelper') - @mock.patch('yardstick.benchmark.contexts.standalone.model.Server') - def test___init__(self, mock_helper, mock_server, *args): + @mock.patch.object(model, 'StandaloneContextHelper') + @mock.patch.object(model, 'Libvirt') + @mock.patch.object(model, 'Server') + def test___init__(self, mock_helper, mock_libvirt, mock_server): + # pylint: disable=unused-argument # NOTE(ralonsoh): this test doesn't cover function execution. self.sriov.helper = mock_helper self.sriov.vnf_node = mock_server @@ -97,9 +99,11 @@ class SriovContextTestCase(unittest.TestCase): self.sriov.wait_for_vnfs_to_start = mock.Mock(return_value={}) self.assertIsNone(self.sriov.deploy()) - @mock.patch('yardstick.benchmark.contexts.standalone.sriov.Libvirt') @mock.patch.object(ssh, 'SSH', return_value=(0, "a", "")) - def test_undeploy(self, mock_ssh, *args): + @mock.patch.object(model, 'Libvirt') + def test_undeploy(self, mock_libvirt, mock_ssh): + # pylint: disable=unused-argument + # NOTE(ralonsoh): the pylint exception should be removed. self.sriov.vm_deploy = False self.assertIsNone(self.sriov.undeploy()) @@ -237,11 +241,11 @@ class SriovContextTestCase(unittest.TestCase): self.sriov._get_vf_data = mock.Mock(return_value="") self.assertIsNone(self.sriov.configure_nics_for_sriov()) - @mock.patch('yardstick.benchmark.contexts.standalone.sriov.Libvirt') - @mock.patch.object(ssh, 'SSH') - def test__enable_interfaces(self, mock_ssh, *args): - mock_ssh.return_value = 0, "a", "" - + @mock.patch.object(ssh, 'SSH', return_value=(0, "a", "")) + @mock.patch.object(model, 'Libvirt') + def test__enable_interfaces(self, mock_libvirt, mock_ssh): + # pylint: disable=unused-argument + # NOTE(ralonsoh): the pylint exception should be removed. self.sriov.vm_deploy = True self.sriov.connection = mock_ssh self.sriov.vm_names = ['vm_0', 'vm_1'] @@ -251,20 +255,12 @@ class SriovContextTestCase(unittest.TestCase): self.assertIsNone(self.sriov._enable_interfaces( 0, 0, ["private_0"], 'test')) - @mock.patch('yardstick.benchmark.contexts.standalone.model.Server') - @mock.patch('yardstick.benchmark.contexts.standalone.sriov.Libvirt') - def test_setup_sriov_context(self, mock_libvirt, *args): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "a", "")) - ssh_mock.put = \ - mock.Mock(return_value=(0, "a", "")) - ssh.return_value = ssh_mock - self.sriov.vm_deploy = True - self.sriov.connection = ssh_mock - self.sriov.vm_names = ['vm_0', 'vm_1'] - self.sriov.drivers = [] + @mock.patch.object(model.Libvirt, 'build_vm_xml') + @mock.patch.object(model.Libvirt, 'check_if_vm_exists_and_delete') + @mock.patch.object(model.Libvirt, 'write_file') + @mock.patch.object(model.Libvirt, 'virsh_create_vm') + def test_setup_sriov_context(self, mock_create_vm, mock_write_file, + mock_check, mock_build_vm_xml): self.sriov.servers = { 'vnf_0': { 'network_ports': { @@ -274,15 +270,31 @@ class SriovContextTestCase(unittest.TestCase): } } } - self.sriov.networks = self.NETWORKS - self.sriov.host_mgmt = {} - self.sriov.flavor = {} - self.sriov.configure_nics_for_sriov = mock.Mock(return_value="") - mock_libvirt.build_vm_xml = mock.Mock( - return_value=[6, "00:00:00:00:00:01"]) - self.sriov._enable_interfaces = mock.Mock(return_value="") - self.sriov.vnf_node.generate_vnf_instance = mock.Mock(return_value={}) - self.assertIsNotNone(self.sriov.setup_sriov_context()) + connection = mock.Mock() + self.sriov.connection = connection + self.sriov.host_mgmt = {'ip': '1.2.3.4'} + self.sriov.vm_flavor = 'flavor' + self.sriov.networks = 'networks' + self.sriov.configure_nics_for_sriov = mock.Mock() + cfg = '/tmp/vm_sriov_0.xml' + vm_name = 'vm_0' + xml_out = mock.Mock() + mock_build_vm_xml.return_value = (xml_out, '00:00:00:00:00:01') + + with mock.patch.object(self.sriov, 'vnf_node') as mock_vnf_node, \ + mock.patch.object(self.sriov, '_enable_interfaces'): + mock_vnf_node.generate_vnf_instance = mock.Mock( + return_value='node') + nodes_out = self.sriov.setup_sriov_context() + self.assertEqual(['node'], nodes_out) + mock_vnf_node.generate_vnf_instance.assert_called_once_with( + 'flavor', 'networks', '1.2.3.4', 'vnf_0', + self.sriov.servers['vnf_0'], '00:00:00:00:00:01') + mock_build_vm_xml.assert_called_once_with( + connection, 'flavor', vm_name, 0) + mock_create_vm.assert_called_once_with(connection, cfg) + mock_check.assert_called_once_with(vm_name, connection) + mock_write_file.assert_called_once_with(cfg, xml_out) def test__get_vf_data(self): with mock.patch("yardstick.ssh.SSH") as ssh: |