Ansible根据字符串列表进行拆分,输入为一个列表

编程语言 2026-07-11

我正在努力寻找一种更好的方法,在Ansible中从域名列表中提取出多个带完整限定域名(FQDN)的域名。我需要把域名和未限定名拆分成一个字典。

input_fqdns:
  - 'host1.mydomain.internal'
  - 'host2.mydomain.net'  
known_domains:
  - 'mydomain.internal'
  - 'mydomain.net'

desired_output:
  - unqualified: 'host1'
    domain_name: 'mydomain.internal'
  - unqualified: 'host2'
    domain_name: 'mydomain.net'

我似乎找不到一种方法,能够在一组分隔符上进行拆分。

解决方案

  1. 最简单的选项是用点来分割名称
    - name: Split by dots.
      vars:
        _split: "{{ input_fqdns | map('split', '.', 1) }}"
        _output: "{{ _split | map('zip', ['unqualified', 'domain_name'])
                            | map('map', 'reverse')
                            | map('community.general.dict') }}"
      debug:
        msg: |
          desired_output:
            {{ _output | to_yaml(indent=2) | indent(2) }}

你将得到所需的输出

  msg: |-
      desired_output:
        - {domain_name: mydomain.internal, unqualified: host1}
        - {domain_name: mydomain.net, unqualified: host2}

SEE: The filter community.general.dict

  1. 但是,如果你想把名字 based on a list of strings 拆分开来,请使用过滤器 regex_replace。例如,
    - name: Split by regex.
      vars:
        _regex1: "\\.({{ known_domains | join('|') }})"
        _unqualified: "{{ input_fqdns | map('regex_replace', _regex1, '') }}"
        _regex2: "^.*({{ known_domains | join('|') }})"
        _replace2: '\1'
        _domain_name: "{{ input_fqdns | map('regex_replace', _regex2, _replace2) }}"
        _output: "{{ _unqualified | zip(_domain_name)
                                  | map('zip', ['unqualified', 'domain_name'])
                                  | map('map', 'reverse') 
                                  | map('community.general.dict') }}"
      debug:
        msg: |
          _unqualified:
            {{ _unqualified | to_yaml(indent=2) | indent(2) }}
          _domain_name:
            {{ _domain_name | to_yaml(indent=2) | indent(2) }}
          desired_output:
            {{ _output | to_yaml(indent=2) | indent(2) }}

也会得到所需的输出

  msg: |-
      _unqualified:
        [host1, host2]
       _domain_name:
        [mydomain.internal, mydomain.net]
      desired_output:
        - {domain_name: mydomain.internal, unqualified: host1}
        - {domain_name: mydomain.net, unqualified: host2}

source code

备选方案1

我最终创建了一个 自定义过滤插件:

#!/usr/bin/python3

class FilterModule(object):

    def filters(self):
        return {
            'split_multi_contains': self.split_multi_contains
        }

    def split_multi_contains( self, inputList, needleList, delimiter = ' ', delimiter_limit = -1 ):
        result = []
        for inputItem in inputList :
            splitFound=False
            for needleItem in needleList :
                if  needleItem in inputItem :
                    result.append(inputItem.split(delimiter,delimiter_limit))
                    splitFound=True
            if splitFound == False :
                result.append(inputItem)
        return result

备选方案2

另外需要强调的是,已经有一个可用的 [Community] 过滤器,用来实现 get_registrable_domain。一个最小示例的playbook

---
- hosts: localhost
  become: false
  gather_facts: false

  vars:

    input_fqdns:
      - 'host1.mydomain.internal'
      - 'host2.mydomain.net'

  tasks:

    - name: Split FQDNs
      debug:
        msg: "{{ item | community.dns.get_registrable_domain }}"
      loop: "{{ input_fqdns }}"

将输出以下结果

TASK [Split FQDNs] *********************************
ok: [localhost] => (item=host1.mydomain.internal) =>
  msg: mydomain.internal
ok: [localhost] => (item=host2.mydomain.net) =>
  msg: mydomain.net

或通过附加 map 过滤器 使之更简化

    - name: Split FQDNs
      debug:
        msg: "{{ input_fqdns | map('community.dns.get_registrable_domain') }}"

得到以下结果

TASK [Split FQDNs] *********************************
ok: [localhost] =>
  msg:
  - mydomain.internal
  - mydomain.net
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章