如何从ansible中的变量文件中调用类似值的列表

How to call list like values from the variable file in ansible

我有一个 ansible 剧本,其中我有多个参数要传递,这些参数有时足够长并且使游戏看起来很胖,因此我正在考虑创建一个变量文件并将所有可能的值保留在该文件中,以便从那里调用它们以使游戏变苗条,同时这将避免对剧本进行更改,我们可以像 cloud_vars.yml.

一样对变量文件进行调整

下面是我的变量文件:

$ cat azure_vars.yml
---
azure_subnet_name: "infra"
azure_os_disk_type: Standard_LRS
azure_nprod_vnet: "/subscriptions/XXXXXXXX-XXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg001/providers/Microsoft.Network/virtualNetworks/vnet"
azure_prod03_vnet: "/subscriptions/XXXXXXXX-XXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg002/providers/Microsoft.Network/virtualNetworks/vnet"
azure_prod02_vnet: "/subscriptions/XXXXXXXX-XXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg003/providers/Microsoft.Network/virtualNetworks/vnet"
public_key: "ssh-rsa:XXXX "
azure_image_id: "/subscriptions/XXXXXXXX-XXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/mgt01-rg001/providers/Microsoft.Compute/galleries/imagegallery/images/myimage/versions/0.0.3"
    
# Azure domains
azure_domains:
  - "eu-azrc1"
  - "us-azrc2"
  - "us-sea01"

# Resource group
azure_res_group:
  - "rg001"
  - "rg002"
  - "rg003"

# Azure locations
azure_location:
  - "westus2"
  - "westeurope"
  - "southcentralus"
...

下面的剧本

下面是设置facts的剧本,供以后在剧本中使用,我很期待知道如何使用azure_domainsazure_res_groupazure_location来自 vaiable 文件的变量,因为它们在列表中定义,截至目前,我已经对名称和位置等进行了硬编码。

$ cat new_vm_Creation.yml
---
- name: create azure vm
  hosts: localhost
  connection: local
  tasks:
   -  include_vars: azure_vars.yml

   - set_fact:
      host: "{{ azure_vm_name.split('.') }}"

   - set_fact:
       azure_domain: "{{ host.1 }}.{{ host.2 }}"

   - name: azure_domain
     debug:
      msg: "{{ azure_domain }}"

   - set_fact:
      azure_location: "westus2"
     when: azure_domain == "us-sea01"

   - set_fact:
      azure_location: "westeurope"
     when: azure_domain == "eu-azrc1"

   - set_fact:
      azure_location: "southcentralus"
     when: azure_domain == "us-azrc2"

   - name: azure_location
     debug:
      msg: "{{ azure_location }}"

   - set_fact:
      res_group: "rg001"
     when: azure_domain == "us-sea01"

   - set_fact:
      res_group: "rg002"
     when: azure_domain == "eu-azrc1"

   - set_fact:
      res_group: "rg003"
     when: azure_domain == "us-azrc2"

   - name: Resource Group
     debug:
      msg: "{{ res_group }}"

   - set_fact:
      vnet: "{{ azure_nprod_vnet }}"
     when: azure_domain == "us-sea01"

   - set_fact:
      vnet: "{{ azure_prod03_vnet }}"
     when: azure_domain == "eu-azrc1"

   - set_fact:
      vnet: "{{ azure_prod02_vnet }}"
     when: azure_domain == "us-azrc2"

   - name: Vnet
     debug:
      msg: "{{ vnet }}"

   - name: create network security group that allows ssh
     azure_rm_securitygroup:
      resource_group: "{{ res_group }}"
      location: "{{ location }}"
      name: "{{ azure_vm_name }}-nsg"
      rules:
        - name: ssh
          protocol: Tcp
          destination_port_range: 22
          access: Allow
          priority: 100
          direction: Inbound

       - name: create virtual network interface card
         azure_rm_networkinterface:
          resource_group: "{{ res_group }}"
          location: "{{ location }}"
          name: "{{ azure_vm_name }}-nic1"
          subnet: "{{ azure_subnet_name }}"
          virtual_network: "{{ vnet }}"
          security_group: "{{ azure_vm_name }}-nsg"
          enable_accelerated_networking: true
          public_ip: no
          state: present
    
       - name: create vm
         azure_rm_virtualmachine:
          resource_group: "{{ res_group }}"
          location: "{{ location }}"
          name: "{{ azure_vm_name }}"
          vm_size: Standard_D4s_v3
          admin_username: some_id
          ssh_password_enabled: false
          ssh_public_keys:
            - path: /home/some_id/.ssh/authorized_keys
              key_data: "{{ public_key }}"
          network_interfaces: "{{ azure_vm_name }}-nic1"
          os_disk_name: "{{ azure_vm_name }}-osdisk"
          managed_disk_type: "{{ azure_os_disk_type }}"
          os_disk_caching: ReadWrite
          os_type: Linux
          image:
            id: "{{ azure_image_id }}"
            publisher: redhat
          plan:
            name: rhel-lvm78
            product: rhel-byos
            publisher: redhat
    ...

