web-dev-qa-db-fra.com

Ansible. remplacer la clé de dictionnaire unique

J'utilise ansible pour gérer la configuration comme pour la production, ainsi que pour la boite vagabonde. J'ai un fichier avec des valeurs par défaut: 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"

Dans Host_vars/vagrantbox je veux avoir quelque chose comme:

db:
    root_pwd: super_easy_password

Mais celui-ci remplace complètement dbtrionary db, alors que je veux remplacer une seule clé. Comment y parvenir?

MISE À JOUR 1 Juste vérifié avec 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

J'obtiens l'erreur suivante:

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

Ce que je fais mal?

26
Jevgeni Smirnov

Par défaut, Ansible remplace les variables au premier niveau. Si vous voulez pouvoir fusionner des dictionnaires, vous devez changer votre ansible.cfg fichier et ensemble:

hash_behaviour=merge

(la valeur par défaut étant replace).

Notez que l'équipe Ansible ne le recommande pas (mais n'explique pas pourquoi). Je suppose que c'est un véritable paramètre de division entre les utilisateurs. Une sorte de décision qui se fait une fois pour toutes: lorsque vous commencez à utiliser cette fonctionnalité, vous ne pouvez pas revenir en arrière et vous ne pouvez probablement pas partager votre playbook avec des personnes de type replace-.

Cependant, vous pouvez toujours bénéficier des playbooks (je ne pense pas que les playbooks utilisent le comportement replace comme "fonctionnalité"). C'est comme avoir un groupe sanguin AB, être un récepteur universel ... mais comme la magie se produit généralement à résolution variable, pas à l'intérieur de tâches ou de modèles, je pense qu'il est souvent possible de partager vos rôles sans aucun changement.

Si vous devez remplacer une seule clé de, disons, les paramètres de rôle, vous devrez passer les paramètres d'une manière compliquée.

Par exemple, pour remplacer post_max_size et upload_max_size touches dans un php5 dictionnaire pour un rôle spécifique, vous devrez le faire de cette façon:

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

Cela étant dit, j'utilise le comportement merge depuis le début, et j'en suis assez content. Il est très pratique de garder les variables organisées.

17
leucos

À partir d'Ansible 2.0, vous pouvez utiliser le filtre Jinja2 combine pour fusionner les hachages/dictionnaires YAML sans avoir à définir hash_behavior=merge au niveau mondial dans votre ansible.cfg fichier.

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

14
Jeff Widman

La meilleure façon que j'ai trouvée est d'utiliser des variables comme valeur de l'élément de dictionnaire et de les remplacer. Je trouve que cela permet une priorité de variable simple et puissante en ce qui concerne l'ordre de variable de ansible

role/parent/defaults/main.yml

---
root_pw_value: ParentPassword

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

role/child/defaults/main.yml

Remarque: role/child/meta/main.yml contient dependencies: - { role: parent }

---
root_pw_value: ChildPassword

play-me.yml

---
  - hosts: all
    roles:
      - child

rôles/parent/tâches/main.yml & rôles/enfant/tâches/main.yml

- debug: var=parent_dict

Courir ansible -i localhost, --connection="local" play-me.yml et vous obtenez la sortie suivante:

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

Et ce sont des valeurs par défaut. Si vous spécifiez root_pw_value à des niveaux de priorité plus spécifiques, tels que les variables de groupe d'inventaire/hôte, les variables de rôle, les extra_vars sur la ligne de commande, ou quoi que ce soit de l'ordre de priorité [0], vous les obtiendrez.

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

5
MeanderingCode

Je viens d'essayer avec ansible 1.9.3 et cela fonctionne très bien. Pas sûr, mais il semble que vous ayez juste une faute de frappe dans le nom de group_vars répertoire (pas groups_vars).

0
Borys Borysenko