Starts an existing guest, or defines and starts a new VM with specified arguments.

    .. versionadded:: 2016.3.0

    :param name: name of the virtual machine to run
    :param cpu: number of CPUs for the virtual machine to create
    :param mem: amount of memory in MiB for the new virtual machine
    :param image: disk image to use for the first disk of the new VM

        .. deprecated:: 2019.2.0
    :param vm_type: force virtual machine type for the new VM. The default value is taken from
        the host capabilities. This could be useful for example to use ``'qemu'`` type instead
        of the ``'kvm'`` one.

        .. versionadded:: 2019.2.0
    :param disk_profile:
        Name of the disk profile to use for the new virtual machine

        .. versionadded:: 2019.2.0
    :param disks:
        List of disk to create for the new virtual machine.
        See the **Disk Definitions** section of the :py:func:`virt.init
        <salt.modules.virt.init>` function for more details on the items on
        this list.

        .. versionadded:: 2019.2.0
    :param nic_profile:
        Name of the network interfaces profile to use for the new virtual machine

        .. versionadded:: 2019.2.0
    :param interfaces:
        List of network interfaces to create for the new virtual machine.
        See the **Network Interface Definitions** section of the
        :py:func:`virt.init <salt.modules.virt.init>` function for more details
        on the items on this list.

        .. versionadded:: 2019.2.0
    :param graphics:
        Graphics device to create for the new virtual machine.
        See the **Graphics Definition** section of the :py:func:`virt.init
        <salt.modules.virt.init>` function for more details on this dictionary.

        .. versionadded:: 2019.2.0
    :param loader:
        Firmware loader for the new virtual machine.
        See the **Loader Definition** section of the :py:func:`virt.init
        <salt.modules.virt.init>` function for more details on this dictionary.

        .. versionadded:: 2019.2.0
    :param saltenv:
        Fileserver environment (Default: ``'base'``).
        See :mod:`cp module for more details <salt.modules.cp>`

        .. versionadded:: 2019.2.0
    :param seed: ``True`` to seed the disk image. Only used when the ``image`` parameter is provided.
                 (Default: ``True``)

        .. versionadded:: 2019.2.0
    :param install: install salt minion if absent (Default: ``True``)

        .. versionadded:: 2019.2.0
    :param pub_key: public key to seed with (Default: ``None``)

        .. versionadded:: 2019.2.0
    :param priv_key: public key to seed with (Default: ``None``)

        .. versionadded:: 2019.2.0
    :param seed_cmd: Salt command to execute to seed the image. (Default: ``'seed.apply'``)

        .. versionadded:: 2019.2.0
    :param update: set to ``True`` to update a defined module. (Default: ``False``)

        .. versionadded:: 2019.2.0
    :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
    :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``.
        Only used when creating a new virtual machine.

        .. versionadded:: Neon
    :param arch:
        architecture of the virtual machine. The default value is taken from the host capabilities,
        but ``x86_64`` is prefed over ``i686``. Only used when creating a new virtual machine.

        .. versionadded:: Neon

    .. rubric:: Example States

    Make sure an already-defined virtual machine called ``domain_name`` is running:

    .. code-block:: yaml

        domain_name:
          virt.running

    Do the same, but define the virtual machine if needed:

    .. code-block:: yaml

        domain_name:
          virt.running:
            - cpu: 2
            - mem: 2048
            - disk_profile: prod
            - disks:
              - name: system
                size: 8192
                overlay_image: True
                pool: default
                image: /path/to/image.qcow2
              - name: data
                size: 16834
            - nic_profile: prod
            - interfaces:
              - name: eth0
                mac: 01:23:45:67:89:AB
              - name: eth1
                type: network
                source: admin
            - graphics:
              - type: spice
                listen:
                  - type: address
                    address: 192.168.0.125

