dummy.py (salt-3002.1) | : | dummy.py (salt-3002.2) | ||
---|---|---|---|---|
""" | """ | |||
This is the a dummy proxy-minion designed for testing the proxy minion subsystem . | This is the a dummy proxy-minion designed for testing the proxy minion subsystem . | |||
""" | """ | |||
import copy | ||||
import logging | import logging | |||
import os | import os | |||
import pickle | import pprint | |||
from contextlib import contextmanager | ||||
import salt.utils.files | import salt.utils.files | |||
import salt.utils.msgpack | ||||
# This must be present or the Salt loader won't load this module | # This must be present or the Salt loader won't load this module | |||
__proxyenabled__ = ["dummy"] | __proxyenabled__ = ["dummy"] | |||
# Variables are scoped to this module so we can have persistent data | ||||
# across calls to fns in here. | ||||
DETAILS = {} | ||||
DETAILS["services"] = {"apache": "running", "ntp": "running", "samba": "stopped" | ||||
} | ||||
DETAILS["packages"] = { | ||||
"coreutils": "1.0", | ||||
"apache": "2.4", | ||||
"tinc": "1.4", | ||||
"redbull": "999.99", | ||||
} | ||||
FILENAME = salt.utils.files.mkstemp() | ||||
log = logging.getLogger(__file__) | log = logging.getLogger(__file__) | |||
# This does nothing, it's here just as an example and to provide a log | # This does nothing, it's here just as an example and to provide a log | |||
# entry when the module is loaded. | # entry when the module is loaded. | |||
def __virtual__(): | def __virtual__(): | |||
""" | """ | |||
Only return if all the modules are available | Only return if all the modules are available | |||
""" | """ | |||
log.debug("dummy proxy __virtual__() called...") | log.debug("dummy proxy __virtual__() called...") | |||
return True | return True | |||
def _save_state(details): | def _save_state(opts, details): | |||
with salt.utils.files.fopen(FILENAME, "wb") as pck: | cachefile = os.path.join(opts["cachedir"], "dummy-proxy.cache") | |||
pickle.dump(details, pck) | with salt.utils.files.fopen(cachefile, "wb") as pck: | |||
pck.write(salt.utils.msgpack.packb(details, use_bin_type=True)) | ||||
log.warning("Dummy Proxy Saved State(%s):\n%s", cachefile, pprint.pformat(de | ||||
tails)) | ||||
def _load_state(): | def _load_state(opts): | |||
cachefile = os.path.join(opts["cachedir"], "dummy-proxy.cache") | ||||
try: | ||||
with salt.utils.files.fopen(cachefile, "rb") as pck: | ||||
state = salt.utils.msgpack.unpackb(pck.read(), raw=False) | ||||
except FileNotFoundError: | ||||
state = _initial_state() | ||||
_save_state(opts, state) | ||||
except Exception as exc: # pylint: disable=broad-except | ||||
log.exception("Failed to load state: %s", exc, exc_info=True) | ||||
state = _initial_state() | ||||
_save_state(opts, state) | ||||
log.warning("Dummy Proxy Loaded State(%s):\n%s", cachefile, pprint.pformat(s | ||||
tate)) | ||||
return state | ||||
@contextmanager | ||||
def _loaded_state(opts): | ||||
state = _load_state(opts) | ||||
original = copy.deepcopy(state) | ||||
try: | try: | |||
with salt.utils.files.fopen(FILENAME, "rb") as pck: | yield state | |||
DETAILS = pickle.load(pck) | finally: | |||
except EOFError: | if state != original: | |||
DETAILS = {} | _save_state(opts, state) | |||
DETAILS["initialized"] = False | ||||
_save_state(DETAILS) | ||||
return DETAILS | def _initial_state(): | |||
return { | ||||
"services": {"apache": "running", "ntp": "running", "samba": "stopped"}, | ||||
"packages": { | ||||
"coreutils": "1.0", | ||||
"apache": "2.4", | ||||
"tinc": "1.4", | ||||
"redbull": "999.99", | ||||
}, | ||||
} | ||||
# Every proxy module needs an 'init', though you can | # Every proxy module needs an 'init', though you can | |||
# just put DETAILS['initialized'] = True here if nothing | # just put DETAILS['initialized'] = True here if nothing | |||
# else needs to be done. | # else needs to be done. | |||
def init(opts): | def init(opts): | |||
log.debug("dummy proxy init() called...") | log.debug("dummy proxy init() called...") | |||
DETAILS["initialized"] = True | with _loaded_state(opts) as state: | |||
_save_state(DETAILS) | state["initialized"] = True | |||
def initialized(): | def initialized(): | |||
""" | """ | |||
Since grains are loaded in many different places and some of those | Since grains are loaded in many different places and some of those | |||
places occur before the proxy can be initialized, return whether | places occur before the proxy can be initialized, return whether | |||
our init() function has been called | our init() function has been called | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
return DETAILS.get("initialized", False) | return state.get("initialized", False) | |||
def grains(): | def grains(): | |||
""" | """ | |||
Make up some grains | Make up some grains | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
if "grains_cache" not in DETAILS: | if "grains_cache" not in state: | |||
DETAILS["grains_cache"] = { | state["grains_cache"] = { | |||
"dummy_grain_1": "one", | "dummy_grain_1": "one", | |||
"dummy_grain_2": "two", | "dummy_grain_2": "two", | |||
"dummy_grain_3": "three", | "dummy_grain_3": "three", | |||
} | } | |||
_save_state(DETAILS) | return state["grains_cache"] | |||
return DETAILS["grains_cache"] | ||||
def grains_refresh(): | def grains_refresh(): | |||
""" | """ | |||
Refresh the grains | Refresh the grains | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
DETAILS["grains_cache"] = None | if "grains_cache" in state: | |||
_save_state(DETAILS) | state.pop("grains_cache") | |||
return grains() | return grains() | |||
def fns(): | def fns(): | |||
return { | return { | |||
"details": "This key is here because a function in " | "details": "This key is here because a function in " | |||
"grains/rest_sample.py called fns() here in the proxymodule." | "grains/rest_sample.py called fns() here in the proxymodule." | |||
} | } | |||
def service_start(name): | def service_start(name): | |||
""" | """ | |||
Start a "service" on the dummy server | Start a "service" on the dummy server | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
DETAILS["services"][name] = "running" | state["services"][name] = "running" | |||
_save_state(DETAILS) | ||||
return "running" | return "running" | |||
def service_stop(name): | def service_stop(name): | |||
""" | """ | |||
Stop a "service" on the dummy server | Stop a "service" on the dummy server | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
DETAILS["services"][name] = "stopped" | state["services"][name] = "stopped" | |||
_save_state(DETAILS) | ||||
return "stopped" | return "stopped" | |||
def service_restart(name): | def service_restart(name): | |||
""" | """ | |||
Restart a "service" on the REST server | Restart a "service" on the REST server | |||
""" | """ | |||
return True | return True | |||
def service_list(): | def service_list(): | |||
""" | """ | |||
List "services" on the REST server | List "services" on the REST server | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
return list(DETAILS["services"]) | return list(state["services"]) | |||
def service_status(name): | def service_status(name): | |||
""" | """ | |||
Check if a service is running on the REST server | Check if a service is running on the REST server | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
if DETAILS["services"][name] == "running": | if state["services"][name] == "running": | |||
return {"comment": "running"} | return {"comment": "running"} | |||
else: | else: | |||
return {"comment": "stopped"} | return {"comment": "stopped"} | |||
def package_list(): | def package_list(): | |||
""" | """ | |||
List "packages" installed on the REST server | List "packages" installed on the REST server | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
return DETAILS["packages"] | return state["packages"] | |||
def package_install(name, **kwargs): | def package_install(name, **kwargs): | |||
""" | """ | |||
Install a "package" on the REST server | Install a "package" on the REST server | |||
""" | """ | |||
DETAILS = _load_state() | ||||
if kwargs.get("version", False): | if kwargs.get("version", False): | |||
version = kwargs["version"] | version = kwargs["version"] | |||
else: | else: | |||
version = "1.0" | version = "1.0" | |||
DETAILS["packages"][name] = version | with _loaded_state(__opts__) as state: | |||
_save_state(DETAILS) | state["packages"][name] = version | |||
return {name: version} | return {name: version} | |||
def upgrade(): | def upgrade(): | |||
""" | """ | |||
"Upgrade" packages | "Upgrade" packages | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
pkgs = uptodate() | for p in state["packages"]: | |||
DETAILS["packages"] = pkgs | version_float = float(state["packages"][p]) | |||
_save_state(DETAILS) | version_float = version_float + 1.0 | |||
return pkgs | state["packages"][p] = str(version_float) | |||
return state["packages"] | ||||
def uptodate(): | def uptodate(): | |||
""" | """ | |||
Call the REST endpoint to see if the packages on the "server" are up to date . | Call the REST endpoint to see if the packages on the "server" are up to date . | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
for p in DETAILS["packages"]: | return state["packages"] | |||
version_float = float(DETAILS["packages"][p]) | ||||
version_float = version_float + 1.0 | ||||
DETAILS["packages"][p] = str(version_float) | ||||
return DETAILS["packages"] | ||||
def package_remove(name): | def package_remove(name): | |||
""" | """ | |||
Remove a "package" on the REST server | Remove a "package" on the REST server | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
DETAILS["packages"].pop(name) | state["packages"].pop(name) | |||
_save_state(DETAILS) | return state["packages"] | |||
return DETAILS["packages"] | ||||
def package_status(name): | def package_status(name): | |||
""" | """ | |||
Check the installation status of a package on the REST server | Check the installation status of a package on the REST server | |||
""" | """ | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
if name in DETAILS["packages"]: | if name in state["packages"]: | |||
return {name: DETAILS["packages"][name]} | return {name: state["packages"][name]} | |||
def ping(): | def ping(): | |||
""" | """ | |||
Degenerate ping | Degenerate ping | |||
""" | """ | |||
log.debug("dummy proxy returning ping") | log.debug("dummy proxy returning ping") | |||
return True | return True | |||
def shutdown(opts): | def shutdown(opts): | |||
""" | """ | |||
For this proxy shutdown is a no-op | For this proxy shutdown is a no-op | |||
""" | """ | |||
log.debug("dummy proxy shutdown() called...") | log.debug("dummy proxy shutdown() called...") | |||
DETAILS = _load_state() | with _loaded_state(__opts__) as state: | |||
if "filename" in DETAILS: | if "filename" in state: | |||
os.unlink(DETAILS["filename"]) | os.unlink(state["filename"]) | |||
def test_from_state(): | def test_from_state(): | |||
""" | """ | |||
Test function so we have something to call from a state | Test function so we have something to call from a state | |||
:return: | :return: | |||
""" | """ | |||
log.debug("test_from_state called") | log.debug("test_from_state called") | |||
return "testvalue" | return "testvalue" | |||
End of changes. 24 change blocks. | ||||
82 lines changed or deleted | 91 lines changed or added |