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
最后修改:2021 年 08 月 18 日 08 : 55 PM