推荐Ansible InventoryPlugin
这是2021年樱互联网Advent Calendar的第16篇文章。
简而言之
在生成Ansible清单的动态方法中,人们通常会使用“动态清单”,但还有一种叫做“清单插件”的替代方法。
有时候,使用库存插件可以更简洁地构建剧本,尽管与动态库存相比,库存插件的机制稍微复杂一些。
立刻試試看
作为一个例子,让我们尝试将以下Excel文件(book1.xlsx)用作Ansible的清单。
从左到右,这些是主机名、IP地址和用途等图像。
请指定库存插件位置。
为了方便操作,我们会设置一个目录来引用默认的库插件。
[defaults]
inventory_plugins=./plugins/inventory
默认值的详细信息请参阅以下文件。
创建库存文件
用 ansible-playbook 命令的 -i 选项来指定创建清单文件。
在插件中写下将要创建的清单插件名称,并在文件中定义要加载的Excel文件。
plugin: xlsx
files:
- "book1.xlsx"
创建库存插件
这是一个很简单但有效的脚本,它可以读取Excel文件并将内容添加到库存中。
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"
]
}
}
這是額外的禮物。
只需将其添加到库存文件中即可。
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
作为结束。
在使用动态清单时,我认为主要使用环境变量作为提供的参数。而对于清单插件的情况,则可以在清单文件中定义任意数量的选项,这样可以获得更高的自由度,构建更加灵活的清单。如果对于动态清单感到困惑,请务必尝试一下。