Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a new mod_beacon function to pkg, service, and file state modules #59559

Merged
merged 10 commits into from
Feb 26, 2021
Merged
1 change: 1 addition & 0 deletions changelog/59559.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adding mod_beacon function to pkg, service, and file state modules. This function will act similar to the mod_watch function. This will allow supported functions in those state modules to automatically add associated beacons to monitor for changes to the respective resources in the state file and fire events to the event bus when changes occur.
6 changes: 4 additions & 2 deletions salt/beacons/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,9 @@ def validate_beacon(self, name, beacon_data):
"""
Return available beacon functions
"""
validate_str = "{}.validate".format(name)
beacon_name = next(item.get("beacon_module", name) for item in beacon_data)

validate_str = "{}.validate".format(beacon_name)
# Run the validate function if it's available,
# otherwise there is a warning about it being missing
if validate_str in self.beacons:
Expand All @@ -288,7 +290,7 @@ def validate_beacon(self, name, beacon_data):
else:
vcomment = (
"Beacon {} does not have a validate"
" function, skipping validation.".format(name)
" function, skipping validation.".format(beacon_name)
)
valid = True

Expand Down
24 changes: 15 additions & 9 deletions salt/modules/beacons.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def list_(return_yaml=True, include_pillar=True, include_opts=True, **kwargs):
# Effectively a no-op, since we can't really return without an event system
ret = {}
ret["result"] = False
ret["comment"] = "Event module not available. Beacon add failed."
ret["comment"] = "Event module not available. Beacon list failed."
return ret

if beacons:
Expand Down Expand Up @@ -110,11 +110,11 @@ def list_available(return_yaml=True, **kwargs):
)
if event_ret and event_ret["complete"]:
beacons = event_ret["beacons"]
except KeyError:
except KeyError as e:
# Effectively a no-op, since we can't really return without an event system
ret = {}
ret["result"] = False
ret["comment"] = "Event module not available. Beacon add failed."
ret["comment"] = "Event module not available. Beacon list_available failed."
return ret

if beacons:
Expand Down Expand Up @@ -196,7 +196,7 @@ def add(name, beacon_data, **kwargs):
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret["result"] = False
ret["comment"] = "Event module not available. Beacon add failed."
ret["comment"] = "Event module not available. Beacon validation failed."
return ret

try:
Expand All @@ -214,7 +214,9 @@ def add(name, beacon_data, **kwargs):
)
if event_ret and event_ret["complete"]:
beacons = event_ret["beacons"]
if name in beacons and beacons[name] == beacon_data:
if name in beacons and all(
[item in beacons[name] for item in beacon_data]
):
ret["result"] = True
ret["comment"] = "Added beacon: {}.".format(name)
elif event_ret:
Expand Down Expand Up @@ -416,7 +418,7 @@ def delete(name, **kwargs):
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret["result"] = False
ret["comment"] = "Event module not available. Beacon add failed."
ret["comment"] = "Event module not available. Beacon delete failed."
return ret


Expand Down Expand Up @@ -561,7 +563,7 @@ def disable(**kwargs):
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret["result"] = False
ret["comment"] = "Event module not available. Beacons enable job failed."
ret["comment"] = "Event module not available. Beacons disable job failed."
return ret


Expand Down Expand Up @@ -646,7 +648,9 @@ def enable_beacon(name, **kwargs):
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret["result"] = False
ret["comment"] = "Event module not available. Beacon enable job failed."
ret[
"comment"
] = "Event module not available. Beacon enable_beacon job failed."
return ret


Expand Down Expand Up @@ -721,7 +725,9 @@ def disable_beacon(name, **kwargs):
except KeyError:
# Effectively a no-op, since we can't really return without an event system
ret["result"] = False
ret["comment"] = "Event module not available. Beacon disable job failed."
ret[
"comment"
] = "Event module not available. Beacon disable_beacon job failed."
return ret


Expand Down
29 changes: 29 additions & 0 deletions salt/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -3116,6 +3116,33 @@ def call_chunk(self, low, running, chunks):

return running

def call_beacons(self, chunks, running):
"""
Find all of the beacon routines and call the associated mod_beacon runs
"""
listeners = []
crefs = {}
beacons = []
for chunk in chunks:
if "beacon" in chunk:
beacons.append(chunk)
mod_beacons = []
errors = {}
for chunk in beacons:
low = chunk.copy()
low["sfun"] = chunk["fun"]
low["fun"] = "mod_beacon"
low["__id__"] = "beacon_{}".format(low["__id__"])
mod_beacons.append(low)
ret = self.call_chunks(mod_beacons)

running.update(ret)
for err in errors:
errors[err]["__run_num__"] = self.__run_num
self.__run_num += 1
running.update(errors)
return running

def call_listen(self, chunks, running):
"""
Find all of the listen routines and call the associated mod_watch runs
Expand All @@ -3134,6 +3161,7 @@ def call_listen(self, chunks, running):
listeners.append(
{(key, val, "lookup"): [{chunk["state"]: chunk["__id__"]}]}
)

mod_watchers = []
errors = {}
for l_dict in listeners:
Expand Down Expand Up @@ -3240,6 +3268,7 @@ def call_high(self, high, orchestration_jid=None):
return errors
ret = self.call_chunks(chunks)
ret = self.call_listen(chunks, ret)
ret = self.call_beacons(chunks, ret)

def _cleanup_accumulator_data():
accum_data_path = os.path.join(
Expand Down
56 changes: 56 additions & 0 deletions salt/states/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -8848,3 +8848,59 @@ def not_cached(name, saltenv="base"):
ret["result"] = True
ret["comment"] = "{} is not cached".format(name)
return ret


def mod_beacon(name, **kwargs):
"""
Create a beacon to monitor a file based on a beacon state argument.

.. note::
This state exists to support special handling of the ``beacon``
state argument for supported state functions. It should not be called directly.

"""
sfun = kwargs.pop("sfun", None)
supported_funcs = ["managed", "directory"]

if sfun in supported_funcs:
if kwargs.get("beacon"):
beacon_module = "inotify"

data = {}
_beacon_data = kwargs.get("beacon_data", {})

default_mask = ["create", "delete", "modify"]
data["mask"] = _beacon_data.get("mask", default_mask)

if sfun == "directory":
data["auto_add"] = _beacon_data.get("auto_add", True)
data["recurse"] = _beacon_data.get("recurse", True)
data["exclude"] = _beacon_data.get("exclude", [])

beacon_name = "beacon_{}_{}".format(beacon_module, name)
beacon_kwargs = {
"name": beacon_name,
"files": {name: data},
"interval": _beacon_data.get("interval", 60),
"coalesce": _beacon_data.get("coalesce", False),
"beacon_module": beacon_module,
}

ret = __states__["beacon.present"](**beacon_kwargs)
return ret
else:
return {
"name": name,
"changes": {},
"comment": "Not adding beacon.",
"result": True,
}
else:
return {
"name": name,
"changes": {},
"comment": "file.{} does not work with the beacon state function".format(
sfun
),
"result": False,
}
Loading