# Copyright (c) 2025 Kim Jarvis TPF Software Services S.A. kim.jarvis@tpfsystems.com # This software is licensed under the MIT License. See the LICENSE file for details.#fromreemote.commandimportCommandimporttime
[docs]classReboot:""" A class to encapsulate the functionality of rebooting machines in Unix-like operating systems. It allows users to specify various reboot parameters such as delays, messages, custom commands, and timeout settings. The class waits for the machine to go down, come back up, and respond to commands. Attributes: boot_time_command (str): Command to run that returns a unique string indicating the last time the system was booted. connect_timeout (int): Maximum seconds to wait for a successful connection to the managed hosts before trying again. msg (str): Message to display to users before reboot. post_reboot_delay (int): Seconds to wait after the reboot command was successful before attempting to validate the system rebooted successfully. pre_reboot_delay (int): Seconds to wait before reboot. Passed as a parameter to the reboot command. reboot_command (str): Command to run that reboots the system, including any parameters passed to the command. reboot_timeout (int): Maximum seconds to wait for machine to reboot and respond to a test command. search_paths (list): Paths to search on the remote machine for the shutdown command. test_command (str): Command to run on the rebooted host and expect success from to determine the machine is ready for further tasks. **Examples:** .. code:: python # Unconditionally reboot the machine with all defaults r = yield Reboot() # Reboot a slow machine that might have lots of updates to apply r = yield Reboot(reboot_timeout=3600) # Reboot a machine with shutdown command in unusual place r = yield Reboot(search_paths=['/lib/molly-guard']) # Reboot machine using a custom reboot command r = yield Reboot( reboot_command="launchctl reboot userspace", boot_time_command="uptime | cut -d ' ' -f 5" ) # Reboot machine and send a message r = yield Reboot(msg="Rebooting machine in 5 seconds") Usage: This class is designed to be used in a generator-based workflow where commands are yielded for execution. Notes: - PATH is ignored on the remote node when searching for the shutdown command. Use search_paths to specify locations to search if the default paths do not work. - For Windows targets, use the ansible.windows.win_reboot module instead. """def__init__(self,boot_time_command:str="cat /proc/sys/kernel/random/boot_id",connect_timeout:int=None,msg:str="Reboot initiated by Ansible",post_reboot_delay:int=0,pre_reboot_delay:int=0,reboot_command:str=None,reboot_timeout:int=600,search_paths:list=["/sbin","/bin","/usr/sbin","/usr/bin","/usr/local/sbin"],test_command:str="whoami"):self.boot_time_command=boot_time_commandself.connect_timeout=connect_timeoutself.msg=msgself.post_reboot_delay=post_reboot_delayself.pre_reboot_delay=pre_reboot_delayself.reboot_command=reboot_commandself.reboot_timeout=reboot_timeoutself.search_paths=search_pathsself.test_command=test_commanddef__repr__(self):return(f"Reboot(boot_time_command={self.boot_time_command!r}, "f"connect_timeout={self.connect_timeout!r}, "f"msg={self.msg!r}, "f"post_reboot_delay={self.post_reboot_delay!r}, "f"pre_reboot_delay={self.pre_reboot_delay!r}, "f"reboot_command={self.reboot_command!r}, "f"reboot_timeout={self.reboot_timeout!r}, "f"search_paths={self.search_paths!r}, "f"test_command={self.test_command!r})")defexecute(self):start_time=time.time()# Get initial boot time to compare laterboot_time_result=yieldCommand(self.boot_time_command)initial_boot_time=boot_time_result.cp.stdout.strip()ifboot_time_result.cpelse""# Construct reboot commandifself.reboot_command:reboot_cmd=self.reboot_commandelse:# Default reboot command with delay and messageifself.pre_reboot_delay>0:reboot_cmd=f"shutdown -r +{max(0,self.pre_reboot_delay//60)} '{self.msg}'"else:reboot_cmd=f"shutdown -r now '{self.msg}'"# Execute reboot commandyieldCommand(reboot_cmd,sudo=True)# Wait for post_reboot_delayifself.post_reboot_delay>0:time.sleep(self.post_reboot_delay)# Wait for system to go down and come back upelapsed=0rebooted=Falsewhileelapsed<self.reboot_timeout:try:# Try to connect and run test commandtest_result=yieldCommand(self.test_command,guard=False)iftest_result.cpandtest_result.cp.returncode==0:# System is back up, verify it's actually rebootedboot_time_result=yieldCommand(self.boot_time_command,guard=False)current_boot_time=boot_time_result.cp.stdout.strip()ifboot_time_result.cpelse""ifcurrent_boot_time!=initial_boot_time:rebooted=TruebreakexceptException:# Connection failed, system is probably downpass# Wait before retryingtime.sleep(5)elapsed=time.time()-start_time# Set return valuesr=type('Result',(),{})()r.elapsed=int(time.time()-start_time)r.rebooted=rebootedr.changed=True