您可以在 azure_vars.yml 文件中定义这些结构,包括 jinja2 模板,但只要知道将它们放在 vars 文件中 并不能解析它们 -- jinja2 模板评估在 ansible 中是递归的,所以第一次使用它们 时你会看到成功或可怕的 "VARIABLE IS NOT DEFINED!"

给定 azure_vars.yml

azure_nprod_vnet: "/subscriptions/alpha-nprod/resourceGroups/rg001/providers/Microsoft.Network/virtualNetworks/vnet"
azure_prod03_vnet: "/subscriptions/beta-prod03/resourceGroups/rg002/providers/Microsoft.Network/virtualNetworks/vnet"
azure_prod02_vnet: "/subscriptions/charlie-prod02/resourceGroups/rg003/providers/Microsoft.Network/virtualNetworks/vnet"

things_by_azure_domain:
  "us-sea01":
    azure_location: "westus2"
    res_group: "rg001"
    vnet: "{{ azure_nprod_vnet }}"
  "eu-azrc1": 
    azure_location: "westeurope"
    res_group: "rg002"
    vnet: "{{ azure_prod03_vnet }}"
  "us-azrc2": 
    azure_location: "southcentralus"
    res_group: "rg003"
    vnet: "{{ azure_prod02_vnet }}"

vnet: "{{ things_by_azure_domain[azure_domain].vnet }}"

然后在将 azure_domain 放入作用域后,使用 {{ vnet }} 将递归地计算该表达式:

  tasks:
  # OBSERVE that we can include this, even with `azure_domain` not yet defined
  # because `include_vars` DOES NOT evaluate those jinja2 expressions
  - include_vars: azure_vars.yml
  - set_fact:
      azure_domain: us-azrc2
  - debug:
      var: vnet

屈服

ok: [localhost] => {
    "vnet": "/subscriptions/charlie-prod02/resourceGroups/rg003/providers/Microsoft.Network/virtualNetworks/vnet"

但是,正如我所说,您需要谨慎行事,因为 fat-finger 不会有好的结局:

  tasks:
  - include_vars: azure_vars.yml
  - set_fact:
      azure_domain: us-yankee-doodle
  - debug:
      var: vnet

产量

ok: [localhost] => {
    "vnet": "VARIABLE IS NOT DEFINED!"
}

但至少在我的 ansible 2.9.13 中,运行 在更高的冗长程度下确实浮出了根本原因:

ok: [localhost] => {
    "vnet": "VARIABLE IS NOT DEFINED!: 'dict object' has no attribute 'us-yankee-doodle'"
}

我喜欢 @mdaniel 的想法,但我不知道以后谁可以将它们添加到您的 playbook 中用于不同 tasks:

根据你的post,你可以稍微对齐你的azure_vars.yml,以便让它们都按相同的顺序排列,这将有助于稍后在游戏中轻松调用它们。

因此,我将美国区域排在最前面,欧洲排在最后。

变量文件:

# Azure domains
azure_domains:
  - us-sea01
  - us-azrc2
  - eu-azrc1


# Resource group
azure_res_group:
  - rg001
  - rg002
  - rg003

# Azure locations
azure_location:
  - westus2
  - southcentralus
  - westeurope
...

播放:

现在你可以稍微让你的Playbook更苗条,这将帮助你只修改azure_vars.yml而不是在游戏中。

---
- name: create azure vm
  hosts: localhost
  connection: local
  tasks:
   -  include_vars: azure_vars.yml

   - set_fact:
      host: "{{ azure_vm_name.split('.') }}"

   - set_fact:
       domain: "{{ host.1 }}.{{ host.2 }}"

   - name: Domain
     debug:
      msg: "{{ domain }}"

   - set_fact:
      location: "{{ azure_location[0] }}"
     when: 'domain == azure_domain[0]'

   - set_fact:
      location: "{{ azure_location[1] }}"
     when: 'domain == azure_domain[1]'

   - set_fact:
      location: "{{ azure_location[2] }}"
     when: 'domain == azure_domain[2]'

   - name: Location
     debug:
      msg: "{{ location }}"

   - set_fact:
      res_group: "{{ azure_res_group[0] }}"
     when: 'domain == azure_domain[0]'

   - set_fact:
      res_group: "{{ azure_res_group[1] }}"
     when: 'domain == azure_domain[1]'

   - set_fact:
      res_group: "{{ azure_res_group[2] }}"
     when: 'domain == azure_domain[2]'

   - name: Resource Group
     debug:
      msg: "{{ res_group }}"

   - set_fact:
      vnet: "{{ azure_nprod_vnet }}"
     when: 'domain == azure_domain[0]'

   - set_fact:
      vnet: "{{ azure_prod03_vnet }}"
     when: 'domain == azure_domain[2]'

   - set_fact:
      vnet: "{{ azure_prod02_vnet }}"
     when: 'domain == azure_domain[1]'

   - name: Vnet
     debug:
      msg: "{{ vnet }}"