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

Add support to make determine/process reboot-cause services restartable #86

Merged
merged 2 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions scripts/determine-reboot-cause
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ REBOOT_CAUSE_FILE = os.path.join(REBOOT_CAUSE_DIR, "reboot-cause.txt")
PREVIOUS_REBOOT_CAUSE_FILE = os.path.join(REBOOT_CAUSE_DIR, "previous-reboot-cause.json")
FIRST_BOOT_PLATFORM_FILE = "/tmp/notify_firstboot_to_platform"
REBOOT_TYPE_KEXEC_FILE = "/proc/cmdline"
TMP_DIR="/tmp"
REBOOT_PROCESSED_FILE = os.path.join(TMP_DIR, "previous-reboot-cause-processed")
# The following SONIC_BOOT_TYPEs come from the warm/fast reboot script which is in sonic-utilities
# Because the system can be rebooted from some old versions, we have to take all possible BOOT options into consideration.
# On 201803, 201807 we have
Expand Down Expand Up @@ -218,6 +220,10 @@ def main():
sonic_logger.log_error("User {} does not have permission to execute".format(pwd.getpwuid(os.getuid()).pw_name))
sys.exit("This utility must be run as root")

if os.path.exists(REBOOT_PROCESSED_FILE):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anamehra can you add RemainAfterExit=true in the determine-reboot-cause.service, that should ensure systemd starts this service only once (unless someone manually starts the service, not the point of this PR)

sonic_logger.log_info("User {} : reboot-cause already processed. Nothing to do. Exiting...".format(pwd.getpwuid(os.getuid()).pw_name))
return

# Create REBOOT_CAUSE_DIR if it doesn't exist
if not os.path.exists(REBOOT_CAUSE_DIR):
os.makedirs(REBOOT_CAUSE_DIR)
Expand Down Expand Up @@ -257,6 +263,10 @@ def main():
with open(REBOOT_CAUSE_FILE, "w") as cause_file:
cause_file.write(REBOOT_CAUSE_UNKNOWN)

# Create tmp reboot processed file to mark processing of last reboot cause during current boot.
# This is used to prevent reprocessing of reboot cause if this service restarts.
with open(REBOOT_PROCESSED_FILE, "w") as reboot_processed_file:
reboot_processed_file.write("processed last reboot cause")

if __name__ == "__main__":
main()
38 changes: 37 additions & 1 deletion tests/determine-reboot-cause_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
EXPECTED_KERNEL_PANIC_REBOOT_CAUSE_DICT = {'comment': '', 'gen_time': '2021_3_28_13_48_49', 'cause': 'Kernel Panic', 'user': 'N/A', 'time': 'Sun Mar 28 13:45:12 UTC 2021'}

REBOOT_CAUSE_DIR="host/reboot-cause/"

TMP_DIR="tmp/"
REBOOT_PROCESSED_FILE="tmp/previous-reboot-cause-processed"
class TestDetermineRebootCause(object):
def test_parse_warmfast_reboot_from_proc_cmdline(self):
with mock.patch("os.path.isfile") as mock_isfile:
Expand Down Expand Up @@ -179,23 +180,58 @@ def test_determine_reboot_cause_software_hardware(self):
assert additional_info == EXPECTED_FIND_SOFTWARE_REBOOT_CAUSE_USER

@mock.patch('determine_reboot_cause.REBOOT_CAUSE_DIR', os.path.join(os.getcwd(), REBOOT_CAUSE_DIR))
@mock.patch('determine_reboot_cause.TMP_DIR', os.path.join(os.getcwd(), TMP_DIR))
@mock.patch('determine_reboot_cause.REBOOT_CAUSE_HISTORY_DIR', os.path.join(os.getcwd(), 'host/reboot-cause/history/'))
@mock.patch('determine_reboot_cause.PREVIOUS_REBOOT_CAUSE_FILE', os.path.join(os.getcwd(), 'host/reboot-cause/previous-reboot-cause.json'))
@mock.patch('determine_reboot_cause.REBOOT_CAUSE_FILE', os.path.join(os.getcwd(),'host/reboot-cause/reboot-cause.txt'))
@mock.patch('determine_reboot_cause.REBOOT_PROCESSED_FILE', os.path.join(os.getcwd(),'tmp/previous-reboot-cause-processed'))
def test_determine_reboot_cause_main_without_reboot_cause_dir(self):
if os.path.exists(REBOOT_CAUSE_DIR):
shutil.rmtree(REBOOT_CAUSE_DIR)
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
if os.path.exists(REBOOT_PROCESSED_FILE):
os.remove(REBOOT_PROCESSED_FILE)
with mock.patch("os.geteuid", return_value=0):
determine_reboot_cause.main()
assert os.path.exists("host/reboot-cause/reboot-cause.txt") == True
assert os.path.exists("host/reboot-cause/previous-reboot-cause.json") == True
assert os.path.exists(REBOOT_PROCESSED_FILE) == True

