From 71ea99d10f11bac04464d024e0397d7e54abddce Mon Sep 17 00:00:00 2001 From: Dominik Wombacher Date: Thu, 14 Oct 2021 21:24:23 +0200 Subject: [PATCH] ssh_config: Add 'forwardagent' option (#3495) * Integration Tests for Options added, includes 'proxycommand' * New option 'forwardagent' added to integration tests * Missing double quotes added to 'forwardagent' values to enforce handling as string * New option 'forwardagent' added * yamllint error resolved * 'forwardagent' type changed from str to choices (yes/no) * Changelog added * correct typo Co-authored-by: Felix Fontein * version info added to new option Co-authored-by: Felix Fontein * fix(ssh_config): option name to snake_case, type str to bool * fix(ssh_config): convert bool true/false to str yes/no * fix(ssh_config): rename option to 'forward_agent' in integration test * fix(ssh_config): args key 'forwardagent' renamed to 'forward_agent' * fix(ssh_config): 'else' replaced with 'if' statement to cover case when value is 'None' * increase version_added to 4.0.0 Co-authored-by: Felix Fontein * simplify if statement for True/False to yes/no mapping Co-authored-by: Felix Fontein * update comment to better describe functionality Co-authored-by: Felix Fontein * fix(ssh_config): avoid overwrite of existing option in case of None value * test(ssh_config): case added to verify no changes on existing option if not given in playbook Co-authored-by: Felix Fontein --- ...495-ssh_config_add_forwardagent_option.yml | 3 + plugins/modules/system/ssh_config.py | 12 ++ .../targets/ssh_config/tasks/main.yml | 3 + .../targets/ssh_config/tasks/options.yml | 194 ++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100644 changelogs/fragments/3495-ssh_config_add_forwardagent_option.yml create mode 100644 tests/integration/targets/ssh_config/tasks/options.yml diff --git a/changelogs/fragments/3495-ssh_config_add_forwardagent_option.yml b/changelogs/fragments/3495-ssh_config_add_forwardagent_option.yml new file mode 100644 index 0000000000..9336921ade --- /dev/null +++ b/changelogs/fragments/3495-ssh_config_add_forwardagent_option.yml @@ -0,0 +1,3 @@ +minor_changes: + - ssh_config - new feature to set ``ForwardAgent`` option to ``yes`` or ``no`` + (https://github.com/ansible-collections/community.general/issues/2473). diff --git a/plugins/modules/system/ssh_config.py b/plugins/modules/system/ssh_config.py index 49525849f1..18262a2aae 100644 --- a/plugins/modules/system/ssh_config.py +++ b/plugins/modules/system/ssh_config.py @@ -76,6 +76,11 @@ options: description: - Sets the C(ProxyCommand) option. type: str + forward_agent: + description: + - Sets the C(ForwardAgent) option. + type: bool + version_added: 4.0.0 ssh_config_file: description: - SSH config file. @@ -203,6 +208,12 @@ class SSHConfig(): proxycommand=self.params.get('proxycommand'), ) + # Convert True / False to 'yes' / 'no' for usage in ssh_config + if self.params['forward_agent'] is True: + args['forward_agent'] = 'yes' + if self.params['forward_agent'] is False: + args['forward_agent'] = 'no' + config_changed = False hosts_changed = [] hosts_change_diff = [] @@ -288,6 +299,7 @@ def main(): identity_file=dict(type='path'), port=dict(type='str'), proxycommand=dict(type='str', default=None), + forward_agent=dict(type='bool'), remote_user=dict(type='str'), ssh_config_file=dict(default=None, type='path'), state=dict(type='str', default='present', choices=['present', 'absent']), diff --git a/tests/integration/targets/ssh_config/tasks/main.yml b/tests/integration/targets/ssh_config/tasks/main.yml index 74a6f02fd2..0d4c10a111 100644 --- a/tests/integration/targets/ssh_config/tasks/main.yml +++ b/tests/integration/targets/ssh_config/tasks/main.yml @@ -219,3 +219,6 @@ - short_name.hosts_added == ["full"] - short_name.hosts_changed == [] - short_name.hosts_removed == [] + +- name: Include integration tests for additional options (e.g. proxycommand) + include: 'options.yml' diff --git a/tests/integration/targets/ssh_config/tasks/options.yml b/tests/integration/targets/ssh_config/tasks/options.yml new file mode 100644 index 0000000000..a8ab3010ef --- /dev/null +++ b/tests/integration/targets/ssh_config/tasks/options.yml @@ -0,0 +1,194 @@ +# Reset ssh_config before testing options +- name: Copy sample config file + copy: + src: 'files/ssh_config_test' + dest: '{{ ssh_config_test }}' + +- name: Options - Add in check mode + community.general.ssh_config: + ssh_config_file: "{{ ssh_config_test }}" + host: "options.example.com" + proxycommand: "ssh jumphost.example.com -W %h:%p" + forward_agent: true + state: present + register: options_add + check_mode: yes + +- name: Options - Check if changes are made in check mode + assert: + that: + - options_add.changed + - "'options.example.com' in options_add.hosts_added" + - options_add.hosts_changed is defined + - options_add.hosts_removed is defined + +- name: "Options - Get content of {{ ssh_config_test }}" + slurp: + src: "{{ ssh_config_test }}" + register: slurp_ssh_config + +- name: "Options - Verify that nothign was added to {{ ssh_config_test }} during change mode" + assert: + that: + - "'options.example.com' not in slurp_ssh_config['content'] | b64decode" + +- name: Options - Add a host + community.general.ssh_config: + ssh_config_file: "{{ ssh_config_test }}" + host: "options.example.com" + proxycommand: "ssh jumphost.example.com -W %h:%p" + forward_agent: true + state: present + register: options_add + +- name: Options - Check if changes are made + assert: + that: + - options_add.changed + - "'options.example.com' in options_add.hosts_added" + - options_add.hosts_changed is defined + - options_add.hosts_removed is defined + +- name: Options - Add same host again for idempotency + community.general.ssh_config: + ssh_config_file: "{{ ssh_config_test }}" + host: "options.example.com" + proxycommand: "ssh jumphost.example.com -W %h:%p" + forward_agent: true + state: present + register: options_add_again + +- name: Options - Check for idempotency + assert: + that: + - not options_add_again.changed + - options_add.hosts_changed is defined + - options_add.hosts_removed is defined + - options_add.hosts_added is defined + +- name: "Options - Get content of {{ ssh_config_test }}" + slurp: + src: "{{ ssh_config_test }}" + register: slurp_ssh_config + +- name: "Verify that {{ ssh_config_test }} contains added options" + assert: + that: + - "'proxycommand ssh jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode" + - "'forwardagent yes' in slurp_ssh_config['content'] | b64decode" + +- name: Options - Update host + community.general.ssh_config: + ssh_config_file: "{{ ssh_config_test }}" + host: "options.example.com" + proxycommand: "ssh new-jumphost.example.com -W %h:%p" + forward_agent: no + state: present + register: options_update + +- name: Options - Check for update operation + assert: + that: + - options_update.changed + - options_update.hosts_changed is defined + - "'options.example.com' in options_update.hosts_changed" + - options_update.hosts_removed is defined + - options_update.hosts_added is defined + - options_update.hosts_change_diff is defined + +- name: Options - Update host again + community.general.ssh_config: + ssh_config_file: "{{ ssh_config_test }}" + host: "options.example.com" + proxycommand: "ssh new-jumphost.example.com -W %h:%p" + forward_agent: no + state: present + register: options_update + +- name: Options - Check update operation for idempotency + assert: + that: + - not options_update.changed + - options_update.hosts_changed is defined + - options_update.hosts_removed is defined + - options_update.hosts_added is defined + - options_update.hosts_change_diff is defined + +- name: "Options - Get content of {{ ssh_config_test }}" + slurp: + src: "{{ ssh_config_test }}" + register: slurp_ssh_config + +- name: "Verify that {{ ssh_config_test }} contains changed options" + assert: + that: + - "'proxycommand ssh new-jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode" + - "'forwardagent no' in slurp_ssh_config['content'] | b64decode" + +- name: Options - Ensure no update in case option exist in ssh_config file but wasn't defined in playbook + community.general.ssh_config: + ssh_config_file: "{{ ssh_config_test }}" + host: "options.example.com" + state: present + register: options_no_update + +- name: Options - Check that no update took place + assert: + that: + - not options_update.changed + - options_update.hosts_changed is defined + - options_update.hosts_removed is defined + - options_update.hosts_added is defined + - options_update.hosts_change_diff is defined + +- name: "Options - Get content of {{ ssh_config_test }}" + slurp: + src: "{{ ssh_config_test }}" + register: slurp_ssh_config + +- name: "Verify that {{ ssh_config_test }} wasn't changed" + assert: + that: + - "'proxycommand ssh new-jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode" + - "'forwardagent no' in slurp_ssh_config['content'] | b64decode" + +- name: Options - Delete a host + community.general.ssh_config: + ssh_config_file: "{{ ssh_config_test }}" + host: "options.example.com" + state: absent + register: options_delete + +- name: Options - Check if host was removed + assert: + that: + - options_delete.changed + - "'options.example.com' in options_delete.hosts_removed" + - options_delete.hosts_changed is defined + - options_delete.hosts_added is defined + +- name: Options - Delete same host again for idempotency + community.general.ssh_config: + ssh_config_file: "{{ ssh_config_test }}" + host: "options.example.com" + state: absent + register: options_delete_again + +- name: Options - Check delete operation for idempotency + assert: + that: + - not options_delete_again.changed + - options_delete_again.hosts_changed is defined + - options_delete_again.hosts_removed is defined + - options_delete_again.hosts_added is defined + +- name: "Options - Get content of {{ ssh_config_test }}" + slurp: + src: "{{ ssh_config_test }}" + register: slurp_ssh_config + +- name: "Verify that {{ ssh_config_test }} does not contains deleted options" + assert: + that: + - "'proxycommand ssh new-jumphost.example.com -W %h:%p' not in slurp_ssh_config['content'] | b64decode" + - "'forwardagent no' not in slurp_ssh_config['content'] | b64decode"