Alteração possível do valor padrão de acordo com uma condição

16

É possível alterar o valor padrão da variável de função de acordo com alguma condição (ou seja, o valor de outra variável)?

Detalhes

Eu tenho duas variáveis ​​relacionadas para um comando enve composer_opts.

Se ambos forem deixados no padrão ( env = "prod"e composer_opts = "--no-dev") tudo está ok.

Se eu mudar envpara dev, o padrão para o outro interromperá meu comando, portanto, sempre preciso definir os dois. Seria possível evitar isso definindo um valor padrão condicional com um script personalizado / if?

Importante: não quero sempre definir o composer_optsvalor de acordo com o envvalor. Quero defini-lo apenas se ainda não estiver definido (ou seja, um valor padrão dinâmico).

Pseudo-código

Gostaria de fazer algo assim (o código a seguir não é válido, apenas pseudocódigo para expressar minha necessidade)

---
# defaults/main.yml

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

Respostas:

12

Sugiro esta solução:

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

Ele definirá composer_optsvariável como string ""quando a variável envfor igual a ' dev'.

Aqui está um exemplo de manual com base na pergunta atualizada:

$ 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

Saída de amostra:

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
fonte
1
Isso faz parte da solução. Ele sempre será definido composer_optscomo string vazia quando envfor "dev", substituindo qualquer valor real definido. Eu acho que a condicional deve ser alargado como este: when: "{{env}}" == 'dev' and "{{composer_opts}}" is undefined. Parece bom? Você pode atualizar sua pergunta de acordo?
Francesco Abeni
composer_opts será definido porque possui seu valor padrão. Você precisa de outra expressão para resolver sua tarefa. Por exemplo, variável custom_composer_opts.
Navern
Elabore com pseudocódigo o que você deseja fazer. Vou atualizar minha resposta de acordo.
Navern
Atualizei minha pergunta com uma explicação adicional e um exemplo de pseudocódigo. Obrigado.
Francesco Abeni
Eu atualizei minha resposta. Confira. Eu acredito que entendi o que você precisa.
Navern
4

Embora a resposta do @ Navern funcione, achei a notação Jinja2 ( "{% if env == 'prod' %} ...) embutida extremamente sensível à notação e, portanto, bastante frágil. Por exemplo, ao agrupar a linha em questão para melhor legibilidade, como neste código não testado :

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

Acabei com resultados inesperados, como espaço \nem branco adicional ou in composer_opts.

A abordagem que uso é muito mais estúpida, mas também mais estável:

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

Também achei este post útil, o que essencialmente segue a mesma abordagem.

ssc
fonte
@sec se você usar em |vez de >não ter o problema de espaço em branco. (ou você vai ter mais do mesmo LOL)
Michael
@sec Use '> -' e verifique a especificação ansible. Ele tem muitas opções para manipular corretamente seqüências multilinhas. yaml-multiline.info Observe, em particular, o indicador de chomping de bloco.
DylanYoung
Observe que esta solução também teve problemas de precedência. Um fato não é um padrão.
DylanYoung
2

Ansible set_fact com base na condição em um liner:

- name: "set composer_opts based on environment"
  set_fact:
     composer_opts:  "{{ '--no-dev --optimize-autoloader --no-interaction' if (env == 'prod') else '' }}"
SK Venkat
fonte
Os mesmos problemas de precedência que as outras soluções (um fato não é um padrão); no entanto, se você colocar esse direito condicional em seu arquivo defaults.yml, essa solução funcionará. Fica muito rápido muito feia se você tem um número de defaults dependente da condição
DylanYoung