def _GenerateKVMRuntime(self, instance, block_devices, startup_paused,
                          kvmhelp):
    """Generate KVM information to start an instance.

    @type kvmhelp: string
    @param kvmhelp: output of kvm --help
    @attention: this function must not have any side-effects; for
        example, it must not write to the filesystem, or read values
        from the current system the are expected to differ between
        nodes, since it is only run once at instance startup;
        actions/kvm arguments that can vary between systems should be
        done in L{_ExecuteKVMRuntime}

    """
    # pylint: disable=R0912,R0914,R0915
    hvp = instance.hvparams
    self.ValidateParameters(hvp)

    pidfile = self._InstancePidFile(instance.name)
    kvm = hvp[constants.HV_KVM_PATH]
    kvm_cmd = [kvm]
    # used just by the vnc server, if enabled
    kvm_cmd.extend(["-name", instance.name])
    kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])

    smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
    if hvp[constants.HV_CPU_CORES]:
      smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
    if hvp[constants.HV_CPU_THREADS]:
      smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
    if hvp[constants.HV_CPU_SOCKETS]:
      smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])

    kvm_cmd.extend(["-smp", ",".join(smp_list)])

    kvm_cmd.extend(["-pidfile", pidfile])

    bus_slots = self._GetBusSlots(hvp)

    # As requested by music lovers
    if hvp[constants.HV_SOUNDHW]:
      soundhw = hvp[constants.HV_SOUNDHW]
      kvm_cmd.extend(["-soundhw", soundhw])

    if hvp[constants.HV_DISK_TYPE] in constants.HT_SCSI_DEVICE_TYPES:
      # In case a SCSI disk is given, QEMU adds a SCSI contorller
      # (LSI Logic / Symbios Logic 53c895a) implicitly.
      # Here, we add the controller explicitly with the default id.
      kvm_cmd.extend([
        "-device",
        "%s,id=scsi" % hvp[constants.HV_KVM_SCSI_CONTROLLER_TYPE]
        ])

    kvm_cmd.extend(["-balloon", "virtio"])
    kvm_cmd.extend(["-daemonize"])
    if not instance.hvparams[constants.HV_ACPI]:
      kvm_cmd.extend(["-no-acpi"])
    if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
        constants.INSTANCE_REBOOT_EXIT:
      kvm_cmd.extend(["-no-reboot"])

    mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
    if not mversion:
      mversion = self._GetDefaultMachineVersion(kvm)
    if self._MACHINE_RE.search(kvmhelp):
      # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as
      # extra hypervisor parameters. We should also investigate whether and how
      # shadow_mem should be considered for the resource model.
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
        specprop = ",accel=kvm"
      else:
        specprop = ""
      machinespec = "%s%s" % (mversion, specprop)
      kvm_cmd.extend(["-machine", machinespec])
    else:
      kvm_cmd.extend(["-M", mversion])
      if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
          self._ENABLE_KVM_RE.search(kvmhelp)):
        kvm_cmd.extend(["-enable-kvm"])
      elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
            self._DISABLE_KVM_RE.search(kvmhelp)):
        kvm_cmd.extend(["-disable-kvm"])

    kernel_path = hvp[constants.HV_KERNEL_PATH]
    if kernel_path:
      boot_cdrom = boot_floppy = boot_network = False
    else:
      boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
      boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
      boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK

    if startup_paused:
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])

    if boot_network:
      kvm_cmd.extend(["-boot", "n"])

    disk_type = hvp[constants.HV_DISK_TYPE]

    # Now we can specify a different device type for CDROM devices.
    cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
    if not cdrom_disk_type:
      cdrom_disk_type = disk_type

    cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH]
    if cdrom_image1:
      needs_boot_flag = self._BOOT_RE.search(kvmhelp)
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom,
                        needs_boot_flag)

    cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
    if cdrom_image2:
      self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False)

    floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
    if floppy_image:
      options = ",format=raw,media=disk"
      if boot_floppy:
        kvm_cmd.extend(["-boot", "a"])
        options = "%s,boot=on" % options
      if_val = ",if=floppy"
      options = "%s%s" % (options, if_val)
      drive_val = "file=%s%s" % (floppy_image, options)
      kvm_cmd.extend(["-drive", drive_val])

    if kernel_path:
      kvm_cmd.extend(["-kernel", kernel_path])
      initrd_path = hvp[constants.HV_INITRD_PATH]
      if initrd_path:
        kvm_cmd.extend(["-initrd", initrd_path])
      root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
                     hvp[constants.HV_KERNEL_ARGS]]
      if hvp[constants.HV_SERIAL_CONSOLE]:
        serial_speed = hvp[constants.HV_SERIAL_SPEED]
        root_append.append("console=ttyS0,%s" % serial_speed)
      kvm_cmd.extend(["-append", " ".join(root_append)])

    mem_path = hvp[constants.HV_MEM_PATH]
    if mem_path:
      kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])

    monitor_dev = ("unix:%s,server,nowait" %
                   self._InstanceMonitor(instance.name))
    kvm_cmd.extend(["-monitor", monitor_dev])
    if hvp[constants.HV_SERIAL_CONSOLE]:
      serial_dev = ("unix:%s,server,nowait" %
                    self._InstanceSerial(instance.name))
      kvm_cmd.extend(["-serial", serial_dev])
    else:
      kvm_cmd.extend(["-serial", "none"])

    mouse_type = hvp[constants.HV_USB_MOUSE]
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
    spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
    spice_ip_version = None

    kvm_cmd.extend(["-usb"])

    if mouse_type:
      kvm_cmd.extend(["-usbdevice", mouse_type])
    elif vnc_bind_address:
      kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])

    if vnc_bind_address:
      if netutils.IsValidInterface(vnc_bind_address):
        if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address)
        if_ip4_addresses = if_addresses[constants.IP4_VERSION]
        if len(if_ip4_addresses) < 1:
          logging.error("Could not determine IPv4 address of interface %s",
                        vnc_bind_address)
        else:
          vnc_bind_address = if_ip4_addresses[0]
      if netutils.IP4Address.IsValid(vnc_bind_address):
        if instance.network_port > constants.VNC_BASE_PORT:
          display = instance.network_port - constants.VNC_BASE_PORT
          if vnc_bind_address == constants.IP4_ADDRESS_ANY:
            vnc_arg = ":%d" % (display)
          else:
            vnc_arg = "%s:%d" % (vnc_bind_address, display)
        else:
          logging.error("Network port is not a valid VNC display (%d < %d),"
                        " not starting VNC",
                        instance.network_port, constants.VNC_BASE_PORT)
          vnc_arg = "none"

        # Only allow tls and other option when not binding to a file, for now.
        # kvm/qemu gets confused otherwise about the filename to use.
        vnc_append = ""
        if hvp[constants.HV_VNC_TLS]:
          vnc_append = "%s,tls" % vnc_append
          if hvp[constants.HV_VNC_X509_VERIFY]:
            vnc_append = "%s,x509verify=%s" % (vnc_append,
                                               hvp[constants.HV_VNC_X509])
          elif hvp[constants.HV_VNC_X509]:
            vnc_append = "%s,x509=%s" % (vnc_append,
                                         hvp[constants.HV_VNC_X509])
        if hvp[constants.HV_VNC_PASSWORD_FILE]:
          vnc_append = "%s,password" % vnc_append

        vnc_arg = "%s%s" % (vnc_arg, vnc_append)

      else:
        vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)

      kvm_cmd.extend(["-vnc", vnc_arg])
    elif spice_bind:
      # FIXME: this is wrong here; the iface ip address differs
      # between systems, so it should be done in _ExecuteKVMRuntime
      if netutils.IsValidInterface(spice_bind):
        # The user specified a network interface, we have to figure out the IP
        # address.
        addresses = netutils.GetInterfaceIpAddresses(spice_bind)
        spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]

        # if the user specified an IP version and the interface does not
        # have that kind of IP addresses, throw an exception
        if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
          if not addresses[spice_ip_version]:
            raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
                                         " for %s" % (spice_ip_version,
                                                      spice_bind))

        # the user did not specify an IP version, we have to figure it out
        elif (addresses[constants.IP4_VERSION] and
              addresses[constants.IP6_VERSION]):
          # we have both ipv4 and ipv6, let's use the cluster default IP
          # version
          cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
          spice_ip_version = \
            netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
        elif addresses[constants.IP4_VERSION]:
          spice_ip_version = constants.IP4_VERSION
        elif addresses[constants.IP6_VERSION]:
          spice_ip_version = constants.IP6_VERSION
        else:
          raise errors.HypervisorError("SPICE: Unable to get an IP address"
                                       " for %s" % (spice_bind))

        spice_address = addresses[spice_ip_version][0]

      else:
        # spice_bind is known to be a valid IP address, because
        # ValidateParameters checked it.
        spice_address = spice_bind

      spice_arg = "addr=%s" % spice_address
      if hvp[constants.HV_KVM_SPICE_USE_TLS]:
        spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
                     (spice_arg, instance.network_port,
                      pathutils.SPICE_CACERT_FILE))
        spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
                     (spice_arg, pathutils.SPICE_CERT_FILE,
                      pathutils.SPICE_CERT_FILE))
        tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
        if tls_ciphers:
          spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
      else:
        spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)

      if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
        spice_arg = "%s,disable-ticketing" % spice_arg

      if spice_ip_version:
        spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)

      # Image compression options
      img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
      img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
      img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
      if img_lossless:
        spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
      if img_jpeg:
        spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
      if img_zlib_glz:
        spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)

      # Video stream detection
      video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
      if video_streaming:
        spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)

      # Audio compression, by default in qemu-kvm it is on
      if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
        spice_arg = "%s,playback-compression=off" % spice_arg
      if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
        spice_arg = "%s,agent-mouse=off" % spice_arg
      else:
        # Enable the spice agent communication channel between the host and the
        # agent.
        kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice"])
        kvm_cmd.extend([
          "-device",
          "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
          ])
        kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])

      logging.info("KVM: SPICE will listen on port %s", instance.network_port)
      kvm_cmd.extend(["-spice", spice_arg])

    else:
      # From qemu 1.4 -nographic is incompatible with -daemonize. The new way
      # also works in earlier versions though (tested with 1.1 and 1.3)
      if self._DISPLAY_RE.search(kvmhelp):
        kvm_cmd.extend(["-display", "none"])
      else:
        kvm_cmd.extend(["-nographic"])

    if hvp[constants.HV_USE_LOCALTIME]:
      kvm_cmd.extend(["-localtime"])

    if hvp[constants.HV_KVM_USE_CHROOT]:
      kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])

    # Add qemu-KVM -cpu param
    if hvp[constants.HV_CPU_TYPE]:
      kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])

    # Pass a -vga option if requested, or if spice is used, for backwards
    # compatibility.
    if hvp[constants.HV_VGA]:
      kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
    elif spice_bind:
      kvm_cmd.extend(["-vga", "qxl"])

    # Various types of usb devices, comma separated
    if hvp[constants.HV_USB_DEVICES]:
      for dev in hvp[constants.HV_USB_DEVICES].split(","):
        kvm_cmd.extend(["-usbdevice", dev])

    # Set system UUID to instance UUID
    if self._UUID_RE.search(kvmhelp):
      kvm_cmd.extend(["-uuid", instance.uuid])

    if hvp[constants.HV_KVM_EXTRA]:
      kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))

    def _generate_kvm_device(dev_type, dev):
      """Helper for generating a kvm device out of a Ganeti device."""
      kvm_devid = _GenerateDeviceKVMId(dev_type, dev)
      hv_dev_type = _DEVICE_TYPE[dev_type](hvp)
      dev.hvinfo = _GenerateDeviceHVInfo(dev_type, kvm_devid,
                                         hv_dev_type, bus_slots)

    kvm_disks = []
    for disk, link_name, uri in block_devices:
      _generate_kvm_device(constants.HOTPLUG_TARGET_DISK, disk)
      kvm_disks.append((disk, link_name, uri))

    kvm_nics = []
    for nic in instance.nics:
      _generate_kvm_device(constants.HOTPLUG_TARGET_NIC, nic)
      kvm_nics.append(nic)

    hvparams = hvp

    return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
dataset/ETHPy150Open ganeti/ganeti/lib/hypervisor/hv_kvm/__init__.py/KVMHypervisor._GenerateKVMRuntime/original