]> git.apps.os.sepia.ceph.com Git - ceph-ansible.git/commitdiff
Replace ipaddr() with ips_in_ranges()
authorHarald Jensås <hjensas@redhat.com>
Wed, 14 Aug 2019 17:14:09 +0000 (19:14 +0200)
committerGuillaume Abrioux <gabrioux@redhat.com>
Fri, 27 Sep 2019 15:49:46 +0000 (17:49 +0200)
This change implements a filter_plugin that is used in the
ceph-facts, ceph-validate roles and infrastucture-playbooks.
The new filter plugin will return a list of all IP address
that reside in any one of the given IP ranges. The new filter
replaces the use of the ipaddr filter.

ceph.conf already support a comma separated list of CIDRs
for the public_network and cluster_network options.

Changes: [1] and [2] introduced a regression in ceph-ansible
where public_network can no longer be a comma separated list
of cidrs.

With this change a comma separated list of subnet CIDRs can
also be used for monitor_address_block and radosgw_address_block.

[1] commit: d67230b2a26b40651c1c1dbee68a92b0e851f3d5
[2] commit: 20e4852888ecc76d8d0fa194a438fa2a90e1cde3

Related-To: https://bugs.launchpad.net/tripleo/+bug/1840030
Related-To: https://bugzilla.redhat.com/show_bug.cgi?id=1740283
Closes: #4333
Please backport to stable-4.0

Signed-off-by: Harald Jensås <hjensas@redhat.com>
(cherry picked from commit e695efcaf79909e2237197fd473117930e8d83e5)

14 files changed:
.travis.yml
ansible.cfg
infrastructure-playbooks/purge-cluster.yml
infrastructure-playbooks/purge-docker-cluster.yml
plugins/filter/__init__.py [new file with mode: 0644]
plugins/filter/ipaddrs_in_ranges.py [new file with mode: 0644]
plugins/filter/test_ipaddrs_in_ranges.py [new file with mode: 0644]
roles/ceph-facts/tasks/facts.yml
roles/ceph-facts/tasks/set_monitor_address.yml
roles/ceph-facts/tasks/set_radosgw_address.yml
roles/ceph-validate/tasks/check_ipaddr_mon.yml
tox-podman.ini
tox-update.ini
tox.ini

index 8dfe111677542d5a78e2f8fddefb086ef74ffddc..37e13911fa5cd0ca6d273f59c24eb3c826ab8185 100644 (file)
@@ -9,5 +9,5 @@ install:
   - pip install ansible-lint pytest
 script:
   - if [[ -n $(grep --exclude-dir=.git -P "\xa0" -r .) ]]; then echo 'NBSP characters found'; exit 1; fi
-  - pytest -vvvv library/
+  - pytest -vvvv library/ plugins/
   - for i in $(ls -1 roles/); do ansible-lint -x 204 -v roles/$i/ ; done
index 1773833a4f7d65281bb01f02fac8082ce1de40f6..356b0b5776169713c59e682a2b8c5e4809485a00 100644 (file)
@@ -6,6 +6,7 @@ ansible_managed = Please do not change this file directly since it is managed by
 library = ./library
 action_plugins = plugins/actions
 callback_plugins = plugins/callback
+filter_plugins = plugins/filter
 roles_path = ./roles
 # Be sure the user running Ansible has permissions on the logfile
 log_path = $HOME/ansible/ansible.log
index ac9110fafdeae073d643166e0f98480b05675728..c5333ed86e418f1e49117249efcbb12cf4ff0bce 100644 (file)
@@ -67,7 +67,7 @@
           run_once: true
 
         - name: get all nfs-ganesha mount points
-          command: grep "{{ hostvars[item]['ansible_all_ipv4_addresses'] | ipaddr(public_network) | first }}" /proc/mounts
+          command: grep "{{ hostvars[item]['ansible_all_ipv4_addresses'] | ips_in_ranges(public_network.split(',')) | first }}" /proc/mounts
           register: nfs_ganesha_mount_points
           failed_when: false
           with_items: "{{ groups[nfs_group_name] }}"
