Rewrite memcached state/module

This commit is contained in:
Erik Johnson 2013-12-20 13:39:37 -06:00
parent 99ad03ca99
commit 570cef8f34
2 changed files with 257 additions and 397 deletions

View File

@ -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 <host> <port>
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 <host> <port> <key>
salt '*' memcached.get <key>
'''
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 <host> <port> <key>
salt '*' memcached.set <key> <value>
'''
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 <host> <port> <key>
salt '*' memcached.delete <key>
'''
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 <host> <port> <key> <val>
salt '*' memcached.add <key> <value>
'''
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
<salt.modules.memcached.add>`
CLI Example:
.. code-block:: bash
salt '*' memcache.incr <host> <port> <key> <delta>
salt '*' memcached.replace <key> <value>
'''
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 <host> <port> <key> <delta>
salt '*' memcached.increment <key>
salt '*' memcached.increment <key> 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 <host> <port> <key> <val>
salt '*' memcached.decrement <key>
salt '*' memcached.decrement <key> 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

View File

@ -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