2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

さくらインターネットAdvent Calendar 2021

Day 16

Ansible InventoryPluginのススメ

Last updated at Posted at 2021-12-15

さくらインターネット Advent Calendar 2021 16日目の記事です。

概要

Ansibleのインベントリを動的に生成する方法として、「ダイナミックインベントリ」がよく使われていると思いますが、「インベントリプラグイン」という別の方法もあるよ、というお話です。

インベントリプラグインは、ダイナミックインベントリと比べて仕組みが少し複雑ですが、ケースによってはインベントリプラグインを用いたほうが簡潔にプレイブックを構成できる場合があります。

さっそく試してみる

例として、以下のようなExcelファイル(book1.xlsx)をAnsibleのインベントリとして利用してみます。
左から、ホスト名、IPアドレス、用途といったイメージです。

book1.png

インベントリプラグイン場所を指定しておく

デフォルトのままだと扱いにくいため、インベントリプラグインを参照するディレクトリを設定しておきます。

ansible.cfg
[defaults]
inventory_plugins=./plugins/inventory

デフォルトの値は以下のドキュメントに記載があります。

インベントリファイルを作る

ansible-playbook コマンドの -i オプションで指定する、インベントリファイルを作成します。
plugin にはこれから作成するインベントリプラグイン名を記載し、filesには読み込むExcelファイルを定義しておきます。

xlsx.yml
plugin: xlsx
files:
  - "book1.xlsx"

インベントリプラグインをつくる

とても雑ですが、Excelファイルを読み込んでインベントリに追加するスクリプトです。

plugins/inventory/xlsx.py
import openpyxl
from ansible.plugins.inventory import BaseInventoryPlugin


class InventoryModule(BaseInventoryPlugin):
    NAME = "xlsx"

    def verify_file(self, path):
        valid = False
        if super(InventoryModule, self).verify_file(path):
            if path.endswith(".yml"):
                valid = True
                return valid
        return True

    def _load_xlsx(self, path):
        inventory_data = self.loader.load_from_file(path, cache=False)
        nodes = []
        for f in inventory_data.get("files"):
            wb = openpyxl.load_workbook(f)
            ws = wb["Sheet1"]
            for row in ws.rows:
                nodes.append(
                    {
                        "hostname": row[0].value,
                        "address": row[1].value,
                        "role": row[2].value,
                    }
                )
        return nodes

    def parse(self, inventory, loader, path, cache=True):
        super(InventoryModule, self).parse(inventory, loader, path, cache)

        xlsx_data = self._load_xlsx(path)

        for data in xlsx_data:
            self.inventory.add_host(data["hostname"])
            self.inventory.set_variable(
                data["hostname"], "ansible_host", data["address"]
            )
            self.inventory.add_group(data["role"])
            self._populate_host_vars([data["hostname"]], {}, data["role"])
            self.inventory.add_child("all", data["role"])

詳細は割愛します。自作される場合は以下のリポジトリが大変参考になります。

実行してみる

無事にExcelファイルの中身をインベントリとして扱うことができました!

$ ansible-inventory -i xlsx.yml --list
{
    "_meta": {
        "hostvars": {
            "node1": {
                "ansible_host": "192.0.2.1"
            },
            "node2": {
                "ansible_host": "192.0.2.2"
            },
            "node3": {
                "ansible_host": "192.0.2.3"
            }
        }
    },
    "all": {
        "children": [
            "db",
            "ungrouped",
            "web"
        ]
    },
    "db": {
        "hosts": [
            "node2",
            "node3"
        ]
    },
    "web": {
        "hosts": [
            "node1"
        ]
    }
}

おまけ

たとえばこんなファイル(book2.xlsx)が追加されたとしても
book2.png

インベントリファイルに追加するだけでOKです。

xlsx.yml
plugin: xlsx
files:
  - "book1.xlsx"
  - "book2.xlsx"
$ ansible-inventory -i xlsx.yml --list
{
    "_meta": {
        "hostvars": {
            "node1": {
                "ansible_host": "192.0.2.1"
            },
            "node2": {
                "ansible_host": "192.0.2.2"
            },
            "node3": {
                "ansible_host": "192.0.2.3"
            },
            "node4": {
                "ansible_host": "192.0.2.4"
            },
            "node5": {
                "ansible_host": "192.0.2.5"
            },
            "node6": {
                "ansible_host": "192.0.2.6"
            }
        }
    },
    "all": {
        "children": [
            "db",
            "ungrouped",
            "web"
        ]
    },
    "db": {
        "hosts": [
            "node2",
            "node3",
            "node5",
            "node6"
        ]
    },
    "web": {
        "hosts": [
            "node1",
            "node4"
        ]
    }
}

なお作成したファイルのディレクトリ構造は以下の通りです。

$ tree
.
├── ansible.cfg
├── book1.xlsx
├── book2.xlsx
├── plugins
│   └── inventory
│       └── xlsx.py
└── xlsx.yml

おわりに

ダイナミックインベントリの場合、与えられる引数として環境変数を主に使うことになるかと思いますが、インベントリプラグインの場合はインベントリファイルにいくらでも定義ができるため自由度が高く、より柔軟なインベントリを構成することができます。ダイナミックインベントリで悩んでいる方はぜひお試しください。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?