salt.cache.etcd3_cache#
Minion data cache plugin for the etcd key/value store, using API v3.
New in version 3009.0.
A from-scratch cache backend built around etcd v3 semantics: a flat
keyspace, native byte values, single-PUT atomicity, and lease-based
expiry. It is not a port of
salt.cache.etcd_cache, which targets the
v2 HTTP API; the two use different etcd APIs and storage and do not share
data.
Storage model#
Each cache entry is a single etcd key whose value is
salt.payload.dumps({"d": <data>, "t": <epoch>}) -- the data and its
modification timestamp wrapped together. A single etcd PUT is atomic, so
there is no sibling timestamp key to keep consistent. The bank/key
hierarchy is mapped to a key path by joining components with /; prefix
operations always use a trailing slash so bank foo does not match keys
under bank foobar.
Concretely, with the default prefix, bank grains key minion-1 is
stored at the etcd key /salt_cache/grains/minion-1 and its value is the
msgpack-encoded {"d": <data>, "t": <epoch>} envelope as raw bytes (not
base64). To inspect the cache directly:
etcdctl get --prefix /salt_cache/
The v2 salt.cache.etcd_cache driver shares
the default /salt_cache prefix, but the etcd v2 and v3 APIs use
independent keyspaces, so the two do not collide even on the same cluster.
No other Salt etcd integration (the etcd execution module, state, or
SDB) writes under this prefix.
Setup#
Install the etcd3-py client:
pip install etcd3-py
Enable as the master's data cache:
cache: etcd3
Optional configuration (defaults shown):
etcd.host: 127.0.0.1
etcd.port: 2379
etcd.username: null
etcd.password: null
etcd.ca: null
etcd.client_cert: null
etcd.client_key: null
etcd.path_prefix: /salt_cache
A profile may be used instead of top-level options by setting
etcd.cache_profile: my_etcd_config on the master and placing the
etcd.* keys under my_etcd_config.
Behaviour notes#
store(bank, key, data, expires=N)with a positiveexpiresattaches the key to an etcd v3 lease with that TTL in seconds; etcd deletes the key when the lease expires. This is used bysalt.authfor token expiry, so expired tokens are reaped by etcd rather than persisting until a manual flush.listandcontainsfollowsalt.cache.localfssemantics:list(bank)returns the immediate children (direct keys and immediate sub-bank names), which is what callers such assalt.utils.master._get_cached_minion_data()expect fromcache.list('minions').flushreturnsTrueon success, matchingsalt.cache.redis_cache.The driver refuses to initialize if
etcd.path_prefixresolves to an empty or root path, so a misconfiguration cannot turn a bank flush into a range-delete at the cluster root.
Migrating from the v2 etcd cache#
The v2 API uses a store isolated from v3, so the v3 cache cannot read v2
data (and cannot interfere with it). Because the master cache is
ephemeral and repopulates as minions check in, migration is just: install
etcd3-py, change cache: etcd to cache: etcd3, and restart the
master. Old v2 keys are orphaned in the v2 store; remove them with
ETCDCTL_API=2 etcdctl rm --recursive /salt_cache if desired.
The one user-visible behaviour change is list: the v2 driver returned
recursive leaf names, so cache.list('minions') produced
['data', 'data', ...]; this driver returns the immediate children
(['minion-1', 'minion-2', ...]).
Value-size limit#
etcd's default --max-request-bytes is 1.5 MiB per request. Grains,
mine returns, tokens and minion keys are well under this, but a large
pillar tree may exceed it, in which case store raises
SaltCacheError wrapping etcdserver: request is too large. Raise
the etcd flag (up to ~10 MiB) or use localfs/redis for very large
pillar.
- salt.cache.etcd3_cache.contains(bank, key)#
Return whether
bank/keyexists, or -- whenkeyisNone-- whether anything exists under the bank prefix (matchingsalt.cache.localfs'sos.path.isdir(bank)semantic).- Raises:
salt.exceptions.SaltCacheError -- On any etcd error.
- salt.cache.etcd3_cache.fetch(bank, key)#
Return the data stored at
bank/key, or{}on a miss (the cache contract every Salt backend honours).- Raises:
salt.exceptions.SaltCacheError -- On any etcd or deserialization error.
- salt.cache.etcd3_cache.flush(bank, key=None)#
Remove
bank/key, or the entirebank(and sub-banks) whenkeyisNone, via a single etcd delete.- Returns:
Trueon success, including the no-op case where nothing was deleted (idempotent; matchessalt.cache.redis_cache).- Raises:
salt.exceptions.SaltCacheError -- On any etcd error.
- salt.cache.etcd3_cache.init_kwargs(kwargs)#
Cache-plugin hook; no per-instance state is needed, so this always returns an empty dict (parity with
salt.cache.redis_cache).
- salt.cache.etcd3_cache.ls(bank)#
Return the immediate children of
bank: direct keys plus immediate sub-bank names, deduplicated. Matchessalt.cache.localfs.Uses a keys-only range scan, so listing a large bank does not transfer the stored values.
- Parameters:
bank -- Bank path. The empty bank
""lists the top-level bank names (thesalt.runners.cache.migrate()case).- Returns:
A
listof child names;[]for an empty or nonexistent bank.- Raises:
salt.exceptions.SaltCacheError -- On any etcd error.
- salt.cache.etcd3_cache.store(bank, key, data, expires=None)#
Store
dataatbank/keyas a single etcd key.- Parameters:
bank -- Bank path. May contain
/for nested banks.key -- Leaf key name within the bank.
data -- Anything serializable by
salt.payload.expires -- If a positive integer, the key is attached to an etcd v3 lease with that TTL in seconds and etcd deletes it on expiry.
None,0or a negative value stores without a lease.
- Returns:
Noneon success.- Raises:
salt.exceptions.SaltCacheError -- On any etcd or serialization error.
- salt.cache.etcd3_cache.updated(bank, key)#
Return the Unix-epoch timestamp at which
bank/keywas last stored, orNoneon a miss.- Raises:
salt.exceptions.SaltCacheError -- On any etcd error.