Ansible: Dapatkah saya menggunakan vars_files ketika beberapa file tidak ada

17

Itu bagiannya:

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

Jika file vars/vars.ymltidak ada - di sini ada kesalahan.

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

Bagaimana saya bisa memuat variabel tambahan dari file ini hanya jika ada? (tanpa kesalahan)

Sergey
sumber

Jawaban:

27

Cukup sederhana kok. Anda dapat memeras item vars_files yang berbeda ke dalam satu tuple dan Ansible akan secara otomatis melewati masing-masing item hingga menemukan file yang ada dan memuatnya. Ex:

vars_files:
  - [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]
Garrett
sumber
4
Menurut pengembang Ansible , solusi ini akan memuat semua file, bukan hanya yang pertama ditemukan.
tjanez
10

Menurut pengembang Ansible , cara yang tepat untuk menyelesaikan ini adalah dengan menggunakan sesuatu seperti:

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

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

Lebih jauh, mereka mengatakan :

Di atas hanya akan memuat file pertama yang ditemukan dengan benar, dan lebih fleksibel daripada mencoba melakukan ini melalui vars_fileskata kunci bahasa.

tjanez
sumber
"hanya file pertama yang ditemukan" - idenya adalah untuk mendefinisikan ulang beberapa variabel, tidak semuanya
Sergey
@ Muncul, membaca lagi pertanyaan Anda, saya melihat bahwa apa yang Anda inginkan agak berbeda. Terima kasih telah menunjukkan ini. Saya akan meninggalkan jawabannya seolah-olah ada orang lain yang menganggapnya berguna.
tjanez
1
kecuali bahwa include_varsdalam tugas akan memberikan prioritas yang lebih tinggi dari variabel dibandingkan dengan peran defaultsatauvars
Alex F
2

Saya mengalami masalah ini dalam pengaturan di mana saya perlu membuat beberapa lingkungan penempatan (hidup, demo, kotak pasir) ke server fisik yang sama (tidak diizinkan mesin virtual di sini), dan kemudian skrip untuk menggunakan repo svn sewenang-wenang

Ini membutuhkan susunan direktori dari file variabel.yml (opsional), yang akan menggabungkan satu sama lain dan tidak melempar pengecualian jika ada di mana ada yang hilang

Mulailah dengan mengaktifkan penggabungan variabel dalam kemungkinan - perhatikan bahwa penggabungan hash dangkal ini (kedalaman 1 level) dan penggabungan mendalam tidak sepenuhnya rekursif

ansible.cfg

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

Layout direktori yang memungkinkan

/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

peran / menyebarkan / tugas / include.yml

Ini adalah logika utama untuk pohon direktori dari file variabel opsional.

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

Konfigurasikan variabel default untuk proyek dan berbagai pengguna dan lingkungan

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

peran / deploy / vars / main.yml

standar proyek

ansible_project:
  node_env:   development
  node_port:  4200
  nginx_port: 4400

role / deploy / vars / project_1.yml

default untuk project_1

ansible_project:
  node_port:  4201
  nginx_port: 4401

peran / deploy / vars / live / main.yml

default untuk lingkungan hidup, menimpa default proyek

ansible_project:
  node_env: production

role / deploy / vars / live / project_1.yml

penggantian akhir untuk project_1 di lingkungan langsung

ansible_project:
  nginx_port: 80

playbooks / demo.yml

Konfigurasikan buku pedoman terpisah untuk setiap lingkungan

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

PERINGATAN: Karena semua lingkungan hidup pada satu host, semua playbook harus dijalankan secara terpisah, jika tidak, Ansible akan mencoba menjalankan semua skrip sebagai pengguna login ssh pertama dan hanya menggunakan variabel untuk pengguna pertama. Jika Anda perlu menjalankan semua skrip secara berurutan, maka gunakan xargs untuk menjalankannya masing-masing sebagai perintah terpisah.

find ./playbooks/*.yml | xargs -L1 time ansible-playbook
James McGuigan
sumber
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 }}"

Catatan: Tes jalur (adalah file, ada, ...) hanya berfungsi dengan jalur absolut atau jalur relatif ke direktori kerja saat ini ketika menjalankan perintah playbook yang mungkin. Ini adalah alasan kami menggunakan pencarian. pencarian menerima jalur relatif ke direktori playbook dan mengembalikan jalur absolut ketika file ada.

Ejez
sumber
0

Atau dengan cara yang lebih yaml:

- 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 }}"

Artinya, alih-alih menulis array pada satu baris dengan tanda kurung, seperti:

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

Gunakan cara yaml untuk menulis nilai array pada banyak baris, seperti:

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

Seperti disebutkan ini mencari file vars bernama {{ ansible_hostname }}.yml, dan jika tidak ada gunanyadefault.yml

Donn Lee
sumber
Jawaban ini menggunakan kode yang sama dengan yang ini kecuali ia menggunakan data yang berbeda. Yaitu {{ ansible_hostname }}.ymlnama file, bukan ../path/to/file1. Apa gunanya? Seseorang dapat menambahkan jumlah nama file input yang tidak terbatas.
techraf
@ techraf: Ok, saya menambahkan beberapa klarifikasi / amplifikasi tentang mengapa jawaban baru diajukan. Itu karena komentar serverfault tidak mendukung potongan kode multi-baris, dan saya baru saja menekankan bahwa array yaml sering (sebaiknya?) Ditulis pada banyak baris. Saya juga akan baik-baik saja jika jawaban sebelumnya diedit dan format array multi-line ditampilkan, seperti yang saya lihat lebih sering. Maka jawaban saya bisa dihapus.
Donn Lee
Kedua notasi tersebut ditentukan dalam dokumen Ansible dalam bab Dasar-Dasar YAML . Fakta bahwa Anda melihat satu lebih sering daripada yang lain belum menjadikan ini jawaban baru.
techraf
0

Menyatukan berbagai bagian bersama-sama ... include_vars dengan klausa when yang benar ketika file ada. yaitu

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

Jawaban baru berdasarkan pada versi Ansible terbaru — pada dasarnya, Anda harus menggunakan with_first_found, bersama skip: trueuntuk melewati tugas jika tidak ada file yang ditemukan.

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

Ini membuatnya jadi Anda tidak perlu memiliki file vars cadangan dalam daftar itu.

Lihat yang terkait: /programming//a/39544405/100134

geerlingguy
sumber