Python Ansible、YAML和语法

Python Ansible、YAML和语法,python,networking,yaml,ansible,ansible-playbook,Python,Networking,Yaml,Ansible,Ansible Playbook,我正在尝试创建一个Ansible配置,它将运行一个playbook,并利用一个变量文件创建一个包含多个项目的配置。我正在尝试以下语法,但失败了。我怎样才能解决这个问题 vars/main.yml --- or1host1: - interface: 1/1 description: or1-servertest TRUNK: true allowedVlans: 101-103 NVLAN: true

我正在尝试创建一个Ansible配置,它将运行一个playbook,并利用一个变量文件创建一个包含多个项目的配置。我正在尝试以下语法,但失败了。我怎样才能解决这个问题

vars/main.yml

---
or1host1:

      - interface: 1/1
        description: or1-servertest
        TRUNK: true
        allowedVlans: 101-103
        NVLAN: true
        nativeVLAN: 101
        ACCESS: false
        accessVlan: none
        PC: true
        pcNUM: 10

      - interface: 1/2
        description: or1-servertest2
        TRUNK: false
        allowedVlans: 101-103
        NVLAN: false
        nativeVLAN: 101
        ACCESS: true
        accessVlan: none
        PC: true
        pcNUM: 10
---
nxos:
- {hostname: testhost}
interfaces:
- {ACCESS: 'true', NVLAN: 'true', PC: 'true', TRUNK: 'true', accessVlan: '1', allowedVlans: 500-600,
  desC: serverhost-1005, intF: eth1/1, nativeVLAN: '56', pcNUM: '23'}
- {ACCESS: 'true', NVLAN: 'true', PC: 'true', TRUNK: 'true', accessVlan: '1', allowedVlans: 500-600,
  desC: serverhost-1006, intF: eth1/2, nativeVLAN: '56', pcNUM: '23'}
模板/nxos.j2

{% for interface in or1host1 %}
interface Ethernet{{item.interface}}
description {{item.description}}
{% if item.TRUNK %}
  switchport mode trunk
  switchport trunk allowed vlan {{item.allowedVlans}}
  spanning-tree port type edge trunk
{% if item.NVLAN %}
  switchport trunk native vlan {{item.nativeVLAN}}
{% endif %}
{% endif %}
{% if item.ACCESS %}
  switchport mode access
  switchport access vlan {{item.accessVlan}}
  spanning-tree port type edge
{% endif %}
{% if item.PC %}
  channel-group {{item.pcNUM}} mode active
{% endif %}
  no shut
{% endfor %}
HOST: {{item.hostname}}

-----------------------------------------------------------
-----------------------------------------------------------

{%for i in interfaces %}
interface Ethernet{{i.intF}}
  description {{i.desC}}
{% if i.TRUNK %}
  switchport mode trunk
  switchport trunk allowed vlan {{i.allowedVlans}}
  spanning-tree port type edge trunk
{% if i.NVLAN %}
  switchport trunk native vlan {{i.nativeVLAN}}
{% endif %}
{% endif %}
{% if i.ACCESS %}
  switchport mode access
  switchport access vlan {{i.accessVlan}}
  spanning-tree port type edge
{% endif %}
{% if i.PC %}
  channel-group {{i.pcNUM}} mode active
{% endif %}
  no shut
!
{% endfor %}
运行剧本时,我收到以下错误。

PLAY [Generate Configuration Files] ******************************************* 

GATHERING FACTS *************************************************************** 
ok: [localhost]

