From 570cef8f349a66d6eaa869ba9046626f66875fda Mon Sep 17 00:00:00 2001 From: Erik Johnson Date: Fri, 20 Dec 2013 13:39:37 -0600 Subject: [PATCH] Rewrite memcached state/module --- salt/modules/memcached.py | 259 +++++++++++++++---------- salt/states/memcached.py | 395 ++++++++++---------------------------- 2 files changed, 257 insertions(+), 397 deletions(-) diff --git a/salt/modules/memcached.py b/salt/modules/memcached.py index 0f3dc19a6e..146d242315 100644 --- a/salt/modules/memcached.py +++ b/salt/modules/memcached.py @@ -1,14 +1,17 @@ # -*- coding: utf-8 -*- ''' -Module to provide Memcache functionality to Salt +Module for Management of Memcached Keys +======================================= +.. versionadded:: Hydrogen ''' # Import python libs import logging # Import salt libs -from salt.exceptions import SaltException +from salt.exceptions import CommandExecutionError, SaltInvocationError +from salt._compat import integer_types # Import third party libs try: @@ -17,201 +20,247 @@ try: except ImportError: HAS_MEMCACHE = False - -def __virtual__(): - ''' - Only load if have installed python memcache module - ''' - if not HAS_MEMCACHE: - return False - return 'memcache' +DEFAULT_HOST = '127.0.0.1' +DEFAULT_PORT = 11211 +DEFAULT_TIME = 0 +DEFAULT_MIN_COMPRESS_LEN = 0 log = logging.getLogger(__name__) -# Don't shadow built-in's. +# Don't shadow built-ins __func_alias__ = { 'set_': 'set' } +__virtualname__ = 'memcached' -def _connect(host, port): + +def __virtual__(): + ''' + Only load if python-memcache is installed + ''' + return __virtualname__ if HAS_MEMCACHE else False + + +def _connect(host=DEFAULT_HOST, port=DEFAULT_PORT): ''' Returns a tuple of (user, host, port) with config, pillar, or default values assigned to missing values. ''' - if not host: - host = __salt__['config.option']('memcache.host') - if not port: - port = __salt__['config.option']('memcache.port') - - if not HAS_MEMCACHE: - raise SaltException('Error: python-memcached is not installed.') - else: - if str(port).isdigit(): - conn = memcache.Client(["%s:%s" % (host, port)], debug=0) - else: - raise SaltException('Error: port must be a number.') - - return conn + if str(port).isdigit(): + return memcache.Client(['{0}:{1}'.format(host, port)], debug=0) + raise SaltInvocationError('port must be an integer') -def status(host, port): +def _check_stats(conn): ''' - get memcache status + Helper function to check the stats data passed into it, and raise an + execption if none are returned. Otherwise, the stats are returned. + ''' + stats = conn.get_stats() + if not stats: + raise CommandExecutionError( + 'memcached server is down or does not exist' + ) + return stats + + +def status(host=DEFAULT_HOST, port=DEFAULT_PORT): + ''' + Get memcached status CLI Example: .. code-block:: bash - salt '*' memcache.status + salt '*' memcached.status ''' conn = _connect(host, port) - status = conn.get_stats() - if status == []: + try: + stats = _check_stats(conn)[0] + except (CommandExecutionError, IndexError): return False else: - ret = {} - server = status[0][0] - stats = status[0][1] - ret[server] = stats - - return ret + return {stats[0]: stats[1]} -def get(host, port, key): +def get(key, host=DEFAULT_HOST, port=DEFAULT_PORT): ''' - get key from memcache server + Retrieve value for a key CLI Example: .. code-block:: bash - salt '*' memcache.get + salt '*' memcached.get ''' conn = _connect(host, port) - status = conn.get_stats() - if status == []: - raise SaltException('Error: memcache server is down or not exists.') - else: - return conn.get(key) + _check_stats(conn) + return conn.get(key) -def set_(host, port, key, val, time=0, min_compress_len=0): +def set_(key, + value, + host=DEFAULT_HOST, + port=DEFAULT_PORT, + time=DEFAULT_TIME, + min_compress_len=DEFAULT_MIN_COMPRESS_LEN): ''' - insert key to memcache server + Set a key on the memcached server, overwriting the value if it exists. CLI Example: .. code-block:: bash - salt '*' memcache.set + salt '*' memcached.set ''' + if not isinstance(time, integer_types): + raise SaltInvocationError('\'time\' must be an integer') + if not isinstance(min_compress_len, integer_types): + raise SaltInvocationError('\'min_compress_len\' must be an integer') conn = _connect(host, port) - status = conn.get_stats() - if status == []: - raise SaltException('Error: memcache server is down or not exists.') - else: - ret = conn.set(key, val, time, min_compress_len) - return ret + _check_stats(conn) + return conn.set(key, value, time, min_compress_len) -def delete(host, port, key, time=0): +def delete(key, + host=DEFAULT_HOST, + port=DEFAULT_PORT, + time=DEFAULT_TIME): ''' - delete key from memcache server + Delete a key from memcache server CLI Example: .. code-block:: bash - salt '*' memcache.delete + salt '*' memcached.delete ''' + if not isinstance(time, integer_types): + raise SaltInvocationError('\'time\' must be an integer') conn = _connect(host, port) - status = conn.get_stats() - if status == []: - raise SaltException('Error: memcache server is down or not exists.') - else: - ret = conn.delete(key, time) - if ret: - return True - else: - return False + _check_stats(conn) + return bool(conn.delete(key, time)) -def add(host, port, key, val, time=0, min_compress_len=0): +def add(key, + value, + host=DEFAULT_HOST, + port=DEFAULT_PORT, + time=DEFAULT_TIME, + min_compress_len=DEFAULT_MIN_COMPRESS_LEN): ''' - add key to memcache server + Add a key to the memcached server, but only if it does not exist. Returns + False if the key already exists. CLI Example: .. code-block:: bash - salt '*' memcache.add + salt '*' memcached.add ''' + if not isinstance(time, integer_types): + raise SaltInvocationError('\'time\' must be an integer') + if not isinstance(min_compress_len, integer_types): + raise SaltInvocationError('\'min_compress_len\' must be an integer') conn = _connect(host, port) - status = conn.get_stats() - if status == []: - raise SaltException('Error: memcache server is down or not exists.') - else: - return conn.add(key, val, time=0, min_compress_len=0) + _check_stats(conn) + return conn.add( + key, + value, + time=time, + min_compress_len=min_compress_len + ) -def incr(host, port, key, delta=1): +def replace(key, + value, + host=DEFAULT_HOST, + port=DEFAULT_PORT, + time=DEFAULT_TIME, + min_compress_len=DEFAULT_MIN_COMPRESS_LEN): ''' - incr key + Replace a key on the memcached server. This only succeeds if the key + already exists. This is the opposite of :mod:`memcached.add + ` CLI Example: .. code-block:: bash - salt '*' memcache.incr + salt '*' memcached.replace ''' + if not isinstance(time, integer_types): + raise SaltInvocationError('\'time\' must be an integer') + if not isinstance(min_compress_len, integer_types): + raise SaltInvocationError('\'min_compress_len\' must be an integer') conn = _connect(host, port) status = conn.get_stats() - if status == []: - raise SaltException('Error: memcache server is down or not exists.') - else: - try: - ret = conn.incr(key, delta) - except ValueError: - raise SaltException('Error: incr key must be a number.') - return ret + return conn.replace( + key, + value, + time=time, + min_compress_len=min_compress_len + ) -def decr(host, port, key, delta=1): +def increment(key, delta=1, host=DEFAULT_HOST, port=DEFAULT_PORT): ''' - decr key + Increment the value of a key CLI Example: .. code-block:: bash - salt '*' memcache.decr + salt '*' memcached.increment + salt '*' memcached.increment 2 ''' conn = _connect(host, port) - status = conn.get_stats() - if status == []: - raise SaltException('Error: memcache server is down or not exists.') - else: - try: - ret = conn.decr(key, delta) - except ValueError: - raise SaltException('Error: decr key must be a number.') - return ret + _check_stats(conn) + cur = get(key) + + if cur is None: + raise CommandExecutionError('Key {0!r} does not exist'.format(key)) + elif not isinstance(cur, integer_types): + raise CommandExecutionError( + 'Value for key {0!r} must be an integer to be ' + 'incremented'.format(key) + ) + + try: + return conn.incr(key, delta) + except ValueError: + raise SaltInvocationError('Delta value must be an integer') + +incr = increment -def replace(host, port, key, val, time=0, min_compress_len=0): +def decrement(key, delta=1, host=DEFAULT_HOST, port=DEFAULT_PORT): ''' - replace key from memcache server + Decrement the value of a key CLI Example: .. code-block:: bash - salt '*' memcache.replace + salt '*' memcached.decrement + salt '*' memcached.decrement 2 ''' conn = _connect(host, port) - status = conn.get_stats() - if status == []: - raise SaltException('Error: memcache server is down or not exists.') - else: - return conn.replace(key, val, time=0, min_compress_len=0) + _check_stats(conn) + + cur = get(key) + if cur is None: + raise CommandExecutionError('Key {0!r} does not exist'.format(key)) + elif not isinstance(cur, integer_types): + raise CommandExecutionError( + 'Value for key {0!r} must be an integer to be ' + 'decremented'.format(key) + ) + + try: + return conn.decr(key, delta) + except ValueError: + raise SaltInvocationError('Delta value must be an integer') + +decr = decrement diff --git a/salt/states/memcached.py b/salt/states/memcached.py index f999001025..0bc553e41a 100644 --- a/salt/states/memcached.py +++ b/salt/states/memcached.py @@ -1,357 +1,168 @@ # -*- coding: utf-8 -*- ''' +States for Management of Memcached Keys +======================================= -Management of Memcached Server. -===================================================== - -This module is used to manage memcached server. +.. versionadded:: Hydrogen ''' +from salt.modules.memcached import ( + DEFAULT_HOST, + DEFAULT_PORT, + DEFAULT_TIME, + DEFAULT_MIN_COMPRESS_LEN +) +from salt.exceptions import CommandExecutionError, SaltInvocationError -# Import third party libs -try: - import memcache - HAS_MEMCACHE = True -except ImportError: - HAS_MEMCACHE = False - -# Define a function alias in order not to shadow built-in's -__func_alias__ = { - 'set_': 'set' -} +__virtualname__ = 'memcached' def __virtual__(): ''' - Only load if have installed python memcache module + Only load if memcache module is available ''' - if not HAS_MEMCACHE: - return False - return 'memcache' + return __virtualname__ \ + if '{0}.status'.format(__virtualname__) in __salt__ \ + else False -def set_(name, - host=None, - port=None, - val=None): +def managed(name, + value=None, + host=DEFAULT_HOST, + port=DEFAULT_PORT, + time=DEFAULT_TIME, + min_compress_len=DEFAULT_MIN_COMPRESS_LEN): ''' - Set key to memcached server. + Manage a memcached key. name - The key - - host - The memcached server ip - - port - The memcached server port + The key to manage value - The value - - .. code-block:: yaml - - k1: - memcached.set: - - host: 10.0.0.1 - - port: 11211 - - val: v1 - ''' - ret = {'name': name, - 'changes': {}, - 'result': True, - 'comment': ''} - - #check memcached server - if __salt__['memcached.status'](host, port): - if __opts__['test']: - ret['result'] = None - ret['comment'] = ('set key {0} to memcached server {1}:{2}' - ).format(name, host, port) - return ret - if __salt__['memcached.set'](host, port, name, val): - ret['comment'] = 'set key {0} to memcached server {1}:{2}'.format(name, host, port) - ret['changes'][name] = 'to be set' - return ret - - ret['comment'] = ('memcached server {0}:{1} is down or not exists.' - ).format(host, port) - return ret - - -def get(name, - host=None, - port=None): - ''' - Get key to memcached server. - - name - The key + The value to set for that key host - The memcached server ip + The memcached server IP address port The memcached server port + .. code-block:: yaml - k1: - memcached.get: - - host: 10.0.0.1 - - port: 11211 + foo: + memcached.managed: + - value: bar ''' ret = {'name': name, 'changes': {}, - 'result': True, + 'result': False, 'comment': ''} - #check memcached server - if __salt__['memcached.status'](host, port): - if __opts__['test']: - ret['result'] = None - ret['comment'] = ('get key {0} from memcached server {1}:{2}' - ).format(name, host, port) - return ret - ret['comment'] = __salt__['memcached.get'](host, port, name) + try: + cur = __salt__['memcached.get'](name, host, port) + except CommandExecutionError as exc: + ret['comment'] = str(exc) return ret - ret['comment'] = ('memcached server {0}:{1} is down or not exists.' - ).format(host, port) - return ret + if cur == value: + ret['result'] = True + ret['comment'] = 'Key {0!r} does not need to be updated'.format(name) + return ret - -def delete(name, - host=None, - port=None): - ''' - Delete key from memcached server. - - name - The key - - host - The memcached server ip - - port - The memcached server port - - .. code-block:: yaml - - k1: - memcached.delete: - - host: 10.0.0.1 - - port: 11211 - ''' - ret = {'name': name, - 'changes': {}, - 'result': True, - 'comment': ''} - - #check memcached server - if __salt__['memcached.status'](host, port): - if __opts__['test']: - ret['result'] = None - ret['comment'] = ('delete key {0} from memcached server {1}:{2}' - ).format(name, host, port) - return ret - if __salt__['memcached.delete'](host, port, name): - ret['comment'] = 'delete key {0} from memcached server {1}:{2}'.format(name, host, port) - ret['changes'][name] = 'to be delete' - return ret - - ret['comment'] = ('memcached server {0}:{1} is down or not exists.' - ).format(host, port) - return ret - - -def add(name, - host=None, - port=None, - val=None): - ''' - Add key to memcached server. - - name - The key - - host - The memcached server ip - - port - The memcached server port - - val - The value - - .. code-block:: yaml - - k1: - memcached.add: - - host: 10.0.0.1 - - port: 11211 - - val: v1 - ''' - ret = {'name': name, - 'changes': {}, - 'result': True, - 'comment': ''} - - #check memcached server - if __salt__['memcached.status'](host, port): - if __opts__['test']: - ret['result'] = None - ret['comment'] = ('add key {0} to memcached server {1}:{2}' - ).format(name, host, port) - return ret - if __salt__['memcached.add'](host, port, name, val): - ret['comment'] = 'add key {0} to memcached server {1}:{2}'.format(name, host, port) - ret['changes'][name] = 'to be add' - return ret + if __opts__['test']: + ret['result'] = None + if cur is None: + ret['comment'] = 'Key {0!r} would be added'.format(name) else: - ret['comment'] = 'key {0} is exists in memcached server {1}:{2}'.format(name, host, port) - return ret + ret['comment'] = 'Value of key {0!r} would be changed'.format(name) + return ret - ret['comment'] = ('memcached server {0}:{1} is down or not exists.' - ).format(host, port) + try: + ret['result'] = __salt__['memcached.set']( + name, value, host, port, time, min_compress_len + ) + except (CommandExecutionError, SaltInvocationError) as exc: + ret['comment'] = str(exc) + else: + if ret['result']: + ret['comment'] = 'Successfully set key {0!r}'.format(name) + if cur is not None: + ret['changes'] = {'old': cur, 'new': value} + else: + ret['changes'] = {'key added': name, 'value': value} + else: + ret['comment'] = 'Failed to set key {0!r}'.format(name) return ret -def incr(name, - host=None, - port=None, - delta=1): +def absent(name, + value=None, + host=DEFAULT_HOST, + port=DEFAULT_PORT, + time=DEFAULT_TIME): ''' - Incr key to memcached server. + Ensure that a memcached key is not present. name The key + value : None + If specified, only ensure that the key is absent if it matches the + specified value. + host - The memcached server ip + The memcached server IP address port The memcached server port - delta - The default value is 1 .. code-block:: yaml - k1: - memcached.incr: + foo: + memcached.absent + + bar: + memcached.absent: - host: 10.0.0.1 - - port: 11211 - - delta: 100 ''' ret = {'name': name, 'changes': {}, - 'result': True, + 'result': False, 'comment': ''} - #check memcached server - if __salt__['memcached.status'](host, port): - if __opts__['test']: - ret['result'] = None - ret['comment'] = ('incr key {0} to memcached server {1}:{2}' - ).format(name, host, port) - return ret - ret['comment'] = __salt__['memcached.incr'](host, port, name, delta) + try: + cur = __salt__['memcached.get'](name, host, port) + except CommandExecutionError as exc: + ret['comment'] = str(exc) return ret - ret['comment'] = ('memcached server {0}:{1} is down or not exists.' - ).format(host, port) - return ret - - -def decr(name, - host=None, - port=None, - delta=1): - ''' - Decr key to memcached server. - - name - The key - - host - The memcached server ip - - port - The memcached server port - - delta - The default value is 1 - - .. code-block:: yaml - - k1: - memcached.decr: - - host: 10.0.0.1 - - port: 11211 - - delta: 100 - ''' - ret = {'name': name, - 'changes': {}, - 'result': True, - 'comment': ''} - - #check memcached server - if __salt__['memcached.status'](host, port): - if __opts__['test']: - ret['result'] = None - ret['comment'] = ('decr key {0} to memcached server {1}:{2}' - ).format(name, host, port) + if value is not None: + if cur is not None and cur != value: + ret['result'] = True + ret['comment'] = ( + 'Value of key {0!r} ({1!r}) is not {2!r}' + .format(name, cur, value) + ) return ret - ret['comment'] = __salt__['memcached.decr'](host, port, name, delta) + if cur is None: + ret['result'] = True + ret['comment'] = 'Key {0!r} does not exist'.format(name) return ret - ret['comment'] = ('memcached server {0}:{1} is down or not exists.' - ).format(host, port) - return ret - - -def replace(name, - host=None, - port=None, - val=None): - ''' - Replace key from memcached server. - - name - The key - - host - The memcached server ip - - port - The memcached server port - - Val - The value - - .. code-block:: yaml - - k1: - memcached.replace: - - host: 10.0.0.1 - - port: 11211 - - val: v1 - ''' - ret = {'name': name, - 'changes': {}, - 'result': True, - 'comment': ''} - - #check memcached server - if __salt__['memcached.status'](host, port): - if __opts__['test']: - ret['result'] = None - ret['comment'] = ('replace key {0} from memcached server {1}:{2}' - ).format(name, host, port) - return ret - ret['comment'] = __salt__['memcached.replace'](host, port, name, val) + if __opts__['test']: + ret['result'] = None + ret['comment'] = 'Key {0!r} would be deleted'.format(name) return ret - ret['comment'] = ('memcached server {0}:{1} is down or not exists.' - ).format(host, port) + try: + ret['result'] = __salt__['memcached.delete'](name, host, port, time) + except (CommandExecutionError, SaltInvocationError) as exc: + ret['comment'] = str(exc) + else: + if ret['result']: + ret['comment'] = 'Successfully deleted key {0!r}'.format(name) + ret['changes'] = {'key deleted': name, 'value': cur} + else: + ret['comment'] = 'Failed to delete key {0!r}'.format(name) return ret