_states/tmp_state.py
author Paul Tonelli <paul.tonelli@logilab.fr>
Tue, 12 Mar 2013 11:51:26 +0100
changeset 66 23a31e4cbb65
parent 51 555bcf9abc33
child 73 dae7b424b347
permissions -rw-r--r--
the scripts now cleans the ssh keys if present as well as the apt cache

# -*- coding: utf-8 -*-
# author: Paul Tonelli <ptonelli@logilab.fr>

import salt.utils
import os

def local_managed(name, source):
    '''
    Manage a file locally: if name is different from source (md5sum), then copy it

    name
        The location of the managed file
    source
        The location of the source file
    '''
    ret = {'name': name,
            'changes': {},
            'result': True,
            'comment':  ''}
    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'Local_copyfile will copy {0} to {1} if they are different'.format(source, name)
        return ret
    if os.path.isdir(name):
        ret['result'] = False
        ret['comment'] = "destination is a directory"
    if os.path.isdir(name) or os.path.isdir(source):
        ret['result'] = False
        ret['comment'] = "Source is a directory"
    if not os.path.exists(source):
        ret['result'] = False
        ret['comment'] = "Source does not exist"
    stats_source = __salt__['file.stats'](source, 'md5')
    if ret['result'] and os.path.exists(name):
        stats_destination = __salt__['file.stats'](name, 'md5')
    else:
        stats_destination = {'sum':''}
    if ret['result'] and stats_source['sum'] != stats_destination['sum']:
        try:
            salt.utils.copyfile(source, name)
            ret['changes']['copy'] = 'copied {0} to {1} with md5sum = {2}'.format(source, name, stats_source['sum'])
        except IOError:
            ret['comment'] = 'IOError'
            ret['result'] = False
    return ret

def umounted(name):
    '''
    Make sure nothing is mounted into name and, if possible, umounts it (fails if it contains others mounts)

    name
        The location of the mounting point
    '''

    ret = {'name': name,
            'changes': {},
            'result': True,
            'comment':  ''}
    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'Umounted will check that there is nothing mounted in {0}, no recursion'.format(name)
        return ret
    active = __salt__['mount.active']()
    if name in active:
        for mount in active:
            if name in mount and str(name) != str(mount) :
                ret['result'] = False
                ret['comment'] = 'cannot umount while subdirectory {0} is a mounting point for {1}'.format(name, mount)
        if ret['result']:
            output = __salt__['mount.umount'](name)
            print type(mount)
            if output == True:
                ret['changes']['umount'] = 'device {1} has been umounted from {0}'.format(name, active[mount]['device'])
            else:
                ret['reslt'] = False
                ret['comment'] = output
    return ret

def resized(name, size=0):
    '''
    Resize partition and filesystem on a file with an ext* fs whenever
    possible (size in Mb) and check the integrity (for ext* fs)

    implemented checks:
        - check if file exists
        - preliminary filesystem check
        - check if there is enough space available

    ### TODO : this scripts can only be used for files containing fs and
    not devices ###

    If no size is provided, will shrink the filesystem to the minimal size

    name
        name of the filesystem to resize

    size
        new size, (can use suffixes like K, M...). If this size is too small,
        the filesystem will be minimized
    '''
    ret = {'name': name,
            'changes': {},
            'result': True,
            'comment':  ''}
    block_size = os.statvfs(name).f_frsize
    new_size = _convert_to_units(size)
    current_size = os.stat(name).st_size / block_size
    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'if possible will resize {0} to size {1}'.format(name, new_size)
        return ret
    if not os.path.isfile(name):
        ret['result'] = False
        ret['comment'] = '{0} is not a file'.format(name, new_size)
        return ret
    additionnal_flags = ''
    minimize = ''
    info = __salt__['cmd.run_all']('e2fsck -n -f ' + name)
    if info['retcode']:
        ret['result'] = False
        ret['comment'] = 'Error while checking fs {0}: {1}'.format(name, info['stderr'])
        return ret
    change_value = new_size - current_size * block_size
    minimum_size = int(__salt__['cmd.run_all']('resize2fs -P -f ' + name)['stdout'].split(':')[-1])
    if abs(change_value) < pow(1024, 2) or (new_size < minimum_size and minimum_size == current_size):
        ret['result'] = True
        ret['comment'] = 'Filesystem {0} is already at the correct/smaller size'.format(name)
        return ret
    if change_value > 0: #increase size
        if not _has_enough_free_space(name, change_value):
            ret['result'] = False
            ret['comment'] = 'Not enough free space'
            return ret
    if minimum_size < new_size: #change size to what asked
        additionnal_flags = ' ' + str(new_size / block_size)
    else: #minimise to min possible
        minimize = '-M '
    info = __salt__['cmd.run_all']('resize2fs -f ' + minimize + name + additionnal_flags)
    if info['retcode']:
        ret['result'] = False
        ret['comment'] = 'Error while resizing {0}: {1}'.format(name, info['stderr'])
        return ret
    if additionnal_flags:
        info = __salt__['cmd.run_all']('fallocate -l ' + str(new_size /
            block_size) + ' ' + name )
    ret['changes']['resized'] = True
    ret['comment'] = 'Resized filesystem {0} from {1} to {2}'.format(name, str(current_size * block_size), str(max(new_size, minimum_size)))
    return ret

def _has_enough_free_space(fs, space):
    info = os.statvfs(fs)
    free_space = (info.f_bavail * info.f_frsize)
    if free_space > space:
        return True
    return False

def _convert_to_units(value):
    '''
    convert value to a float in the correct unit. Accepted units are:
        - K (kilobytes)
        - M (megabytes)
        - G (gigabytes)
        - T (terabytes)
    '''
    conversion_factor={'K': 1, 'M': 2, 'G': 3, 'T': 4}
    if str(value)[-1].isalpha():
        assert str(value)[-1] in conversion_factor
        factor = conversion_factor[str(value)[-1]]
        value = str(value)[:-1]
    else:
        factor = 0
    value=float(value)
    return int(value * pow(1024,factor))