Skip to content

Commit f014a6f

Browse files
committed
PillarCache: reimplement using salt.cache
took the liberty of making it a proper subclass in the process. this now uses the salt.cache infrastructure such that it can be driven by the base cache driver or a different one if so desired. functionality should be equivalent, including using the base bank=pillar key=minion_id for merged pillar, such that minion_data_cache can take advantage of the same cache. because we are updating the cache at the source, we no longer need to update the cache in master/masterapi.
1 parent a4afc6b commit f014a6f

File tree

5 files changed

+92
-143
lines changed

5 files changed

+92
-143
lines changed

salt/cache/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,12 @@ def __init__(self, opts, cachedir=None, **kwargs):
6363
self.cachedir = opts.get("cachedir", salt.syspaths.CACHE_DIR)
6464
else:
6565
self.cachedir = cachedir
66-
self.driver = opts.get("cache", salt.config.DEFAULT_MASTER_OPTS["cache"])
66+
67+
if "driver" in kwargs:
68+
self.driver = kwargs["driver"]
69+
else:
70+
self.driver = opts.get("cache", salt.config.DEFAULT_MASTER_OPTS["cache"])
71+
6772
self._modules = None
6873
self._kwargs = kwargs
6974
self._kwargs["cachedir"] = self.cachedir

salt/config/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,8 @@ def _gather_buffer_space():
10161016
"signing_algorithm": str,
10171017
# Master publish channel signing
10181018
"publish_signing_algorithm": str,
1019+
# optional cache driver for pillar cache
1020+
"pillar.cache_driver": (type(None), str),
10191021
}
10201022
)
10211023

@@ -1679,6 +1681,7 @@ def _gather_buffer_space():
16791681
"cluster_pool_port": 4520,
16801682
"features": {},
16811683
"publish_signing_algorithm": "PKCS1v15-SHA1",
1684+
"pillar.cache_driver": None,
16821685
}
16831686
)
16841687