TASK: [nxos | Generate configuration files] *********************************** 
fatal: [localhost] => {'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'str object' has no attribute 'interface'", 'failed': True}
fatal: [localhost] => {'msg': 'One or more items failed.', 'failed': True, 'changed': False, 'results': [{'msg': "AnsibleUndefinedVariable: One or more undefined variables: 'str object' has no attribute 'interface'", 'failed': True}]}

FATAL: all hosts have already failed -- aborting

PLAY RECAP ******************************************************************** 
           to retry, use: --limit @/home/gituser/site.retry

localhost                  : ok=1    changed=0    unreachable=1    failed=

这里有几件事。首先,当您不在JSON模式下时,您确实需要注意缩进。当使用4个项目缩进列表项时,所有其他列表项都需要具有相同数量的空格。第二项有6个空格,如果没有完全松散的元素
接口:1/2
,这将是一个语法错误,这是这里的主要问题,因为它没有意义,也无法将其解析为数据结构。在列表中,可以有任意数量的列表项,但在同一级别上没有松散的属性。我想你是想把它放在第二个列表中。这两种情况都已纠正,如下所示:

---
or1-host1:
  - { interface: 1/1, 
      description: or1-servertest, 
      TRUNK: true, allowedVlans: 101-103, 
      NVLAN: true, nativeVLAN: 101, 
      ACCESS: false, accessVlan: none, 
      PC: true, pcNUM: 10
    }

  - {  interface: 1/2,
       description: or1-servertest2, 
       TRUNK: false, allowedVlans: 101-103, 
       NVLAN: false, nativeVLAN: 101, 
       ACCESS: true, accessVlan: none, 
       PC: true, pcNUM: 10
    }
虽然JSON是YML的一个有效子集,但我发现严格使用YML语法更具可读性,如下所示:

--- 
or1-host1:
  - interface: 1/1
    description: or1-servertest
    TRUNK: true
    allowedVlans: 101-103
    NVLAN: true
    nativeVLAN: 101
    ACCESS: false
    accessVlan: none
    PC: true
    pcNUM: 10

  - interface: 1/2 
    description: or1-servertest2
    TRUNK: false
    allowedVlans: 101-103
    NVLAN: false
    nativeVLAN: 101
    ACCESS: true
    accessVlan: none 
    PC: true
    pcNUM: 10
...
在模板中,您将无法访问
1/1
1/2
这样的内容。也许您想在模板中的接口上循环?我不确定

{% for interface in or1-host1 %}
  ...
{% endfor %}

我认为您必须重命名
或1-host1
,因为由于连字符,
或1_host1
将起作用。

最终解决了这个问题,请参见下面的示例

~/vars/mail.yml

---
or1host1:

      - interface: 1/1
        description: or1-servertest
        TRUNK: true
        allowedVlans: 101-103
        NVLAN: true
        nativeVLAN: 101
        ACCESS: false
        accessVlan: none
        PC: true
        pcNUM: 10

      - interface: 1/2
        description: or1-servertest2
        TRUNK: false
        allowedVlans: 101-103
        NVLAN: false
        nativeVLAN: 101
        ACCESS: true
        accessVlan: none
        PC: true
        pcNUM: 10
---
nxos:
- {hostname: testhost}
interfaces:
- {ACCESS: 'true', NVLAN: 'true', PC: 'true', TRUNK: 'true', accessVlan: '1', allowedVlans: 500-600,
  desC: serverhost-1005, intF: eth1/1, nativeVLAN: '56', pcNUM: '23'}
- {ACCESS: 'true', NVLAN: 'true', PC: 'true', TRUNK: 'true', accessVlan: '1', allowedVlans: 500-600,
  desC: serverhost-1006, intF: eth1/2, nativeVLAN: '56', pcNUM: '23'}
~/templates/nxos.j2

{% for interface in or1host1 %}
interface Ethernet{{item.interface}}
description {{item.description}}
{% if item.TRUNK %}
  switchport mode trunk
  switchport trunk allowed vlan {{item.allowedVlans}}
  spanning-tree port type edge trunk
{% if item.NVLAN %}
  switchport trunk native vlan {{item.nativeVLAN}}
{% endif %}
{% endif %}
{% if item.ACCESS %}
  switchport mode access
  switchport access vlan {{item.accessVlan}}
  spanning-tree port type edge
{% endif %}
{% if item.PC %}
  channel-group {{item.pcNUM}} mode active
{% endif %}
  no shut
{% endfor %}
HOST: {{item.hostname}}

-----------------------------------------------------------
-----------------------------------------------------------

{%for i in interfaces %}
interface Ethernet{{i.intF}}
  description {{i.desC}}
{% if i.TRUNK %}
  switchport mode trunk
  switchport trunk allowed vlan {{i.allowedVlans}}
  spanning-tree port type edge trunk
{% if i.NVLAN %}
  switchport trunk native vlan {{i.nativeVLAN}}
{% endif %}
{% endif %}
{% if i.ACCESS %}
  switchport mode access
  switchport access vlan {{i.accessVlan}}
  spanning-tree port type edge
{% endif %}
{% if i.PC %}
  channel-group {{i.pcNUM}} mode active
{% endif %}
  no shut
!
{% endfor %}
配置

HOST: testhost

-----------------------------------------------------------
-----------------------------------------------------------

interface Etherneteth1/1
  description serverhost-1005
  switchport mode trunk
  switchport trunk allowed vlan 500-600
  spanning-tree port type edge trunk
  switchport trunk native vlan 56
  switchport mode access
  switchport access vlan 1
  spanning-tree port type edge
  channel-group 23 mode active
  no shut
!
interface Etherneteth1/2
  description serverhost-1006
  switchport mode trunk
  switchport trunk allowed vlan 500-600
  spanning-tree port type edge trunk
  switchport trunk native vlan 56
  switchport mode access
  switchport access vlan 1
  spanning-tree port type edge
  channel-group 23 mode active
  no shut
!

您遇到了什么样的错误?我编辑了我的原始问题,以考虑下面提到的一些更改,并包括以下错误。感谢您的回答,我编辑了我上面的问题并发布了我遇到的错误。我认为剩下的问题是如何访问属性的符号。尝试
item[“interface”]
而不是
item.interface
,对其他属性也是如此。看起来这可能会起作用,但是,我需要弄清楚if语句。使用更改的变量名运行剧本时会出现以下错误:致命:[localhost]=>{'msg':“AnsibleUndefinedVariable:一个或多个未定义的变量:'TRUNK'未定义“,'failed':True}致命:[localhost]=>{'msg':'One or more items failed','failed':True,'changed','False,'results':[{'msg':“AnsibleUndefinedVariable:一个或多个未定义的变量:'TRUNK'未定义“,'failed':True}]}但定义了
TRUNK
,并且在您的条件下使用
tiem[“TRUNK”]
?如果
TRUNK
是可选元素,您可以使用
测试它是否存在。