diff --git a/changelogs/fragments/78748-fix-known-hosts-wrong-changed-status.yaml b/changelogs/fragments/78748-fix-known-hosts-wrong-changed-status.yaml new file mode 100644 index 00000000000..514c8cf18a7 --- /dev/null +++ b/changelogs/fragments/78748-fix-known-hosts-wrong-changed-status.yaml @@ -0,0 +1,2 @@ +bugfixes: + - known_hosts - do not return changed status when a non-existing key is removed (https://github.com/ansible/ansible/issues/78598) diff --git a/lib/ansible/modules/known_hosts.py b/lib/ansible/modules/known_hosts.py index ff3bf34a470..b0c888807c3 100644 --- a/lib/ansible/modules/known_hosts.py +++ b/lib/ansible/modules/known_hosts.py @@ -143,6 +143,12 @@ def enforce_state(module, params): params['diff'] = compute_diff(path, found_line, replace_or_add, state, key) + # check if we are trying to remove a non matching key, + # in that case return with no change to the host + if state == 'absent' and not found_line and key: + params['changed'] = False + return params + # We will change state if found==True & state!="present" # or found==False & state=="present" # i.e found XOR (state=="present") diff --git a/test/integration/targets/known_hosts/defaults/main.yml b/test/integration/targets/known_hosts/defaults/main.yml index eb0a4ba3714..b1b56ac74b2 100644 --- a/test/integration/targets/known_hosts/defaults/main.yml +++ b/test/integration/targets/known_hosts/defaults/main.yml @@ -1,3 +1,6 @@ --- example_org_rsa_key: > example.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAglyZmHHWskQ9wkh8LYbIqzvg99/oloneH7BaZ02ripJUy/2Zynv4tgUfm9fdXvAb1XXCEuTRnts9FBer87+voU0FPRgx3CfY9Sgr0FspUjnm4lqs53FIab1psddAaS7/F7lrnjl6VqBtPwMRQZG7qlml5uogGJwYJHxX0PGtsdoTJsM= + +example_org_ed25519_key: > + example.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIzlnSq5ESxLgW0avvPk3j7zLV59hcAPkxrMNdnZMKP2 \ No newline at end of file diff --git a/test/integration/targets/known_hosts/tasks/main.yml b/test/integration/targets/known_hosts/tasks/main.yml index 67f0e5a6793..dc00dedd871 100644 --- a/test/integration/targets/known_hosts/tasks/main.yml +++ b/test/integration/targets/known_hosts/tasks/main.yml @@ -96,6 +96,37 @@ - 'result.diff.before == result.diff.after' - 'known_hosts.stdout == known_hosts_v2.stdout' +# https://github.com/ansible/ansible/issues/78598 +# test removing nonexistent host key when the other keys exist for the host +- name: remove different key + known_hosts: + name: example.org + key: "{{ example_org_ed25519_key }}" + state: absent + path: "{{remote_tmp_dir}}/known_hosts" + register: result + +- name: remove nonexistent key with check mode + known_hosts: + name: example.org + key: "{{ example_org_ed25519_key }}" + state: absent + path: "{{remote_tmp_dir}}/known_hosts" + check_mode: yes + register: check_mode_result + +- name: get the file content + command: "cat {{remote_tmp_dir}}/known_hosts" + register: known_hosts_different_key_removal + +- name: assert that no changes happened + assert: + that: + - 'result is not changed' + - 'check_mode_result is not changed' + - 'result.diff.before == result.diff.after' + - 'known_hosts_v2.stdout == known_hosts_different_key_removal.stdout' + # test removal - name: remove the host in check mode @@ -129,6 +160,7 @@ - name: assert that the key was removed and ordering preserved assert: that: + - 'diff is changed' - 'result is changed' - '"example.org" not in known_hosts_v3.stdout' - 'known_hosts_v3.stdout_lines[0].startswith("example.com")'