"""An engine that uses presence detection to keep track of which minionshave been recently connected and remove their keys if they have not beenconnected for a certain period of time.Requires that the :conf_master:`minion_data_cache` option be enabled... versionadded:: 2017.7.0:configuration: Example configuration: .. code-block:: yaml engines: - stalekey: interval: 3600 expire: 86400"""importloggingimportosimporttimeimportsalt.configimportsalt.keyimportsalt.utils.filesimportsalt.utils.minionsimportsalt.utils.msgpackimportsalt.wheellog=logging.getLogger(__name__)def__virtual__():ifnot__opts__.get("minion_data_cache"):return(False,"stalekey engine requires minion_data_cache to be enabled")returnTruedef_get_keys():""" Get the keys """withsalt.key.get_key(__opts__)askeys:minions=keys.all_keys()returnminions["minions"]def_delete_keys(stale_keys,minions):""" Delete the keys """wheel=salt.wheel.WheelClient(__opts__)forkinstale_keys:log.info("Removing stale key for %s",k)wheel.cmd("key.delete",[salt.utils.stringutils.to_unicode(k)])delminions[k]returnminionsdef_read_presence(presence_file):""" Read minion data from presence file """error=Falseminions={}ifos.path.exists(presence_file):try:withsalt.utils.files.fopen(presence_file,"rb")asf:_minions=salt.utils.msgpack.load(f)# ensure all keys are unicode, not bytes.forminionin_minions:_minion=salt.utils.stringutils.to_unicode(minion)minions[_minion]=_minions[minion]exceptOSErrorase:error=Truelog.error("Could not open presence file %s: %s",presence_file,e)returnerror,minionsdef_write_presence(presence_file,minions):""" Write minion data to presence file """error=Falsetry:withsalt.utils.files.fopen(presence_file,"wb")asf:salt.utils.msgpack.dump(minions,f)exceptOSErrorase:error=Truelog.error("Could not write to presence file %s: %s",presence_file,e)returnerror
[docs]defstart(interval=3600,expire=604800):""" Start the engine """ck=salt.utils.minions.CkMinions(__opts__)presence_file=f"{__opts__['cachedir']}/presence.p"wheel=salt.wheel.WheelClient(__opts__)whileTrue:log.debug("Checking for present minions")minions={}error,minions=_read_presence(presence_file)iferror:time.sleep(interval)continueminion_keys=_get_keys()now=time.time()present=ck.connected_ids()# For our existing keys, check which are presentforminminion_keys:# If we have a key that's not in the presence file,# it may be a new minion # It could also mean this# is the first time this engine is running and no# presence file was foundifmnotinminions:minions[m]=nowelifminpresent:minions[m]=nowlog.debug("Finished checking for present minions")# Delete old keysstale_keys=[]form,seeninminions.items():ifnow-expire>seen:stale_keys.append(m)ifstale_keys:minions=_delete_keys(stale_keys,minions)error=_write_presence(presence_file,minions)time.sleep(interval)