Beispiel #1
0
def get(zpool, prop=None, show_source=False, parsable=False):
    '''
    .. versionadded:: 2016.3.0

    Retrieves the given list of properties

    zpool : string
        Name of storage pool

    prop : string
        Optional name of property to retrieve

    show_source : boolean
        Show source of property

    parsable : boolean
        Display numbers in parsable (exact) values

        .. versionadded:: 2018.3.0

    CLI Example:

    .. code-block:: bash

        salt '*' zpool.get myzpool
    '''
    ret = OrderedDict()
    ret[zpool] = OrderedDict()

    properties = 'property,value,source'.split(',')

    # get zpool list data
    zpool_cmd = _check_zpool()
    cmd = '{zpool_cmd} get -H -o {properties}{parsable} {prop} {zpool}'.format(
        zpool_cmd=zpool_cmd,
        properties=','.join(properties),
        parsable=' -p' if parsable else '',
        prop=prop if prop else 'all',
        zpool=zpool)
    res = __salt__['cmd.run_all'](cmd, python_shell=False)
    if res['retcode'] != 0:
        ret['error'] = res['stderr'] if 'stderr' in res else res['stdout']
        return ret

    # parse zpool list data
    for zp in res['stdout'].splitlines():
        zp = zp.split("\t")
        zp_data = {}

        for prop in properties:
            zp_data[prop] = _conform_value(zp[properties.index(prop)])

        if show_source:
            ret[zpool][zp_data['property']] = zp_data
            del ret[zpool][zp_data['property']]['property']
        else:
            ret[zpool][zp_data['property']] = zp_data['value']

    return ret
Beispiel #2
0
def snapshot_present(name, recursive=False, properties=None):
    '''
    ensure snapshot exists and has properties set

    name : string
        name of snapshot
    recursive : boolean
        recursively create snapshots of all descendent datasets
    properties : dict
        additional zfs properties (-o)

    .. note:
        Properties are only set at creation time

    '''
    ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''}

    # check params
    if not properties:
        properties = {}

    log.debug('zfs.snapshot_present::%s::config::recursive = %s', name,
              recursive)
    log.debug('zfs.snapshot_present::%s::config::properties = %s', name,
              properties)

    for prop in properties:
        properties[prop] = _conform_value(properties[prop], True)

    if '@' not in name:
        ret['result'] = False
        ret['comment'] = 'invalid snapshot name: {0}'.format(name)
        return ret

    if __salt__['zfs.exists'](name, **{'type': 'snapshot'}):  # we are all good
        ret['comment'] = 'snapshot already exists'
    else:  # create snapshot
        result = {name: 'snapshotted'}
        if not __opts__['test']:
            result = __salt__['zfs.snapshot'](name, **{
                'recursive': recursive,
                'properties': properties
            })

        ret['result'] = name in result and result[name] == 'snapshotted'
        if ret['result']:
            ret['changes'][name] = properties if len(
                properties) > 0 else result[name]
            ret['comment'] = 'snapshot {0} was created'.format(name)
        else:
            ret['comment'] = 'failed to create snapshot {0}'.format(name)
            if name in result:
                ret['comment'] = result[name]

    return ret
Beispiel #3
0
def _zfs_pool_data():
    '''
    Provide grains about zpools
    '''
    grains = {}

    # collect zpool data
    zpool_cmd = salt.utils.path.which('zpool')
    for zpool in __salt__['cmd.run']('{zpool} list -H -p -o name,size'.format(zpool=zpool_cmd)).splitlines():
        if 'zpool' not in grains:
            grains['zpool'] = {}
        zpool = zpool.split()
        grains['zpool'][zpool[0]] = _conform_value(zpool[1], True)

    # return grain data
    return grains
Beispiel #4
0
def set(zpool, prop, value):
    '''
    .. versionadded:: 2016.3.0

    Sets the given property on the specified pool

    zpool : string
        name of storage pool
    prop : string
        name of property
    value : string
        value to set property to

    CLI Example:

    .. code-block:: bash

        salt '*' zpool.set myzpool readonly yes
    '''
    ret = {}
    ret[zpool] = {}

    # make sure value is what zfs expects
    value = _conform_value(value)

    # get zpool list data
    zpool_cmd = _check_zpool()
    cmd = '{zpool_cmd} set {prop}={value} {zpool}'.format(
        zpool_cmd=zpool_cmd,
        prop=prop,
        value=value,
        zpool=zpool
    )
    res = __salt__['cmd.run_all'](cmd, python_shell=False)
    if res['retcode'] != 0:
        ret[zpool][prop] = res['stderr'] if 'stderr' in res else res['stdout']
    else:
        ret[zpool][prop] = value
    return ret