index 5007f61e8ca80c736e98749d9d0afca72224be49..dc0cf920d2620b7554c571c8a2b37847a67592df 100644 (file)
@@ -51,7 +51,7 @@
           run_once: true
 
         - name: get all nfs-ganesha mount points
-          command: grep "{{ hostvars[item]['ansible_all_ipv4_addresses'] | ipaddr(public_network) | first }}" /proc/mounts
+          command: grep "{{ hostvars[item]['ansible_all_ipv4_addresses'] | ips_in_ranges(public_network.split(',')) | first }}" /proc/mounts
           register: nfs_ganesha_mount_points
           failed_when: false
           with_items: "{{ groups[nfs_group_name] }}"
diff --git a/plugins/filter/__init__.py b/plugins/filter/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/plugins/filter/ipaddrs_in_ranges.py b/plugins/filter/ipaddrs_in_ranges.py
new file mode 100644 (file)
index 0000000..1073e7e
--- /dev/null
@@ -0,0 +1,30 @@
+from ansible import errors
+
+try:
+    import netaddr
+except ImportError:
+    # in this case, we'll make the filter return an error message (see bottom)
+    netaddr = None
+
+
+class FilterModule(object):
+   ''' IP addresses within IP ranges '''
+
+   def ips_in_ranges(self, ip_addresses, ip_ranges):
+       ips_in_ranges = list()
+       for ip_addr in ip_addresses:
+           for ip_range in ip_ranges:
+               if netaddr.IPAddress(ip_addr) in netaddr.IPNetwork(ip_range):
+                   ips_in_ranges.append(ip_addr)
+       return ips_in_ranges
+
+   def filters(self):
+       if netaddr:
+           return {
+               'ips_in_ranges': self.ips_in_ranges
+           }
+       else:
+           # Need to install python's netaddr for these filters to work
+           raise errors.AnsibleFilterError(
+               "The ips_in_ranges filter requires python's netaddr be "
+               "installed on the ansible controller.")
diff --git a/plugins/filter/test_ipaddrs_in_ranges.py b/plugins/filter/test_ipaddrs_in_ranges.py
new file mode 100644 (file)
index 0000000..3fb2135
--- /dev/null
@@ -0,0 +1,43 @@
+from . import ipaddrs_in_ranges
+
+filter_plugin = ipaddrs_in_ranges.FilterModule()
+
+class TestIpaddrsInRanges(object):
+
+    def test_one_ip_one_range(self):
+        ips = ['10.10.10.1']
+        ranges = ['10.10.10.1/24']
+        result = filter_plugin.ips_in_ranges(ips, ranges)
+        assert ips[0] in result
+        assert len(result) == 1
+
+    def test_two_ip_one_range(self):
+        ips = ['192.168.1.1', '10.10.10.1']
+        ranges = ['10.10.10.1/24']
+        result = filter_plugin.ips_in_ranges(ips, ranges)
+        assert ips[0] not in result
+        assert ips[1] in result
+        assert len(result) == 1
+
+    def test_one_ip_two_ranges(self):
+        ips = ['10.10.10.1']
+        ranges = ['192.168.1.0/24', '10.10.10.1/24']
+        result = filter_plugin.ips_in_ranges(ips, ranges)
+        assert ips[0] in result
+        assert len(result) == 1
+
+    def test_multiple_ips_multiple_ranges(self):
+        ips = ['10.10.10.1', '192.168.1.1', '172.16.10.1']
+        ranges = ['192.168.1.0/24', '10.10.10.1/24', '172.16.17.0/24']
+        result = filter_plugin.ips_in_ranges(ips, ranges)
+        assert ips[0] in result
+        assert ips[1] in result
+        assert ips[2] not in result
+        assert len(result) == 2
+
+    def test_no_ips_in_ranges(self):
+        ips = ['10.10.20.1', '192.168.2.1', '172.16.10.1']
+        ranges = ['192.168.1.0/24', '10.10.10.1/24', '172.16.17.0/24']
+        result = filter_plugin.ips_in_ranges(ips, ranges)
+        assert result == []
+
index 2bad00eb62723908f98c874e5d227a5a551079a5..faf58f8b11aef89c97c7abc8fa93b30c8ab8fa72 100644 (file)
 
 - name: set grafana_server_addr fact - ipv4
   set_fact:
-    grafana_server_addr: "{{ hostvars[inventory_hostname]['ansible_all_ipv4_addresses'] | ipaddr(public_network) | first }}"
+    grafana_server_addr: "{{ hostvars[inventory_hostname]['ansible_all_ipv4_addresses'] | ips_in_ranges(public_network.split(',')) | first }}"
   when:
     - groups.get(grafana_server_group_name, []) | length > 0
     - ip_version == 'ipv4'
 
 - name: set grafana_server_addr fact - ipv6
   set_fact:
-    grafana_server_addr: "{{ hostvars[inventory_hostname]['ansible_all_ipv6_addresses'] | ipaddr(public_network) | last | ipwrap }}"
+    grafana_server_addr: "{{ hostvars[inventory_hostname]['ansible_all_ipv6_addresses'] | ips_in_ranges(public_network.split(',')) | last | ipwrap }}"
   when:
     - groups.get(grafana_server_group_name, []) | length > 0
     - ip_version == 'ipv6'
index f92df413411cd6817e2e152dc8b6b40ebcf75754..201880737de9e49f68c7ae1e68b7ff43de6ec8d0 100644 (file)
@@ -1,7 +1,7 @@
 ---
 - name: set_fact _monitor_address to monitor_address_block ipv4
   set_fact:
-    _monitor_addresses: "{{ _monitor_addresses | default([]) + [{ 'name': item, 'addr': hostvars[item]['ansible_all_ipv4_addresses'] | ipaddr(hostvars[item]['monitor_address_block']) | first }] }}"
+    _monitor_addresses: "{{ _monitor_addresses | default([]) + [{ 'name': item, 'addr': hostvars[item]['ansible_all_ipv4_addresses'] | ips_in_ranges(hostvars[item]['monitor_address_block'].split(',')) | first }] }}"
   with_items: "{{ groups.get(mon_group_name, []) }}"
   when:
     - "item not in _monitor_addresses | default([]) | selectattr('name', 'defined') |  map(attribute='name') | list"
@@ -11,7 +11,7 @@
 
 - name: set_fact _monitor_address to monitor_address_block ipv6
   set_fact:
-    _monitor_addresses: "{{ _monitor_addresses | default([]) + [{ 'name': item, 'addr': hostvars[item]['ansible_all_ipv6_addresses'] | ipaddr(hostvars[item]['monitor_address_block']) | last | ipwrap }] }}"
+    _monitor_addresses: "{{ _monitor_addresses | default([]) + [{ 'name': item, 'addr': hostvars[item]['ansible_all_ipv6_addresses'] | ips_in_ranges(hostvars[item]['monitor_address_block'].split(',')) | last | ipwrap }] }}"
   with_items: "{{ groups.get(mon_group_name, []) }}"
   when:
     - "item not in _monitor_addresses | default([]) | selectattr('name', 'defined') |  map(attribute='name') | list"
index 1ff6f71fa14b70502c46c5669f90d8bf041d02d2..dcca72be195b34a6e887267efad6b1a10fb79993 100644 (file)
@@ -1,7 +1,7 @@
 ---
 - name: set_fact _radosgw_address to radosgw_address_block ipv4
   set_fact:
-    _radosgw_address: "{{ hostvars[inventory_hostname]['ansible_all_ipv4_addresses'] | ipaddr(radosgw_address_block) | first }}"
+    _radosgw_address: "{{ hostvars[inventory_hostname]['ansible_all_ipv4_addresses'] | ips_in_ranges(hostvars[item]['radosgw_address_block'].split(',')) | first }}"
   when:
     - radosgw_address_block is defined
     - radosgw_address_block != 'subnet'
@@ -9,7 +9,7 @@
 
 - name: set_fact _radosgw_address to radosgw_address_block ipv6
   set_fact:
