diff --git a/changelog/62986.fixed b/changelog/62986.fixed new file mode 100644 index 00000000000..e2e5c1b029a --- /dev/null +++ b/changelog/62986.fixed @@ -0,0 +1 @@ +Fix file.tidied FileNotFoundError diff --git a/salt/states/file.py b/salt/states/file.py index b3a8cec3412..db0b5a41d69 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -2102,49 +2102,52 @@ def tidied( mysize = 0 deleteme = True path = os.path.join(root, elem) - if os.path.islink(path): - # Get timestamp of symlink (not symlinked file) - if time_comparison == "ctime": - mytimestamp = os.lstat(path).st_ctime - elif time_comparison == "mtime": - mytimestamp = os.lstat(path).st_mtime + try: + if os.path.islink(path): + # Get timestamp of symlink (not symlinked file) + if time_comparison == "ctime": + mytimestamp = os.lstat(path).st_ctime + elif time_comparison == "mtime": + mytimestamp = os.lstat(path).st_mtime + else: + mytimestamp = os.lstat(path).st_atime else: - mytimestamp = os.lstat(path).st_atime - else: - # Get timestamp of file or directory - if time_comparison == "ctime": - mytimestamp = os.path.getctime(path) - elif time_comparison == "mtime": - mytimestamp = os.path.getmtime(path) + # Get timestamp of file or directory + if time_comparison == "ctime": + mytimestamp = os.path.getctime(path) + elif time_comparison == "mtime": + mytimestamp = os.path.getmtime(path) + else: + mytimestamp = os.path.getatime(path) + + if elem in dirs: + # Check if directories should be deleted at all + deleteme = rmdirs + else: + # Get size of regular file + mysize = os.path.getsize(path) + + # Calculate the age and set the name to match + myage = abs(today - date.fromtimestamp(mytimestamp)) + filename = elem + if full_path_match: + filename = path + + # Verify against given criteria, collect all elements that should be removed + if age_size_only and age_size_only.lower() in ["age", "size"]: + if age_size_only.lower() == "age": + compare_age_size = myage.days >= age + else: + compare_age_size = mysize >= size + elif age_size_logical_operator.upper() == "AND": + compare_age_size = mysize >= size and myage.days >= age else: - mytimestamp = os.path.getatime(path) + compare_age_size = mysize >= size or myage.days >= age - if elem in dirs: - # Check if directories should be deleted at all - deleteme = rmdirs - else: - # Get size of regular file - mysize = os.path.getsize(path) - - # Calculate the age and set the name to match - myage = abs(today - date.fromtimestamp(mytimestamp)) - filename = elem - if full_path_match: - filename = path - - # Verify against given criteria, collect all elements that should be removed - if age_size_only and age_size_only.lower() in ["age", "size"]: - if age_size_only.lower() == "age": - compare_age_size = myage.days >= age - else: - compare_age_size = mysize >= size - elif age_size_logical_operator.upper() == "AND": - compare_age_size = mysize >= size and myage.days >= age - else: - compare_age_size = mysize >= size or myage.days >= age - - if compare_age_size and _matches(name=filename) and deleteme: - todelete.append(path) + if compare_age_size and _matches(name=filename) and deleteme: + todelete.append(path) + except FileNotFoundError: + continue # Now delete the stuff if todelete: diff --git a/tests/pytests/unit/states/file/test_tidied.py b/tests/pytests/unit/states/file/test_tidied.py index 2dde8b29c39..7a34b7125d6 100644 --- a/tests/pytests/unit/states/file/test_tidied.py +++ b/tests/pytests/unit/states/file/test_tidied.py @@ -550,3 +550,31 @@ def test_tidied_age_size_args_AND_operator_size_and_age(): } assert ret == exp assert remove.call_count == 3 + + +def test_tidied_filenotfound(tmp_path): + name = tmp_path / "not_found_test" + name.mkdir(parents=True, exist_ok=True) + name = str(tmp_path / "not_found_test") + walker = [ + (os.path.join(name, "test1"), [], ["file1"]), + (os.path.join(name, "test2", "test3"), [], []), + (os.path.join(name, "test2"), ["test3"], ["file2"]), + (name, ["test1", "test2"], ["file3"]), + ] + # mock the walk, but files aren't there + with patch("os.walk", return_value=walker), patch( + "os.path.islink", return_value=False + ): + ret = filestate.tidied( + name=name, + age=1, + size=9, + ) + exp = { + "name": name, + "changes": {}, + "result": True, + "comment": "Nothing to remove from directory {}".format(name), + } + assert ret == exp