Beispiel #5
0
def volume_present(name,
                   volume_size,
                   sparse=False,
                   create_parent=False,
                   properties=None,
                   cloned_from=None):
    '''
    ensure volume exists and has properties set

    name : string
        name of volume
    volume_size : string
        size of volume
    sparse : boolean
        create sparse volume
    create_parent : boolean
        creates all the non-existing parent datasets.
        any property specified on the command line using the -o option is ignored.
    cloned_from : string
        name of snapshot to clone
    properties : dict
        additional zfs properties (-o)

    .. note::
        ``cloned_from`` is only use if the volume does not exist yet,
        when ``cloned_from`` is set after the volume exists it will be ignored.

    .. note::
        Properties do not get cloned, if you specify the properties in the state file
        they will be applied on a subsequent run.

        ``volume_size`` is considered a property, so the volume's size will be
        corrected when the properties get updated if it differs from the
        original volume.

        The sparse parameter is ignored when using ``cloned_from``.

    '''
    ret = {'name': name, 'changes': {}, 'result': True, 'comment': ''}

    # check params
    if not properties:
        properties = {}

    log.debug('zfs.volume_present::%s::config::volume_size = %s', name,
              volume_size)
    log.debug('zfs.volume_present::%s::config::sparse = %s', name, sparse)
    log.debug('zfs.volume_present::%s::config::create_parent = %s', name,
              create_parent)
    log.debug('zfs.volume_present::%s::config::cloned_from = %s', name,
              cloned_from)
    log.debug('zfs.volume_present::%s::config::properties = %s', name,
              properties)

    volume_size = _conform_value(volume_size, True)
    for prop in properties:
        properties[prop] = _conform_value(properties[prop], True)

    if '@' in name or '#' in name:
        ret['result'] = False
        ret['comment'] = 'invalid filesystem or volume name: {0}'.format(name)
        return ret

    if cloned_from:
        if '@' not in cloned_from:
            ret['result'] = False
            ret['comment'] = '{0} is not a snapshot'.format(cloned_from)
            return ret

        if not __salt__['zfs.exists'](cloned_from, **{'type': 'snapshot'}):
            ret['result'] = False
            ret['comment'] = 'snapshot {0} does not exist'.format(cloned_from)
            return ret

        cloned_parent = cloned_from[:cloned_from.index('@')]
        if not __salt__['zfs.exists'](cloned_parent, **{'type': 'volume'}):
            ret['result'] = False
            ret['comment'] = 'snapshot {0} is not from a volume'.format(
                cloned_from)
            return ret

    if __salt__['zfs.exists'](name, **{
            'type': 'volume'
    }):  # update properties if needed
        properties['volsize'] = volume_size  # add volume_size to properties
        result = __salt__['zfs.get'](name, **{
            'properties': ','.join(properties.keys()),
            'fields': 'value',
            'depth': 1,
            'parsable': True
        })

        for prop in properties:
            if properties[prop] != result[name][prop]['value']:
                if name not in ret['changes']:
                    ret['changes'][name] = {}
                ret['changes'][name][prop] = properties[prop]

        if len(ret['changes']) > 0:
            if not __opts__['test']:
                result = __salt__['zfs.set'](name, **ret['changes'][name])
                if name not in result:
                    ret['result'] = False
                else:
                    for prop in result[name]:
                        if result[name][prop] != 'set':
                            ret['result'] = False

            if ret['result']:
                ret['comment'] = 'volume {0} was updated'.format(name)
            else:
                ret['changes'] = {}
                ret['comment'] = 'volume {0} failed to be updated'.format(name)
        else:
            ret['comment'] = 'volume {0} is up to date'.format(name)
    else:  # create volume
        result = {name: 'created'}
        if not __opts__['test']:
            if not cloned_from:
                result = __salt__['zfs.create'](name, **{
                    'volume_size': volume_size,
                    'sparse': sparse,
                    'create_parent': create_parent,
                    'properties': properties
                })
            else:
                result = __salt__['zfs.clone'](cloned_from, name, **{
                    'create_parent': create_parent,
                    'properties': properties
                })

        ret['result'] = name in result
        if ret['result']:
            ret['result'] = result[name] == 'created' or result[
                name].startswith('cloned')
        if ret['result']:
            ret['changes'][name] = properties if len(
                properties) > 0 else result[name]
            ret['comment'] = 'volume {0} was created'.format(name)
        else:
            ret['comment'] = 'failed to create volume {0}'.format(name)
            if name in result:
                ret['comment'] = result[name]
    return ret
