regexredisansibleregex-groupredis-cluster

Redis Cluster: How to get the number of slots of a particular master node?


How to catch, ONLY the total number of slots an specific master node has in Ansible?

I know that if you run:

redis-cli --cluster check

You'll get this output for example:

192.168.56.115:6379 (7d0fb9ab...) -> 0 keys | 4242 slots | 0 slaves.
192.168.56.116:6379 (9fe57cd1...) -> 0 keys | 3950 slots | 0 slaves.
192.168.56.117:6379 (d37e89a6...) -> 0 keys | 4096 slots | 0 slaves.
192.168.56.118:6379 (e0eb74db...) -> 0 keys | 4096 slots | 0 slaves.
[OK] 0 keys in 4 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 192.168.56.115:6379)
M: 7d0fb9abd91d6397f11e6f606c8ecf919ba2d1fe 192.168.56.115:6379
   slots:[0-4241] (4242 slots) master
M: 9fe57cd1faaa6e77d0e89c504b9f8b69f72c52aa 192.168.56.116:6379
   slots:[4242-8191] (3950 slots) master
M: d37e89a685ec31f3ce85544203132f862d8330a7 192.168.56.117:6379
   slots:[8192-12287] (4096 slots) master
M: e0eb74db5c6ccbc469538d05bf98302d056c7e05 192.168.56.118:6379
   slots:[12288-16383] (4096 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

I want to write an Ansible playbook that given the target node's ip as target_node_ip, it gives this output: for example for target_node_ip = 192.168.56.116

3950 

I've tried many regex patterns, but they didn't help me.

For example, I wrote these tasks:

- name: Catch --cluster check
  command: >
    redis-cli --user default --cluster check 192.168.56.115:6379
  register: cluster_check_output

- name: Catch the number of slots the target currently has
  set_fact:
    node_slots: "{{cluster_check_output.stdout | regex_replace('.*{{ target_node_ip }}:6379 \\(.{8}\\.{3}\\) -> \\d+ keys | (\\d+) slots | \\d+ slaves.*', '\\1')}}"

- name: Debug node_slots
  debug:
    var: node_slots

And the output is this:

TASK [Debug node_slots] ***********************************************************************************************************************
task path: /home/behnia/projects/redis-test/redis-cluster/redis-cluster-management/playbooks/remove_node.yml:64
ok: [server3] => {
    "node_slots": "192.168.56.115:6379 (7d0fb9ab...) -> 0 keys |4242|\n192.168.56.116:6379 (9fe57cd1...) -> 0 keys |3950|\n192.168.56.117:6379 (d37e89a6...) -> 0 keys |4096|\n192.168.56.118:6379 (e0eb74db...) -> 0 keys |4096|\n\u001b[32;1m[OK] 0 keys in 4 masters.\n\u001b[0m0.00 keys per slot on average.\n\u001b[29;1m>>> Performing Cluster Check (using node 192.168.56.115:6379)\n\u001b[0mM: 7d0fb9abd91d6397f11e6f606c8ecf919ba2d1fe 192.168.56.115:6379\n   slots:[0-4241] (4242 slots) master\nM: 9fe57cd1faaa6e77d0e89c504b9f8b69f72c52aa 192.168.56.116:6379\n   slots:[4242-8191] (3950 slots) master\nM: d37e89a685ec31f3ce85544203132f862d8330a7 192.168.56.117:6379\n   slots:[8192-12287] (4096 slots) master\nM: e0eb74db5c6ccbc469538d05bf98302d056c7e05 192.168.56.118:6379\n   slots:[12288-16383] (4096 slots) master\n\u001b[32;1m[OK] All nodes agree about slots configuration.\n\u001b[0m\u001b[29;1m>>> Check for open slots...\n\u001b[0m\u001b[29;1m>>> Check slots coverage...\n\u001b[0m\u001b[32;1m[OK] All16384covered.\n\u001b[0m"
}

If you see, instead of replacing the whole output with 3950, it replaced every | <#> slots | with |#|, where # is number of slots (in this context 4242, 3950, 4096, 4096).

What I want is just 3950 (for target_node_ip = 192.168.56.116)


Solution

  • As already mentioned within the comments one minimal example playbook ...

    Pre-processing in shell

    on Remote Node(s) and in order to catch up the final result set only.

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
        target_node_ip: 192.168.56.116
    
      tasks:
    
      - name: Catch --cluster check
        shell: |
          cat redis.stdout |           # redis-cli --cluster check
          grep {{ target_node_ip }} |  # for specific node only
          head -n 1 |                  # first line found
          cut -d '|' -f 2 |            # result between pipes
          grep -o '[0-9]' |            # and numbers only
          tr -d '\n'                   #
        register: slots
    
      - name: Show the number of slots the target currently has
        debug:
          var: slots.stdout
    

    will result into an output of

    TASK [Show the number of slots the target currently has] ******
    ok: [localhost] =>
      slots.stdout: '3950'
    

    Ansible Custom Fact

    Somehow similar can be implemented as a Custom fact. Then just gather_facts or setup would be necessary. See How to implement and use a Custom Fact?