【问题标题】:Conditionally define variable in Ansible在 Ansible 中有条件地定义变量
【发布时间】:2015-07-09 07:22:20
【问题描述】:

我想有条件地在 Ansible 剧本中定义一个变量,如下所示:

my_var: "{{ 'foo' if my_condition}}"

如果条件未解析为 true,我希望变量保持未定义。

如果我尝试执行代码,Ansible 会给出以下错误:

fatal: [foo.local] => {'msg': 'AnsibleUndefinedVariable: One or more undefined
                       variables: the inline if-expression on line 1 evaluated
                       to false and no else section was defined.', 'failed': True}

为什么这是一个错误?

完整的案例如下:

{role: foo, my_var: "foo"}

如果定义了my_var,角色会做一些特别的事情。在某些情况下,我不希望角色这样做。我可以使用when: condition,但是我必须复制整个角色块。我也可以使用额外的 bool 变量,但我想要一个无需更改角色的“接口”的解决方案。

有什么想法吗?

【问题讨论】:

  • 根据 Jinja 模板设计器文档,“else 部分是可选的。如果未提供,else 块将隐式计算为 Undefined 对象(无论环境中的 undefined 设置为什么)”。我猜对于 Ansible,Undefined 是不允许的,您应该使用已接受答案中指示的 else。奇怪的是,在我自己的一些 Ansible 安装中,这绝对可以在没有 else 的情况下工作,但不是在工作中。

标签: ansible


【解决方案1】:

你可以这样使用:

my_var: "{{ 'foo' if my_condition else '' }}"

如果条件不匹配,将发生“else”,在这种情况下将为变量设置一个空值。我认为这是一个简短、易读且优雅的解决方案。

【讨论】:

  • 如果 my_var 应该设置为其他可能未定义的变量值,请尝试类似:{{ var_a if var_a is defined else var_b | default('default value') }}
  • 可以用类似的方式设置成字典吗?试过:my_var: "{{ '{key1: value1, key2: value2 }' if my_condition }}" 没有任何运气(((
  • OP 告诉你:“我希望变量保持未定义”,而你却将其设置为 ''
  • @poige Ansible 中的未定义变量是一个棘手的问题,因为 Ansible 不使用完整的编程语言。因此,您可以做的最好的事情是将变量的值设置为空值,或者根本不设置变量。
【解决方案2】:

这可以像 bool 一样设置:

- name: Conditional (true and false)
  set_fact: 
      my_boolean_set_to_be: "{{ 'true' if my_var == 'foo' else 'false' }}"  

- name: Display Variable
  debug: msg="{{ my_boolean_set_to_be }}"

这可以设置为更多的条件,如“if-ifelse-else”语句:

- name: Conditional for 'my_var' (2 options and one default)
  set_fact: 
      my_var_set_to_be: "{{ 'breakfast' if my_var == 'morning' else 'lunch' if my_var == 'afternoon' else 'dinner' }}"  

- name: Display Variable
  debug: msg="{{ my_var_set_to_be }}"

【讨论】:

    【解决方案3】:

    这段代码可以帮助你定义一个带条件的变量。

    - hosts: node1
      gather_facts: yes
      tasks:
       - name: Check File
         shell: ls -ld /etc/postfix/post-install
         register: result
         ignore_errors: yes
    
       - name: Define Variable
         set_fact:
             exists: "{{ result.stdout }}"
         when: result|success
    
       - name: Display Variable
         debug: msg="{{ exists }}"
         ignore_errors: yes
    

    所以这里exists 将仅在条件为true 时显示。

    【讨论】:

    • 我建议使用 stat 模块来检查文件,而不是使用 shell 命令。
    【解决方案4】:

    我的例子,在https://stackoverflow.com/a/43403229/5025060之后:

    vars:
        sudoGroup: "{{ 'sudo' if ansible_distribution == 'Ubuntu' else 'wheel' }}"
    

    由于 Ubuntu 与其他平台使用的 sudo 约定不同,这里我告诉 Ansible 如果平台是 Ubuntu,则将名为 sudoGroup 的变量设置为 sudo,否则将其设置为 wheel

    稍后在我的剧本中,我将变量与 Ansible 的 user 模块结合起来,根据运行 Ansible 的操作系统将 sudowheel 添加到帐户的辅助组:

    - name: Add or update bob account
      user:
        name: bob
        uid: 3205
        groups: "{{ sudoGroup }}"
        append: yes
    

    注意事项:

    • 在上面的user: groups: 定义中,{{ variable }} 周围需要双引号
    • 一旦我在 playbook 的全局 vars: 部分中定义了 sudoGroup,Ansible 就会在运行时为我在 hosts: 部分中定义的每个目标配置它(基于 ansible_distribution)。

    【讨论】:

      【解决方案5】:

      我相信您在使用 default(omit) 过滤器。 (Reference)。

      根据示例,mode 的行为就像在循环中的前两项完全没有设置一样。

      - name: touch files with an optional mode
        file:
          dest: "{{item.path}}"
          state: touch
          mode: "{{item.mode|default(omit)}}"
        loop:
          - path: /tmp/foo
          - path: /tmp/bar
          - path: /tmp/baz
            mode: "0444"
      

      【讨论】:

      • 您还可以在其中塞入几乎任何其他值(例如foo | default(5)docs
      猜你喜欢
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      • 2020-03-23
      • 1970-01-01
      • 1970-01-01
      • 2017-01-04
      • 2022-11-21
      • 2021-12-01
      相关资源
      最近更新 更多