Beispiel #6
0
def split(zpool, newzpool, **kwargs):
    '''
    .. versionadded:: Oxygen

    Splits devices off pool creating newpool.

    .. note::

        All vdevs in pool must be mirrors.  At the time of the split,
        newpool will be a replica of pool.

    zpool : string
        name of storage pool
    newzpool : string
        name of new storage pool
    mountpoint : string
        sets the mount point for the root dataset
    altroot : string
        sets altroot for newzpool
    properties : dict
        additional pool properties for newzpool

    CLI Example:

    .. code-block:: bash

        salt '*' zpool.split datamirror databackup
        salt '*' zpool.split datamirror databackup altroot=/backup

    .. note::

        Zpool properties can be specified at the time of creation of the pool by
        passing an additional argument called "properties" and specifying the properties
        with their respective values in the form of a python dictionary::

            properties="{'property1': 'value1', 'property2': 'value2'}"

        Example:

        .. code-block:: bash

            salt '*' zpool.split datamirror databackup properties="{'readonly': 'on'}"
    '''
    ret = {}

    # Check if the pool_name is already being used
    if __salt__['zpool.exists'](newzpool):
        ret[newzpool] = 'storage pool already exists'
        return ret

    if not __salt__['zpool.exists'](zpool):
        ret[zpool] = 'storage pool does not exists'
        return ret

    zpool_cmd = _check_zpool()
    altroot = kwargs.get('altroot', None)
    properties = kwargs.get('properties', None)
    cmd = '{0} split'.format(zpool_cmd)

    # apply extra arguments from kwargs
    if properties:  # create "-o property=value" pairs
        proplist = []
        for prop in properties:
            proplist.append('-o {0}={1}'.format(prop, _conform_value(properties[prop])))
        cmd = '{0} {1}'.format(cmd, ' '.join(proplist))
    if altroot:  # set altroot
        cmd = '{0} -R {1}'.format(cmd, altroot)
    cmd = '{0} {1} {2}'.format(cmd, zpool, newzpool)

    # Create storage pool
    res = __salt__['cmd.run_all'](cmd, python_shell=False)

    # Check and see if the pools is available
    if res['retcode'] != 0:
        ret[newzpool] = res['stderr'] if 'stderr' in res else res['stdout']
    else:
        ret[newzpool] = 'split off from {}'.format(zpool)

    return ret
