Skip to content

Commit

Permalink
Merge pull request #1067 from philfry/host_key_checking
Browse files Browse the repository at this point in the history
Fix add_hosts when ansible_host_key_checking is passed to the new host
  • Loading branch information
moreati authored May 11, 2024
2 parents 0f34e25 + 60f8682 commit 0ce9ffc
Show file tree
Hide file tree
Showing 12 changed files with 215 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .ci/localhost_ansible_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,5 @@
with ci_lib.Fold('ansible'):
os.chdir(TESTS_DIR)
playbook = os.environ.get('PLAYBOOK', 'all.yml')
ci_lib.run('./run_ansible_playbook.py %s -l target %s',
ci_lib.run('./run_ansible_playbook.py %s %s',
playbook, ' '.join(sys.argv[1:]))
2 changes: 1 addition & 1 deletion ansible_mitogen/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def _connect_ssh(spec):
"""
Return ContextService arguments for an SSH connection.
"""
if C.HOST_KEY_CHECKING:
if spec.host_key_checking():
check_host_keys = 'enforce'
else:
check_host_keys = 'ignore'
Expand Down
23 changes: 23 additions & 0 deletions ansible_mitogen/transport_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import ansible.constants as C

from ansible.module_utils.six import with_metaclass
from ansible.module_utils.parsing.convert_bool import boolean

# this was added in Ansible >= 2.8.0; fallback to the default interpreter if necessary
try:
Expand Down Expand Up @@ -245,6 +246,12 @@ def python_path(self):
Path to the Python interpreter on the target machine.
"""

@abc.abstractmethod
def host_key_checking(self):
"""
Whether or not to check the keys of the target machine
"""

@abc.abstractmethod
def private_key_file(self):
"""
Expand Down Expand Up @@ -466,6 +473,14 @@ def python_path(self, rediscover_python=False):
action=self._action,
rediscover_python=rediscover_python)

def host_key_checking(self):
def candidates():
yield self._connection.get_task_var('ansible_ssh_host_key_checking')
yield self._connection.get_task_var('ansible_host_key_checking')
yield C.HOST_KEY_CHECKING
val = next((v for v in candidates() if v is not None), True)
return boolean(val)

def private_key_file(self):
return self._play_context.private_key_file

Expand Down Expand Up @@ -692,6 +707,14 @@ def python_path(self, rediscover_python=False):
action=self._action,
rediscover_python=rediscover_python)

def host_key_checking(self):
def candidates():
yield self._host_vars.get('ansible_ssh_host_key_checking')
yield self._host_vars.get('ansible_host_key_checking')
yield C.HOST_KEY_CHECKING
val = next((v for v in candidates() if v is not None), True)
return boolean(val)

