1""" 2Functions for interacting with the job cache 3""" 4 5 6import logging 7 8import salt.minion 9import salt.utils.event 10import salt.utils.jid 11import salt.utils.verify 12 13log = logging.getLogger(__name__) 14 15 16def store_job(opts, load, event=None, mminion=None): 17 """ 18 Store job information using the configured master_job_cache 19 """ 20 # Generate EndTime 21 endtime = salt.utils.jid.jid_to_time(salt.utils.jid.gen_jid(opts)) 22 # If the return data is invalid, just ignore it 23 if any(key not in load for key in ("return", "jid", "id")): 24 return False 25 if not salt.utils.verify.valid_id(opts, load["id"]): 26 return False 27 if mminion is None: 28 mminion = salt.minion.MasterMinion(opts, states=False, rend=False) 29 30 job_cache = opts["master_job_cache"] 31 if load["jid"] == "req": 32 # The minion is returning a standalone job, request a jobid 33 load["arg"] = load.get("arg", load.get("fun_args", [])) 34 load["tgt_type"] = "glob" 35 load["tgt"] = load["id"] 36 37 prep_fstr = "{}.prep_jid".format(opts["master_job_cache"]) 38 try: 39 load["jid"] = mminion.returners[prep_fstr]( 40 nocache=load.get("nocache", False) 41 ) 42 except KeyError: 43 emsg = "Returner '{}' does not support function prep_jid".format(job_cache) 44 log.error(emsg) 45 raise KeyError(emsg) 46 except Exception: # pylint: disable=broad-except 47 log.critical( 48 "The specified '%s' returner threw a stack trace:\n", 49 job_cache, 50 exc_info=True, 51 ) 52 53 # save the load, since we don't have it 54 saveload_fstr = "{}.save_load".format(job_cache) 55 try: 56 mminion.returners[saveload_fstr](load["jid"], load) 57 except KeyError: 58 emsg = "Returner '{}' does not support function save_load".format(job_cache) 59 log.error(emsg) 60 raise KeyError(emsg) 61 except Exception: # pylint: disable=broad-except 62 log.critical( 63 "The specified '%s' returner threw a stack trace", 64 job_cache, 65 exc_info=True, 66 ) 67 elif salt.utils.jid.is_jid(load["jid"]): 68 # Store the jid 69 jidstore_fstr = "{}.prep_jid".format(job_cache) 70 try: 71 mminion.returners[jidstore_fstr](False, passed_jid=load["jid"]) 72 except KeyError: 73 emsg = "Returner '{}' does not support function prep_jid".format(job_cache) 74 log.error(emsg) 75 raise KeyError(emsg) 76 except Exception: # pylint: disable=broad-except 77 log.critical( 78 "The specified '%s' returner threw a stack trace", 79 job_cache, 80 exc_info=True, 81 ) 82 83 if event: 84 # If the return data is invalid, just ignore it 85 log.info("Got return from %s for job %s", load["id"], load["jid"]) 86 event.fire_event( 87 load, salt.utils.event.tagify([load["jid"], "ret", load["id"]], "job") 88 ) 89 event.fire_ret_load(load) 90 91 # if you have a job_cache, or an ext_job_cache, don't write to 92 # the regular master cache 93 if not opts["job_cache"] or opts.get("ext_job_cache"): 94 return 95 96 # do not cache job results if explicitly requested 97 if load.get("jid") == "nocache": 98 log.debug( 99 "Ignoring job return with jid for caching %s from %s", 100 load["jid"], 101 load["id"], 102 ) 103 return 104 105 # otherwise, write to the master cache 106 savefstr = "{}.save_load".format(job_cache) 107 getfstr = "{}.get_load".format(job_cache) 108 fstr = "{}.returner".format(job_cache) 109 updateetfstr = "{}.update_endtime".format(job_cache) 110 if "fun" not in load and load.get("return", {}): 111 ret_ = load.get("return", {}) 112 if "fun" in ret_: 113 load.update({"fun": ret_["fun"]}) 114 if "user" in ret_: 115 load.update({"user": ret_["user"]}) 116 117 # Try to reach returner methods 118 try: 119 savefstr_func = mminion.returners[savefstr] 120 getfstr_func = mminion.returners[getfstr] 121 fstr_func = mminion.returners[fstr] 122 except KeyError as error: 123 emsg = "Returner '{}' does not support function {}".format(job_cache, error) 124 log.error(emsg) 125 raise KeyError(emsg) 126 127 if job_cache != "local_cache": 128 try: 129 mminion.returners[savefstr](load["jid"], load) 130 except KeyError as e: 131 log.error("Load does not contain 'jid': %s", e) 132 except Exception: # pylint: disable=broad-except 133 log.critical( 134 "The specified '%s' returner threw a stack trace", 135 job_cache, 136 exc_info=True, 137 ) 138 139 try: 140 mminion.returners[fstr](load) 141 except Exception: # pylint: disable=broad-except 142 log.critical( 143 "The specified '%s' returner threw a stack trace", job_cache, exc_info=True 144 ) 145 146 if opts.get("job_cache_store_endtime") and updateetfstr in mminion.returners: 147 mminion.returners[updateetfstr](load["jid"], endtime) 148 149 150def store_minions(opts, jid, minions, mminion=None, syndic_id=None): 151 """ 152 Store additional minions matched on lower-level masters using the configured 153 master_job_cache 154 """ 155 if mminion is None: 156 mminion = salt.minion.MasterMinion(opts, states=False, rend=False) 157 job_cache = opts["master_job_cache"] 158 minions_fstr = "{}.save_minions".format(job_cache) 159 160 try: 161 mminion.returners[minions_fstr](jid, minions, syndic_id=syndic_id) 162 except KeyError: 163 raise KeyError( 164 "Returner '{}' does not support function save_minions".format(job_cache) 165 ) 166 167 168def get_retcode(ret): 169 """ 170 Determine a retcode for a given return 171 """ 172 retcode = 0 173 # if there is a dict with retcode, use that 174 if isinstance(ret, dict) and ret.get("retcode", 0) != 0: 175 return ret["retcode"] 176 # if its a boolean, False means 1 177 elif isinstance(ret, bool) and not ret: 178 return 1 179 return retcode 180 181 182# vim:set et sts=4 ts=4 tw=80: 183