【问题标题】:Ansible. override single dictionary key [duplicate]安西布尔。覆盖单个字典键[重复]
【发布时间】:2014-08-05 00:52:29
【问题描述】:

我正在使用 ansible 来管理生产配置以及 vagrant box。 我有默认值的文件:group_vars/all。

---
env: prod
wwwuser: www-data

db:
    root_pwd: root_pwd
    pdo_driver: pdo_mysql
    host: localhost
    name: test
    user: test
    pwd: test
    charset: utf8

domain: somedomain
projectdir: /var/www/application
webrootdir: "{{ projectdir }}/web"

在 host_vars/vagrantbox 我想要类似的东西:

db:
    root_pwd: super_easy_password

但是这个完全覆盖了 db 字典,而我想覆盖单个键。 如何实现?

更新 1 刚刚检查了 ansible.cfg:

[defaults]
host_key_checking=false
hash_behaviour=merge

groups_vars/all

db:
    root_pwd: some_strong_pwd
    pdo_driver: pdo_mysql
    host: localhost
    name: dbname
    user: dbuser
    pwd: some password
    charset: utf8

host_vars/vagrantbox

db:
    root_pwd: root

我收到以下错误:

One or more undefined variables: 'dict object' has no attribute 'name'

我做错了什么?

【问题讨论】:

    标签: python yaml ansible


    【解决方案1】:

    默认情况下,Ansible 在第一级覆盖变量。如果您希望能够合并字典,则必须更改您的 ansible.cfg 文件并设置:

    hash_behaviour=merge
    

    (默认值为replace)。

    请注意,Ansible 团队 does not recommend this。 我想这是用户之间真正的划分设置。一种一劳永逸的决定:当您开始使用此功能时,您将无法返回,并且您可能无法与replace-type 的人分享您的剧本。

    但是,您仍然可以从现有的剧本中受益(我不认为剧本将 replace 行为用作“功能”)。这就像拥有 AB 血型,成为一个通用接收器......但由于魔法通常发生在可变分辨率上,而不是在任务或模板内部,我认为通常可以在没有任何变化的情况下分享你的角色。

    如果您需要从角色参数中覆盖单个键,则必须以某种复杂的方式传递参数。

    例如,要为特定角色覆盖 php5 字典中的 post_max_size 和 upload_max_size 键,您必须这样做:

    - { role: php5-fpm, php5: { post_max_size: 40M,
                                upload_max_filesize: 20M }}
    

    话虽如此,我从一开始就使用merge 行为,我对此非常满意。保持变量井井有条非常方便。

    【讨论】:

    • 查看这个帖子,了解为什么它被视为“糟糕的做法”:groups.google.com/forum/#!topic/ansible-project/1f8Y1JCkwvI TLDR:它鼓励复杂的行为,而 ansible 的创建者认为这是一件坏事。
    • 我想每个人都将复杂的行为视为 BadThing™。但是说“使用哈希比普通变量更复杂”确实是主观的。我个人认为使用哈希并不复杂或产生复杂的行为。同样,您可以对您的配置进行分组,当您有复杂的设置时,它最终使事情更具可读性,并且具有有趣的“范围界定”副作用。但是它有一个 BIG 的缺点:您不能将某个哈希键值重用为同一哈希中键的另一个值(这真的很烦人!)
    • 我不明白缺点,需要详细说明吗?你永远不能在同一个哈希中使用同一个键两次..
    • @grasshopper: 例如,你不能定义 : foo.bar: 5 和同一个 dict foo.baz: {{ foo.bar }} (对不起,不能放代码在 cmets 中;您必须想象这种“yaml 风格”。
    • 肯定有必要添加一个运算符以使显式合并仅在需要的地方成为可能?将其视为某种全球魔法实在是太奇怪了。
    【解决方案2】:

    从 Ansible 2.0 开始,您可以使用 Jinja2 combine 过滤器来合并 YAML 哈希/字典,而无需在 ansible.cfg 文件中的全局级别设置 hash_behavior=merge。

    相关文档:https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#sts=Combining%20hashes/dictionaries%C2%B6

    【讨论】:

    【解决方案3】:

    我发现最好的方法是使用变量作为字典项的值,并覆盖它。我发现这允许关于 ansible 的变量顺序的简单而强大的变量优先级

    role/parent/defaults/main.yml

    ---
    root_pw_value: ParentPassword
    
    parent_dict:
      - root_pw: "{{ root_pw_value }}"
    

    role/child/defaults/main.yml

    注意:role/child/meta/main.yml 包含 dependencies: - { role: parent }

    ---
    root_pw_value: ChildPassword
    

    play-me.yml

    ---
      - hosts: all
        roles:
          - child
    

    roles/parent/tasks/main.yml & roles/child/tasks/main.yml

    - debug: var=parent_dict
    

    运行ansible -i localhost, --connection="local" play-me.yml,你会得到以下输出:

    PLAY [all] ******************************************************************** 
    
    GATHERING FACTS *************************************************************** 
    ok: [localhost]
    
    TASK: [parent | debug var=parent_dict] **************************************** 
    ok: [localhost] => {
        "var": {
            "parent_dict": [
                {
                    "root_pw": "ParentPassword"
                }
            ]
        }
    }
    
    TASK: [child | debug var=parent_dict] ***************************************** 
    ok: [localhost] => {
        "var": {
            "parent_dict": [
                {
                    "root_pw": "ChildPassword"
                }
            ]
        }
    }
    
    PLAY RECAP ******************************************************************** 
    localhost                  : ok=3    changed=0    unreachable=0    failed=0
    

    这些是默认值。如果您在更具体的优先级别指定 root_pw_value,例如清单组/主机变量、角色变量、命令行上的 extra_vars 或任何来自优先顺序 [0] 的内容,您将得到这些。

    [0]http://docs.ansible.com/ansible/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable

    【讨论】:

      【解决方案4】:

      刚刚尝试使用 ansible 1.9.3,它工作正常。不确定,但您似乎只是在group_vars 目录的名称中有错字(不是groups_vars)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-21
        • 2015-11-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多