salt/daemons/masterapi.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,6 @@ def _pillar(self, load):
768768
)
769769
data = pillar.compile_pillar()
770770
if self.opts.get("minion_data_cache", False):
771-
self.cache.store("pillar", load["id"], data)
772771
self.cache.store("grains", load["id"], load["grains"])
773772
if self.opts.get("minion_data_cache_events") is True:
774773
self.event.fire_event(

salt/master.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,6 @@ def _pillar(self, load):
17891789
self.fs_.update_opts()
17901790
if self.opts.get("minion_data_cache", False):
17911791
self.masterapi.cache.store("grains", load["id"], load["grains"])
1792-
self.masterapi.cache.store("pillar", load["id"], data)
17931792

17941793
if self.opts.get("minion_data_cache_events") is True:
17951794
self.event.fire_event(

salt/pillar/__init__.py

Lines changed: 83 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,25 @@
44

55
import collections
66
import copy
7+
import datetime
78
import fnmatch
89
import logging
9-
import os
1010
import sys
1111
import time
1212
import traceback
1313

1414
import tornado.gen
1515

16+
import salt.cache
1617
import salt.channel.client
1718
import salt.fileclient
1819
import salt.loader
1920
import salt.minion
2021
import salt.utils.args
21-
import salt.utils.cache
2222
import salt.utils.crypt
2323
import salt.utils.data
2424
import salt.utils.dictupdate
25+
import salt.utils.master
2526
import salt.utils.url
2627
from salt.exceptions import SaltClientError
2728
from salt.template import compile_template
@@ -393,144 +394,6 @@ def __del__(self):
393394
# pylint: enable=W1701
394395

395396

396-
class PillarCache:
397-
"""
398-
Return a cached pillar if it exists, otherwise cache it.
399-
400-
Pillar caches are structed in two diminensions: minion_id with a dict of
401-
saltenvs. Each saltenv contains a pillar dict
402-
403-
Example data structure:
404-
405-
```
406-
{'minion_1':
407-
{'base': {'pilar_key_1' 'pillar_val_1'}
408-
}
409-
"""
410-
411-
# TODO ABC?
412-
def __init__(
413-
self,
414-
opts,
415-
grains,
416-
minion_id,
417-
saltenv,
418-
ext=None,
419-
functions=None,
420-
pillar_override=None,
421-
pillarenv=None,
422-
extra_minion_data=None,
423-
clean_cache=False,
424-
):
425-
# Yes, we need all of these because we need to route to the Pillar object
426-
# if we have no cache. This is another refactor target.
427-
428-
# Go ahead and assign these because they may be needed later
429-
self.opts = opts
430-
self.grains = grains
431-
self.minion_id = minion_id
432-
self.ext = ext
433-
self.functions = functions
434-
self.pillar_override = pillar_override
435-
self.pillarenv = pillarenv
436-
self.clean_cache = clean_cache
437-
self.extra_minion_data = extra_minion_data
438-
439-
if saltenv is None:
440-
self.saltenv = "base"
441-
else:
442-
self.saltenv = saltenv
443-
444-
# Determine caching backend
445-
self.cache = salt.utils.cache.CacheFactory.factory(
446-
self.opts["pillar_cache_backend"],
447-
self.opts["pillar_cache_ttl"],
448-
minion_cache_path=self._minion_cache_path(minion_id),
449-
)
450-
451-
def _minion_cache_path(self, minion_id):
452-
"""
453-
Return the path to the cache file for the minion.
454-
455-
Used only for disk-based backends
456-
"""
457-
return os.path.join(self.opts["cachedir"], "pillar_cache", minion_id)
458-
459-
def fetch_pillar(self):
460-
"""
461-
In the event of a cache miss, we need to incur the overhead of caching
462-
a new pillar.
463-
"""
464-
log.debug("Pillar cache getting external pillar with ext: %s", self.ext)
465-
fresh_pillar = Pillar(
466-
self.opts,
467-
self.grains,
468-
self.minion_id,
469-
self.saltenv,
470-
ext=self.ext,
471-
functions=self.functions,
472-
pillar_override=None,
473-
pillarenv=self.pillarenv,
474-
extra_minion_data=self.extra_minion_data,
475-
)
476-
return fresh_pillar.compile_pillar()
477-
478-
def clear_pillar(self):
479-
"""
480-
Clear the cache
481-
"""
482-
self.cache.clear()
483-
484-
return True
485-
486-
def compile_pillar(self, *args, **kwargs): # Will likely just be pillar_dirs
487-
if self.clean_cache:
488-
self.clear_pillar()
489-
log.debug(
490-
"Scanning pillar cache for information about minion %s and pillarenv %s",
491-
self.minion_id,
492-
self.pillarenv,
493-
)
494-
if self.opts["pillar_cache_backend"] == "memory":
495-
cache_dict = self.cache
496-
else:
497-
cache_dict = self.cache._dict
498-
499-
log.debug("Scanning cache: %s", cache_dict)
500-
# Check the cache!
501-
if self.minion_id in self.cache: # Keyed by minion_id
502-
# TODO Compare grains, etc?
503-
if self.pillarenv in self.cache[self.minion_id]:
504-
# We have a cache hit! Send it back.
505-
log.debug(
506-
"Pillar cache hit for minion %s and pillarenv %s",
507-
self.minion_id,
508-
self.pillarenv,
509-
)
510-
return self.cache[self.minion_id][self.pillarenv]
511-
else:
512-
# We found the minion but not the env. Store it.
513-
fresh_pillar = self.fetch_pillar()
514-
515-
minion_cache = self.cache[self.minion_id]
516-
minion_cache[self.pillarenv] = fresh_pillar
517-
self.cache[self.minion_id] = minion_cache
518-
519-
log.debug(
520-
"Pillar cache miss for pillarenv %s for minion %s",
521-
self.pillarenv,
522-
self.minion_id,
523-
)
524-
return fresh_pillar
525-
else:
526-
# We haven't seen this minion yet in the cache. Store it.
527-
fresh_pillar = self.fetch_pillar()
528-
self.cache[self.minion_id] = {self.pillarenv: fresh_pillar}
529-
log.debug("Pillar cache miss for minion %s", self.minion_id)
530-
log.debug("Current pillar cache: %s", cache_dict) # FIXME hack!
531-
return fresh_pillar
532-
533-
534397
class Pillar:
535398
"""
536399
Read over the pillar top files and render the pillar data
@@ -1391,3 +1254,83 @@ class AsyncPillar(Pillar):
13911254
def compile_pillar(self, ext=True):
13921255
ret = super().compile_pillar(ext=ext)
13931256
raise tornado.gen.Return(ret)
1257+
1258+
1259+
class PillarCache(Pillar):
1260+
"""
1261+
Return a cached pillar if it exists, otherwise cache it.
1262+
1263+
Pillar caches are structed in two diminensions: minion_id with a dict of
1264+
saltenvs. Each saltenv contains a pillar dict
1265+
1266+
Example data structure:
1267+
1268+
```
1269+
{'minion_1':
1270+
{'base': {'pilar_key_1' 'pillar_val_1'}
1271+
}
1272+
"""
1273+
1274+
def __init__(
1275+
self,
1276+
*args,
1277+
clean_cache=False,
1278+
pillar_override=None,
1279+
**kwargs,
1280+
):
1281+
super().__init__(*args, **kwargs)
1282+
self.clean_cache = clean_cache
1283+
self.pillar_override = pillar_override
1284+
self.cache = salt.cache.factory(
1285+
self.opts, driver=self.opts["pillar.cache_driver"]
1286+
)
1287+
1288+
# matching to consume the same dataset
1289+
if not self.opts["pillarenv"]:
1290+
self.pillar_key = self.minion_id
1291+
else:
1292+
self.pillar_key = f"{self.minion_id}/{self.opts['pillarenv']}"
1293+
1294+
def compile_pillar(self, *args, **kwargs): # Will likely just be pillar_dirs
1295+
if self.clean_cache:
1296+
self.cache.flush("pillar", self.pillar_key)
1297+
log.debug(
1298+
"Scanning pillar cache for information about minion %s and pillarenv %s",
1299+
self.minion_id,
1300+
self.opts["pillarenv"],
1301+
)
1302+
1303+
# Check the cache!
1304+
pillar_data = self.cache.fetch("pillar", self.pillar_key)
1305+
if pillar_data:
1306+
log.debug(
1307+
"Pillar cache hit for minion %s and pillarenv %s",
1308+
self.minion_id,
1309+
self.opts["pillarenv"],
1310+
)
1311+
else:
1312+
# We found the minion but not the env. Store it.
1313+
log.debug(
1314+
"Pillar cache miss for pillarenv %s for minion %s",
1315+
self.opts["pillarenv"],
1316+
self.minion_id,
1317+
)
1318+
pillar_data = super().compile_pillar(*args, **kwargs)
1319+
1320+
expiry = datetime.datetime.now() + datetime.timedelta(
1321+
seconds=self.opts["pillar_cache_ttl"]
1322+
)
1323+
self.cache.store("pillar", self.pillar_key, pillar_data, expires=expiry)
1324+
1325+
# we dont want the pillar_override baked into the cached fetch_pillar from above
1326+
if self.pillar_override:
1327+
pillar_data = merge(
1328+
pillar_data,
1329+
self.pillar_override,
1330+
self.opts.get("pillar_source_merging_strategy", "smart"),
1331+
self.opts.get("renderer", "yaml"),
1332+
self.opts.get("pillar_merge_lists", False),
1333+
)
1334+
pillar_data.update(self.pillar_override)
1335+
1336+
return pillar_data

0 commit comments

Comments
 (0)