@mock.patch('determine_reboot_cause.REBOOT_CAUSE_DIR', os.path.join(os.getcwd(), REBOOT_CAUSE_DIR))
@mock.patch('determine_reboot_cause.TMP_DIR', os.path.join(os.getcwd(), TMP_DIR))
@mock.patch('determine_reboot_cause.REBOOT_CAUSE_HISTORY_DIR', os.path.join(os.getcwd(), 'host/reboot-cause/history/'))
@mock.patch('determine_reboot_cause.PREVIOUS_REBOOT_CAUSE_FILE', os.path.join(os.getcwd(), 'host/reboot-cause/previous-reboot-cause.json'))
@mock.patch('determine_reboot_cause.REBOOT_CAUSE_FILE', os.path.join(os.getcwd(),'host/reboot-cause/reboot-cause.txt'))
@mock.patch('determine_reboot_cause.REBOOT_PROCESSED_FILE', os.path.join(os.getcwd(),'tmp/previous-reboot-cause-processed'))
def test_determine_reboot_cause_main_with_reboot_cause_dir(self):
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
if os.path.exists(REBOOT_PROCESSED_FILE):
os.remove(REBOOT_PROCESSED_FILE)
with mock.patch("os.geteuid", return_value=0):
determine_reboot_cause.main()
assert os.path.exists("host/reboot-cause/reboot-cause.txt") == True
assert os.path.exists("host/reboot-cause/previous-reboot-cause.json") == True
assert os.path.exists(REBOOT_PROCESSED_FILE) == True

@mock.patch('determine_reboot_cause.REBOOT_CAUSE_DIR', os.path.join(os.getcwd(), REBOOT_CAUSE_DIR))
@mock.patch('determine_reboot_cause.TMP_DIR', os.path.join(os.getcwd(), TMP_DIR))
@mock.patch('determine_reboot_cause.REBOOT_CAUSE_HISTORY_DIR', os.path.join(os.getcwd(), 'host/reboot-cause/history/'))
@mock.patch('determine_reboot_cause.PREVIOUS_REBOOT_CAUSE_FILE', os.path.join(os.getcwd(), 'host/reboot-cause/previous-reboot-cause.json'))
@mock.patch('determine_reboot_cause.REBOOT_CAUSE_FILE', os.path.join(os.getcwd(),'host/reboot-cause/reboot-cause.txt'))
@mock.patch('determine_reboot_cause.REBOOT_PROCESSED_FILE', os.path.join(os.getcwd(),'tmp/previous-reboot-cause-processed'))
def test_determine_reboot_cause_test_restart(self):
if os.path.exists(REBOOT_CAUSE_DIR):
shutil.rmtree(REBOOT_CAUSE_DIR)
if not os.path.exists(TMP_DIR):
os.makedirs(TMP_DIR)
if not os.path.exists(REBOOT_PROCESSED_FILE):
os.mknod(REBOOT_PROCESSED_FILE)
with mock.patch("os.geteuid", return_value=0):
determine_reboot_cause.main()
assert os.path.exists("host/reboot-cause/reboot-cause.txt") == False
assert os.path.exists("host/reboot-cause/previous-reboot-cause.json") == False
assert os.path.exists(REBOOT_PROCESSED_FILE) == True
if os.path.exists(TMP_DIR):
shutil.rmtree(TMP_DIR)
Loading