Modification possible de la valeur par défaut en fonction d'une condition

16

Est-il possible de changer la valeur par défaut d'une variable de rôle en fonction d'une condition (c'est-à-dire la valeur d'une autre variable)?

Détails

J'ai deux variables liées pour une commande, envet composer_opts.

Si les deux sont laissés par défaut ( env = "prod"et composer_opts = "--no-dev") tout va bien.

Si je passe envà dev, la valeur par défaut pour l'autre casse ma commande, j'ai donc toujours besoin de définir les deux. Serait-il possible d'éviter cela en définissant une valeur conditionnelle par défaut avec un script personnalisé / if?

Important: je ne veux pas toujours définir la composer_optsvaleur en fonction de la envvaleur. Je veux le définir uniquement s'il n'est pas déjà défini (c'est-à-dire une valeur dynamique par défaut).

Pseudocode

Je voudrais faire quelque chose comme ça (le code suivant n'est pas valide, juste un pseudocode pour exprimer mon besoin)

---
# defaults/main.yml

env: prod
composer_opts: 
    when: "{{env}}" = 'prod'
        '--no-dev --optimize-autoloader --no-interaction'
    when: "{{env}}" = 'dev'
        '' 
Francesco Abeni
la source

Réponses:

12

Je suggère cette solution:

---
 - set_fact:
     composer_opts: ""
   when: "{{env}}" == 'dev'

Il mettra composer_optsvariable à chaîne ""lorsque la variable envest égale à ' dev'.

Voici un exemple de playbook basé sur une question mise à jour:

$ cat test.yml

---
- hosts: 127.0.0.1
  connection: local
  tasks:
  - set_fact:
      composer_opts: "{% if env == 'prod' %} '--no-dev --optimize-autoloader --no-interaction' {% else %} '' {% endif %}"

  - debug: var=composer_opts

Exemple de sortie:

sudo ansible-playbook test.yml -e env=dev

PLAY [127.0.0.1] ************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [127.0.0.1]

TASK: [set_fact ] ************************************************************* 
ok: [127.0.0.1]

TASK: [debug var="{{composer_opts}}"] ***************************************** 
ok: [127.0.0.1] => {
    "var": {
        " '' ": " '' "
    }
}

PLAY RECAP ******************************************************************** 
127.0.0.1                  : ok=3    changed=0    unreachable=0    failed=0   


sudo ansible-playbook test.yml -e env=prod

PLAY [127.0.0.1] ************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [127.0.0.1]

TASK: [set_fact ] ************************************************************* 
ok: [127.0.0.1]

TASK: [debug var="{{composer_opts}}"] ***************************************** 
ok: [127.0.0.1] => {
    "var": {
        " '--no-dev --optimize-autoloader --no-interaction' ": " '--no-dev --optimize-autoloader --no-interaction' "
    }
}

PLAY RECAP ******************************************************************** 
127.0.0.1                  : ok=3    changed=0    unreachable=0    failed=0   
Navern
la source
1
Cela fait partie de la solution. Il sera toujours défini composer_optssur une chaîne vide lorsque envest "dev", écrasant tout ensemble de valeurs réelles. Je pense que le conditionnel devrait être étendue comme ceci: when: "{{env}}" == 'dev' and "{{composer_opts}}" is undefined. Ça a l'air bien? Pouvez-vous mettre à jour votre question en conséquence?
Francesco Abeni
composer_opts sera défini car il a sa valeur par défaut. Vous avez besoin d'une autre expression pour résoudre votre tâche. Par exemple, variable custom_composer_opts.
Navern
Veuillez élaborer avec pseudocode ce que vous voulez faire. Je mettrai à jour ma réponse en conséquence.
Navern
J'ai mis à jour ma question avec des explications supplémentaires et un échantillon de pseudocode. Je vous remercie.
Francesco Abeni
J'ai mis à jour ma réponse. Vérifie ça. Je crois avoir compris ce dont vous avez besoin.
Navern
4

Bien que la réponse de @ Navern fonctionne, j'ai trouvé que la notation Jinja2 intégrée ( "{% if env == 'prod' %} ...) était extrêmement sensible à la notation et donc plutôt fragile. Par exemple, lors de l'habillage de la ligne en question pour une meilleure lisibilité, comme dans ce code non testé :

composer_opts: >
               "{% if env == 'prod' %}
                   '--no-dev --optimize-autoloader --no-interaction'
                {% else %}
                   ''
                {% endif %}"

Je me suis retrouvé avec des résultats inattendus, tels que des espaces supplémentaires ou \ndans composer_opts.

L'approche que j'utilise est beaucoup plus stupide, mais aussi plus stable:

- name: set composer_opts for dev env
  set_fact:
     composer_opts: ''
     when: "{{env}}" == 'dev'

- name: set composer_opts for prod env
  set_fact:
     composer_opts: '--no-dev --optimize-autoloader --no-interaction'
     when: "{{env}}" == 'prod'

J'ai également trouvé cet article de blog utile qui suit essentiellement la même approche.

ssc
la source
@sec si vous utilisez à la |place de >vous pourriez ne pas avoir de problème d'espace. (ou vous en aurez plus LOL)
Michael
@sec Utilisez '> -' et consultez la spécification ansible. Il a de nombreuses options pour manipuler correctement les chaînes multilignes. yaml-multiline.info Notez, en particulier, l'indicateur de blocage de bloc.
DylanYoung
Notez que cette solution avait également des problèmes de priorité. Un fait n'est pas un défaut.
DylanYoung
2

Ansible set_fact basé sur la condition dans une doublure:

- name: "set composer_opts based on environment"
  set_fact:
     composer_opts:  "{{ '--no-dev --optimize-autoloader --no-interaction' if (env == 'prod') else '' }}"
SK Venkat
la source
Mêmes problèmes de priorité que les autres solutions (un fait n'est pas une valeur par défaut), cependant, si vous mettez ce droit conditionnel dans votre fichier defaults.yml, cette solution fonctionnera. Cela devient très laid très vite si vous avez un certain nombre de défauts dépendant de la condition
DylanYoung