From 987830a433835ba4fe5df55b06b5274a6eb76551 Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Tue, 10 May 2022 13:59:58 -0400 Subject: [PATCH 1/6] fixes saltstack/salt#62044 add ignore_missing to file.comment state --- changelog/62044.added | 1 + salt/states/file.py | 17 +++++++++++++++-- tests/pytests/unit/states/file/test_comment.py | 10 +++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 changelog/62044.added diff --git a/changelog/62044.added b/changelog/62044.added new file mode 100644 index 000000000000..9a96045d8abc --- /dev/null +++ b/changelog/62044.added @@ -0,0 +1 @@ +Add ignore_missing parameter to file.comment state diff --git a/salt/states/file.py b/salt/states/file.py index 3534b2459500..b29a07058248 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -6004,8 +6004,11 @@ def blockreplace( return ret -def comment(name, regex, char="#", backup=".bak"): +def comment(name, regex, char="#", backup=".bak", ignore_missing=False): """ + .. versionadded:: 0.9.5 + .. versionchanged:: 3005 + Comment out specified lines in a file. name @@ -6030,6 +6033,12 @@ def comment(name, regex, char="#", backup=".bak"): after the first invocation. Set to False/None to not keep a backup. + ignore_missing + Ignore a failure to find the regex in the file. This is useful for + scenarios where a line must only be commented if it is found in the + file. + + .. versionadded:: 3005 Usage: @@ -6039,7 +6048,6 @@ def comment(name, regex, char="#", backup=".bak"): file.comment: - regex: ^bind 127.0.0.1 - .. versionadded:: 0.9.5 """ name = os.path.expanduser(name) @@ -6062,6 +6070,10 @@ def comment(name, regex, char="#", backup=".bak"): ret["comment"] = "Pattern already commented" ret["result"] = True return ret + elif ignore_missing: + ret["comment"] = "Pattern not found and ignore_missing set to True" + ret["result"] = True + return ret else: return _error(ret, "{}: Pattern not found".format(unanchor_regex)) @@ -6070,6 +6082,7 @@ def comment(name, regex, char="#", backup=".bak"): ret["comment"] = "File {} is set to be updated".format(name) ret["result"] = None return ret + with salt.utils.files.fopen(name, "rb") as fp_: slines = fp_.read() slines = slines.decode(__salt_system_encoding__) diff --git a/tests/pytests/unit/states/file/test_comment.py b/tests/pytests/unit/states/file/test_comment.py index 8c655621baee..3ec4ee2bc4bb 100644 --- a/tests/pytests/unit/states/file/test_comment.py +++ b/tests/pytests/unit/states/file/test_comment.py @@ -65,12 +65,20 @@ def test_comment(): with patch.object(os.path, "isabs", mock_t): with patch.dict( filestate.__salt__, - {"file.search": MagicMock(side_effect=[False, True, False, False])}, + { + "file.search": MagicMock( + side_effect=[False, True, False, False, False, False] + ) + }, ): comt = "Pattern already commented" ret.update({"comment": comt, "result": True}) assert filestate.comment(name, regex) == ret + comt = "Pattern not found and ignore_missing set to True" + ret.update({"comment": comt, "result": True}) + assert filestate.comment(name, regex, ignore_missing=True) == ret + comt = "{}: Pattern not found".format(regex) ret.update({"comment": comt, "result": False}) assert filestate.comment(name, regex) == ret From 346e6e60ff5abcf95c5c609a6a799d98a584341c Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Tue, 10 May 2022 14:26:56 -0400 Subject: [PATCH 2/6] fixes saltstack/salt#61662 fix file.comment reports changes in test mode --- salt/states/file.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/states/file.py b/salt/states/file.py index b29a07058248..76ca93f7251b 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -6062,10 +6062,11 @@ def comment(name, regex, char="#", backup=".bak", ignore_missing=False): # remove (?i)-like flags, ^ and $ unanchor_regex = re.sub(r"^(\(\?[iLmsux]\))?\^?(.*?)\$?$", r"\2", regex) + uncomment_regex = "[^{}]".format(char) + unanchor_regex comment_regex = char + unanchor_regex # Make sure the pattern appears in the file before continuing - if not __salt__["file.search"](name, regex, multiline=True): + if not __salt__["file.search"](name, uncomment_regex, multiline=True): if __salt__["file.search"](name, comment_regex, multiline=True): ret["comment"] = "Pattern already commented" ret["result"] = True @@ -6097,7 +6098,7 @@ def comment(name, regex, char="#", backup=".bak", ignore_missing=False): nlines = nlines.splitlines(True) # Check the result - ret["result"] = __salt__["file.search"](name, unanchor_regex, multiline=True) + ret["result"] = __salt__["file.search"](name, comment_regex, multiline=True) if slines != nlines: if not __utils__["files.is_text"](name): From a26cfb085e4d9e8cfce1545a127adf5c94f7c2cb Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Tue, 10 May 2022 14:30:04 -0400 Subject: [PATCH 3/6] add 61662.fixed changelog --- changelog/61662.fixed | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/61662.fixed diff --git a/changelog/61662.fixed b/changelog/61662.fixed new file mode 100644 index 000000000000..450560171f17 --- /dev/null +++ b/changelog/61662.fixed @@ -0,0 +1 @@ +Fix file.comment incorrectly reports changes in test mode From 96ef55d73b4def717a68da554c7ecc068633170f Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Tue, 10 May 2022 14:44:13 -0400 Subject: [PATCH 4/6] add final test mode run after comment is successful --- tests/pytests/unit/states/file/test_comment.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/pytests/unit/states/file/test_comment.py b/tests/pytests/unit/states/file/test_comment.py index 3ec4ee2bc4bb..dceca84fc270 100644 --- a/tests/pytests/unit/states/file/test_comment.py +++ b/tests/pytests/unit/states/file/test_comment.py @@ -86,7 +86,9 @@ def test_comment(): with patch.dict( filestate.__salt__, { - "file.search": MagicMock(side_effect=[True, True, True]), + "file.search": MagicMock( + side_effect=[True, True, True, False, True] + ), "file.comment": mock_t, "file.comment_line": mock_t, }, @@ -106,6 +108,11 @@ def test_comment(): ret.update({"comment": comt, "result": True, "changes": {}}) assert filestate.comment(name, regex) == ret + with patch.dict(filestate.__opts__, {"test": True}): + comt = "Pattern already commented" + ret.update({"comment": comt, "result": True, "changes": {}}) + assert filestate.comment(name, regex) == ret + # 'uncomment' function tests: 1 def test_uncomment(): From 401d6921dfcd3343816163f1f5fb7a85a35fd837 Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Tue, 10 May 2022 16:17:36 -0400 Subject: [PATCH 5/6] fix uncomment_regex --- salt/states/file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/states/file.py b/salt/states/file.py index 76ca93f7251b..e45b1a14e955 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -6062,7 +6062,7 @@ def comment(name, regex, char="#", backup=".bak", ignore_missing=False): # remove (?i)-like flags, ^ and $ unanchor_regex = re.sub(r"^(\(\?[iLmsux]\))?\^?(.*?)\$?$", r"\2", regex) - uncomment_regex = "[^{}]".format(char) + unanchor_regex + uncomment_regex = "[^{}]?".format(char) + unanchor_regex comment_regex = char + unanchor_regex # Make sure the pattern appears in the file before continuing From 1fd44a8baa51d277e28f8d32fc679896dcc03f7b Mon Sep 17 00:00:00 2001 From: nicholasmhughes Date: Tue, 10 May 2022 18:16:33 -0400 Subject: [PATCH 6/6] fix uncomment_regex --- salt/states/file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/states/file.py b/salt/states/file.py index e45b1a14e955..b27907f8b468 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -6062,7 +6062,7 @@ def comment(name, regex, char="#", backup=".bak", ignore_missing=False): # remove (?i)-like flags, ^ and $ unanchor_regex = re.sub(r"^(\(\?[iLmsux]\))?\^?(.*?)\$?$", r"\2", regex) - uncomment_regex = "[^{}]?".format(char) + unanchor_regex + uncomment_regex = "^(?!.*{}).*".format(char) + unanchor_regex comment_regex = char + unanchor_regex # Make sure the pattern appears in the file before continuing