回答:某些文件不存在时,我可以使用vars_files吗?


17

那是一部分:

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

如果文件vars/vars.yml不存在-这是一个错误。

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

仅当该文件存在时,如何才能从该文件中加载其他变量?(无错误)

Answers:


27

真的很简单。您可以将不同的vars_files项压缩为一个元组,Ansible将自动遍历每个项,直到找到存在的文件并加载它。例如:

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

4
根据Ansible开发人员的说法,此解决方案将加载所有文件,而不仅是找到的第一个文件。
tjanez 2014年

10

根据Ansible开发人员的说法,解决此问题的正确方法是使用类似以下内容的方法:

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

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

此外,他们说

上面的代码将仅正确加载找到的第一个文件,并且比通过vars_fileslanguage关键字尝试加载更为灵活。


“仅找到第一个文件” –想法是重新定义一些变量,而不是所有变量
Sergey 2014年

@Sergey,再次阅读您的问题,我发现您想要的内容有所不同。感谢您指出了这一点。如果其他人觉得有用,我将保留原样。
tjanez 2014年

1
除了include_vars与角色相比,在任务中变量的优先级更高,defaults或者vars
Alex F

2

我在一个安装程序中遇到了此问题,在该安装程序中,我需要向同一物理服务器(此处不允许使用虚拟机)创建多个部署环境(实时,演示,沙箱),然后创建用于部署任意svn仓库的脚本

这需要一个(可选)variable.yml文件的目录树,该目录树将彼此合并,并且在缺少任何地方时不会引发异常

首先在ansible中启用变量合并-请注意,这会进行浅层哈希合并(深度为1级),而不是完全递归的深度合并

ansible.cfg

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

Ansible目录布局

/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

角色/部署/任务/includes.yml

这是可选变量文件的目录树的主要逻辑。

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

为项目以及各种用户和环境配置默认变量

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

角色/部署/vars/main.yml

项目默认值

ansible_project:
  node_env:   development
  node_port:  4200
  nginx_port: 4400

角色/部署/vars/project_1.yml

project_1的默认值

ansible_project:
  node_port:  4201
  nginx_port: 4401

角色/部署/vars/live/main.yml

现场环境的默认设置,覆盖项目默认设置

ansible_project:
  node_env: production

角色/部署/vars/live/project_1.yml

实时环境中project_1的最终替代

ansible_project:
  nginx_port: 80

剧本/demo.yml

为每种环境配置单独的剧本

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

警告:由于所有环境都位于单个主机上,因此所有剧本都必须单独运行,否则Ansible会尝试以第一个ssh登录用户身份运行所有脚本,并且仅对第一个用户使用变量。如果需要顺序运行所有脚本,请使用xargs将它们作为单独的命令运行。

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

注意:在运行ansible-playbook命令时,路径测试(是文件,是否存在...)仅适用于绝对路径或相对于当前工作目录的路径。这就是我们使用查找的原因。查找接受相对于剧本目录的路径,并在文件存在时返回绝对路径。


0

或者以一种更传统的方式:

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

也就是说,与其在方括号的一行上写一个数组,不如:

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

使用yaml在多行上写数组值的方式,例如:

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

如前所述,这将查找名为的vars文件{{ ansible_hostname }}.yml,如果不存在,则使用default.yml


除了使用不同的数据外,此答案使用与代码相同的代码。即用{{ ansible_hostname }}.yml文件名代替../path/to/file1。重点是什么?可以添加无限数量的输入文件名。
techraf 2016年

@techraf:好的,我对为什么要提交新答案进行了一些说明/放大。这是因为serverfault注释不支持多行代码段,而我只是想指出,yaml数组经常(最好是?)写在多行上。如果以前的答案已被编辑并显示多行数组格式,我也很好,因为我看到的更多。然后我的答案可以删除。
Donn Lee

这两种表示法都在Ansible文档的YAML基础一章中指定。您比其他人经常看到的事实并不能使这个问题得到新的答案。
techraf

0

将各个部分拼凑在一起... include_vars和when子句在文件存在时为true。即

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

0

基于最新Ansible版本的新答案-基本上,如果找不到文件,则应使用with_first_foundskip: true跳过任务。

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

这样一来,您就不必在该列表中有一个后备vars文件。

参见相关文章:https : //stackoverflow.com/a/39544405/100134

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.