在Ansible中追加到列表或向字典添加键


34

(与Ansible角色中的回调或挂钩以及可重复使用的一系列任务有关):

有没有比(ab)使用jina2模板表达式更好的方法来追加到列表或在Ansible中向字典添加键?

我知道您可以执行以下操作:

- name: this is a hack
  shell: echo "{% originalvar.append('x') %}New value of originalvar is {{originalvar}}"

但是真的没有某种元任务或辅助工具可以做到这一点吗?

它感觉很脆弱,似乎没有记录,并且依赖于有关Ansible中变量如何工作的许多假设。

我的用例是多个角色(数据库服务器扩展),每个角色都需要为基本角色(数据库服务器)提供一些配置。它不像在db服务器配置文件中添加一行一样简单。每次更改都适用于同一行,例如扩展名,bdr并且pg_stat_statements必须都出现在目标行上:

shared_preload_libaries = 'bdr, pg_stat_statements'

Ansible方法是使用正则表达式多次提取配置文件(每次扩展名一次)来处理配置文件吗,该正则表达式会提取当前值,对其进行解析,然后对其进行重写?如果是这样,您如何在多次运行中使该幂等?

如果配置比此解析难,并且不像附加另一个逗号分隔的值那么简单怎么办?考虑一下XML配置文件。


你知道吗 我喜欢你的副作用-FUL吊臂☺切
DomQ

Answers:


13

您可以使用将两个列表合并到一个变量中+。假设您有一个group_vars包含以下内容的文件:

---
# group_vars/all
pgsql_extensions:
  - ext1
  - ext2
  - ext3

它用在pgsql.conf.j2像这样的模板中:

# {{ ansible_managed }}
pgsql_extensions={% for item in pgsql_extensions %}{{ item }}, {% endfor %}

然后,您可以将扩展名附加到测试数据库服务器,如下所示:

---
# group_vars/testing_db
append_exts:
  - ext4
  - ext5
pgsql_extensions: "{{ pgsql_extensions + append_exts }}"

当角色在任何测试服务器中运行时,将添加其他扩展。

我不确定这是否也适用于字典,也请注意空格,并在行尾留下一个悬挂的逗号。


您可以,但是您必须做所有事情group_vars,角色不能照顾自己设置扩展的细节。它是从我特别需要的角色中追加变量,因此一个角色可以追加到另一角色公开的变量中。
克雷格·林格

您的基本角色是否了解每个扩展角色?我有一个类似的案例,我可以将连接置为with_items句子。
GnP

不,这确实是问题。在一次部署中,基本角色可能是al
Craig Ringer

4
似乎如果尝试执行此操作以连接两个列表,它会认为这是一个无限递归的模板,因为左侧也在右侧。我误会了如何使用吗?
易卜拉欣

2
@spectras至少从Ansible 2.7开始,此功能无效。正如易卜拉欣建议的那样,这将导致错误:“在模板字符串中检测到递归循环”。
鲁巴

35

从Ansible v2.x开始,您可以执行以下操作:

# use case I: appending to LIST variable:

      - name: my appender
        set_fact:
          my_list_var: '{{my_list_myvar + new_items_list}}'

# use case II: appending to LIST variable one by one:

      - name: my appender
        set_fact:
          my_list_var: '{{my_list_var + [item]}}'
        with_items: '{{my_new_items|list}}'

# use case III: appending more keys DICT variable in a "batch":

      - name: my appender
        set_fact:
          my_dict_var: '{{my_dict_var|combine(my_new_keys_in_a_dict)}}'