Beispiel #7
0
def create(zpool, *vdevs, **kwargs):
    '''
    .. versionadded:: 2015.5.0
    .. versionchanged:: 2016.3.0

    Create a simple zpool, a mirrored zpool, a zpool having nested VDEVs, a hybrid zpool with cache, spare and log drives or a zpool with RAIDZ-1, RAIDZ-2 or RAIDZ-3

    zpool : string
        name of storage pool
    *vdevs : string
        one or move devices
    force : boolean
        forces use of vdevs, even if they appear in use or specify a conflicting replication level.
    mountpoint : string
        sets the mount point for the root dataset
    altroot : string
        equivalent to "-o cachefile=none,altroot=root"
    properties : dict
        additional pool properties
    filesystem_properties : dict
        additional filesystem properties
    createboot : boolean
        ..versionadded:: Oxygen
        create a boot partition

    CLI Example:

    .. code-block:: bash

        salt '*' zpool.create myzpool /path/to/vdev1 [...] [force=True|False]
        salt '*' zpool.create myzpool mirror /path/to/vdev1 /path/to/vdev2 [...] [force=True|False]
        salt '*' zpool.create myzpool raidz1 /path/to/vdev1 /path/to/vdev2 raidz2 /path/to/vdev3 /path/to/vdev4 /path/to/vdev5 [...] [force=True|False]
        salt '*' zpool.create myzpool mirror /path/to/vdev1 [...] mirror /path/to/vdev2 /path/to/vdev3 [...] [force=True|False]
        salt '*' zpool.create myhybridzpool mirror /tmp/file1 [...] log mirror /path/to/vdev1 [...] cache /path/to/vdev2 [...] spare /path/to/vdev3 [...] [force=True|False]

    .. note::

        Zpool properties can be specified at the time of creation of the pool by
        passing an additional argument called "properties" and specifying the properties
        with their respective values in the form of a python dictionary::

            properties="{'property1': 'value1', 'property2': 'value2'}"

        Filesystem properties can be specified at the time of creation of the pool by
        passing an additional argument called "filesystem_properties" and specifying the properties
        with their respective values in the form of a python dictionary::

            filesystem_properties="{'property1': 'value1', 'property2': 'value2'}"

        Example:

        .. code-block:: bash

            salt '*' zpool.create myzpool /path/to/vdev1 [...] properties="{'property1': 'value1', 'property2': 'value2'}"
    '''
    ret = {}

    # Check if the pool_name is already being used
    if __salt__['zpool.exists'](zpool):
        ret[zpool] = 'storage pool already exists'
        return ret

    if not vdevs:
        ret[zpool] = 'no devices specified'
        return ret

    devs = ' '.join(vdevs)
    zpool_cmd = _check_zpool()
    force = kwargs.get('force', False)
    altroot = kwargs.get('altroot', None)
    createboot = kwargs.get('createboot', False)
    mountpoint = kwargs.get('mountpoint', None)
    properties = kwargs.get('properties', None)
    filesystem_properties = kwargs.get('filesystem_properties', None)
    cmd = '{0} create'.format(zpool_cmd)

    # bootsize implies createboot
    if properties and 'bootsize' in properties:
        createboot = True

    # make sure values are in the format zfs expects
    if properties:
        for prop in properties:
            properties[prop] = _conform_value(properties[prop])

    if filesystem_properties:
        for prop in filesystem_properties:
            filesystem_properties[prop] = _conform_value(filesystem_properties[prop])

    # apply extra arguments from kwargs
    if force:  # force creation
        cmd = '{0} -f'.format(cmd)
    if createboot:  # create boot paritition
        cmd = '{0} -B'.format(cmd)
    if properties:  # create "-o property=value" pairs
        proplist = []
        for prop in properties:
            proplist.append('-o {0}={1}'.format(prop, properties[prop]))
        cmd = '{0} {1}'.format(cmd, ' '.join(proplist))
    if filesystem_properties:  # create "-O property=value" pairs
        fsproplist = []
        for prop in filesystem_properties:
            fsproplist.append('-O {0}={1}'.format(prop, filesystem_properties[prop]))
        cmd = '{0} {1}'.format(cmd, ' '.join(fsproplist))
    if mountpoint:  # set mountpoint
        cmd = '{0} -m {1}'.format(cmd, mountpoint)
    if altroot:  # set altroot
        cmd = '{0} -R {1}'.format(cmd, altroot)
    cmd = '{0} {1} {2}'.format(cmd, zpool, devs)

    # Create storage pool
    res = __salt__['cmd.run_all'](cmd, python_shell=False)

    # Check and see if the pools is available
    if res['retcode'] != 0:
        ret[zpool] = res['stderr'] if 'stderr' in res else res['stdout']
    else:
        ret[zpool] = 'created with {0}'.format(devs)

    return ret
Beispiel #8
0
def list_(properties='size,alloc,free,cap,frag,health', zpool=None, parsable=False):
    '''
    .. versionadded:: 2015.5.0
    .. versionchanged:: Oxygen

    Return information about (all) storage pools

    zpool : string
        optional name of storage pool
    properties : string
        comma-separated list of properties to list
    parsable : boolean
        display numbers in parsable (exact) values
        .. versionadded:: Oxygen

    .. note::
        the 'name' property will always be included, the 'frag' property will get removed if not available

    zpool : string
        optional zpool

    .. note::
        multiple storage pool can be provded as a space separated list

    CLI Example:

    .. code-block:: bash

        salt '*' zpool.list
        salt '*' zpool.list zpool=tank
        salt '*' zpool.list 'size,free'
        salt '*' zpool.list 'size,free' tank
    '''
    ret = OrderedDict()

    # remove 'frag' property if not available
    properties = properties.split(',')
    if 'name' in properties:
        properties.remove('name')
    properties.insert(0, 'name')
    if not _check_features() and 'frag' in properties:
        properties.remove('frag')

    # get zpool list data
    zpool_cmd = _check_zpool()
    cmd = '{zpool_cmd} list -H -o {properties}{parsable}{zpool}'.format(
        zpool_cmd=zpool_cmd,
        properties=','.join(properties),
        parsable=' -p' if parsable else '',
        zpool=' {0}'.format(zpool) if zpool else ''
    )
    res = __salt__['cmd.run_all'](cmd, python_shell=False)
    if res['retcode'] != 0:
        ret['error'] = res['stderr'] if 'stderr' in res else res['stdout']
        return ret

    # parse zpool list data
    for zp in res['stdout'].splitlines():
        zp = zp.split("\t")
        zp_data = {}

        for prop in properties:
            zp_data[prop] = _conform_value(zp[properties.index(prop)])

        ret[zp_data['name']] = zp_data
        del ret[zp_data['name']]['name']

    return ret