-    _radosgw_address: "{{ hostvars[inventory_hostname]['ansible_all_ipv6_addresses'] | ipaddr(radosgw_address_block) | last | ipwrap }}"
+    _radosgw_address: "{{ hostvars[inventory_hostname]['ansible_all_ipv6_addresses'] | ips_in_ranges(hostvars[item]['radosgw_address_block'].split(',')) | last | ipwrap }}"
   when:
     - radosgw_address_block is defined
     - radosgw_address_block != 'subnet'
index 1fab8ea82c5fdd4887e2fc48b3a6cf656b2599c3..3bcd462691ec37977deba4d41410dc6d952687ba 100644 (file)
@@ -2,4 +2,4 @@
 - name: "fail if {{ inventory_hostname }} does not have any {{ ip_version }} address on {{ monitor_address_block }}"
   fail:
     msg: "{{ inventory_hostname }} does not have any {{ ip_version }} address on {{ monitor_address_block }}"
-  when: hostvars[inventory_hostname]['ansible_all_' + ip_version + '_addresses'] | ipaddr(hostvars[inventory_hostname]['monitor_address_block']) | length == 0
+  when: hostvars[inventory_hostname]['ansible_all_' + ip_version + '_addresses'] | ips_in_ranges(hostvars[inventory_hostname]['monitor_address_block'].split(',')) | length == 0
index 017ffcd18f6a0e1deefe8964f49b0e8336afc71b..19186cd23fd36993b777b46cf4e4096eabe7244d 100644 (file)
@@ -15,8 +15,6 @@ sitepackages=True
 setenv=
   ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config -o ControlMaster=auto -o ControlPersist=600s -o PreferredAuthentications=publickey
   ANSIBLE_CONFIG = {toxinidir}/ansible.cfg
-  ANSIBLE_ACTION_PLUGINS = {toxinidir}/plugins/actions
-  ANSIBLE_CALLBACK_PLUGINS = {toxinidir}/plugins/callback
   ANSIBLE_CALLBACK_WHITELIST = profile_tasks
   ANSIBLE_KEEP_REMOTE_FILES = 1
   ANSIBLE_CACHE_PLUGIN = memory
index 079a81c32144fb978a620ddb99e8e663d0599a88..e4c2353b064914eef446d304aead65f0814c7c98 100644 (file)
@@ -13,8 +13,6 @@ passenv=*
 setenv=
   ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config -o ControlMaster=auto -o ControlPersist=600s -o PreferredAuthentications=publickey
   ANSIBLE_CONFIG = {toxinidir}/ansible.cfg
-  ANSIBLE_ACTION_PLUGINS = {toxinidir}/plugins/actions
-  ANSIBLE_CALLBACK_PLUGINS = {toxinidir}/plugins/callback
   ANSIBLE_CALLBACK_WHITELIST = profile_tasks
   ANSIBLE_CACHE_PLUGIN = memory
   ANSIBLE_GATHERING = implicit
diff --git a/tox.ini b/tox.ini
index 405f2186870fc74efff1a67b8b5d4975d3067712..143fa724f3934490cbf1e4a9378aabceecd09756 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -22,6 +22,7 @@ setenv=
   ANSIBLE_ACTION_PLUGINS = {toxinidir}/plugins/actions
   ANSIBLE_CALLBACK_PLUGINS = {toxinidir}/plugins/callback
   ANSIBLE_CALLBACK_WHITELIST = profile_tasks
+  ANSIBLE_FILTER_PLUGINS = {toxinidir}/plugins/filter
   CEPH_STABLE_RELEASE = luminous
   # only available for ansible >= 2.5
   ANSIBLE_STDOUT_CALLBACK = yaml
@@ -357,8 +358,6 @@ sitepackages=True
 setenv=
   ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config -o ControlMaster=auto -o ControlPersist=600s -o PreferredAuthentications=publickey
   ANSIBLE_CONFIG = {toxinidir}/ansible.cfg
-  ANSIBLE_ACTION_PLUGINS = {toxinidir}/plugins/actions
-  ANSIBLE_CALLBACK_PLUGINS = {toxinidir}/plugins/callback
   ANSIBLE_CALLBACK_WHITELIST = profile_tasks
   ANSIBLE_KEEP_REMOTE_FILES = 1
   ANSIBLE_CACHE_PLUGIN = memory