赵占旭的博客

Playbooks了解

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 这里面指定了我们的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

1
2
3
4
5
6
7
8
9
10
# 其实有好多,我们先看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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 应用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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 没有指定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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
- 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- 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

注意:所有文章非特别说明皆为原创。为保证信息与源同步,转载时请务必注明文章出处!谢谢合作 :-)

原始链接:http://zhaozhanxu.com/2018/08/13/SONiC/2018-08-13-SONiC-playbooks/

许可协议: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。