0

So, the scenario is I have producers and consumers in ratio 7:1, and I want to have a consistent and deterministic multilple mapping b/w the producers and consumers in my service. List of consumers is provided in the config to each of the producer, which is done via ansible. So, I try to implement the mapping logic in the ansible itself, rather than passing the entire list of consumers, and doing it inside producer service. So, I thought of using a custom filter to filter out from the list of consumers, and assign it to producer. Below is the custom filter I wrote:

#!/usr/bin/python

class FilterModule(object):

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

    # consumer_servers: complete list of consumers servers
    # producer_id: provided to each producer for mapping purpose
    # producer_count: total no. of producers
    # map_consumer_count: no. of consumers need to be mapped to each producer
    # consumer_count: total no. of consumers

    def map_producer_to_consumer(self, consumer_servers, producer_id, producer_count, map_consumer_count):
        consumer_count = len(consumer_servers)
        index_offset = 0 if  producer_count%consumer_count else 1
        rotation_count = (producer_id/consumer_count) % (map_consumer_count-1) # used for left rotation of mapped servers
        map_consumer_indexes = [ (producer_count*i  + producer_id + index_offset*i) % consumer_count for i in xrange(map_consumer_count)]
        mapped_consumer_servers = [consumer_servers[map_consumer_indexes[0]]]
        for i in xrange(1, map_consumer_count):
            index = (i + rotation_count) % map_consumer_count
            if i + rotation_count >= map_consumer_count:
                mapped_consumer_servers.append( consumer_servers[map_consumer_indexes[index] + 1] )
            else:
                mapped_consumer_servers.append( consumer_servers[map_consumer_indexes[index]] )
        return (',').join(mapped_consumer_servers) 

This filter is working as expected, when using with static arguements like this:

"{{ tsdb_boxes | map_producer_to_consumer(2,3,3) }}"

but I want to make it use dynamic arguments via jinja2 templating, something like:

"{{ groups['producers'] | map_producer_to_consumer ({{ consumer_servers }}, {{ producer_id }}, {{ producer_count }}, {{ map_consumer_count }}) }}"

but its resulting in errors due to nesting of variables, which is not allowed in Jinja2. If I try something like this:

"{{ groups['producers'] }} | map_producer_to_consumer ({{ consumer_servers }}, {{ producer_id }}, {{ producer_count }}, {{ map_consumer_count }})"

it results in printing out the string like this:

['ip-1', 'ip-2'...] | map_producer_to_consumer (1000, 10, 150, 3)

Can someone please suggest what should be the best ansible way to achieve this. Should I use script module and convert the logic in bash, or it will be better to keep this inside the service only.

ks2bmallik
  • 184
  • 3
  • 18
  • Why not try `{{ groups['producers'] | map_producer_to_consumer(consumer_servers, producer_id, producer_count, map_consumer_count) }}`? – Konstantin Suvorov Jul 14 '17 at 06:48
  • [Moustaches don’t stack](http://docs.ansible.com/ansible/faq.html#when-should-i-use-also-how-to-interpolate-variables-or-dynamic-variable-names) – techraf Jul 14 '17 at 06:58
  • Thanks a lot @KonstantinSuvorov. Didn't tried it that way, just lost in the braces of Jinja. Thanks again. :) – ks2bmallik Jul 14 '17 at 07:18

1 Answers1

1

Answer from comments:

Why not try {{ groups['producers'] | map_producer_to_consumer(consumer_servers, producer_id, producer_count, map_consumer_count) }}

And link from @techraf about nesting.

Konstantin Suvorov
  • 65,183
  • 9
  • 162
  • 193