web-dev-qa-db-fra.com

Ansible: comment construire une variable à partir d'une autre variable puis récupérer sa valeur

Voici mon problème. Je dois utiliser une variable 'target_Host' puis ajouter '_Host' à sa valeur pour obtenir un autre nom de variable dont j'ai besoin. Si vous regardez mon playbook. La tâche n ° 1, 2, 3 récupère la valeur de la variable, mais la n ° 4 n’est pas capable de faire ce que j’attendais. Existe-t-il un autre moyen d'atteindre le même objectif?

   ---
    - name: "Play to for dynamic groups"
      hosts: local 
      vars:
        - target_Host: smtp
        - smtp_Host: smtp.max.com
      tasks:
        - name: testing
          debug: msg={{ target_Host }}
        - name: testing
          debug: msg={{ smtp_Host }}
        - name: testing
          debug: msg={{ target_Host }}_Host
        - name: testing
          debug: msg={{ {{ target_Host }}_Host }}


Output:

TASK: [testing] *************************************************************** 
ok: [127.0.0.1] => {
    "msg": "smtp"
}

TASK: [testing] *************************************************************** 
ok: [127.0.0.1] => {
    "msg": "smtp.max.com"
}

TASK: [testing] *************************************************************** 
ok: [127.0.0.1] => {
    "msg": "smtp_Host"
}

TASK: [testing] *************************************************************** 
ok: [127.0.0.1] => {
    "msg": "{{{{target_Host}}_Host}}"
}
26
Max

Vous devez mettre des citations autour de cela:

- hosts: local
  vars: [ target_Host: smtp ]
  tasks:
    debug: msg="{{ target_Host }}_Host"

-- modifier --

Kashyap, je dois passer à un niveau de plus que cela. Imaginez qu'il y ait une autre variable 'smtp_Host' et je veux construire cette variable à runtime en utilisant une autre variable (target_Host) et en joignant une chaîne 'Host' à elle. = {{{{{host_ target}} _ Host}} - Max

Ma faute. Je n'ai pas lu assez attentivement.

Ceci (autant que je sache) n'est pas possible. La principale limitation qui nous empêche de le faire (peu importe comment vous le tournez), est le "développement variable" dans ansible est un processus en un seul passage et ce que vous voulez nécessite plusieurs passages.

Les seuls moyens auxquels je puisse penser sont:

  • Créez le playbook de manière dynamique à partir de votre playbook en utilisant template et exécutez-le.
  • J'ai entendu que le moteur Jinja2 effectue l'évaluation multi-passes. Peut-être si vous mettez ces chaînes dans un modèle, puis utilisez le filtre lookup('template', ...). Malheureusement, je n'ai aucune expérience avec les modèles Jinja2, donc je ne sais pas vraiment si c'est encore une option.
2
Kashyap

Si vous avez une variable comme

vars: myvar: xxx xxx_var: anothervalue

la syntaxe de travail Ansible:

- debug: msg={{ vars[myvar + '_var'] }}

vous donnera l'analogue de:

- debug: msg={{ xxx_var }}

16
Nikita Kazantsev

Vous pouvez utiliser "hostvars" pour transmettre la variable. Les informations sur l'hôte peuvent être chargées à partir de vars de groupe ou de vars d'hôte.

yml

---
- name: "Play to for dynamic groups"
  hosts: x0
  vars:
    - target_Host: smtp
  tasks:
    - set_fact: smtp_Host="smtp.max.com"
    - set_fact: Host_var_name={{target_Host}}_Host
    - set_fact: dym_target_Host={{hostvars[inventory_hostname][Host_var_name]}}

    - name: testing
      debug: msg={{ target_Host }}
    - name: testing
      debug: msg={{ smtp_Host }}
    - name: testing
      debug: msg={{ target_Host }}_Host
    - name: testing
      debug: msg={{ dym_target_Host }}

sortie:

PLAY [Play to for dynamic groups] *********************************************

GATHERING FACTS ***************************************************************
ok: [x0]

TASK: [set_fact smtp_Host="smtp.max.com"] *************************************
ok: [x0]

TASK: [set_fact Host_var_name=smtp_Host] **************************************
ok: [x0]

TASK: [set_fact dym_target_Host={{hostvars[inventory_hostname][Host_var_name]}}] ***
ok: [x0]

TASK: [testing] ***************************************************************
ok: [x0] => {
    "msg": "smtp"
}

TASK: [testing] ***************************************************************
ok: [x0] => {
    "msg": "smtp.max.com"
}

TASK: [testing] ***************************************************************
ok: [x0] => {
    "msg": "smtp_Host"
}

TASK: [testing] ***************************************************************
ok: [x0] => {
    "msg": "smtp.max.com"
}

PLAY RECAP ********************************************************************
x0                         : ok=8    changed=0    unreachable=0    failed=0
12
lichon

Vous avez deux façons de choisir:
1. Général utilisant. 

vars:
    - target_Host: smtp
    - smtp: smtp.max.com
tasks: 
    - name: testing
        debug: msg={{ target_Host }}
    - name: testing
        debug: msg={{ smtp }}
    - name: testing
        debug: msg={{ vars[target_Host] }}

2. Utiliser fact

tasks: 
    - set_fact: target_Host=smtp
    - set_fact: smtp=smtp.max.com
    - name: testing
        debug: msg={{ target_Host }}
    - name: testing
        debug: msg={{ smtp }}
    - name: testing
        debug: msg={{hostvars[inventory_hostname][target_Host]}}
3
Xinyuan.Yan

J'utilise actuellement la syntaxe de type tableau de Jinja 2 . Je ne pense pas que ce soit une bonne solution, mais je n’ai pas encore trouvé de solution meilleure.

Permettez-moi de donner un exemple avec l'une de mes tâches abstraites. Voir ma configuration de variable et exemple de tâche ci-dessous:

# Variables file, available in the task context
containers:
  app:
    image: mynamespace/myappcontainer:snapshot
  web:
    image: nginx:latest
  db:
    image: mariadb:latest



# Example task
- name: Start containers
  docker_container:
    name: "{{ item }}"
    image: "{{ containers[item].image }}"
  with_items:
    - app
    - web
    - db

Dans l'exemple ci-dessus, j'utilise le with_items Ansible loop, qui exécute la tâche pour chaque élément et rend la variable {{ item }} disponible en conséquence.
Il en résulte la création de 3 conteneurs Docker, chacun avec le nom de conteneur approprié en fonction de la liste des éléments et l'image appropriée extraite des variables externes que j'ai configurées.

Même si cet exemple utilise with_items, il est bien sûr adaptable à votre problème d'utilisation de vos propres variables.

Bien que cela fonctionne parfaitement dans cette situation, j'ai bien peur que cela nécessite que les variables auxquelles vous souhaitez accéder fassent partie d'une variable parent (containers dans cet exemple). Par conséquent, je recommanderais de scinder les variables avec un . pour construire une hiérarchie, et non avec un _.

Une variable comme a.b.c, où b est dynamique, serait accessible à l'aide de a[b].c.
Une variable comme a.b, où b est dynamique, serait accessible à l'aide de a[b].


Une solution que vous utiliseriez pourrait ressembler à (non testée):

- name: "Play to for dynamic groups"
  hosts: local 
  vars:
    - target: smtp
    - hosts:
        smtp: smtp.max.com
        imap: imap.max.com
  tasks:
    - name: testing
      debug: msg={{ hosts[target] }}

Notez que les variables sont configurées légèrement différemment, car sa structure est hiérarchique.

3
Tim Visée

Il me semble que vous pouvez simplement utiliser l’option var au lieu de msg:

  debug: var="{{ target_Host }}_Host"

Donne:

TASK [testing] ********************************************************************************************************************************
ok: [localhost] => {
    "smtp_Host": "smtp.max.com"
}
0
Jack

Vous pouvez imbriquer vos recherches de la manière suivante:

---
- hosts: local
  connection: local
  gather_facts: no
  vars:
    target_Host: smtp
    lookup_Host: "{{ target_Host }}_Host"
    smtp_Host: smtp.max.com
  tasks:
    - debug: var="{{ lookup_Host }}"
0
J0hnG4lt