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

If check mode enabled and file missing set changed to true 32676 #33967

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
38 changes: 32 additions & 6 deletions lib/ansible/module_utils/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,10 @@ def set_context_if_different(self, path, context, changed, diff=None):

if not HAVE_SELINUX or not self.selinux_enabled():
return changed

if self.check_file_absent_if_check_mode(path):
return True

cur_context = self.selinux_context(path)
new_context = list(cur_context)
# Iterate over the current context instead of the
Expand Down Expand Up @@ -1102,11 +1106,17 @@ def set_context_if_different(self, path, context, changed, diff=None):
return changed

def set_owner_if_different(self, path, owner, changed, diff=None, expand=True):

if owner is None:
return changed

b_path = to_bytes(path, errors='surrogate_or_strict')
if expand:
b_path = os.path.expanduser(os.path.expandvars(b_path))
if owner is None:
return changed

if self.check_file_absent_if_check_mode(b_path):
return True

orig_uid, orig_gid = self.user_and_group(b_path, expand)
try:
uid = int(owner)
Expand Down Expand Up @@ -1137,11 +1147,17 @@ def set_owner_if_different(self, path, owner, changed, diff=None, expand=True):
return changed

def set_group_if_different(self, path, group, changed, diff=None, expand=True):

if group is None:
return changed

b_path = to_bytes(path, errors='surrogate_or_strict')
if expand:
b_path = os.path.expanduser(os.path.expandvars(b_path))
if group is None:
return changed

if self.check_file_absent_if_check_mode(b_path):
return True

orig_uid, orig_gid = self.user_and_group(b_path, expand)
try:
gid = int(group)
Expand Down Expand Up @@ -1172,13 +1188,17 @@ def set_group_if_different(self, path, group, changed, diff=None, expand=True):
return changed

def set_mode_if_different(self, path, mode, changed, diff=None, expand=True):

if mode is None:
return changed

b_path = to_bytes(path, errors='surrogate_or_strict')
if expand:
b_path = os.path.expanduser(os.path.expandvars(b_path))
path_stat = os.lstat(b_path)

if mode is None:
return changed
if self.check_file_absent_if_check_mode(b_path):
return True

if not isinstance(mode, int):
try:
Expand Down Expand Up @@ -1256,6 +1276,9 @@ def set_attributes_if_different(self, path, attributes, changed, diff=None, expa
if expand:
b_path = os.path.expanduser(os.path.expandvars(b_path))

if self.check_file_absent_if_check_mode(b_path):
return True

existing = self.get_file_attributes(b_path)

if existing.get('attr_flags', '') != attributes:
Expand Down Expand Up @@ -1450,6 +1473,9 @@ def set_fs_attributes_if_different(self, file_args, changed, diff=None, expand=T
)
return changed

def check_file_absent_if_check_mode(self, file_path):
return self.check_mode and not os.path.exists(file_path)

def set_directory_attributes_if_different(self, file_args, changed, diff=None, expand=True):
return self.set_fs_attributes_if_different(file_args, changed, diff, expand)

Expand Down
12 changes: 9 additions & 3 deletions test/units/module_utils/basic/test_set_mode_if_different.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,18 @@ def mock_lchmod(mocker):
yield m_lchmod


@pytest.mark.parametrize('previous_changes, check_mode, stdin',
product((True, False), (True, False), ({},)),
@pytest.mark.parametrize('previous_changes, check_mode, exists, stdin',
product((True, False), (True, False), (True, False), ({},)),
indirect=['stdin'])
def test_no_mode_given_returns_previous_changes(am, mock_stats, mock_lchmod, mocker, previous_changes, check_mode):
def test_no_mode_given_returns_previous_changes(am, mock_stats, mock_lchmod, mocker, previous_changes, check_mode, exists):
am.check_mode = check_mode
mocker.patch('os.lstat', side_effect=[mock_stats['before']])
m_lchmod = mocker.patch('os.lchmod', return_value=None, create=True)
m_path_exists = mocker.patch('os.path.exists', return_value=exists)

assert am.set_mode_if_different('/path/to/file', None, previous_changes) == previous_changes
assert not m_lchmod.called
assert not m_path_exists.called


@pytest.mark.parametrize('mode, check_mode, stdin',
Expand All @@ -71,6 +73,7 @@ def test_mode_changed_to_0660(am, mock_stats, mocker, mode, check_mode):
am.check_mode = check_mode
mocker.patch('os.lstat', side_effect=[mock_stats['before'], mock_stats['after'], mock_stats['after']])
m_lchmod = mocker.patch('os.lchmod', return_value=None, create=True)
mocker.patch('os.path.exists', return_value=True)

assert am.set_mode_if_different('/path/to/file', mode, False)
if check_mode:
Expand All @@ -89,6 +92,7 @@ def test_mode_unchanged_when_already_0660(am, mock_stats, mocker, mode, check_mo
am.check_mode = check_mode
mocker.patch('os.lstat', side_effect=[mock_stats['after'], mock_stats['after'], mock_stats['after']])
m_lchmod = mocker.patch('os.lchmod', return_value=None, create=True)
mocker.patch('os.path.exists', return_value=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

For consistency, shouldn't you assert that this is called, like os.lchmod ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Following @Spredzy advice, in order to be consistent with mock of os.lstat, assert not m_path_exists.called was removed :)
We kept it only when return_value of the os.path.exists mock is parametrized.

Adding this assert for every os.path.exists mock doesn't hurt, what do you think ?


assert not am.set_mode_if_different('/path/to/file', mode, False)
assert not m_lchmod.called
Expand All @@ -111,6 +115,7 @@ def _hasattr(obj, name):
mocker.patch('os.lstat', side_effect=[mock_stats['before'], mock_stats['after']])
mocker.patch.object(builtins, 'hasattr', side_effect=_hasattr)
mocker.patch('os.path.islink', return_value=False)
mocker.patch('os.path.exists', return_value=True)
m_chmod = mocker.patch('os.chmod', return_value=None)

assert am.set_mode_if_different('/path/to/file/no_lchmod', 0o660, False)
Expand All @@ -137,6 +142,7 @@ def _hasattr(obj, name):
mocker.patch('os.lstat', side_effect=[mock_stats['before'], mock_stats['after']])
mocker.patch.object(builtins, 'hasattr', side_effect=_hasattr)
mocker.patch('os.path.islink', return_value=True)
mocker.patch('os.path.exists', return_value=True)
m_chmod = mocker.patch('os.chmod', return_value=None)
mocker.patch('os.stat', return_value=mock_stats['after'])

Expand Down