使用图形数据库管理Ansible的配置信息

这是NIFTY Advent Calendar第13天的文章。

我是Nifty(两年工龄)的 @ntoofu。

昨天是关于@umiiiiins的botocore和Python轻松使用Nifty Cloud API的文章。

我想谈论的不是我使用我们的服务的故事,而是关于我在工作期间进行的一项努力。

简约即美。

为了提高重复利用性,我们将作为Ansible库存文件进行管理的配置信息存储在图形数据库Neo4j中,并使其能够作为动态库存进行处理。

经过

    • サーバやネットワークの情報が分散・重複して管理されている

 

    • 情報を統合するために、構成情報をまとめてグラフDBで管理してみようと考えた

サーバとサーバが接続するネットワークのように、管理情報間で関係を持つことが多いから
登録する項目が増えたりすることも考え、柔軟性のためグラフDBを使ってみることにした

自チームではプログラムから扱いやすい形で構成情報を最も多く持っているのがAnsibleのインベントリだった
手始めに、Ansibleの情報をグラフDBに入れ、利用はDynamic Inventoryを作成することにした

Dynamic InventoryはAnsibleにおいて、本来テキストファイルとして記述する管理ホストの情報をまとめたファイルを、プログラムによって動的生成するもの

方法

這裡有我們所建立的程式碼。
Ansible 的前提版本是 2.1.0。

简要概述

    • Ansibleが内部で使っているモジュールを利用してインベントリファイルのパースを実施

 

    • パースして得たデータを一部加工してNeo4jに投入

 

    • Neo4jの内容を取得し、Dynamic Inventoryとして扱える形式で返す

 

    インベントリファイルをパースしたデータと、作成したDynamic Inventoryを元にパースしたデータが一致するかテスト

解析Ansible清单

一般情况下,Ansible的清单文件采用INI文件格式,类似于提供的示例,并且手动解析有点困难。因此,我们决定使用Ansible自身在解析时使用的模块,如下所示。

    from ansible.inventory import Inventory
    from ansible.vars import VariableManager
    from ansible.parsing.dataloader import DataLoader

    variable_manager = VariableManager()
    loader = DataLoader()
    if vault_pass:
        loader.set_vault_password(vault_pass)
    inventory = Inventory(loader=loader,
                          variable_manager=variable_manager,
                          host_list=inventory_file)
    inventory.set_playbook_basedir(base_dir)
    variable_manager.set_inventory(inventory)

对Neo4j的读写

我使用了这个驱动程序。关于驱动程序的使用方法,我会参考官方文档。

我要特别注意的是处理字典类型的数据。
在Neo4j中,我们可以为节点分配键值对作为属性,但无法将字典类型的数据作为值接收。

据说可以使用Bulbs来将字典类型转换为JSON字符串格式,并进行处理。然而,由于要处理的字典类型的信息是网络信息等在多个主机上共享使用的值,所以我们决定将字典类型的数据内容直接创建为节点,并将其作为关系存在。

考试

我认为当从传统的基于文件的清单迁移到动态清单时,共有的问题是需要提供一种简便的方法来确认新旧清单之间是否有差异。
在这次操作中,我使用Ansible内部模块来解析两个清单,然后创建并测试一个脚本,用于比较它们之间的差异是否存在。

实践

# 必要なライブラリを用意(適宜環境にあわせて下さい)
git clone https://github.com/ntoofu/neo4j-ansible-inventory
cd neo4j-ansible-inventory
git submodule init && git submodule update
pip install -r requirements.txt

# テスト用インベントリ準備(既にあれば不要)
git clone https://github.com/ansible/ansible-examples
ansible_basedir=./ansible-examples/lamp_haproxy
ansible_inventory_path=./ansible-examples/lamp_haproxy/hosts

# Neo4jをlocalhostに作成
docker run -d -p 7474:7474 -p 7687:7687 -e NEO4J_AUTH='none' -v /tmp/neo4j/data:/data -v /tmp/neo4j/logs:/logs --name neo4j neo4j:3.0

# 適当なインベントリの情報をNeo4jへ
python store.py -n localhost -i ${ansible_inventory_path} -b ${ansible_basedir}

# Neo4jからDynamic Inventory
python inventory.py -n localhost --list
Pasted image at 2016_12_13 11_02.png

未来的挑战

这次情况是将Ansible的清单中的信息直接导入到Neo4j中,因此结构保持了清单的结构,包括变量名等全部保留不变的情况。

由于希望Neo4j能够以一种不仅限于Ansible的方式存储配置信息,我们有时候也需要转换Ansible中使用的变量名(如添加前缀以避免意外覆盖)。

此外,Neo4j希望能够在Ansible的目录之外导入数据源,并希望可以从除了Ansible之外的其他来源进行使用。他们也希望能够以一种通用的结构将数据放入,而不仅仅局限于Ansible的特定需求。

我想还有一种情况,即使是在使用Ansible变量时,我们可能也希望使用复杂的查询。(例如,当存在具有相同属性的组层次结构时,我们可能希望引用最近的父属性,等等)

因此,我认为我们需要一个稍微复杂的映射机制,而不是简单的映射,因此我们需要考虑如何处理这个部分。


明天是@plan0213的“网络设备命令自动化”计划。