.. versionchanged:: 2015.8.0

        The :mod:`lxc.created <salt.states.lxc.created>` state has been renamed
        to ``lxc.present``, and the :mod:`lxc.cloned <salt.states.lxc.cloned>`
        state has been merged into this state.

    Create the named container if it does not exist

    name
        The name of the container to be created

    path
        path to the container parent
        default: /var/lib/lxc (system default)

        .. versionadded:: 2015.8.0


    running : False
        * If ``True``, ensure that the container is running
        * If ``False``, ensure that the container is stopped
        * If ``None``, do nothing with regards to the running state of the
          container

        .. versionadded:: 2015.8.0

    clone_from
        Create named container as a clone of the specified container

    snapshot : False
        Use Copy On Write snapshots (LVM). Only supported with ``clone_from``.

    profile
        Profile to use in container creation (see the :ref:`LXC Tutorial
        <tutorial-lxc-profiles-container>` for more information). Values in a
        profile will be overridden by the parameters listed below.

    network_profile
        Network Profile to use in container creation
        (see the :ref:`LXC Tutorial <tutorial-lxc-profiles-container>`
        for more information). Values in a profile will be overridden by
        the parameters listed below.

        .. versionadded:: 2015.5.2

    **Container Creation Arguments**

    template
        The template to use. For example, ``ubuntu`` or ``fedora``.
        For a full list of available templates, check out
        the :mod:`lxc.templates <salt.modules.lxc.templates>` function.

        Conflicts with the ``image`` argument.

        .. note::

            The ``download`` template requires the following three parameters
            to be defined in ``options``:

            * **dist** - The name of the distribution
            * **release** - Release name/version
            * **arch** - Architecture of the container

            The available images can be listed using the :mod:`lxc.images
            <salt.modules.lxc.images>` function.

    options

        .. versionadded:: 2015.5.0

        Template-specific options to pass to the lxc-create command. These
        correspond to the long options (ones beginning with two dashes) that
        the template script accepts. For example:

        .. code-block:: yaml

            web01:
              lxc.present:
                - template: download
                - options:
                    dist: centos
                    release: 6
                    arch: amd64

        Remember to double-indent the options, due to :ref:`how PyYAML works
        <nested-dict-indentation>`.

        For available template options, refer to the lxc template scripts
        which are ususally located under ``/usr/share/lxc/templates``,
        or run ``lxc-create -t <template> -h``.

    image
        A tar archive to use as the rootfs for the container. Conflicts with
        the ``template`` argument.

    backing
        The type of storage to use. Set to ``lvm`` to use an LVM group.
        Defaults to filesystem within /var/lib/lxc.

    fstype
        Filesystem type to use on LVM logical volume

    size
        Size of the volume to create. Only applicable if ``backing`` is set to
        ``lvm``.

    vgname : lxc
        Name of the LVM volume group in which to create the volume for this
        container. Only applicable if ``backing`` is set to ``lvm``.

    lvname
        Name of the LVM logical volume in which to create the volume for this
        container. Only applicable if ``backing`` is set to ``lvm``.

    thinpool
        Name of a pool volume that will be used for thin-provisioning this
        container. Only applicable if ``backing`` is set to ``lvm``.