# use case IV: appending keys DICT variable one by one from tuples
      - name: setup list of tuples (for 2.4.x and up
        set_fact:
          lot: >
            [('key1', 'value1',), ('key2', 'value2',), ..., ('keyN', 'valueN',)],
      - name: my appender
        set_fact:
          my_dict_var: '{{my_dict_var|combine({item[0]: item[1]})}}'
        with_items: '{{lot}}'
# use case V: appending keys DICT variable one by one from list of dicts (thanks to @ssc)

  - name: add new key / value pairs to dict
    set_fact:
      my_dict_var: "{{ my_dict_var | combine({item.key: item.value}) }}"
    with_items:
    - { key: 'key01', value: 'value 01' }
    - { key: 'key02', value: 'value 03' }
    - { key: 'key03', value: 'value 04' }

以上所有内容均记录在:http : //docs.ansible.com/ansible/playbooks_filters.html


1
用例IV刚刚追加u'(': u\"'\"}"
ssc

1
谢谢,@ ssc。我发现它不与ansible工作2.4.x(固定)
最大Kovgan

根据用例#4,我添加了默认值来处理我的场景中的未定义错误set_fact: my_dict_var: '{{my_dict_var|default({})|combine({item[0]: item[1]})}}'。使用某些过滤或未注册任何结果时,会出现未定义的错误。
SK Venkat '18年

SK Venkat先生,此处的示例代码仅演示了非常具体的内容(从元组添加字典项)。如果您需要执行其他操作,则此代码不是您的复制粘贴。
Max Kovgan

3

您需要将循环分成2个

--- 
-主机:localhost
  任务: 
    -include_vars:堆栈
    -set_facts:role = {{stacks.Roles | 分裂(' ')}}
    -包括:addhost.yml
      with_items:“ {{roles}}”

和addhost.yml

-set_facts:groupname = {{item}}
-set_facts:ips = {{stacks [item] | split('')}}
-local_action:add_host主机名= {{item}} groupname = {{groupname}}
  with_items:{{ips}}

1

不知道他们什么时候添加的,但是至少对于字典/哈希(不是列表/数组),您可以像这样设置变量hash_behaviourhash_behaviour = merge在中ansible.cfg

花了我几个小时不小心偶然发现了这个设置:S


这非常方便,但是请注意在现有代码库上启用它。可能会破坏一些鸡蛋。
Max Kovgan '18年

0

这里几乎所有的答案都需要更改任务,但是我需要在vars定义中动态合并字典,而不是在运行过程中。

例如,我想在中定义一些共享变量all group_vars,然后在其他group或中扩展它们host_vars。在担任角色时非常有用。

如果尝试使用combineunion过滤器覆盖var文件中的原始变量,则在模板化过程中将以无限循环结尾,因此我创建了此替代方法(这不是解决方案)。

您可以基于某些名称模式定义多个变量,然后自动将其加载为角色。

group_vars/all.yml

dictionary_of_bla:
  - name: blabla
    value1 : blabla
    value2 : blabla

group_vars/group1.yml

dictionary_of_bla_group1:
  - name: blabla2
    value1 : blabla2
    value2 : blabla2

角色代码段

tasks:
  - name: Run for all dictionary_of_bla.* variations
    include_tasks: do_some_stuff.yml
    with_items: "{{ lookup('varnames','dictionary_of_bla.*').split(',') }}"
    loop_control:
      loop_var: _dictionary_of_bla

do_some_stuff.yml

- name: do magic
  magic:
    trick_name: item.name
    trick_value1: item.value1
    trick_value2: item.value2
  with_items: "{{ vars[_dictionary_of_bla] }}"

这只是一个片段,但是您应该了解它是如何工作的。注意:从ansible 2.8开始可以使用lookup('varnames','')

我猜也可以dictionary_of_bla.*在运行时使用相同的查找将所有变量合并到一个字典中。

这种方法的优点是您不需要设置变量名称的确切列表,而只有模式和用户可以动态设置它。


-4

Ansible是一个自动化系统,就配置文件管理而言,它与并没有太大区别apt。越来越多的软件提供从conf.d目录中读取配置摘要的功能的原因是,使此类自动化系统具有不同的程序包/角色,可以为软件添加配置。我相信这不是哲学Ansible,而是要运用conf.d技巧。如果正在配置的软件不提供此功能,则可能会造成麻烦。

由于您提到了XML配置文件,因此我趁此机会做了一些抱怨。Unix传统使用纯文本配置文件是有原因的。二进制配置文件不能很好地适应系统自动化,因此任何类型的二进制格式都会给您带来麻烦,并且可能需要您创建一个程序来处理配置。(如果有人认为XML是纯文本格式,则应该动脑筋。)

现在,关于您的特定PostgreSQL问题。PostgreSQL确实支持这个conf.d技巧。首先,我将检查是否shared_preload_libraries可以多次指定。我在文档中没有找到任何提示,但是我仍然会尝试。如果不能多次指定,我将向大家解释我的问题PostgreSQL,以防他们有想法。这是一个PostgreSQL问题,而不是一个Ansible问题。如果没有解决方案,而我真的无法将不同的角色合并到一个角色中,那么我将实现一个系统来在托管主机上编译配置。在这种情况下,我可能会创建一个/usr/local/sbin/update_postgresql_config可以编译/etc/postgresql/postgresql.conf.jinja成的脚本/etc/postgresql/9.x/main/postgresql.conf。该脚本将从中读取共享的预加载库/etc/postgresql/shared_preload_libraries.txt,每行一个库,并将其提供给jinja。

自动化系统通常会这样做。Debian exim4软件包就是一个例子。


PostgreSQL支持一个conf.dinclude机制,并幸运地使用纯文本文件。但是,在某些配置选项中,多个扩展可能对此有意见-例如“将max_wal_senders从以前的值增加10”。
Craig Ringer 2015年

4
似乎您是在说应更改应用程序以解决配置管理系统中的限制,否则我应该放弃拥有可重复使用的角色。
Craig Ringer
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.