Resolvido: Posso usar vars_files quando alguns arquivos não existem


17

Essa é a parte:

vars_files:
  - vars/vars.default.yml
  - vars/vars.yml

Se um arquivo vars/vars.ymlnão existir - aqui está um erro.

ERROR: file could not read: /.../vars/vars.yml

Como carregar variáveis ​​adicionais desse arquivo somente se ele existir? (sem erros)

Respostas:


27

É bem simples mesmo. Você pode compactar seus diferentes itens vars_files em uma única tupla e o Ansible passará automaticamente por cada um deles até encontrar um arquivo existente e carregá-lo. Ex:

vars_files:
  - [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]

4
Segundo os desenvolvedores da Ansible , esta solução carregará todos os arquivos, não apenas o primeiro encontrado.
tjanez

10

De acordo com os desenvolvedores da Ansible , a maneira correta de resolver isso é usar algo como:

vars_files_locs: ['../path/to/file1', '../path/to/file2', ...]

- include_vars: "{{ item }}"
  with_first_found: vars_files_locs

Além disso, eles dizem :

O acima irá carregar corretamente apenas o primeiro arquivo encontrado e é mais flexível do que tentar fazer isso através da vars_filespalavra-chave language.


"apenas o primeiro arquivo encontrado" - a idéia era redefinir algumas variáveis, nem todas elas
Sergey

@ Emery, lendo novamente sua pergunta, vejo que o que você queria é um pouco diferente. Obrigado por apontar isso. Deixarei a resposta como é se alguém achar útil.
tjanez 25/11

1
exceto que include_varsna tarefa dará uma alta precedência de variáveis ​​em relação à função defaultsou #vars
Alex F

2

Eu encontrei esse problema em uma instalação na qual eu precisava criar vários ambientes de implantação (ao vivo, demo, sandbox) no mesmo servidor físico (não são permitidas máquinas virtuais aqui) e, em seguida, um script para implantar repositórios svn arbitrários

Isso requeria uma árvore de diretórios de arquivos variable.yml (opcionais), que se fundissem uns sobre os outros e não gerasse uma exceção, se houver alguma, em falta

Comece ativando a mesclagem de variáveis ​​no ansible - observe que isso faz a mesclagem superficial de hash (1 nível de profundidade) e não é a mesclagem profunda totalmente recursiva

ansible.cfg

[defaults]
hash_behaviour=merge ;; merge rather than replace dictionaries http://docs.ansible.com/ansible/intro_configuration.html###hash-behaviour

Layout de diretório responsável

/group_vars
└── all.yml

/playbooks
├── boostrap.yml
├── demo.yml
├── live.yml
└── sandbox.yml

/roles/deploy/
├── files
├── tasks
│   ├── includes.yml
│   ├── main.yml
└── vars
    ├── main.yml
    ├── project_1.yml
    ├── project_2.yml
    ├── demo
    │   ├── project_1.yml
    │   ├── project_2.yml   
    │   └── main.yml
    ├── live
    │   ├── project_1.yml
    │   ├── project_2.yml   
    │   └── main.yml
    └── sandbox
        ├── project_1.yml
        ├── project_2.yml   
        └── main.yml

role / deploy / tasks / includes.yml

Essa é a lógica principal de uma árvore de diretórios de arquivos variáveis ​​opcionais.

;; imports in this order:
;; - /roles/deploy/vars/main.yml
;; - /roles/deploy/vars/{{ project_name }}.yml
;; - /roles/deploy/vars/{{ project_name }}/main.yml
;; - /roles/deploy/vars/{{ project_name }}/{{ project_env }}.yml
- include_vars:
    dir: 'vars'
    files_matching: "{{ item }}"
    depth: 1
  with_items:
    - "main.yml"
    - "{{ project_name }}.yml"

- include_vars:
    dir: 'vars/{{ env_name }}'
    files_matching: "{{ item }}"
    depth: 1
  with_items:
    - "main.yml"
    - "{{ project_name }}.yml"

group_vars / all.yml

Configurar variáveis ​​padrão para o projeto e vários usuários e ambientes

project_users:
    bootstrap:
        env:   bootstrap
        user:  ansible
        group: ansible
        mode:  755
        root:  /cs/ansible/
        home:  /cs/ansible/home/ansible/
        directories:
            - /cs/ansible/
            - /cs/ansible/home/

    live:
        env:   live
        user:  ansible-live
        group: ansible
        mode:  755
        root:  /cs/ansible/live/
        home:  /cs/ansible/home/ansible-live/

    demo:
        env:   demo
        user:  ansible-demo
        group: ansible
        mode:  755
        root:  /cs/ansible/demo/
        home:  /cs/ansible/home/ansible-demo/

    sandbox:
        env:   sandbox
        user:  ansible-sandbox
        group: ansible
        mode:  755
        root:  /cs/ansible/sandbox/
        home:  /cs/ansible/home/ansible-sandbox/    