def running(name,
            cpu=None,
            mem=None,
            image=None,
            vm_type=None,
            disk_profile=None,
            disks=None,
            nic_profile=None,
            interfaces=None,
            graphics=None,
            loader=None,
            seed=True,
            install=True,
            pub_key=None,
            priv_key=None,
            update=False,
            connection=None,
            username=None,
            password=None,
            os_type=None,
            arch=None):
    '''
    Starts an existing guest, or defines and starts a new VM with specified arguments.

    .. versionadded:: 2016.3.0

    :param name: name of the virtual machine to run
    :param cpu: number of CPUs for the virtual machine to create
    :param mem: amount of memory in MiB for the new virtual machine
    :param image: disk image to use for the first disk of the new VM

        .. deprecated:: 2019.2.0
    :param vm_type: force virtual machine type for the new VM. The default value is taken from
        the host capabilities. This could be useful for example to use ``'qemu'`` type instead
        of the ``'kvm'`` one.

        .. versionadded:: 2019.2.0
    :param disk_profile:
        Name of the disk profile to use for the new virtual machine

        .. versionadded:: 2019.2.0
    :param disks:
        List of disk to create for the new virtual machine.
        See the **Disk Definitions** section of the :py:func:`virt.init
        <salt.modules.virt.init>` function for more details on the items on
        this list.

        .. versionadded:: 2019.2.0
    :param nic_profile:
        Name of the network interfaces profile to use for the new virtual machine

        .. versionadded:: 2019.2.0
    :param interfaces:
        List of network interfaces to create for the new virtual machine.
        See the **Network Interface Definitions** section of the
        :py:func:`virt.init <salt.modules.virt.init>` function for more details
        on the items on this list.

        .. versionadded:: 2019.2.0
    :param graphics:
        Graphics device to create for the new virtual machine.
        See the **Graphics Definition** section of the :py:func:`virt.init
        <salt.modules.virt.init>` function for more details on this dictionary.

        .. versionadded:: 2019.2.0
    :param loader:
        Firmware loader for the new virtual machine.
        See the **Loader Definition** section of the :py:func:`virt.init
        <salt.modules.virt.init>` function for more details on this dictionary.

        .. versionadded:: 2019.2.0
    :param saltenv:
        Fileserver environment (Default: ``'base'``).
        See :mod:`cp module for more details <salt.modules.cp>`

        .. versionadded:: 2019.2.0
    :param seed: ``True`` to seed the disk image. Only used when the ``image`` parameter is provided.
                 (Default: ``True``)

        .. versionadded:: 2019.2.0
    :param install: install salt minion if absent (Default: ``True``)

        .. versionadded:: 2019.2.0
    :param pub_key: public key to seed with (Default: ``None``)

        .. versionadded:: 2019.2.0
    :param priv_key: public key to seed with (Default: ``None``)

        .. versionadded:: 2019.2.0
    :param seed_cmd: Salt command to execute to seed the image. (Default: ``'seed.apply'``)

        .. versionadded:: 2019.2.0
    :param update: set to ``True`` to update a defined module. (Default: ``False``)

        .. versionadded:: 2019.2.0
    :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
    :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``.
        Only used when creating a new virtual machine.

        .. versionadded:: Neon
    :param arch:
        architecture of the virtual machine. The default value is taken from the host capabilities,
        but ``x86_64`` is prefed over ``i686``. Only used when creating a new virtual machine.

        .. versionadded:: Neon

    .. rubric:: Example States

    Make sure an already-defined virtual machine called ``domain_name`` is running:

    .. code-block:: yaml

        domain_name:
          virt.running

    Do the same, but define the virtual machine if needed:

    .. code-block:: yaml

        domain_name:
          virt.running:
            - cpu: 2
            - mem: 2048
            - disk_profile: prod
            - disks:
              - name: system
                size: 8192
                overlay_image: True
                pool: default
                image: /path/to/image.qcow2
              - name: data
                size: 16834
            - nic_profile: prod
            - interfaces:
              - name: eth0
                mac: 01:23:45:67:89:AB
              - name: eth1
                type: network
                source: admin
            - graphics:
              - type: spice
                listen:
                  - type: address
                    address: 192.168.0.125

    '''

    ret = {'name': name,
           'changes': {},
           'result': True,
           'comment': '{0} is running'.format(name)
           }

    try:
        try:
            __salt__['virt.vm_state'](name)
            if __salt__['virt.vm_state'](name) != 'running':
                action_msg = 'started'
                if update:
                    status = __salt__['virt.update'](name,
                                                     cpu=cpu,
                                                     mem=mem,
                                                     disk_profile=disk_profile,
                                                     disks=disks,
                                                     nic_profile=nic_profile,
                                                     interfaces=interfaces,
                                                     graphics=graphics,
                                                     live=False,
                                                     connection=connection,
                                                     username=username,
                                                     password=password)
                    if status['definition']:
                        action_msg = 'updated and started'
                __salt__['virt.start'](name)
                ret['changes'][name] = 'Domain {0}'.format(action_msg)
                ret['comment'] = 'Domain {0} {1}'.format(name, action_msg)
            else:
                if update:
                    status = __salt__['virt.update'](name,
                                                     cpu=cpu,
                                                     mem=mem,
                                                     disk_profile=disk_profile,
                                                     disks=disks,
                                                     nic_profile=nic_profile,
                                                     interfaces=interfaces,
                                                     graphics=graphics,
                                                     connection=connection,
                                                     username=username,
                                                     password=password)
                    ret['changes'][name] = status
                    if status.get('errors', None):
                        ret['comment'] = 'Domain {0} updated, but some live update(s) failed'.format(name)
                    elif not status['definition']:
                        ret['comment'] = 'Domain {0} exists and is running'.format(name)
                    else:
                        ret['comment'] = 'Domain {0} updated, restart to fully apply the changes'.format(name)
                else:
                    ret['comment'] = 'Domain {0} exists and is running'.format(name)
        except CommandExecutionError:
            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}.'
                )
            __salt__['virt.init'](name,
                                  cpu=cpu,
                                  mem=mem,
                                  os_type=os_type,
                                  arch=arch,
                                  image=image,
                                  hypervisor=vm_type,
                                  disk=disk_profile,
                                  disks=disks,
                                  nic=nic_profile,
                                  interfaces=interfaces,
                                  graphics=graphics,
                                  loader=loader,
                                  seed=seed,
                                  install=install,
                                  pub_key=pub_key,
                                  priv_key=priv_key,
                                  connection=connection,
                                  username=username,
                                  password=password)
            ret['changes'][name] = 'Domain defined and started'
            ret['comment'] = 'Domain {0} defined and started'.format(name)
    except libvirt.libvirtError as err:
        # Something bad happened when starting / updating the VM, report it
        ret['comment'] = six.text_type(err)
        ret['result'] = False

    return ret