def private_key_file(self):
# TODO: must come from PlayContext too.
return (
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Unreleased
* :gh:issue:`952` Fix Ansible `--ask-become-pass`, add test coverage
* :gh:issue:`957` Fix Ansible exception when executing against 10s of hosts
"ValueError: filedescriptor out of range in select()"
* :gh:issue:`1066` Support Ansible `ansible_host_key_checking` & `ansible_ssh_host_key_checking`


v0.3.7 (2024-04-08)
Expand Down
11 changes: 8 additions & 3 deletions tests/ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
[defaults]
any_errors_fatal = true
# callback_whitelist naming will be deprecated in ansible-core >= 2.15.
# callbacks_enabled naming was added in ansible-core 2.11
# callbacks_enabled was added in Ansible 4 (ansible-core 2.11).
# profile_tasks: Displays timing for each task and summary table of top N tasks
# timer: Displays "Playbook run took 0 days, 0 hours, ..."
callbacks_enabled =
profile_tasks,
timer
# callback_whitelist was deprecated in Ansible >= 8 (ansible-core >= 2.15).
callback_whitelist =
profile_tasks,
timer
Expand Down Expand Up @@ -37,7 +40,9 @@ no_target_syslog = True
# Required by integration/ssh/timeouts.yml
timeout = 30

# On Travis, paramiko check fails due to host key checking enabled.
# Ideally this would be true here and and overridden for hosts/groups. However
# ansible_host_key_checking don't work on Vanilla Ansible 2.10, even for
# static inventory hosts (ansible/ansible#49254, ansible/ansible#73708)
host_key_checking = False

[inventory]
Expand Down
6 changes: 6 additions & 0 deletions tests/ansible/hosts/transport_config.hosts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ tc_become
tc_become_method
tc_become_pass
tc_become_user
tc_host_key_checking
tc_password
tc_port
tc_remote_addr
Expand Down Expand Up @@ -74,6 +75,11 @@ tc-become-pass-password ansible_become_password=apassword
tc-become-pass-pass ansible_become_pass=apass
tc-become-pass-both ansible_become_pass=bpass ansible_become_password=bpassword

[tc_host_key_checking]
tc-hkc-unset
tc-hkc-host-key-checking ansible_host_key_checking=true
tc-hkc-ssh-host-key-checking ansible_ssh_host_key_checking=true

[tc_port]
tc-port-unset
tc-port-explicit-port ansible_port=1234
Expand Down
1 change: 1 addition & 0 deletions tests/ansible/integration/transport_config/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
- import_playbook: become_pass.yml
- import_playbook: become_user.yml
- import_playbook: become.yml
- import_playbook: host_key_checking.yml
- import_playbook: password.yml
- import_playbook: port.yml
- import_playbook: python_path.yml
Expand Down
94 changes: 94 additions & 0 deletions tests/ansible/integration/transport_config/host_key_checking.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Each case is followed by mitogen_via= case to test hostvars method.

- name: integration/transport_config/host_key_checking.yml
hosts: tc-hkc-unset
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 1
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "ignore"
fail_msg: out={{ out }}
tags:
- mitogen_only

- hosts: tc-hkc-unset
vars:
mitogen_via: tc-hkc-host-key-checking
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 2
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "enforce"
- out.result[1].method == "ssh"
- out.result[1].kwargs.check_host_keys == "ignore"
fail_msg: out={{ out }}
tags:
- mitogen_only


- hosts: tc-hkc-host-key-checking
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 1
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "enforce"
fail_msg: out={{ out }}
tags:
- mitogen_only

- hosts: tc-hkc-host-key-checking
vars:
mitogen_via: tc-hkc-unset
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 2
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "ignore"
- out.result[1].method == "ssh"
- out.result[1].kwargs.check_host_keys == "enforce"
fail_msg: out={{ out }}
tags:
- mitogen_only


- hosts: tc-hkc-ssh-host-key-checking
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 1
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "enforce"
fail_msg: out={{ out }}
tags:
- mitogen_only

- hosts: tc-hkc-ssh-host-key-checking
vars:
mitogen_via: tc-hkc-unset
tasks:
- include_tasks: ../_mitogen_only.yml
- {mitogen_get_stack: {}, register: out}
- assert:
that:
- out.result | length == 2
- out.result[0].method == "ssh"
- out.result[0].kwargs.check_host_keys == "ignore"
- out.result[1].method == "ssh"
- out.result[1].kwargs.check_host_keys == "enforce"
fail_msg: out={{ out }}
tags:
- mitogen_only
1 change: 1 addition & 0 deletions tests/ansible/regression/all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
- import_playbook: issue_655__wait_for_connection_error.yml
- import_playbook: issue_776__load_plugins_called_twice.yml
- import_playbook: issue_952__ask_become_pass.yml
- import_playbook: issue_1066__add_host__host_key_checking.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
- name: regression/issue_1066__add_host__host_key_checking.yml
hosts: test-targets[0]
gather_facts: false
become: false
tasks:
- name: Add hosts dynamically
add_host:
name: "{{ item.name }}"
ansible_host_key_checking: "{{ item.host_key_checking | default(omit) }}"
ansible_ssh_host_key_checking: "{{ item.host_ssh_key_checking | default(omit) }}"
ansible_host: "{{ hostvars[inventory_hostname].ansible_host | default(omit) }}"
ansible_password: "{{ hostvars[inventory_hostname].ansible_password | default(omit) }}"
ansible_port: "{{ hostvars[inventory_hostname].ansible_port | default(omit) }}"
ansible_python_interpreter: "{{ hostvars[inventory_hostname].ansible_python_interpreter | default(omit) }}"
ansible_user: "{{ hostvars[inventory_hostname].ansible_user | default(omit) }}"
loop:
- {name: issue-1066-host-hkc-false, host_key_checking: false}
- {name: issue-1066-host-hkc-true, host_key_checking: true}
- {name: issue-1066-host-hskc-false, host_ssh_key_checking: false}
- {name: issue-1066-host-hskc-true, host_ssh_key_checking: true}
delegate_to: localhost
tags:
- issue_1066

- name: regression/issue_1066__add_host__host_key_checking.yml
hosts: issue-1066-host-*
gather_facts: false
become: false
serial: 1
tasks:
- meta: reset_connection

# The host key might be in ~/.ssh/known_hosts. If it's removed then no
# problem - test-targets hosts have host_key_checking=false.
- name: Remove existing host keys
known_hosts:
name: "{{ ansible_host }}"
state: absent
delegate_to: localhost

- name: Ping dynamically added hosts
ping:
ignore_errors: true
ignore_unreachable: true
register: issue_1066_ping

- debug:
var: issue_1066_ping

- name: Confirm dynamically added hosts are/are not reachable
vars:
expected:
issue-1066-host-hkc-false: {}
issue-1066-host-hkc-true: {unreachable: true}
issue-1066-host-hskc-false: {}
issue-1066-host-hskc-true: {unreachable: true}
assert:
that:
- issue_1066_ping.unreachable is defined == expected[inventory_hostname].unreachable is defined
- issue_1066_ping.unreachable | default(42) == expected[inventory_hostname].unreachable | default(42)
# ansible_host_key_checking don't work on Vanilla Ansible 2.10, even for
# static inventory hosts (ansible/ansible#49254, ansible/ansible#73708).
when:
- ansible_version.full is version('2.11', '>=', strict=True)
or is_mitogen
tags:
- issue_1066
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,19 @@
# since things are ran on localhost; Azure DevOps loses connection and fails
# TODO: do we want to install docker a different way to be able to do this for other tests too
---
- name: regression/issue_655_wait_for_connection_error.yml
- name: regression/issue_655__wait_for_connection_error.yml
hosts: localhost
gather_facts: yes
become: no
tasks:
- meta: end_play
when:
# TODO CI currently runs on macOS 11 images in Azure DevOps. MacOS 11
# is no longer supported by homebrew, so the following install
# task fails.
- ansible_facts.system == 'Darwin'
- ansible_facts.distribution_major_version == '11'

- name: set up test container and run tests inside it
block:
- name: install deps
Expand Down
4 changes: 3 additions & 1 deletion tests/ansible/setup/report_controller.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
- name: Report controller parameters
hosts: localhost
hosts: test-targets[0]
gather_facts: false
tasks:
- debug:
Expand All @@ -9,9 +9,11 @@
- $(groups): "{{ lookup('pipe', 'groups') }}"
- $(pwd): "{{ lookup('pipe', 'pwd') }}"
- $(whoami): "{{ lookup('pipe', 'whoami') }}"
- ansible_inventory_sources: "{{ ansible_inventory_sources | default('<unset>') }}"
- ansible_run_tags: "{{ ansible_run_tags | default('<unset>') }}"
- ansible_playbook_python: "{{ ansible_playbook_python | default('<unset>') }}"
- ansible_skip_tags: "{{ ansible_skip_tags | default('<unset>') }}"
- ansible_version.full: "{{ ansible_version.full | default('<unset>') }}"
- is_mitogen: "{{ is_mitogen | default('<unset>') }}"
- playbook_dir: "{{ playbook_dir | default('<unset>') }}"
delegate_to: localhost

0 comments on commit 0ce9ffc

Please sign in to comment.