Qual é a diferença entre include_tasks e import_tasks?

63

No Ansible 2.4, o includemódulo está obsoleto. Em seu lugar, é fornecido com dois módulos de substituição, import_taskse include_tasks. Mas eles têm descrições muito semelhantes:

  • include_tasks: Inclui um arquivo com uma lista de tarefas a serem executadas no manual atual.
  • import_tasks: Importa uma lista de tarefas a serem adicionadas ao manual atual para posterior execução.

Quando devo usar o primeiro e quando devo usar o último?

Ben S
fonte
(Também: o aviso de depreciação refere-se a "dinâmico" e tarefas "estáticas" Eu li os docs, mas não compreendê-los..)
Ben S

Respostas:

70

Há bastante sobre esse tópico na documentação:

A principal diferença é:

Todas as import*instruções são pré-processadas no momento em que os playbooks são analisados.
Todas as include*instruções são processadas como foram encontradas durante a execução do manual.

Então importé estático, includeé dinâmico.

Pela minha experiência, você deve usar importquando lida com "unidades" lógicas. Por exemplo, separe uma longa lista de tarefas em arquivos de subtarefa:

main.yml:

- import_tasks: prepare_filesystem.yml
- import_tasks: install_prerequisites.yml
- import_tasks: install_application.yml

Mas você usaria includepara lidar com diferentes fluxos de trabalho e tomar decisões com base em alguns fatos coletados dinamicamente:

install_prerequisites:

- include_tasks: prerequisites_{{ ansible_os_family | lower }}.yml
Konstantin Suvorov
fonte
8
Achei este link muito útil: docs.ansible.com/ansible/latest/… Exibe um caso em que a importação e a inclusão se comportam de maneira diferente - uma condição 'quando' em que as tarefas no arquivo podem alterar os critérios usados ​​para determinar a importação . Com import_tasks, cada tarefa verifica os critérios, para que o comportamento seja alterado quando o critério for alterado. Com include_tasks, as tarefas estão presentes ou não, com base em se a condição foi avaliada como verdadeira quando a instrução include_tasks foi executada. Se eu entendi bem ...
Ethel Evans
Qual foi o comportamento de include? Se estivéssemos usando includeseria import_taskso equivalente?
Andy Shinn
includetinha static: yes(se comportou como import_tasks) e static: no(como include_tasks).
Konstantin Suvorov
Qual é o padrão static?
Andy Shinn
staticé Nonepor padrão: Desde o Ansible 2.0, as inclusões de tarefas são dinâmicas e se comportam mais como tarefas reais. Isso significa que eles podem ser repetidos, ignorados e usar variáveis ​​de qualquer fonte. O Ansible tenta detectar isso automaticamente, mas você pode usar a diretiva estática (que foi adicionada no Ansible 2.1) para ignorar a detecção automática.
Konstantin Suvorov
17

As importações são estáticas, as inclusões são dinâmicas. As importações acontecem no momento da análise, incluindo no tempo de execução.

As importações basicamente substituem a tarefa pelas tarefas do arquivo. Não há import_tasktempo de execução. Portanto, atributos como tagse when(e provavelmente outros atributos) são copiados para todas as tarefas importadas.

includes são realmente executados. tagse whende uma tarefa incluída se aplicam apenas à tarefa em si.

As tarefas marcadas de um arquivo importado são executadas se a importtarefa não estiver marcada. Nenhuma tarefa é executada a partir de um arquivo incluído se a includetarefa não estiver marcada.

Todas as tarefas de um arquivo importado são executadas se a importtarefa estiver marcada. Somente tarefas marcadas de um arquivo incluído são executadas se a includetarefa estiver marcada.

Limitações de imports:

  • não pode ser usado com with_*ou loopatributos
  • não pode importar um arquivo, cujo nome depende de uma variável

Limitações de includes:

  • --list-tags não mostra tags dos arquivos incluídos
  • --list-tasks não mostra tarefas dos arquivos incluídos
  • você não pode usar notifypara acionar um nome de manipulador que vem de dentro de uma inclusão dinâmica
  • você não pode usar --start-at-taskpara iniciar a execução em uma tarefa dentro de uma inclusão dinâmica

Mais sobre isso aqui e aqui .

Para mim, isso se resume basicamente ao fato de que imports não pode ser usado com atributos de loop.

importcertamente falharia em casos como este :

# playbook.yml
- import_tasks: set-x.yml
  when: x is not defined

# set-x.yml
- set_fact
  x: foo
- debug:
  var: x

debugnão é executado, pois herda whenda import_taskstarefa. Portanto, não há importação de arquivos de tarefas que alteram as variáveis ​​usadas no atributo import's when.

Eu tinha uma política para começar com imports, mas uma vez que eu preciso includegarantir que nada seja importado pelo arquivo incluído ou pelos arquivos que ele inclui. Mas isso é muito difícil de manter. E ainda não está claro se isso vai me proteger de problemas. Significado, misturando includes e imports que eles não recomendam.

Não posso usar apenas imports, pois ocasionalmente preciso repetir includetarefas. Eu provavelmente poderia mudar para apenas includes. Mas decidi mudar para importações em todos os lugares, exceto nos casos em que a tarefa deveria ser executada várias vezes. Decidi experimentar todos esses casos complicados em primeira mão. Talvez não haja nenhum em meus playbooks. Ou espero encontrar uma maneira de fazê-lo funcionar.

UPD Um truque possivelmente útil para criar um arquivo de tarefas que pode ser importado várias vezes, mas executado uma vez :

- name: ...
  ...
  when: not _file_executed | default(False)

- name: ...
  ...
  when: not _file_executed | default(False)

...

- name: Set _file_executed
  set_fact:
    _file_executed: True

UPD Um efeito não esperado da mistura de inclusões e importações é que os vars substituem os de importação:

playbook.yml:

- hosts: all
  tasks:
    - import_tasks: 2.yml
      vars:
        v1: 1
    - include_tasks: 2.yml
      vars:
        v1: 1

2.yml:

- import_tasks: 3.yml
  vars:
    v1: 2

3.yml:

- debug:
    var: v1    # 2 then 1

Provavelmente, porque include_tasksprimeiro faz todas as importações estáticas adicionais e depois altera as variáveis ​​passadas por sua varsdiretiva.

Na verdade, isso acontece não apenas com as importações:

playbook.yml:

- hosts: all
  tasks:
    - import_tasks: 2.yml
      vars:
        v1: 1
    - include_tasks: 2.yml
      vars:
        v1: 1

2.yml:

- debug:
    var: v1    # 2 then 1
  vars:
    v1: 2

UPD Outro caso de mistura inclui e importa.

playbook.yml:

- hosts: all
  tasks:
    # here you're bound to use include, some sort of loop
    - include_tasks: 2.yml
      vars:
        https: yes

2.yml:

- import_tasks: 3.yml
  when: https

3.yml:

- import_tasks: 4.yml
  vars:
    https: no  # here we're trying to temporarily override https var
- import_tasks: 4.yml

4.yml:

- debug:
    var: https

Obtemos truee true, veja o caso anterior (incluir vars têm precedência sobre vars de importação). Então, mudamos para inclui 3.yml. Mas então a primeira inclusão 3.ymlé ignorada. Uma vez que herda when: httpsda tarefa pai, e a última supostamente tira httpsda tarefa vars. A solução é mudar para as inclusões 2.ymltambém. Isso impede a propagação de when: httpspara as tarefas filho.

x-yuri
fonte
4
Ótima resposta!. Fiquei frustrado com todo mundo na internet apenas repetindo o que a documentação diz. Obrigado.
Sergio Acosta