SONiC使用了ansible的playbooks,所以先了解一下playbooks。文章参照Playbooks介绍。
根据上面学到的知识,我们查看一下sonic_mgmt的testbed的运行机制。
首先我们先找一个例子,比如测试vlan的测试用例ansible-playbook test_sonic.yml -i inventory --limit {DUT_NAME} -e "testbed_name={TESTBED_NAME} testcase_name=vlan"
。
首先说一下参数:
test_sonic.yml
表示指定play-i inventory
配置DUTs的信息--limit {DUT_NAME}
表示从inventory指定一个DUT-e "testbed_name={TESTBED_NAME} testcase_name=vlan"
表示EXTRA_VARS
。
我们首先了解test_sonic.yml
- hosts: sonic
vars:
# 以下表示docker的registry地址和用户名密码
docker_registry_host: sonicdev-microsoft.azurecr.io:443
docker_registry_username: 1dafc8d7-d19c-4f58-8653-e8d904f30dab
docker_registry_password: sonic
roles:
# roles目录下的test中对应的tasks、handlers、files、templates、vars分别添加到play中
- { role: test, scope: 'sonic' }
- hosts: [lldp_neighbors]
gather_facts: no
roles:
- { role: test, scope: 'lldp_neighbors' }
接着我们查看ansible/roles/test/task/main.yml
设置了指定的条件scope == sonic
的时候,指定文件sonic.yml
# 这里面指定了我们的testcase_name对应的yml文件
- include_vars: "roles/test/vars/testcases.yml"
# 获取主机的minigraph信息,py代码位于ansible/library
# 获取的xml信息文件位于ansible/minigraph
- name: Gathering minigraph facts about the device
minigraph_facts: host={{ inventory_hostname }}
# 以下三项都是进行配置
- name: Set sonic_hwsku fact
set_fact:
sonic_hwsku: "{{minigraph_hwsku}}"
- name: Set sonic_asic_type fact
set_fact:
sonic_asic_type: broadcom
when: sonic_hwsku in broadcom_hwskus
- name: Set sonic_asic_type fact
set_fact:
sonic_asic_type: mellanox
when: sonic_hwsku in mellanox_hwskus
# 当tags没有指定的时候报错
# 当testbed_name没有指定的时候调用test_sonic_by_tag.yml,我们先忽略,因为一般是指定的。
- block:
- fail: msg="You didn't provide testbed_name=yourtestbedname, so will run by test by tag. Please specify tests you want to run using --tags"
when: tags is not defined
- include: test_sonic_by_tag.yml
when:
- testbed_name is not defined
# 当testbed_name和testcase_name都不指定的时候报错
- fail: msg="Please specify a testcase_name to run a specific test associated with the testbed topology"
when:
- testbed_name is defined
- testcase_name is not defined
- block:
# 连接指定的testbed
- name: Gathering testbed information
test_facts: testbed_name="{{ testbed_name }}"
connection: local
# 如果DUT不属于testbed报错
- fail: msg="The DUT you are trying to run test does not belongs to this testbed"
when: testbed_facts['dut'] != inventory_hostname
- name: set testbed_type
set_fact:
testbed_type: "{{ testbed_facts['topo'] }}"
ptf_host: "{{ testbed_facts['ptf_ip'] }}"
topo: "topo_{{ testbed_facts['topo'] }}.yml"
- name: set vm
set_fact:
vm: "{{ testbed_facts['vm_base'] }}"
when: "testbed_facts['vm_base'] != ''"
- fail: msg="cannot find {{ testcase_name }} in available testcases or is not supported topology of this testbed {{ testbed_name }}"
when: (testcase_name is not defined) or (testbed_type not in testcases[testcase_name]['topologies'])
- include: test_sonic_by_testname.yml
when:
- testbed_name is defined
- testcase_name is defined
接下来就是上面文件引入的文件ansible/roles/test/vars/testcases.yml
# 其实有好多,我们先看vlan一个
testcases:
vlan:
# 指定下一个文件`ansible/roles/test/tasks/vlantb.yml`
filename: vlantb.yml
# 支持的拓扑类型
topologies: [t0, t0-16, t0-116]
required_vars:
ptf_host:
testbed_type:
然后就是文件ansible/roles/test/tasks/vlantb.yml
# 应用vlan配置
- name: Vlan test setup on testbed
include: vlan_configure.yml
tags: vlan_configure
# 执行vlan测试
- name: Vlan test run on testbed
include: vlan_test.yml
tags: vlan_test
# 清除vlan配置
- name: Clean up Vlan test configuration on the testbed
include: vlan_cleanup.yml
tags: vlan_cleanup
vlan配置的文件ansible/roles/test/tasks/vlan_configure.yml
# 没有指定ptf_host报错
- fail: msg="Please set ptf_host variable"
when: ptf_host is not defined
# testbed_type不对的话报错
- fail: msg="Invalid testbed_type value '{{testbed_type}}'"
when: testbed_type not in [ 't0', 't0-116' ]
# 打印一下变量的信息
- debug: var=minigraph_portchannels
- debug: var=minigraph_port_indices
- debug: var=minigraph_ports
# 以vlan_info.j2为模板生成vlan端口信息
- name: Generate VLAN ports information
template: src=roles/test/templates/vlan_info.j2
dest=/tmp/vlan_info.yml
connection: local
# 加载vlan信息
- name: Load VLAN ports info from file
include_vars: '/tmp/vlan_info.yml'
- debug: var=vlan_ports_list
- debug: var=vlan_intf_list
# 清空LAGs的IP信息,通过shell脚本
- name: Flush all IP addresses on the LAGs
shell: ip addr flush {{ item.attachto }}
with_items:
- "{{ minigraph_portchannel_interfaces }}"
become: true
# 删除config DB中LAGs的IP信息
- name: Delete all IP addresses on the LAGs in config DB
shell: docker exec -i database redis-cli -n 4 del "PORTCHANNEL_INTERFACE|{{ item.attachto }}|{{ (item.addr ~ '/' ~ item.mask)|ipaddr()|upper() }}"
with_items:
- "{{ minigraph_portchannel_interfaces }}"
become: true
# down掉LAGs
- name: Shutdown LAGs
shell: ifconfig {{ item.attachto }} down
with_items:
- "{{ minigraph_portchannel_interfaces }}"
become: true
- name: sleep for some time
pause: seconds=10
- name: Generate nessesary configuration for test
template: src=roles/test/templates/vlan_configuration.j2
dest=/etc/sonic/vlan_configuration.json
become: true
- name: Load configuration
shell: config load -y /etc/sonic/vlan_configuration.json
become: true
- name: sleep for some time
pause: seconds=10
然后就是运行vlan测试ansible/roles/test/tasks/vlan_test.yml
- name: Configure route for remote IP
shell: ip route add {{ item[0].permit_vlanid[item[1]].remote_ip }} via {{ item[0].permit_vlanid[item[1]].peer_ip }}
with_nested:
- "{{ vlan_ports_list }}"
- "{{ vlan_ports_list[0].permit_vlanid.keys() }}"
become: true
- name: Set unique MACs to PTF interfaces
script: roles/test/files/helpers/change_mac.sh
delegate_to: "{{ptf_host}}"
- name: Copy ARP responder to PTF
copy: src=roles/test/files/helpers/arp_responder.py dest=/opt
delegate_to: "{{ptf_host}}"
- name: Copy arp responder supervisor configuration to the PTF container
template: src=arp_responder.conf.j2 dest=/etc/supervisor/conf.d/arp_responder.conf
vars:
- arp_responder_args: ''
delegate_to: "{{ ptf_host }}"
- name: Reread supervisor configuration
shell: /usr/local/bin/supervisorctl reread
delegate_to: "{{ptf_host}}"
- name: Update supervisor configuration
shell: /usr/local/bin/supervisorctl update
delegate_to: "{{ ptf_host }}"
- name: Copy tests to the PTF container
copy: src=roles/test/files/ptftests dest=/root
delegate_to: "{{ ptf_host }}"
- block:
- include: ptf_runner.yml
vars:
ptf_test_name: VLAN test
ptf_test_dir: ptftests
ptf_test_path: vlan_test.VlanTest
ptf_platform: remote
ptf_test_params:
- vlan_ports_list = \"{{ vlan_ports_list }}\"
- vlan_intf_list = \"{{ vlan_intf_list }}\"
- router_mac = \"{{ ansible_Ethernet0['macaddress'] }}\"
ptf_extra_options: "--relax --debug info --log-file /tmp/vlan_test.log"
rescue:
- debug: msg="PTF test raise error"
我们顺便看一下ansible/roles/test/tasks/ptf_runner.yml
- fail: msg="Please set ptf_host variable"
when: ptf_host is not defined
- name: "PTF Test - {{ ptf_test_name }}"
debug: msg="ptf --test-dir {{ ptf_test_dir }} {{ ptf_test_path }} {% if ptf_qlen is defined %} --qlen={{ ptf_qlen }} {% endif %} {% if ptf_platform_dir is defined %} --platform-dir {{ ptf_platform_dir }} {% endif %} --platform {{ ptf_platform }} {% if ptf_test_params is defined %} -t \"{{ ptf_test_params | default([]) | join(';') }}\" {% endif %} {{ ptf_extra_options | default(\"\")}} --disable-vxlan --disable-geneve --disable-erspan --disable-mpls --disable-nvgre 2>&1"
- shell: ptf --test-dir {{ ptf_test_dir }} {{ ptf_test_path }} {% if ptf_qlen is defined %} --qlen={{ ptf_qlen }} {% endif %} {% if ptf_platform_dir is defined %} --platform-dir {{ ptf_platform_dir }} {% endif %} --platform {{ ptf_platform }} {% if ptf_test_params is defined %} -t "{{ ptf_test_params | default([]) | join(';') }}" {% endif %} {{ ptf_extra_options | default("")}} --disable-vxlan --disable-geneve --disable-erspan --disable-mpls --disable-nvgre 2>&1
args:
chdir: /root
delegate_to: "{{ ptf_host }}"
failed_when: False
register: out
- debug: var=out.stdout_lines
- fail: msg="Failed test '{{ ptf_test_name }}'"
when: out.rc != 0
最后就是清空vlan测试信息ansible/roles/test/tasks/vlan_cleanup.yml
- name: Restore all IP addresses on the LAGs
shell: ip addr add {{ (item.addr ~ "/" ~ item.mask)|ipaddr() }} dev {{ item.attachto }}
with_items:
- "{{ minigraph_portchannel_interfaces }}"
become: true
- name: Bring up LAGs
shell: ifconfig {{ item.attachto }} up
with_items:
- "{{ minigraph_portchannel_interfaces }}"
become: true
- name: Remove configuration for test
file:
state: absent
path: /etc/sonic/vlan_configuration.json
become: true
- name: Reload configuration
shell: config reload -y
become: true
- name: wait for config reload
pause: seconds=60