add yardstick iruya 9.0.0 release notes
[yardstick.git] / yardstick / benchmark / contexts / standalone / model.py
index ecddcbb..a154268 100644 (file)
@@ -26,6 +26,7 @@ import xml.etree.ElementTree as ET
 from yardstick import ssh
 from yardstick.common import constants
 from yardstick.common import exceptions
+from yardstick.common import utils as common_utils
 from yardstick.common import yaml_loader
 from yardstick.network_services.utils import PciAddress
 from yardstick.network_services.helpers.cpu import CpuSysCores
@@ -45,7 +46,7 @@ VM_TEMPLATE = """
   <vcpu cpuset='{cpuset}'>{vcpu}</vcpu>
  {cputune}
   <os>
-    <type arch="x86_64" machine="pc-i440fx-xenial">hvm</type>
+    <type arch="x86_64" machine="{machine}">hvm</type>
     <boot dev="hd" />
   </os>
   <features>
@@ -89,6 +90,30 @@ VM_TEMPLATE = """
   </devices>
 </domain>
 """
+
+USER_DATA_TEMPLATE = """
+cat > {user_file} <<EOF
+#cloud-config
+preserve_hostname: false
+hostname: {host}
+users:
+{user_config}
+EOF
+"""
+
+NETWORK_DATA_TEMPLATE = """
+cat > {network_file} <<EOF
+#cloud-config
+version: 2
+ethernets:
+  ens3:
+    match:
+      macaddress: {mac_address}
+    addresses:
+      - {ip_address}
+EOF
+"""
+
 WAIT_FOR_BOOT = 30
 
 
@@ -137,7 +162,8 @@ class Libvirt(object):
         return vm_pci
 
     @classmethod
-    def add_ovs_interface(cls, vpath, port_num, vpci, vports_mac, xml_str):
+    def add_ovs_interface(cls, vpath, port_num, vpci, vports_mac, xml_str,
+                          queues):
         """Add a DPDK OVS 'interface' XML node in 'devices' node
 
         <devices>
@@ -179,7 +205,7 @@ class Libvirt(object):
         model.set('type', 'virtio')
 
         driver = ET.SubElement(interface, 'driver')
-        driver.set('queues', '4')
+        driver.set('queues', str(queues))
 
         host = ET.SubElement(driver, 'host')
         host.set('mrg_rxbuf', 'off')
@@ -268,7 +294,7 @@ class Libvirt(object):
         return vm_image
 
     @classmethod
-    def build_vm_xml(cls, connection, flavor, vm_name, index):
+    def build_vm_xml(cls, connection, flavor, vm_name, index, cdrom_img):
         """Build the XML from the configuration parameters"""
         memory = flavor.get('ram', '4096')
         extra_spec = flavor.get('extra_specs', {})
@@ -281,6 +307,7 @@ class Libvirt(object):
         cpuset = Libvirt.pin_vcpu_for_perf(connection, hw_socket)
 
         cputune = extra_spec.get('cputune', '')
+        machine = extra_spec.get('machine_type', 'pc-i440fx-xenial')
         mac = StandaloneContextHelper.get_mac_address(0x00)
         image = cls.create_snapshot_qemu(connection, index,
                                          flavor.get("images", None))
@@ -291,7 +318,11 @@ class Libvirt(object):
             memory=memory, vcpu=vcpu, cpu=cpu,
             numa_cpus=numa_cpus,
             socket=socket, threads=threads,
-            vm_image=image, cpuset=cpuset, cputune=cputune)
+            vm_image=image, cpuset=cpuset,
+            machine=machine, cputune=cputune)
+
+        # Add CD-ROM device
+        vm_xml = Libvirt.add_cdrom(cdrom_img, vm_xml)
 
         return vm_xml, mac
 
@@ -320,6 +351,75 @@ class Libvirt(object):
         et = ET.ElementTree(element=root)
         et.write(file_name, encoding='utf-8', method='xml')
 
