Cambiar el valor predeterminado de acuerdo con una condición

16

¿Es posible cambiar el valor predeterminado de una variable de rol de acuerdo con alguna condición (es decir, el valor de otra variable)?

Detalles

Tengo dos variables relacionadas para un comando, envy composer_opts.

Si ambos se dejan por defecto ( env = "prod"y composer_opts = "--no-dev") todo está bien.

Si cambio enva dev, el valor predeterminado para el otro romperá mi comando, por lo que siempre necesito configurar ambos. ¿Sería posible evitar esto estableciendo un valor predeterminado condicional con un script personalizado / if?

Importante: no quiero establecer siempre el composer_optsvalor de acuerdo con el envvalor. Quiero configurarlo solo si aún no está configurado (es decir, un valor predeterminado dinámico).

Pseudocódigo

Me gustaría hacer algo como esto (el siguiente código no es válido, solo pseudocódigo para expresar mi necesidad)

---
# defaults/main.yml

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

Respuestas:

12

Sugiero esta solución:

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

Establecerá composer_optsvariable en cadena ""cuando variable envsea ​​igual a ' dev'

Aquí hay un ejemplo de libro de jugadas basado en una pregunta actualizada:

$ 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

Salida de muestra:

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
fuente
1
Esta es una parte de la solución. Siempre se establecerá composer_optsen una cadena vacía cuando envsea ​​"dev", sobrescribiendo cualquier conjunto de valores real. Creo que el condicional debe extenderse como esto: when: "{{env}}" == 'dev' and "{{composer_opts}}" is undefined. ¿Se ve bien? ¿Puedes responder tu pregunta en consecuencia?
Francesco Abeni
composer_opts se definirá porque tiene su valor predeterminado. Necesita otra expresión para resolver su tarea. Por ejemplo variable custom_composer_opts.
Navern
Elabore con pseudocódigo lo que desea hacer. Actualizaré mi respuesta en consecuencia.
Navern
He actualizado mi pregunta con una explicación adicional y una muestra de pseudocódigo. Gracias.
Francesco Abeni
He actualizado mi respuesta. Revisalo. Creo que entendí lo que necesitas.
Navern
4

Si bien la respuesta de @ Navern funciona, descubrí que la notación Jinja2 incrustada ( "{% if env == 'prod' %} ...) es extremadamente susceptible a la notación y, por lo tanto, bastante frágil. Por ejemplo, al ajustar la línea en cuestión para una mejor legibilidad, como en este código no probado :

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

Terminé con resultados inesperados, como espacios \nen blanco adicionales o en composer_opts.

El enfoque que uso es mucho más tonto, pero también más estable:

- 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'

También encontré que esta publicación de blog es útil, que esencialmente sigue el mismo enfoque.

ssc
fuente
@sec si usa en |lugar de >no podría tener el problema de espacios en blanco. (o obtendrás más de eso LOL)
Michael
@sec Use '> -' y consulte la especificación ansible. Tiene muchas opciones para manipular correctamente cadenas multilínea. yaml-multiline.info Tenga en cuenta, en particular, el indicador de bloqueo de bloques.
DylanYoung
Tenga en cuenta que esta solución también tenía problemas de precedencia. Un hecho no es un defecto.
DylanYoung
2

Ansible set_fact basado en la condición en un revestimiento:

- name: "set composer_opts based on environment"
  set_fact:
     composer_opts:  "{{ '--no-dev --optimize-autoloader --no-interaction' if (env == 'prod') else '' }}"
SK Venkat
fuente
Sin embargo, si coloca este derecho condicional en su archivo defaults.yml, esta solución funcionará. Se vuelve realmente feo muy rápido si tiene una serie de valores predeterminados que dependen de la condición
DylanYoung