Как стать автором
Обновить

Комментарии 6

Мне кажется, в результате выполнения
zk.connect={% for host in groups['zk_nodes'] %}{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}:{{ zk_port }}, {% endfor %}

мы получим строку с запятой в конце, что неприемлемо для многих приложений. У Вас есть рецепт, как этого избежать?
Замечание совершенно верное, в конце действительно будет запятая. На момент написания статьи средства для избавления от этой запятой у меня не было, но и необходимости от неё избавляться — тоже: приложение на Java эту запятую благополучно игнорирует.

Однако беглый поиск подсказал, что достаточно заключить разделяющую запятую вот в такую конструкцию:

{% if not loop.last %} , {% endif %}

Применительно к строчке из статьи получим вот что:

zk.connect={% for host in groups['zk_nodes'] %}{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}:{{ zk_port }}{% if not loop.last %},{% endif %} {% endfor %}

Или можно использовать второй вариант, приведённый в комментариях на SO по ссылке выше, но лично я в Jinja2 пока не настолько силён, чтобы уверенно написать, как правильно две подстановочные переменные со статическим символом (",") сцепить в список через фильтр «join» :-)
В моем случае инвенторий был статический, и выкрутился написанием плагина на питоне:

# vars_plugins/zookeeper_vars.py
from ansible import errors
from ansible import utils
import ansible.constants as C
from ansible.callbacks import display

class VarsModule(object):

    def __init__(self, inventory):
        self.inventory = inventory
        self.group_cache = {}
        self.known_zoo_ids = []

    def run(self, host, vault_password=None):
        inventory = self.inventory
        group = inventory.get_group('zookeeper')
        zk_addr = []
        if group is not None:
            hosts = group.get_hosts()
            for idx, host in enumerate(hosts):
                host_vars = host.get_variables()
                addr = host_vars.get('node_private_ip')
                if addr is None:
                    addr = host_vars.get('ansible_ssh_host', host.name)

                zk_port = host_vars.get('zookeeper_port', '2181')
                zk_addr.append({'host': addr, 'port': zk_port})

                node_zoo_id = host_vars.get('node_zoo_id', idx + 1)
                self.assign_zoo_id(host, node_zoo_id)

        result = {}
        result['zookeepers'] = zk_addr
        result['zookeepers_list'] = ','.join([':'.join([i['host'], i['port']]) for i in zk_addr])

        return result

    def assign_zoo_id(self, host, zoo_id):
        if zoo_id not in self.known_zoo_ids:
            host.set_variable('node_zoo_id', zoo_id)
            self.known_zoo_ids.append(zoo_id)
        else:
            display("warning: node_zoo_id of %s is already used!" % zoo_id, color='purple')
            new_zoo_id = int(zoo_id) + 1
            if new_zoo_id > 255:
                raise errors.AnsibleError("zoo_id (%s) for host %s is over 255!" % (new_zoo_id, host.name))
            self.assign_zoo_id(host, str(new_zoo_id))
цитата - скрытый код на Python
               node_zoo_id = host_vars.get('node_zoo_id', idx + 1)



Правильно ли я понимаю, что в таком варианте требуется прописывать переменную node_zoo_id для каждого хоста вручную?
Сразу скажу, я не очень разбираюсь во внутренностях Zookeeper.

По идее в кластере zookeeper-ам надо вписывать в конфиг уникальное значение zoo_id (0-255).
Плагин берет указанное значение (node_zoo_id), либо в случае если оно не указано — номер хоста из группы «zookeeper».
Нашёл красивый вариант решения вопроса с нумерацией хостов на GitHub

Но он настолько изящен, что я не могу удержаться от того, чтобы привести его прямо здесь:

templates/myid.j2
Здесь zk-nodes — это имя группы узлов, к которым применяется данный шаблон.
{% for server in groups['zk-nodes'] %}
{% if server == inventory_hostname %}
{{ loop.index }}
{% endif %}
{% endfor %}

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории