PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/states/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/states/win_task.py |
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa383608(v=vs.85).aspx """ State module for adding and removing scheduled tasks using the Windows Task Scheduler. """ import copy import logging import time import salt.utils.data import salt.utils.dateutils import salt.utils.platform try: import pywintypes HAS_PYWIN32 = True except ImportError: HAS_PYWIN32 = False ACTION_PARTS = { "Execute": ["cmd"], "Email": ["from", "to", "cc", "server"], "Message": ["title", "message"], } OPTIONAL_ACTION_PARTS = {"start_in": "", "arguments": ""} TRIGGER_PARTS = { "Event": ["subscription"], "Once": [], "Daily": ["days_interval"], "Weekly": ["days_of_week", "weeks_interval"], "Monthly": ["months_of_year", "days_of_month", "last_day_of_month"], "MonthlyDay": ["months_of_year", "weeks_of_month", "days_of_week"], "OnIdle": [], "OnTaskCreation": [], "OnBoot": [], "OnLogon": [], "OnSessionChange": ["state_change"], } OPTIONAL_TRIGGER_PARTS = { "trigger_enabled": True, "start_date": time.strftime("%Y-%m-%d"), "start_time": time.strftime("%H:%M:%S"), "end_date": None, "end_time": "00:00:00", "random_delay": False, "repeat_interval": None, "repeat_duration": None, "repeat_stop_at_duration_end": False, "execution_time_limit": "3 days", "delay": False, } OPTIONAL_CONDITIONS_PARTS = { "ac_only": True, "run_if_idle": False, "run_if_network": False, "start_when_available": False, } OPTIONAL_SETTINGS_PARTS = { "allow_demand_start": True, "delete_after": False, "execution_time_limit": "3 days", "force_stop": True, "multiple_instances": "No New Instance", "restart_interval": False, "stop_if_on_batteries": True, "wake_to_run": False, } TASK_PARTS = { "actions": {"parts": ACTION_PARTS, "optional": OPTIONAL_ACTION_PARTS}, "triggers": {"parts": TRIGGER_PARTS, "optional": OPTIONAL_TRIGGER_PARTS}, "conditions": {"parts": {}, "optional": OPTIONAL_CONDITIONS_PARTS}, "settings": {"parts": {}, "optional": OPTIONAL_SETTINGS_PARTS}, } log = logging.getLogger(__name__) __virtualname__ = "task" def __virtual__(): """ Load only on minions running on Windows and with task Module loaded. """ if not salt.utils.platform.is_windows(): return False, "State task: Not a Windows System" if not HAS_PYWIN32: return False, "State task: Missing PyWin32 library" return __virtualname__ def _valid_location(location): r""" Test to see if the task location is valid. Args: location (str): task location to check Returns: bool: ``True`` if location is valid, otherwise ``False`` """ try: __salt__["task.list_tasks"](location) except pywintypes.com_error: return False return True def _get_task_state_data(name, location): r""" Get the current state of a task in the task scheduler Args: name (str): Task name location (str): Task location Return: dict: A dictionary containing task configuration information """ task_state = {"location_valid": False, "task_found": False, "task_info": {}} # if valid location then try to get more info on task if _valid_location(location): task_state["location_valid"] = True task_state["task_found"] = name in __salt__["task.list_tasks"](location) # if task was found then get actions and triggers info if task_state["task_found"]: task_info = __salt__["task.info"](name, location) task_state["task_info"] = {key: task_info[key] for key in TASK_PARTS} return task_state def _get_arguments( arguments_given, key_arguments, arguments_need_it, optional_arguments ): """ Make sure all required arguments are passed """ block = {} # check if key arguments are present for key in key_arguments: if key not in arguments_given: return f"Missing key argument {repr(key)}" block[key] = arguments_given[key] # check if key item valid if block[key] not in arguments_need_it: return f"{repr(key)} item {repr(block[key])} is not in key item list {list(arguments_need_it)}" # check if key2 present for key2 in arguments_need_it[block[key]]: if key2 not in arguments_given: return f"Missing {key2} argument" block[key2] = arguments_given[key2] # add optional arguments if they're not present for key in optional_arguments: if key in arguments_given: block[key] = arguments_given[key] else: block[key] = optional_arguments[key] return block def _task_state_prediction_bandage(state): r""" A bandage that standardizes date/time formats and adds additional arguments to a task state. This is so task states can be compared with existing tasks one the system. Args: state (dict): The dictionary of the current settings for the task Returns: dict: A dictionary with parameters with in the expected format """ # Add "enabled = True" to all triggers # This is because triggers will add this argument after they're made if "triggers" in state["task_info"]: for trigger in state["task_info"]["triggers"]: trigger["enabled"] = True # format dates for trigger in state["task_info"]["triggers"]: for key in ["start_date", "end_data"]: if key in trigger: # if except is triggered don"t format the date try: div = [d for d in ["-", "/"] if d in trigger[key]][0] part1, part2, part3 = trigger[key].split(div) if len(part1) == 4: year, month, day = part1, part2, part3 else: month, day, year = part1, part2, part3 if len(year) != 4: year = time.strftime("%Y")[:2] + year trigger[key] = salt.utils.dateutils.strftime( f"{year}-{month}-{day}", "%Y-%m-%d" ) except IndexError: pass except ValueError: pass # format times for trigger in state["task_info"]["triggers"]: for key in ["start_time", "end_time"]: if key in trigger: try: trigger[key] = salt.utils.dateutils.strftime( trigger[key], "%H:%M:%S" ) except ValueError: pass return state def _get_task_state_prediction(state, new_task): r""" Predicts what the new task will look like after it is applied. Used for test=True Args: state (dict): A dictionary containing the current task configuration new_task (dict) A dictionary containing the new task configuration Returns: dict: A dictionary containing predicted result """ new_state = copy.deepcopy(state) # if location not valid state can"t be made if state["location_valid"]: new_state["task_found"] = True new_state["task_info"] = { "actions": [new_task["action"]], "triggers": [new_task["trigger"]], "conditions": new_task["conditions"], "settings": new_task["settings"], } action_keys = set() trigger_keys = set() if state["task_found"]: # get all the arguments used by actions for action in state["task_info"]["actions"]: action_keys = action_keys.union(set(action)) # get all the arguments used by triggers for trigger in state["task_info"]["triggers"]: trigger_keys = trigger_keys.union(set(trigger)) # get setup for the for loop below arguments_filter = [ [ new_state["task_info"]["actions"], action_keys, TASK_PARTS["actions"]["optional"], ], [ new_state["task_info"]["triggers"], trigger_keys, TASK_PARTS["triggers"]["optional"], ], ] # removes any optional arguments that are equal to the default and is not used by the state for argument_list, safe_keys, optional_keys in arguments_filter: for dic in argument_list: for key in list(dic): if key not in safe_keys and key in optional_keys: if dic[key] == optional_keys[key]: del dic[key] # removes add on arguments from triggers # this is because task info does not give this info argument_add_on = set(sum((TRIGGER_PARTS[key] for key in TRIGGER_PARTS), [])) for trigger in new_state["task_info"]["triggers"]: for key in list(trigger): if key in argument_add_on: del trigger[key] return _task_state_prediction_bandage(new_state) def present( name, location="\\", user_name="System", password=None, force=False, **kwargs ): r""" Create a new task in the designated location. This function has many keyword arguments that are not listed here. For additional arguments see: .. versionadded:: 3007.0 - :py:func:`edit_task` - :py:func:`add_action` - :py:func:`add_trigger` Args: name (str): The name of the task. This will be displayed in the task scheduler. location (str): A string value representing the location in which to create the task. Default is "\\" which is the root for the task scheduler (C:\Windows\System32\tasks). user_name (str): The user account under which to run the task. To specify the "System" account, use "System". The password will be ignored. password (str): The password to use for authentication. This should set the task to run whether the user is logged in or not, but is currently not working. force (bool): Overwrite the existing task. Returns: dict: A dictionary containing the results of the state CLI Example: .. code-block:: YAML test_win_task_present: task.present: - name: salt - location: "" - force: True - action_type: Execute - cmd: "del /Q /S C:\\Temp" - trigger_type: Once - start_date: 12-1-16 - start_time: 01:00 """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} before = _get_task_state_data(name, location) # if location not valid the task present will fail if not before["location_valid"]: ret["result"] = False ret["comment"] = f"{repr(location)} is not a valid file location" return ret # split up new task into all its parts new_task = { "action": _get_arguments( kwargs, ["action_type"], TASK_PARTS["actions"]["parts"], TASK_PARTS["actions"]["optional"], ), "trigger": _get_arguments( kwargs, ["trigger_type"], TASK_PARTS["triggers"]["parts"], TASK_PARTS["triggers"]["optional"], ), "conditions": _get_arguments( kwargs, [], TASK_PARTS["conditions"]["parts"], TASK_PARTS["conditions"]["optional"], ), "settings": _get_arguments( kwargs, [], TASK_PARTS["settings"]["parts"], TASK_PARTS["settings"]["optional"], ), } # if win os is higher than 7 then Email and Message action_type is not supported try: if int(__grains__["osversion"].split(".")[0]) >= 8 and new_task["action"][ "action_type" ] in ["Email", "Message"]: log.warning( "This OS %s does not support Email or Message action_type.", __grains__["osversion"], ) except ValueError: pass for key in new_task: # if string is returned then an error happened if isinstance(new_task[key], str): ret["comment"] = f"{key}: {new_task[key]}" ret["result"] = None return ret if __opts__["test"]: # if force is False and task is found then no changes will take place if not force and before["task_found"]: ret["comment"] = ( '"force=True" will allow the new task to replace the old one' ) ret["result"] = None log.warning("force=False") return ret after = _get_task_state_prediction(before, new_task) ret["changes"] = salt.utils.data.compare_dicts(before, after) if ret["changes"]: ret["result"] = None return ret return ret # put all the arguments to kwargs for key in new_task: kwargs.update(new_task[key]) # make task result = __salt__["task.create_task"]( name=name, location=location, user_name=user_name, password=password, force=force, **kwargs, ) # if "task.create_task" returns a str then task did not change if isinstance(result, str): ret["comment"] = '"force=True" will allow the new task to replace the old one' ret["result"] = False log.warning("force=False") return ret after = _get_task_state_data(name, location) if after["task_info"]["actions"][0]["action_type"] != kwargs["action_type"]: ret["comment"] = "failed to make action" ret["result"] = False elif after["task_info"]["triggers"][0]["trigger_type"] != kwargs["trigger_type"]: ret["comment"] = "failed to make trigger" ret["result"] = False ret["changes"] = salt.utils.data.compare_dicts(before, after) return ret def absent(name, location="\\"): r""" Delete a task from the task scheduler. .. versionadded:: 3007.0 Args: name (str): The name of the task to delete. location (str): A string value representing the location of the task. Default is "\\" which is the root for the task scheduler (C:\Windows\System32\tasks). Returns: bool: ``True`` if successful, otherwise ``False`` CLI Example: .. code-block:: YAML test_win_task_absent: task.absent: - name: salt - location: "" """ ret = {"name": name, "changes": {}, "result": True, "comment": ""} before = _get_task_state_data(name, location) # if location not valid the task present will fail if not before["location_valid"]: ret["result"] = False ret["comment"] = f"{repr(location)} is not a valid file location" return ret if __opts__["test"]: # if task was not found then no changes if not before["task_found"]: ret["result"] = True ret["changes"] = salt.utils.data.compare_dicts(before, before) else: # if task was found then changes will happen ret["result"] = None ret["changes"] = salt.utils.data.compare_dicts( before, {"location_valid": True, "task_found": False, "task_info": {}} ) return ret # if task was found then delete it if before["task_found"]: # try to delete task ret["result"] = __salt__["task.delete_task"](name=name, location=location) # if "task.delete_task" returns a str then task was not deleted if isinstance(ret["result"], str): ret["result"] = False ret["changes"] = salt.utils.data.compare_dicts( before, _get_task_state_data(name, location) ) return ret