之前我是通过groups['mfw_test'] | map('extract', hostvars, ['ansible_all_ipv4_addresses'])
这种形式, 去一个inventory group下每一个host的ansible_all_ipv4_addresses
ansible_all_ipv4_address是所有网卡上的ip, 包括手动添加的ip(例如vip)
"msg": {
"centos-1": {
"ansible_all_ipv4_addresses": [
"192.168.124.136",
"172.16.120.10"
],
我们可以通过下面的playbook查看hostvars
- debug:
msg: "{{ hostvars }}"
上面的情况是没有vip, 也就是
[root@centos-1 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:b2:18:33 brd ff:ff:ff:ff:ff:ff
inet 172.16.120.10/24 brd 172.16.120.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::e880:2501:cdab:b11d/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::ada9:2128:e605:334a/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::2f9b:31f4:73e6:e438/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
3: ens37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:50:56:2c:1a:a8 brd ff:ff:ff:ff:ff:ff
inet 192.168.124.166/24 brd 192.168.124.255 scope global dynamic ens37
valid_lft 1452sec preferred_lft 1452sec
inet6 fe80::5c28:fb1e:459:1b9/64 scope link
valid_lft forever preferred_lft forever
如果有vip则是
"msg": {
"centos-1": {
"ansible_all_ipv4_addresses": [
"192.168.124.136",
"172.16.120.10",
"172.16.120.100"
],
之前我为了解决现实服务器网卡名称不统一的问题(现实有叫em2的有叫p6p1的还有team0, eth0等等, 而cmdb中又没有这些信息), 采用了ansible_all_ipv4_addresses
的方法, 取所有ip, 然后根据规则自己过滤(比如过滤掉vip等等). 时间长了就成了这么一坨
{%- for ip_list in (groups[group] | map('extract', hostvars, ['ansible_all_ipv4_addresses'])) -%}
{%- if loop.last -%}
{%- for ip in ip_list -%}
{%- if (ip.startswith('192.168') or ip.startswith('10.163') or ip.startswith('10.152') or ip.startswith('10.132') or ip.startswith('10.133')) and not ip.startswith('192.168.3') and not ip.startswith('192.168.8') and not ip.startswith('192.168.16') and not ip.startswith('10.62') and not ip.startswith('10.32') and not ip.startswith('10.52') and not ip.startswith('10.33') and not (ip.startswith('10.133.1.2') and ip.split('.')[3]|int>=200) -%}
{{ ip }}:2{{ mysql_port }}
{%- endif -%}
{%- endfor %}
{%- else -%}
{%- for ip in ip_list -%}
{%- if (ip.startswith('192.168') or ip.startswith('10.163') or ip.startswith('10.152') or ip.startswith('10.132') or ip.startswith('10.133')) and not ip.startswith('192.168.3') and not ip.startswith('192.168.8') and not ip.startswith('192.168.16') and not ip.startswith('10.62') and not ip.startswith('10.32') and not ip.startswith('10.52') and not ip.startswith('10.33') and not (ip.startswith('10.133.1.2') and ip.split('.')[3]|int>=200) -%}
{{ ip }}:2{{ mysql_port }},
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{%- endfor -%}
写到vars/main.yaml里
group_replication_group_seeds: "{%- for ip_list in (groups[group] | map('extract', hostvars, ['ansible_all_ipv4_addresses'])) -%}{%- if loop.last -%}{%- for ip in ip_list -%}{%- if (ip.startswith('192.168') or ip.startswith('10.163') or ip.startswith('10.152') or ip.startswith('10.132') or ip.startswith('10.133')) and not ip.startswith('192.168.3') and not ip.startswith('192.168.8') and not ip.startswith('192.168.16') and not ip.startswith('10.62') and not ip.startswith('10.32') and not ip.startswith('10.52') and not ip.startswith('10.33') and not (ip.startswith('10.133.1.2') and ip.split('.')[3]|int>=200) -%}{{ ip }}:2{{ mysql_port }}{%- endif -%}{%- endfor %}{%- else -%}{%- for ip in ip_list -%}{%- if (ip.startswith('192.168') or ip.startswith('10.163') or ip.startswith('10.152') or ip.startswith('10.132') or ip.startswith('10.133')) and not ip.startswith('192.168.3') and not ip.startswith('192.168.8') and not ip.startswith('192.168.16') and not ip.startswith('10.62') and not ip.startswith('10.32') and not ip.startswith('10.52') and not ip.startswith('10.33') and not (ip.startswith('10.133.1.2') and ip.split('.')[3]|int>=200) -%}{{ ip }}:2{{ mysql_port }},{%- endif -%}{%- endfor -%}{%- endif -%}{%- endfor -%}"
如果网卡是统一的, 或者我们能知道要部署服务器的网卡叫什么.
一个部署任务的机器网卡名称要一致, 否则下面的方法也用不了
观察hostvars可以发现
ansible_ens33无vip
"msg": {
"centos-1": {
"ansible_all_ipv4_addresses": [
"192.168.124.136",
"172.16.120.10"
],
...省略
"ansible_ens33": {
"active": true,
"device": "ens33",
...省略
"hw_timestamp_filters": [],
"ipv4": {
"address": "172.16.120.10",
"broadcast": "172.16.120.255",
"netmask": "255.255.255.0",
"network": "172.16.120.0"
},
"ipv6": [
{
"address": "fe80::e880:2501:cdab:b11d",
"prefix": "64",
"scope": "link"
}
],
ansible_ens33有vip
"msg": {
"centos-1": {
"ansible_all_ipv4_addresses": [
"192.168.124.136",
"172.16.120.10",
"172.16.120.100"
],
...省略
"ansible_ens33": {
"active": true,
"device": "ens33",
...省略
"hw_timestamp_filters": [],
"ipv4": {
"address": "172.16.120.10",
"broadcast": "172.16.120.255",
"netmask": "255.255.255.0",
"network": "172.16.120.0"
},
"ipv4_secondaries": [ --不知道为什么有俩
{
"address": "172.16.120.100",
"broadcast": "global",
"netmask": "255.255.255.0",
"network": "172.16.120.0"
},
{
"address": "172.16.120.100",
"broadcast": "global",
"netmask": "255.255.255.0",
"network": "172.16.120.0"
}
],
"ipv6": [
{
"address": "fe80::e880:2501:cdab:b11d",
"prefix": "64",
"scope": "link"
}
],
可以这样取map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])
于是
[root@centos-4 ansible]# cat hosts
[mysql]
172.16.120.10 mysql_repl_role=master
172.16.120.11 mysql_repl_role=slave
172.16.120.12 mysql_repl_role=slave
[mha]
172.16.120.13
[proxysql]
172.16.120.10 weight=100 comment=PRIMARY
172.16.120.11 weight=99 comment=SECONDARY
172.16.120.12 weight=99 comment=SECONDARY
[all:vars]
ansible_user=root
#ansible_password=vagrant
ansible_port=22
ansible_become=true
playbook
---
- name: '测试'
hosts: mysql
tasks:
- name: " groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])|list"
debug:
msg: "{{ groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])|list}}"
其中172.16.120.10还是有vip 172.16.120.100的
结果
TASK [groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])|list] *********************************************************************************************************************************************************************
ok: [172.16.120.11] => {
"msg": [
"172.16.120.10",
"172.16.120.11",
"172.16.120.12"
]
}
ok: [172.16.120.10] => {
"msg": [
"172.16.120.10",
"172.16.120.11",
"172.16.120.12"
]
}
ok: [172.16.120.12] => {
"msg": [
"172.16.120.10",
"172.16.120.11",
"172.16.120.12"
]
}
到这一步这是取到了所有ip, 还没完成拼接出group_replication_group_seeds
接下来要用到zip_longest
拿官方文档的例子
- name: '测试'
hosts: 172.16.120.10
tasks:
- name: give me list combo of two lists
debug:
msg: "{{ [1,2,3,4,5] | zip(['a','b','c','d','e','f']) | list }}"
- name: give me shortest combo of two lists
debug:
msg: "{{ [1,2,3] | zip(['a','b','c','d','e','f'], ['!','@','#','$']) | list }}"
- name: give me longest combo of three lists , fill with X
debug:
msg: "{{ [1,2,3] | zip_longest(['a','b','c','d','e','f'], [21, 22, 23], fillvalue='X') | list }}"
结果
TASK [give me list combo of two lists] *************************************************************************************************************************************************************************************************************************
ok: [172.16.120.10] => {
"msg": [
[
1,
"a"
],
[
2,
"b"
],
[
3,
"c"
],
[
4,
"d"
],
[
5,
"e"
]
]
}
TASK [give me shortest combo of two lists] *********************************************************************************************************************************************************************************************************************
ok: [172.16.120.10] => {
"msg": [
[
1,
"a",
"!"
],
[
2,
"b",
"@"
],
[
3,
"c",
"#"
]
]
}
TASK [give me longest combo of three lists , fill with X] ******************************************************************************************************************************************************************************************************
ok: [172.16.120.10] => {
"msg": [
[
1,
"a",
21
],
[
2,
"b",
22
],
[
3,
"c",
23
],
[
"X",
"d",
"X"
],
[
"X",
"e",
"X"
],
[
"X",
"f",
"X"
]
]
}
可以看到在这前两个task中, “多余"的会被舍弃掉, 而且可以zip多个list, 最后一个task使用fillvalue取"补齐”
于是我们就可以
- name: " groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip_longest([], fillvalue=':2'+mysql_port|string) |list"
debug:
msg: "{{ groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address']) | list | zip_longest([], fillvalue=':2'+mysql_port|string) |list}}"
这里为了看到结果所以list一下,否则是一个
TASK [groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip_longest([], fillvalue=':2'+mysql_port|string) |list] **********************************************************************************************************
ok: [172.16.120.10] => {
"msg": [
[
"172.16.120.10",
":23306"
],
[
"172.16.120.11",
":23306"
],
[
"172.16.120.12",
":23306"
]
]
}
ok: [172.16.120.11] => {
"msg": [
[
"172.16.120.10",
":23306"
],
[
"172.16.120.11",
":23306"
],
[
"172.16.120.12",
":23306"
]
]
}
ok: [172.16.120.12] => {
"msg": [
[
"172.16.120.10",
":23306"
],
[
"172.16.120.11",
":23306"
],
[
"172.16.120.12",
":23306"
]
]
}
然后使用map(‘join’),就是将列表里的每一个元素使用join拼接
- name: " groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip_longest([], fillvalue=':2'+mysql_port|string) | map('join')|list "
debug:
msg: "{{ groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address']) | list | zip_longest([], fillvalue=':2'+mysql_port|string) | map('join') |list}}"
TASK [groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip_longest([], fillvalue=':2'+mysql_port|string) | map('join')|list] *********************************************************************************************
ok: [172.16.120.11] => {
"msg": [
"172.16.120.10:23306",
"172.16.120.11:23306",
"172.16.120.12:23306"
]
}
ok: [172.16.120.10] => {
"msg": [
"172.16.120.10:23306",
"172.16.120.11:23306",
"172.16.120.12:23306"
]
}
ok: [172.16.120.12] => {
"msg": [
"172.16.120.10:23306",
"172.16.120.11:23306",
"172.16.120.12:23306"
]
}
最后
---
- name: '测试'
hosts: mysql
vars:
mysql_port: 3306
tasks:
- name: " groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip_longest([], fillvalue=':2'+mysql_port|string) | map('join') | join(',')"
debug:
msg: "{{ groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address']) | list | zip_longest([], fillvalue=':2'+mysql_port|string) | map('join') | join(',')}}"
TASK [groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip_longest([], fillvalue=:3306) | map('join') | join(',')] *******************************************************************************************************
ok: [172.16.120.10] => {
"msg": "172.16.120.10:23306,172.16.120.11:23306,172.16.120.12:23306"
}
ok: [172.16.120.11] => {
"msg": "172.16.120.10:23306,172.16.120.11:23306,172.16.120.12:23306"
}
ok: [172.16.120.12] => {
"msg": "172.16.120.10:23306,172.16.120.11:23306,172.16.120.12:23306"
}
使用hostvars[inventory_hostname]
- name: "hostvars[inventory_hostname]['ansible_ens33']['ipv4']['address']:23306"
debug:
msg: "{{ hostvars[inventory_hostname]['ansible_ens33']['ipv4']['address'] }}:2{{ mysql_port }}"
TASK [hostvars[inventory_hostname]['ansible_ens33']['ipv4']['address']:23306] **********************************************************************************************************************************************************************************
ok: [172.16.120.10] => {
"msg": "172.16.120.10:23306"
}
ok: [172.16.120.11] => {
"msg": "172.16.120.11:23306"
}
ok: [172.16.120.12] => {
"msg": "172.16.120.12:23306"
}
同样, 如果网卡不统一, 只能…
{% for ip in ansible_all_ipv4_addresses -%}
{% if (ip.startswith('192.168') or ip.startswith('10.163') or ip.startswith('10.152') or ip.startswith('10.132') or ip.startswith('10.133')) and not ip.startswith('192.168.3') and not ip.startswith('192.168.8') and not ip.startswith('192.168.16') and not ip.startswith('10.62') and not ip.startswith('10.32') and not ip.startswith('10.52') and not ip.startswith('10.33') and not (ip.startswith('10.133.1.2') and ip.split('.')[3]|int>=200) -%}
loose-group_replication_local_address = {{ ip }}:2{{ mysql_port }}
{% endif %}
{% endfor %}
网卡不统一
- name: 设置/etc/hosts
blockinfile:
path: /etc/hosts
block: |
{{ item }}
with_items: "{{ etc_hosts }}"
etc_hosts: |
{% for ip_list in (groups[group] | map('extract', hostvars, ['ansible_all_ipv4_addresses'])) -%} {% set iploop = loop %}
{% for ip in ip_list -%}
{% for hostname in (groups[group] | map('extract', hostvars, ['ansible_hostname'])) -%}
{% if loop.index == iploop.index -%}
{% if (ip.startswith('192.168') or ip.startswith('10.163') or ip.startswith('10.152') or ip.startswith('10.132') or ip.startswith('10.133') ) and not ip.startswith('192.168.3') and not ip.startswith('192.168.8') and not ip.startswith('192.168.16') and not ip.startswith('10.62') and not ip.startswith('10.32') and not ip.startswith('10.52') and not ip.startswith('10.33') and not (ip.startswith('10.133.1.2') and ip.split('.')[3]|int>=200) -%}
{{ ip }} {{ hostname }}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
网卡统一
---
- name: '测试'
hosts: mysql
vars:
etc_hosts: "{{ groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address']) | list | zip(groups['mysql']|map('extract', hostvars, ['ansible_hostname'])) | map('join',' ') | join('\n') }}"
tasks:
- name: " groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip(groups['mysql']|map('extract', hostvars, ['ansible_hostname'])) | map('join',' ') | join('\n') "
debug:
msg: "{{ groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address']) | list | zip(groups['mysql']|map('extract', hostvars, ['ansible_hostname'])) | map('join',' ') | join('\n') }}"
- name: 设置/etc/hosts
blockinfile:
path: /tmp/hosts.test
block: |
{{ item }}
with_items: "{{ etc_hosts }}"
TASK [groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip(groups['mysql']|map('extract', hostvars, ['ansible_hostname'])) | map('join',' ') | join('
')] ***************************************************************
ok: [172.16.120.10] => {
"msg": "172.16.120.10 centos-1\n172.16.120.11 centos-2\n172.16.120.12 centos-3"
}
ok: [172.16.120.11] => {
"msg": "172.16.120.10 centos-1\n172.16.120.11 centos-2\n172.16.120.12 centos-3"
}
ok: [172.16.120.12] => {
"msg": "172.16.120.10 centos-1\n172.16.120.11 centos-2\n172.16.120.12 centos-3"
}
[root@centos-1 ~]# cat /tmp/hosts.test
# BEGIN ANSIBLE MANAGED BLOCK
172.16.120.10 centos-1
172.16.120.11 centos-2
172.16.120.12 centos-3
# END ANSIBLE MANAGED BLOCK
注意hostname要用groups['mysql']|map('extract', hostvars, ['ansible_hostname'])
取, 不能直接ansible_hostname
- name: " groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip_longest([], fillvalue=' '+ansible_hostname) | map('join')| join('\n') "
debug:
msg: "{{ groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address']) | list | zip_longest([], fillvalue=' '+ansible_hostname) | map('join') | join('\n')}}"
看输出的结果hostname部分, 每个主机都只取到自己的hostname
TASK [groups['mysql']|map('extract', hostvars, ['ansible_ens33', 'ipv4', 'address'])| list | zip_longest([], fillvalue=' '+ansible_hostname) | map('join')| join('
')] ****************************************************************************************
ok: [172.16.120.10] => {
"msg": "172.16.120.10 centos-1\n172.16.120.11 centos-1\n172.16.120.12 centos-1"
}
ok: [172.16.120.11] => {
"msg": "172.16.120.10 centos-2\n172.16.120.11 centos-2\n172.16.120.12 centos-2"
}
ok: [172.16.120.12] => {
"msg": "172.16.120.10 centos-3\n172.16.120.11 centos-3\n172.16.120.12 centos-3"
}