def present(name,
            running=None,
            clone_from=None,
            snapshot=False,
            profile=None,
            network_profile=None,
            template=None,
            options=None,
            image=None,
            config=None,
            fstype=None,
            size=None,
            backing=None,
            vgname=None,
            lvname=None,
            thinpool=None,
            path=None):
    '''
    .. versionchanged:: 2015.8.0

        The :mod:`lxc.created <salt.states.lxc.created>` state has been renamed
        to ``lxc.present``, and the :mod:`lxc.cloned <salt.states.lxc.cloned>`
        state has been merged into this state.

    Create the named container if it does not exist

    name
        The name of the container to be created

    path
        path to the container parent
        default: /var/lib/lxc (system default)

        .. versionadded:: 2015.8.0


    running : False
        * If ``True``, ensure that the container is running
        * If ``False``, ensure that the container is stopped
        * If ``None``, do nothing with regards to the running state of the
          container

        .. versionadded:: 2015.8.0

    clone_from
        Create named container as a clone of the specified container

    snapshot : False
        Use Copy On Write snapshots (LVM). Only supported with ``clone_from``.

    profile
        Profile to use in container creation (see the :ref:`LXC Tutorial
        <tutorial-lxc-profiles-container>` for more information). Values in a
        profile will be overridden by the parameters listed below.

    network_profile
        Network Profile to use in container creation
        (see the :ref:`LXC Tutorial <tutorial-lxc-profiles-container>`
        for more information). Values in a profile will be overridden by
        the parameters listed below.

        .. versionadded:: 2015.5.2

    **Container Creation Arguments**

    template
        The template to use. For example, ``ubuntu`` or ``fedora``.
        For a full list of available templates, check out
        the :mod:`lxc.templates <salt.modules.lxc.templates>` function.

        Conflicts with the ``image`` argument.

        .. note::

            The ``download`` template requires the following three parameters
            to be defined in ``options``:

            * **dist** - The name of the distribution
            * **release** - Release name/version
            * **arch** - Architecture of the container

            The available images can be listed using the :mod:`lxc.images
            <salt.modules.lxc.images>` function.

    options

        .. versionadded:: 2015.5.0

        Template-specific options to pass to the lxc-create command. These
        correspond to the long options (ones beginning with two dashes) that
        the template script accepts. For example:

        .. code-block:: yaml

            web01:
              lxc.present:
                - template: download
                - options:
                    dist: centos
                    release: 6
                    arch: amd64

        Remember to double-indent the options, due to :ref:`how PyYAML works
        <nested-dict-indentation>`.

        For available template options, refer to the lxc template scripts
        which are ususally located under ``/usr/share/lxc/templates``,
        or run ``lxc-create -t <template> -h``.

    image
        A tar archive to use as the rootfs for the container. Conflicts with
        the ``template`` argument.

    backing
        The type of storage to use. Set to ``lvm`` to use an LVM group.
        Defaults to filesystem within /var/lib/lxc.

    fstype
        Filesystem type to use on LVM logical volume

    size
        Size of the volume to create. Only applicable if ``backing`` is set to
        ``lvm``.

    vgname : lxc
        Name of the LVM volume group in which to create the volume for this
        container. Only applicable if ``backing`` is set to ``lvm``.

    lvname
        Name of the LVM logical volume in which to create the volume for this
        container. Only applicable if ``backing`` is set to ``lvm``.

    thinpool
        Name of a pool volume that will be used for thin-provisioning this
        container. Only applicable if ``backing`` is set to ``lvm``.
    '''
    ret = {'name': name,
           'result': True,
           'comment': 'Container \'{0}\' already exists'.format(name),
           'changes': {}}

    if not any((template, image, clone_from)):
        # Take a peek into the profile to see if there is a clone source there.
        # Otherwise, we're assuming this is a template/image creation. Also
        # check to see if none of the create types are in the profile. If this
        # is the case, then bail out early.
        c_profile = __salt__['lxc.get_container_profile'](profile)
        if not any(x for x in c_profile
                   if x in ('template', 'image', 'clone_from')):
            ret['result'] = False
            ret['comment'] = ('No template, image, or clone_from parameter '
                              'was found in either the state\'s arguments or '
                              'the LXC profile')
        else:
            try:
                # Assign the profile's clone_from param to the state, so that
                # we know to invoke lxc.clone to create the container.
                clone_from = c_profile['clone_from']
            except KeyError:
                pass

    # Sanity check(s)
    if clone_from and not __salt__['lxc.exists'](clone_from, path=path):
        ret['result'] = False
        ret['comment'] = ('Clone source \'{0}\' does not exist'
                          .format(clone_from))
    if not ret['result']:
        return ret

    action = 'cloned from {0}'.format(clone_from) if clone_from else 'created'

    state = {'old': __salt__['lxc.state'](name, path=path)}
    if __opts__['test']:
        if state['old'] is None:
            ret['comment'] = (
                'Container \'{0}\' will be {1}'.format(
                    name,
                    'cloned from {0}'.format(clone_from) if clone_from
                    else 'created')
            )
            ret['result'] = None
            return ret
        else:
            if running is None:
                # Container exists and we're not managing whether or not it's
                # running. Set the result back to True and return
                return ret
            elif running:
                if state['old'] in ('frozen', 'stopped'):
                    ret['comment'] = (
                        'Container \'{0}\' would be {1}'.format(
                            name,
                            'unfrozen' if state['old'] == 'frozen'
                                else 'started'
                        )
                    )
                    ret['result'] = None
                    return ret
                else:
                    ret['comment'] += ' and is running'
                    return ret
            else:
                if state['old'] in ('frozen', 'running'):
                    ret['comment'] = (
                        'Container \'{0}\' would be stopped'.format(name)
                    )
                    ret['result'] = None
                    return ret
                else:
                    ret['comment'] += ' and is stopped'
                    return ret

    if state['old'] is None:
        # Container does not exist
        try:
            if clone_from:
                result = __salt__['lxc.clone'](name,
                                               clone_from,
                                               profile=profile,
                                               network_profile=network_profile,
                                               snapshot=snapshot,
                                               size=size,
                                               path=path,
                                               backing=backing)
            else:
                result = __salt__['lxc.create'](
                    name,
                    profile=profile,
                    network_profile=network_profile,
                    template=template,
                    options=options,
                    image=image,
                    config=config,
                    fstype=fstype,
                    size=size,
                    backing=backing,
                    vgname=vgname,
                    path=path,
                    lvname=lvname,
                    thinpool=thinpool)
        except (CommandExecutionError, SaltInvocationError) as exc:
            ret['result'] = False
            ret['comment'] = exc.strerror
        else:
            if clone_from:
                ret['comment'] = ('Cloned container \'{0}\' as \'{1}\''
                                  .format(clone_from, name))
            else:
                ret['comment'] = 'Created container \'{0}\''.format(name)
            state['new'] = result['state']['new']

    if ret['result'] is True:
        # Enforce the "running" parameter
        if running is None:
            # Don't do anything
            pass
        elif running:
            c_state = __salt__['lxc.state'](name, path=path)
            if c_state == 'running':
                ret['comment'] += ' and is running'
            else:
                error = ', but it could not be started'
                try:
                    start_func = 'lxc.unfreeze' if c_state == 'frozen' \
                        else 'lxc.start'
                    state['new'] = __salt__[start_func](
                        name, path=path
                    )['state']['new']
                    if state['new'] != 'running':
                        ret['result'] = False
                        ret['comment'] += error
                except (SaltInvocationError, CommandExecutionError) as exc:
                    ret['result'] = False
                    ret['comment'] += '{0}: {1}'.format(error, exc)
                else:
                    if state['old'] is None:
                        ret['comment'] += ', and the container was started'
                    else:
                        ret['comment'] = (
                            'Container \'{0}\' was {1}'.format(
                                name,
                                'unfrozen' if state['old'] == 'frozen'
                                    else 'started'
                            )
                        )

        else:
            c_state = __salt__['lxc.state'](name, path=path)
            if c_state == 'stopped':
                if state['old'] is not None:
                    ret['comment'] += ' and is stopped'
            else:
                error = ', but it could not be stopped'
                try:
                    state['new'] = __salt__['lxc.stop'](
                        name, path=path
                    )['state']['new']
                    if state['new'] != 'stopped':
                        ret['result'] = False
                        ret['comment'] += error
                except (SaltInvocationError, CommandExecutionError) as exc:
                    ret['result'] = False
                    ret['comment'] += '{0}: {1}'.format(error, exc)
                else:
                    if state['old'] is None:
                        ret['comment'] += ', and the container was stopped'
                    else:
                        ret['comment'] = ('Container \'{0}\' was stopped'
                                          .format(name))

    if 'new' not in state:
        # Make sure we know the final state of the container before we return
        state['new'] = __salt__['lxc.state'](name, path=path)
    if state['old'] != state['new']:
        ret['changes']['state'] = state
    return ret