project_env:  bootstrap
project_user: "{{ ansible_users[project_env] }}" ;; this will be retroactively updated if project_env is redefined later

funções / deploy / vars / main.yml

padrões do projeto

ansible_project:
  node_env:   development
  node_port:  4200
  nginx_port: 4400

funções / deploy / vars / project_1.yml

padrões para project_1

ansible_project:
  node_port:  4201
  nginx_port: 4401

funções / deploy / vars / live / main.yml

padrões para ambiente ativo, substitui os padrões do projeto

ansible_project:
  node_env: production

funções / deploy / vars / live / project_1.yml

substituições finais para project_1 no ambiente ativo

ansible_project:
  nginx_port: 80

playbooks / demo.yml

Configurar playbooks separados para cada ambiente

- hosts: shared_server
  remote_user: ansible-demo
  vars:
    project_env: demo
  pre_tasks:
    - debug: "msg='{{ facter_gid }}@{{ facter_fqdn }} ({{ server_pseudonym }})'"
    - debug: var=project_ssh_user
  roles:
    - { role: deploy, project_name: project_1 }

AVISO: Como todos os ambientes vivem em um único host, todos os playbooks devem ser executados individualmente; caso contrário, o Ansible tentará executar todos os scripts como o primeiro usuário de login ssh e usará apenas as variáveis ​​para o primeiro usuário. Se você precisar executar todos os scripts seqüencialmente, use xargs para executá-los como comandos separados.

find ./playbooks/*.yml | xargs -L1 time ansible-playbook

1
- hosts: all
  vars_files: vars/vars.default.yml
  vars:
    optional_vars_file: "{{ lookup('first_found', 'vars/vars.yml', errors='ignore') }}"
  tasks:
  - when: optional_vars_file is file
    include_vars: "{{ optional_vars_file }}"

Nota: Os testes de caminho (é um arquivo, existe, ...) funcionam apenas com caminhos absolutos ou caminhos relativos ao diretório de trabalho atual ao executar o comando ansible-playbook. Esta é a razão pela qual usamos a pesquisa. a pesquisa aceita caminhos relativos ao diretório do manual e retorna o caminho absoluto quando o arquivo existe.


0

Ou de uma maneira mais divertida:

- hosts: webservers
  vars:
    paths_to_vars_files:
      - vars/{{ ansible_hostname }}.yml
      - vars/default.yml
  tasks:
    - include_vars: "{{ item }}"
      with_first_found: "{{ paths_to_vars_files }}"

Ou seja, em vez de escrever uma matriz em uma linha com colchetes, como:

['path/to/file1', 'path/to/file2', ...]

Use a maneira yaml de escrever valores de matriz em várias linhas, como:

- path/to/file1
- path/to/file2

Conforme mencionado, ele procura um arquivo vars chamado {{ ansible_hostname }}.yml, e se ele não existir, usadefault.yml


Esta resposta usa o mesmo código que este, exceto que usa dados diferentes. Ou seja, {{ ansible_hostname }}.ymlnome do arquivo em vez de ../path/to/file1. Qual é o objetivo? Pode-se adicionar um número ilimitado de nomes de arquivos de entrada.
techraf

@techraf: Ok, adicionei alguns esclarecimentos / amplificações sobre o motivo de uma nova resposta ter sido enviada. É porque os comentários de falha do servidor não suportam trechos de código de várias linhas, e eu estava apenas enfatizando que as matrizes yaml são frequentemente (de preferência?) Escritas em várias linhas. Eu também ficaria bem se a resposta anterior fosse editada e o formato de matriz de várias linhas mostrado, como vejo isso com mais frequência. Então minha resposta pode ser excluída.
precisa

Ambas as notações são especificadas nos documentos Ansible, no capítulo Fundamentos do YAML . O fato de você ver um com mais frequência do que o outro ainda não faz disso uma nova resposta.
techraf 26/12/16

0

Reunindo várias peças ... include_vars com uma cláusula when que é verdadeira quando o arquivo existe. ie

vars:
  file_to_include: /path/to/file
tasks:
  - include_vars: "{{ file_to_include }}"
    when: file_to_include is exists

0

Nova resposta com base nas versões mais recentes do Ansible - basicamente, você deve usar with_first_found, além skip: truede pular a tarefa se nenhum arquivo for encontrado.

- name: Include vars file if one exists meeting our condition.
  include_vars: "{{ item }}"
  with_first_found:
    - files:
        - vars/{{ variable_here }}.yml
      skip: true

Isso faz com que você não precise ter um arquivo de fallback vars nessa lista.

Veja relacionados: /programming//a/39544405/100134

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.