+    @classmethod
+    def add_cdrom(cls, file_path, xml_str):
+        """Add a CD-ROM disk XML node in 'devices' node
+
+        <devices>
+            <disk type='file' device='cdrom'>
+              <driver name='qemu' type='raw'/>
+              <source file='/var/lib/libvirt/images/data.img'/>
+              <target dev='hdb'/>
+              <readonly/>
+            </disk>
+            ...
+        </devices>
+        """
+
+        root = ET.fromstring(xml_str)
+        device = root.find('devices')
+
+        disk = ET.SubElement(device, 'disk')
+        disk.set('type', 'file')
+        disk.set('device', 'cdrom')
+
+        driver = ET.SubElement(disk, 'driver')
+        driver.set('name', 'qemu')
+        driver.set('type', 'raw')
+
+        source = ET.SubElement(disk, 'source')
+        source.set('file', file_path)
+
+        target = ET.SubElement(disk, 'target')
+        target.set('dev', 'hdb')
+
+        ET.SubElement(disk, 'readonly')
+        return ET.tostring(root)
+
+    @staticmethod
+    def gen_cdrom_image(connection, file_path, vm_name, vm_user, key_filename, mac, ip):
+        """Generate ISO image for CD-ROM """
+
+        user_config = ["    - name: {user_name}",
+                       "      ssh_authorized_keys:",
+                       "        - {pub_key_str}"]
+        if vm_user != "root":
+            user_config.append("      sudo: ALL=(ALL) NOPASSWD:ALL")
+
+        meta_data = "/tmp/meta-data"
+        user_data = "/tmp/user-data"
+        network_data = "/tmp/network-config"
+        with open(".".join([key_filename, "pub"]), "r") as pub_key_file:
+            pub_key_str = pub_key_file.read().rstrip()
+        user_conf = os.linesep.join(user_config).format(pub_key_str=pub_key_str, user_name=vm_user)
+
+        cmd_lst = [
+            "touch %s" % meta_data,
+            USER_DATA_TEMPLATE.format(user_file=user_data, host=vm_name, user_config=user_conf),
+            NETWORK_DATA_TEMPLATE.format(network_file=network_data, mac_address=mac,
+                                         ip_address=ip),
+            "genisoimage -output {0} -volid cidata -joliet -r {1} {2} {3}".format(file_path,
+                                                                                  meta_data,
+                                                                                  user_data,
+                                                                                  network_data),
+            "rm {0} {1} {2}".format(meta_data, user_data, network_data),
+        ]
+        for cmd in cmd_lst:
+            LOG.info(cmd)
+            status, _, error = connection.execute(cmd)
+            if status:
+                raise exceptions.LibvirtQemuImageCreateError(error=error)
+
 
 class StandaloneContextHelper(object):
     """ This class handles all the common code for standalone
@@ -331,7 +431,7 @@ class StandaloneContextHelper(object):
     @staticmethod
     def install_req_libs(connection, extra_pkgs=None):
         extra_pkgs = extra_pkgs or []
-        pkgs = ["qemu-kvm", "libvirt-bin", "bridge-utils", "numactl", "fping"]
+        pkgs = ["qemu-kvm", "libvirt-bin", "bridge-utils", "numactl", "fping", "genisoimage"]
         pkgs.extend(extra_pkgs)
         cmd_template = "dpkg-query -W --showformat='${Status}\\n' \"%s\"|grep 'ok installed'"
         for pkg in pkgs:
@@ -455,8 +555,41 @@ class StandaloneContextHelper(object):
             ip = cls.get_mgmt_ip(connection, node["mac"], mgmtip, node)
             if ip:
                 node["ip"] = ip
+                client = ssh.SSH.from_node(node)
+                LOG.debug("OS version: %s",
+                          common_utils.get_os_version(client))
+                LOG.debug("Kernel version: %s",
+                          common_utils.get_kernel_version(client))
+                vnfs_data = common_utils.get_sample_vnf_info(client)
+                for vnf_name, vnf_data in vnfs_data.items():
+                    LOG.debug("VNF name: '%s', commit ID/branch: '%s'",
+                              vnf_name, vnf_data["branch_commit"])
+                    LOG.debug("%s", vnf_data["md5_result"])
         return nodes
 
+    @classmethod
+    def check_update_key(cls, connection, node, vm_name, id_name, cdrom_img, mac):
+        # Generate public/private keys if private key file is not provided
+        user_name = node.get('user')
+        if not user_name:
+            node['user'] = 'root'
+            user_name = node.get('user')
+        if not node.get('key_filename'):
+            key_filename = ''.join(
+                [constants.YARDSTICK_ROOT_PATH,
+                 'yardstick/resources/files/yardstick_key-',
+                 id_name, '-', vm_name])
+            ssh.SSH.gen_keys(key_filename)
+            node['key_filename'] = key_filename
+        # Update image with public key
+        key_filename = node.get('key_filename')
+        ip_netmask = "{0}/{1}".format(node.get('ip'), node.get('netmask'))
+        ip_netmask = "{0}/{1}".format(node.get('ip'),
+                                      IPNetwork(ip_netmask).prefixlen)
+        Libvirt.gen_cdrom_image(connection, cdrom_img, vm_name, user_name, key_filename, mac,
+                                ip_netmask)
+        return node
+
 
 class Server(object):
     """ This class handles geting vnf nodes
@@ -469,7 +602,7 @@ class Server(object):
 
         for key, vfs in vnf["network_ports"].items():
             if key == "mgmt":
-                mgmtip = str(IPNetwork(vfs['cidr']).ip)
+                mgmt_cidr = IPNetwork(vfs['cidr'])
                 continue
 
             vf = ports[vfs[0]]
@@ -486,14 +619,15 @@ class Server(object):
             })
             index = index + 1
 
-        return mgmtip, interfaces
+        return mgmt_cidr, interfaces
 
     @classmethod
     def generate_vnf_instance(cls, flavor, ports, ip, key, vnf, mac):
-        mgmtip, interfaces = cls.build_vnf_interfaces(vnf, ports)
+        mgmt_cidr, interfaces = cls.build_vnf_interfaces(vnf, ports)
 
         result = {
-            "ip": mgmtip,
+            "ip": str(mgmt_cidr.ip),
+            "netmask": str(mgmt_cidr.netmask),
             "mac": mac,
             "host": ip,
             "user": flavor.get('user', 'root'),