diff --git a/ansible/group_vars/ptf/secrets.yml b/ansible/group_vars/ptf/secrets.yml new file mode 100644 index 0000000000..6b34c12f6a --- /dev/null +++ b/ansible/group_vars/ptf/secrets.yml @@ -0,0 +1,7 @@ +ansible_connection: multi_passwd_ssh + +ansible_user: root +ansible_ssh_pass: root +# ansible_altpasswords: +# - fakepassword1 +# - fakepassword2 diff --git a/ansible/group_vars/ptf_host/secrets.yml b/ansible/group_vars/ptf_host/secrets.yml deleted file mode 100644 index ba70b8b113..0000000000 --- a/ansible/group_vars/ptf_host/secrets.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -# Please update the actual ptf username and password based on your lab config -ptf_host_user: root -ptf_host_pass: root diff --git a/ansible/roles/vm_set/tasks/add_topo.yml b/ansible/roles/vm_set/tasks/add_topo.yml index 96c97a9796..99040fa4c2 100644 --- a/ansible/roles/vm_set/tasks/add_topo.yml +++ b/ansible/roles/vm_set/tasks/add_topo.yml @@ -79,6 +79,9 @@ memory_swap: 8G become: yes + - name: Update ptf password + include_tasks: update_ptf_password.yml + - name: Bind ptf_ip to keysight_api_server vm_topology: cmd: "bind_keysight_api_server_ip" @@ -170,6 +173,9 @@ memory_swap: 32G become: yes + - name: Update ptf password + include_tasks: update_ptf_password.yml + - name: Enable ipv6 for docker container ptf_{{ vm_set_name }} command: docker exec -i ptf_{{ vm_set_name }} sysctl -w net.ipv6.conf.all.disable_ipv6=0 become: yes diff --git a/ansible/roles/vm_set/tasks/announce_routes.yml b/ansible/roles/vm_set/tasks/announce_routes.yml index fe309231cb..ffdb682515 100644 --- a/ansible/roles/vm_set/tasks/announce_routes.yml +++ b/ansible/roles/vm_set/tasks/announce_routes.yml @@ -1,22 +1,14 @@ --- -- name: Include variables for PTF containers - include_vars: - dir: "{{ playbook_dir }}/group_vars/ptf_host/" - - name: Set ptf host set_fact: - ptf_host: "ptf_{{ vm_set_name }}" + ptf_host: "{{ ptf_ip.split('/')[0] }}" ptf_host_ip: "{{ ptf_ip.split('/')[0] }}" - name: Add ptf host add_host: - hostname: "{{ ptf_host }}" - ansible_user: "{{ ptf_host_user }}" - ansible_ssh_host: "{{ ptf_host_ip }}" - ansible_ssh_pass: "{{ ptf_host_pass }}" - ansible_python_interpreter: "/usr/bin/python" + name: "{{ ptf_host }}" groups: - - ptf_host + - ptf - name: Set default exabgp_action set_fact: diff --git a/ansible/roles/vm_set/tasks/ptf_change_mac.yml b/ansible/roles/vm_set/tasks/ptf_change_mac.yml index 2ecd6951dd..4e169b1c39 100644 --- a/ansible/roles/vm_set/tasks/ptf_change_mac.yml +++ b/ansible/roles/vm_set/tasks/ptf_change_mac.yml @@ -1,22 +1,14 @@ --- -- name: Include variables for PTF containers - include_vars: - dir: "{{ playbook_dir }}/group_vars/ptf_host/" - - name: Set ptf host set_fact: - ptf_host: "ptf_{{ vm_set_name }}" + ptf_host: "{{ ptf_ip.split('/')[0] }}" ptf_host_ip: "{{ ptf_ip.split('/')[0] }}" - name: Add ptf host add_host: - hostname: "{{ ptf_host }}" - ansible_user: "{{ ptf_host_user }}" - ansible_ssh_host: "{{ ptf_host_ip }}" - ansible_ssh_pass: "{{ ptf_host_pass }}" - ansible_python_interpreter: "/usr/bin/python" + name: "{{ ptf_host }}" groups: - - ptf_host + - ptf - name: wait until ptf is reachable wait_for: diff --git a/ansible/roles/vm_set/tasks/ptf_portchannel.yml b/ansible/roles/vm_set/tasks/ptf_portchannel.yml index 413dbf1566..dc72dc8fd7 100644 --- a/ansible/roles/vm_set/tasks/ptf_portchannel.yml +++ b/ansible/roles/vm_set/tasks/ptf_portchannel.yml @@ -1,22 +1,14 @@ --- -- name: Include variables for PTF containers - include_vars: - dir: "{{ playbook_dir }}/group_vars/ptf_host/" - - name: Set ptf host set_fact: - ptf_host: "ptf_{{ vm_set_name }}" + ptf_host: "{{ ptf_ip.split('/')[0] }}" ptf_host_ip: "{{ ptf_ip.split('/')[0] }}" - name: Add ptf host add_host: - hostname: "{{ ptf_host }}" - ansible_user: "{{ ptf_host_user }}" - ansible_ssh_host: "{{ ptf_host_ip }}" - ansible_ssh_pass: "{{ ptf_host_pass }}" - ansible_python_interpreter: "/usr/bin/python" + name: "{{ ptf_host }}" groups: - - ptf_host + - ptf - name: find downlink portchannel configuration set_fact: diff --git a/ansible/roles/vm_set/tasks/renumber_topo.yml b/ansible/roles/vm_set/tasks/renumber_topo.yml index eefa8450eb..ed24ade8d3 100644 --- a/ansible/roles/vm_set/tasks/renumber_topo.yml +++ b/ansible/roles/vm_set/tasks/renumber_topo.yml @@ -122,6 +122,9 @@ memory_swap: 32G become: yes + - name: Update ptf password + include_tasks: update_ptf_password.yml + - name: Enable ipv6 for docker container ptf_{{ vm_set_name }} command: docker exec -i ptf_{{ vm_set_name }} sysctl -w net.ipv6.conf.all.disable_ipv6=0 become: yes diff --git a/ansible/roles/vm_set/tasks/start_ptf_tgen.yml b/ansible/roles/vm_set/tasks/start_ptf_tgen.yml index 26aecd1f23..981065dfa7 100644 --- a/ansible/roles/vm_set/tasks/start_ptf_tgen.yml +++ b/ansible/roles/vm_set/tasks/start_ptf_tgen.yml @@ -1,55 +1,43 @@ --- -- name: Include variables for PTF containers - include_vars: - dir: "{{ playbook_dir }}/group_vars/ptf_host/" +- name: Set ptf host + set_fact: + ptf_host: "{{ ptf_ip.split('/')[0] }}" + +- name: Add ptf host + add_host: + name: "{{ ptf_host }}" + groups: + - ptf + +- name: Check if ptf_tgen exists + supervisorctl: + name: ptf_tgen + state: present + become: True + delegate_to: "{{ ptf_host }}" + ignore_errors: True + register: ptf_tgen_state - block: - - name: Set ptf host - set_fact: - ptf_host: "ptf_{{ vm_set_name }}" - ptf_host_ip: "{{ ptf_ip.split('/')[0] }}" + - name: Copy scapy scripts to ptf host + copy: + src: "{{ item }}" + dest: "/ptf_tgen/" + with_fileglob: + - "{{ playbook_dir }}/../spytest/spytest/tgen/scapy/*" + - "{{ playbook_dir }}/../spytest/spytest/dicts.py" - - name: Add ptf host - add_host: - hostname: "{{ ptf_host }}" - ansible_user: "{{ ptf_host_user }}" - ansible_ssh_host: "{{ ptf_host_ip }}" - ansible_ssh_pass: "{{ ptf_host_pass }}" - groups: - - ptf_host + - name: Create ptf_tgen service + copy: + src: "/ptf_tgen/service.sh" + dest: "/ptf_tgen/ptf_tgen.sh" + mode: "0755" + remote_src: yes - - name: Check if ptf_tgen exists + - name: Start ptf_tgen supervisorctl: name: ptf_tgen - state: present - become: True - delegate_to: "{{ ptf_host }}" - ignore_errors: True - register: ptf_tgen_state - - - block: - - name: Copy scapy scripts to ptf host - copy: - src: "{{ item }}" - dest: "/ptf_tgen/" - with_fileglob: - - "{{ playbook_dir }}/../spytest/spytest/tgen/scapy/*" - - "{{ playbook_dir }}/../spytest/spytest/dicts.py" - - - name: Create ptf_tgen service - copy: - src: "/ptf_tgen/service.sh" - dest: "/ptf_tgen/ptf_tgen.sh" - mode: "0755" - remote_src: yes - - - name: Start ptf_tgen - supervisorctl: - name: ptf_tgen - state: restarted - become: True - delegate_to: "{{ ptf_host }}" - when: ptf_tgen_state is not failed - when: - - ptf_host_user is defined - - ptf_host_pass is defined + state: restarted + become: True + delegate_to: "{{ ptf_host }}" + when: ptf_tgen_state is not failed diff --git a/ansible/roles/vm_set/tasks/update_ptf_password.yml b/ansible/roles/vm_set/tasks/update_ptf_password.yml new file mode 100644 index 0000000000..5bfe4ad392 --- /dev/null +++ b/ansible/roles/vm_set/tasks/update_ptf_password.yml @@ -0,0 +1,63 @@ +- include_vars: + file: "{{ playbook_dir }}/group_vars/ptf/secrets.yml" + name: raw_ptf_secrets + no_log: true + +- name: Render ptf secrets + set_fact: + ptf_secrets: >- + {{ + dict( + raw_ptf_secrets.keys() | zip(raw_ptf_secrets.values() + ) + ) + }} + no_log: true + +- block: + + - name: Init default ptf_username + set_fact: + ptf_username: "root" + when: ptf_username is not defined + + - name: Init default ptf_password + set_fact: + ptf_password: "root" + when: ptf_password is not defined + no_log: true + + - name: Override default ptf_username + set_fact: + ptf_username: "{{ ptf_secrets['ansible_user'] }}" + when: "'ansible_user' in ptf_secrets" + + - name: Override default ptf_password + set_fact: + ptf_password: "{{ ptf_secrets['ansible_ssh_pass'] }}" + when: "'ansible_ssh_pass' in ptf_secrets" + + - name: Get ptf_alt_passwords from ptf_secrets + set_fact: + ptf_alt_passwords: "{{ ptf_secrets['ansible_altpasswords'] }}" + no_log: true + + - name: If ptf_alt_passwords is a list, set ptf_password to its first value + set_fact: + ptf_password: "{{ ptf_alt_passwords[0] }}" + when: ptf_alt_passwords | type_debug == "list" and ptf_alt_passwords | length > 0 + no_log: true + + - name: If ptf_alt_passwords is not a list, log a debug message + debug: + msg: >- + The 'ansible_altpasswords' field in group_vars/ptf/secrets.yml is not a list. + Falling back to use the 'ansible_ssh_pass' field." + when: ptf_alt_passwords | type_debug != "list" + + - name: Update ptf username and password + command: docker exec -t ptf_{{ vm_set_name }} sh -c 'echo "{{ ptf_username }}:{{ ptf_password }}" | chpasswd' + become: yes + no_log: true + + when: ptf_secrets is defined and 'ansible_altpasswords' in ptf_secrets diff --git a/ansible/veos_vtb b/ansible/veos_vtb index 99a0b73c03..e455ec31da 100644 --- a/ansible/veos_vtb +++ b/ansible/veos_vtb @@ -96,9 +96,6 @@ all: ptf-08: ansible_host: 10.250.0.119 ansible_hostv6: fec0::ffff:afb:5 - vars: - ansible_user: root - ansible_password: root sonic: vars: mgmt_subnet_mask_length: 24 diff --git a/tests/scp/test_scp_copy.py b/tests/scp/test_scp_copy.py index 17cc8ab719..a4a676e287 100644 --- a/tests/scp/test_scp_copy.py +++ b/tests/scp/test_scp_copy.py @@ -1,5 +1,9 @@ +import logging import pytest from tests.common.helpers.assertions import pytest_assert +from tests.common.utilities import get_dut_current_passwd + +logger = logging.getLogger(__name__) pytestmark = [ pytest.mark.disable_loganalyzer, @@ -33,11 +37,33 @@ def setup_teardown(duthosts, enum_rand_one_per_hwsku_hostname, ptfhost, creds): ptfhost.file(path=file, state="absent") +def _gather_passwords(ptfhost, duthost): + + ptfhostvars = duthost.host.options['variable_manager']._hostvars[ptfhost.hostname] + passwords = [] + alt_passwords = ptfhostvars.get("ansible_altpasswords", []) + if alt_passwords: + passwords.extend(alt_passwords) + + for key in ["ansible_password", "ptf_host_pass", "ansible_altpassword"]: + if key in ptfhostvars: + value = ptfhostvars.get(key, None) + if value: + passwords.append(value) + + return passwords + + def test_scp_copy(duthosts, enum_rand_one_per_hwsku_hostname, ptfhost, setup_teardown, creds): duthost = duthosts[enum_rand_one_per_hwsku_hostname] ptf_ip = ptfhost.mgmt_ip + # After PTF default password rotation is supported, need to figure out which password is currently working + _passwords = _gather_passwords(ptfhost, duthost) + logger.warn("_password: " + str(_passwords)) + current_password = get_dut_current_passwd(ptf_ip, "", creds["ptf_host_user"], _passwords) + # Generate the file from /dev/urandom ptfhost.command(("dd if=/dev/urandom of=./{} count=1 bs={} iflag=fullblock" .format(TEST_FILE_NAME, BLOCK_SIZE))) @@ -59,7 +85,7 @@ def test_scp_copy(duthosts, enum_rand_one_per_hwsku_hostname, ptfhost, setup_tea duthost.command("{} perform_scp.py in {} /root/{} /home/{} {} {}" .format(python_version, ptf_ip, TEST_FILE_NAME, - creds['sonicadmin_user'], creds["ptf_host_user"], creds["ptf_host_pass"])) + creds['sonicadmin_user'], creds["ptf_host_user"], current_password)) # Validate file was received res = duthost.command( @@ -80,7 +106,7 @@ def test_scp_copy(duthosts, enum_rand_one_per_hwsku_hostname, ptfhost, setup_tea # Use scp to copy the file into the PTF duthost.command("{} perform_scp.py out {} /home/{}/{} /root/{} {} {}" .format(python_version, ptf_ip, creds['sonicadmin_user'], TEST_FILE_NAME, TEST_FILE_2_NAME, - creds["ptf_host_user"], creds["ptf_host_pass"])) + creds["ptf_host_user"], current_password)) # Validate that the file copied is now present in the PTF res = ptfhost.command(