docs: def init(name,
           cpu,
           mem,
           image=None,
           nic='default',
           interfaces=None,
           hypervisor=None,
           start=True,  # pylint: disable=redefined-outer-name
           disk='default',
           disks=None,
           saltenv='base',
           seed=True,
           install=True,
           pub_key=None,
           priv_key=None,
           seed_cmd='seed.apply',
           enable_vnc=False,
           enable_qcow=False,
           graphics=None,
           os_type=None,
           arch=None,
           loader=None,
           **kwargs):
      '''
      Initialize a new vm
  
      :param name: name of the virtual machine to create
      :param cpu: Number of virtual CPUs to assign to the virtual machine
      :param mem: Amount of memory to allocate to the virtual machine in MiB.
      :param image: Path to a disk image to use as the first disk (Default: ``None``).
          Deprecated in favor of the ``disks`` parameter. To set (or change) the
          image of a disk, add the following to the disks definitions:
  
          .. code-block:: python
  
              {
                'name': 'name_of_disk_to_change',
                'image': '/path/to/the/image'
              }
  
      :param nic: NIC profile to use (Default: ``'default'``).
          The profile interfaces can be customized / extended with the interfaces
          parameter. If set to ``None``, no profile will be used.
  
      :param interfaces:
          List of dictionaries providing details on the network interfaces to create.
          These data are merged with the ones from the nic profile. The structure of
          each dictionary is documented in init-nic-def_.
  
          .. versionadded:: 2019.2.0
  
      :param hypervisor: the virtual machine type. By default the value will be
          computed according to the virtual host capabilities.
  
      :param start: ``True`` to start the virtual machine after having defined it
          (Default: ``True``)
  
      :param disk: Disk profile to use (Default: ``'default'``). If set to
          ``None``, no profile will be used.
  
      :param disks: List of dictionaries providing details on the disk devices to
          create. These data are merged with the ones from the disk profile. The
          structure of each dictionary is documented in init-disk-def_.
  
          .. versionadded:: 2019.2.0
  
      :param saltenv: Fileserver environment (Default: ``'base'``)
  
      :param seed: ``True`` to seed the disk image. Only used when the ``image``
          parameter is provided. (Default: ``True``)
  
      :param install: install salt minion if absent (Default: ``True``)
      :param pub_key: public key to seed with (Default: ``None``)
      :param priv_key: public key to seed with (Default: ``None``)
      :param seed_cmd: Salt command to execute to seed the image. (Default:
          ``'seed.apply'``)
  
      :param enable_vnc:
          ``True`` to setup a vnc display for the VM (Default: ``False``)
  
          Deprecated in favor of the ``graphics`` parameter. Could be replaced with
          the following:
  
          .. code-block:: python
  
              graphics={'type': 'vnc'}
  
          .. deprecated:: 2019.2.0
  
      :param graphics:
          Dictionary providing details on the graphics device to create. (Default: ``None``)
          See init-graphics-def_ for more details on the possible values.
  
          .. versionadded:: 2019.2.0
  
      :param loader:
          Dictionary providing details on the BIOS firmware loader. (Default: ``None``)
          See init-loader-def_ for more details on the possible values.
  
          .. versionadded:: 2019.2.0
      :param os_type:
          type of virtualization as found in the ``//os/type`` element of the libvirt definition.
          The default value is taken from the host capabilities, with a preference for ``hvm``.
  
          .. versionadded:: 2019.2.0
  
      :param arch:
          architecture of the virtual machine. The default value is taken from the host capabilities,
          but ``x86_64`` is prefed over ``i686``.
  
          .. versionadded:: 2019.2.0
  
      :param enable_qcow:
          ``True`` to create a QCOW2 overlay image, rather than copying the image
          (Default: ``False``).
  
          Deprecated in favor of ``disks`` parameter. Add the following to the disks
          definitions to create an overlay image of a template disk image with an
          image set:
  
          .. code-block:: python
  
              {
                  'name': 'name_of_disk_to_change',
                  'overlay_image': True
              }
  
          .. deprecated:: 2019.2.0
  
      :param pool:
          Path of the folder where the image files are located for vmware/esx hypervisors.
  
          Deprecated in favor of ``disks`` parameter. Add the following to the disks
          definitions to set the vmware datastore of a disk image:
  
          .. code-block:: python
  
              {
                  'name': 'name_of_disk_to_change',
                  'pool': 'mydatastore'
              }
  
          .. deprecated:: Flurorine
  
      :param dmac:
          Default MAC address to use for the network interfaces. By default MAC addresses are
          automatically generated.
  
          Deprecated in favor of ``interfaces`` parameter. Add the following to the interfaces
          definitions to force the mac address of a NIC:
  
          .. code-block:: python
  
              {
                  'name': 'name_of_nic_to_change',
                  'mac': 'MY:MA:CC:ADD:RE:SS'
              }
  
          .. deprecated:: 2019.2.0
  
      :param config: minion configuration to use when seeding.  See :mod:`seed
          module <salt.modules.seed>` for more details
  
      :param boot_dev: String of space-separated devices to boot from (Default: ``'hd'``)
      :param serial_type: Serial device type. One of ``'pty'``, ``'tcp'``
          (Default: ``None``)
      :param telnet_port: Telnet port to use for serial device of type ``tcp``.
      :param console: ``True`` to add a console device along with serial one
          (Default: ``True``)
      :param connection: libvirt connection URI, overriding defaults
  
      .. versionadded:: 2019.2.0
  
      :param username: username to connect with, overriding defaults
  
      .. versionadded:: 2019.2.0
  
      :param password: password to connect with, overriding defaults
  
      .. versionadded:: 2019.2.0
  
      .. _init-nic-def:
  
      **Network Interface Definitions**
  
      Network interfaces dictionaries can contain the following properties:
  
      name
          Name of the network interface. This is only used as a key to merge with the profile data
  
      type
          Network type. One of ``'bridge'``, ``'network'``
  
      source
          The network source, typically the bridge or network name
  
      mac
          The desired mac address, computed if ``None`` (Default: ``None``).
  
      model
          The network card model (Default: depends on the hypervisor)
  
      .. _init-disk-def:
  
      **Disk Definitions**
  
      Disk dictionaries can contain the following properties:
  
      name
          Name of the disk. This is mostly used in the name of the disk image and as a key to merge
          with the profile data.
  
      format
          Format of the disk image, like ``'qcow2'``, ``'raw'``, ``'vmdk'``.
          (Default: depends on the hypervisor)
  
      size
          Disk size in MiB
  
      pool
          Path to the folder or name of the pool where disks should be created.
          (Default: depends on hypervisor)
  
      model
          One of the disk busses allowed by libvirt (Default: depends on hypervisor)
  
          See the libvirt `disk element`_ documentation for the allowed bus types.
  
      image
          Path to the image to use for the disk. If no image is provided, an empty disk will be created
          (Default: ``None``)
  
      overlay_image
          ``True`` to create a QCOW2 disk image with ``image`` as backing file. If ``False``
          the file pointed to by the ``image`` property will simply be copied. (Default: ``False``)
  
      hostname_property
          When using ZFS volumes, setting this value to a ZFS property ID will make Salt store the name of the
          virtual machine inside this property. (Default: ``None``)
  
      sparse_volume
          Boolean to specify whether to use a thin provisioned ZFS volume.
  
          Example profile for a bhyve VM with two ZFS disks. The first is
          cloned from the specified image. The second disk is a thin
          provisioned volume.
  
          .. code-block:: yaml
  
              virt:
                disk:
                  two_zvols:
                    - system:
                        image: zroot/bhyve/CentOS-7-x86_64-v1@v1.0.5
                        hostname_property: virt:hostname
                        pool: zroot/bhyve/guests
                    - data:
                        pool: tank/disks
                        size: 20G
                        hostname_property: virt:hostname
                        sparse_volume: True
  
      source_file
          Absolute path to the disk image to use. Not to be confused with ``image`` parameter. This
          parameter is useful to use disk images that are created outside of this module. Can also
          be ``None`` for devices that have no associated image like cdroms.
  
      device
          Type of device of the disk. Can be one of 'disk', 'cdrom', 'floppy' or 'lun'.
          (Default: ``'disk'``)
  
      .. _init-graphics-def:
  
      **Graphics Definition**
  
      The graphics dictionnary can have the following properties:
  
      type
          Graphics type. The possible values are ``none``, ``'spice'``, ``'vnc'`` and other values
          allowed as a libvirt graphics type (Default: ``None``)
  
          See the libvirt `graphics element`_ documentation for more details on the possible types.
  
      port
          Port to export the graphics on for ``vnc``, ``spice`` and ``rdp`` types.
  
      tls_port
          Port to export the graphics over a secured connection for ``spice`` type.
  
      listen
          Dictionary defining on what address to listen on for ``vnc``, ``spice`` and ``rdp``.
          It has a ``type`` property with ``address`` and ``None`` as possible values, and an
          ``address`` property holding the IP or hostname to listen on.
  
          By default, not setting the ``listen`` part of the dictionary will default to
          listen on all addresses.
  
      .. _init-loader-def:
  
      **Loader Definition**
  
      The loader dictionary must have the following property:
  
      path
          Path to the UEFI firmware binary
  
      Optionally, you can provide arbitrary attributes such as ``readonly`` or ``type``. See
      the libvirt documentation for all supported loader parameters.
  
      CLI Example:
  
      .. code-block:: bash
  
          salt 'hypervisor' virt.init vm_name 4 512 salt://path/to/image.raw
          salt 'hypervisor' virt.init vm_name 4 512 /var/lib/libvirt/images/img.raw
          salt 'hypervisor' virt.init vm_name 4 512 nic=profile disk=profile
  
      The disk images will be created in an image folder within the directory
      defined by the ``virt:images`` option. Its default value is
      ``/srv/salt-images/`` but this can changed with such a configuration:
  
      .. code-block:: yaml
  
          virt:
              images: /data/my/vm/images/
  
      .. _disk element: https://libvirt.org/formatdomain.html#elementsDisks
      .. _graphics element: https://libvirt.org/formatdomain.html#elementsGraphics
      '''
      caps = capabilities(**kwargs)
      os_types = sorted({guest['os_type'] for guest in caps['guests']})
      arches = sorted({guest['arch']['name'] for guest in caps['guests']})
      if not hypervisor:
          hypervisor = __salt__['config.get']('libvirt:hypervisor', hypervisor)
          if hypervisor is not None:
              salt.utils.versions.warn_until(
                  'Sodium',
                  '\'libvirt:hypervisor\' configuration property has been deprecated. '
                  'Rather use the \'virt:connection:uri\' to properly define the libvirt '
                  'URI or alias of the host to connect to. \'libvirt:hypervisor\' will '
                  'stop being used in {version}.'
              )
          else:
              # Use the machine types as possible values
              # Prefer 'kvm' over the others if available
              hypervisors = sorted({x for y in [guest['arch']['domains'].keys() for guest in caps['guests']] for x in y})
              hypervisor = 'kvm' if 'kvm' in hypervisors else hypervisors[0]
  
      # esxi used to be a possible value for the hypervisor: map it to vmware since it's the same
      hypervisor = 'vmware' if hypervisor == 'esxi' else hypervisor
  
      log.debug('Using hypervisor %s', hypervisor)
  
      # the NICs are computed as follows:
      # 1 - get the default NICs from the profile
      # 2 - Complete the users NICS
      # 3 - Update the default NICS list to the users one, matching key is the name
      dmac = kwargs.get('dmac', None)
      if dmac:
          salt.utils.versions.warn_until(
              'Sodium',
              '\'dmac\' parameter has been deprecated. Rather use the \'interfaces\' parameter '
              'to properly define the desired MAC address. \'dmac\' will be removed in {version}.'
          )
      nicp = _get_merged_nics(hypervisor, nic, interfaces, dmac=dmac)
  
      # the disks are computed as follows:
      # 1 - get the disks defined in the profile
      # 2 - set the image on the first disk (will be removed later)
      # 3 - update the disks from the profile with the ones from the user. The matching key is the name.
      pool = kwargs.get('pool', None)
      if pool:
          salt.utils.versions.warn_until(
              'Sodium',
              '\'pool\' parameter has been deprecated. Rather use the \'disks\' parameter '
              'to properly define the vmware datastore of disks. \'pool\' will be removed in {version}.'
          )
  
      if image:
          salt.utils.versions.warn_until(
              'Sodium',
              '\'image\' parameter has been deprecated. Rather use the \'disks\' parameter '
              'to override or define the image. \'image\' will be removed in {version}.'
          )
  
      diskp = _disk_profile(disk, hypervisor, disks, name, image=image, pool=pool, **kwargs)
  
      # Create multiple disks, empty or from specified images.
      for _disk in diskp:
          log.debug("Creating disk for VM [ %s ]: %s", name, _disk)
  
          if hypervisor == 'vmware':
              if 'image' in _disk:
                  # TODO: we should be copying the image file onto the ESX host
                  raise SaltInvocationError(
                      'virt.init does not support image '
                      'template in conjunction with esxi hypervisor'
                  )
              else:
                  # assume libvirt manages disks for us
                  log.debug('Generating libvirt XML for %s', _disk)
                  vol_xml = _gen_vol_xml(
                      name,
                      _disk['name'],
                      _disk['format'],
                      _disk['size'],
                      _disk['pool']
                  )
                  define_vol_xml_str(vol_xml)
  
          elif hypervisor in ['qemu', 'kvm', 'xen']:
  
              create_overlay = enable_qcow
              if create_overlay:
                  salt.utils.versions.warn_until(
                      'Sodium',
                      '\'enable_qcow\' parameter has been deprecated. Rather use the \'disks\' '
                      'parameter to override or define the image. \'enable_qcow\' will be removed '
                      'in {version}.'
                  )
              else:
                  create_overlay = _disk.get('overlay_image', False)
  
              if _disk['source_file']:
                  if os.path.exists(_disk['source_file']):
                      img_dest = _disk['source_file']
                  else:
                      img_dest = _qemu_image_create(_disk, create_overlay, saltenv)
              else:
                  img_dest = None
  
              # Seed only if there is an image specified
              if seed and img_dest and _disk.get('image', None):
                  log.debug('Seed command is %s', seed_cmd)
                  __salt__[seed_cmd](
                      img_dest,
                      id_=name,
                      config=kwargs.get('config'),
                      install=install,
                      pub_key=pub_key,
                      priv_key=priv_key,
                  )
  
          elif hypervisor in ['bhyve']:
              img_dest = _zfs_image_create(
                  vm_name=name,
                  pool=_disk.get('pool'),
                  disk_name=_disk.get('name'),
                  disk_size=_disk.get('size'),
                  disk_image_name=_disk.get('image'),
                  hostname_property_name=_disk.get('hostname_property'),
                  sparse_volume=_disk.get('sparse_volume'),
              )
  
          else:
              # Unknown hypervisor
              raise SaltInvocationError(
                  'Unsupported hypervisor when handling disk image: {0}'
                  .format(hypervisor)
              )
  
      log.debug('Generating VM XML')
  
      if enable_vnc:
          salt.utils.versions.warn_until(
              'Sodium',
              '\'enable_vnc\' parameter has been deprecated in favor of '
              '\'graphics\'. Use graphics={\'type\': \'vnc\'} for the same behavior. '
              '\'enable_vnc\' will be removed in {version}. ')
          graphics = {'type': 'vnc'}
  
      if os_type is None:
          os_type = 'hvm' if 'hvm' in os_types else os_types[0]
      if arch is None:
          arch = 'x86_64' if 'x86_64' in arches else arches[0]
  
      vm_xml = _gen_xml(name, cpu, mem, diskp, nicp, hypervisor, os_type, arch, graphics, loader, **kwargs)
      conn = __get_conn(**kwargs)
      try:
          conn.defineXML(vm_xml)
      except libvirtError as err:
          # check if failure is due to this domain already existing
          if "domain '{}' already exists".format(name) in six.text_type(err):
              # continue on to seeding
              log.warning(err)
          else:
              conn.close()
              raise err  # a real error we should report upwards
  
      if start:
          log.debug('Starting VM %s', name)
          _get_domain(conn, name).create()
      conn.close()
  
      return True