Python 能干。覆盖单个字典键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25129728/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 19:46:47  来源:igfitidea点击:

Ansible. override single dictionary key

pythonyamlansible

提问by Jevgeni Smirnov

I am using ansible to manage configuration as for production, as well as for vagrant box. I have file with default values: group_vars/all.

我使用 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"

In host_vars/vagrantboxI want tohave something like:

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

db:
    root_pwd: super_easy_password

But this one is overriding completely db dictrionary, while I want to override single key. How to achieve that?

但是这个完全覆盖了数据库字典,而我想覆盖单个键。如何做到这一点?

UPDATE 1Just checked with ansible.cfg:

更新 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

host_vars/vagrantbox

db:
    root_pwd: root

I am getting following error:

我收到以下错误:

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

What I do wrong?

我做错了什么?

回答by leucos

By default, Ansible overrides variables at the first level. If you want to be able to merge dictionaries, you have to change your ansible.cfgfile and set :

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

hash_behaviour=merge

(the default value being replace).

(默认值为replace)。

Note that the Ansible team does not recommend this(but do not explain why). I guess this is a real dividing setting between users. A kind of decision that is done once for all : when you start using this feature, you can not go back, and you probably can not share your playbook with replace-type people.

请注意,Ansible 团队不建议这样做(但不解释原因)。我想这是用户之间真正的划分设置。一种一劳永逸的决定:当您开始使用此功能时,您将无法返回,并且您可能无法与replace类型的人分享您的剧本。

However, you can still benefit from the playbooks out there (I don't hink playbooks use replacebehaviour as a "feature"). It's like having an AB blood type, being an universal receiver... but since the magic usually happens at variable resolution, not inside tasks or templates, I think it is often possible to share your roles without any changes.

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

If you need to override a single key from, let's say, role parameters, you'll have to pass parameters in some convoluted way.

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

For instance, to override post_max_sizeand upload_max_sizekeys in a php5dictionnary for a specific role, you'll have to do it this way :

例如,要覆盖特定角色的字典中的post_max_sizeupload_max_sizephp5,您必须这样做:

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

This being said, I use mergebehaviour since the beginning, and I'm pretty happy with it. It is very handy to keep variables organised.

话虽如此,我merge从一开始就使用行为,我对此很满意。将变量组织起来非常方便。

回答by Jeff Widman

Starting with Ansible 2.0, you can use the Jinja2 combinefilter to merge YAML hashes/dictionaries without having to set hash_behavior=mergeat a global level in your ansible.cfgfile.

从 Ansible 2.0 开始,您可以使用 Jinja2combine过滤器来合并 YAML 哈希/字典,而无需hash_behavior=mergeansible.cfg文件中进行全局设置。

Relevant docs: http://docs.ansible.com/ansible/playbooks_filters.html#combining-hashes-dictionaries

相关文档:http: //docs.ansible.com/ansible/playbooks_filters.html#combining-hashes-dictionaries

回答by Borys Borysenko

Just tried with ansible 1.9.3 and it works fine. Not sure but it seems you just have a typo within name of group_varsdirectory (not groups_vars).

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

回答by MeanderingCode

The best way I have found is to use variables as the value of the dictionary item, and override that. I find this allows simple and powerful variable precedence with regards to ansible's order of variable

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

role/parent/defaults/main.yml

角色/父/默认值/main.yml

---
root_pw_value: ParentPassword

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

role/child/defaults/main.yml

角色/子/默认值/main.yml

Note: role/child/meta/main.ymlcontains dependencies: - { role: parent }

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

---
root_pw_value: ChildPassword

play-me.yml

play-me.yml

---
  - hosts: all
    roles:
      - child

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

角色/父/任务/main.yml 和角色/子/任务/main.yml

- debug: var=parent_dict

Run ansible -i localhost, --connection="local" play-me.ymland you get the following output:

运行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

And these are defaults. If you specify root_pw_valueat more specific levels of precedence, such as inventory group/host variables, role variables, extra_vars on the command line, or anything from the precedence order[0] you'll get those.

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

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

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