Anisble mongodb dynamic inventory插件开发

引言

Ansible是一种强大的自动化工具,可以简化IT基础架构的管理和部署。它提供了各种各样的插件,以便用户可以轻松地扩展其功能。其中,自定义插件是Ansible的一个重要特性,可以满足用户不同的需求,例如自定义Action、Module、Filter、Lookup、Callback等插件。

在Ansible中,Inventory是由主机清单和组成员组成的。主机清单是一个文本文件,其中列出了所有托管主机的信息,包括主机名、IP地址、用户名、密码等。组成员是一组主机,可以按功能、环境、角色等方式组织在一起。动态Inventory插件允许用户在运行时动态地生成主机清单,而不是使用静态文本文件。。自定义Inventory插件可以是各种类型,例如脚本、API、数据库等。最简单的方式可以通过脚本的方式来做Inventory的解析,实际上,最开始我也是尝试用脚本来搞定的。但是遇到一个问题,因为项目的ssh端口号这些不是协议规定的22端口号,需要通过ansible_ssh_port等变量去纠正,但是发现用脚本来解析时会遇到这些变量没有实际生效的问题,因此研究了一下开发插件来解析的方式。相比于使用脚本来解析,插件还有一些高级特性,例如支持缓存等功能。

本文将重点介绍笔者开发一个从MongoDB读取inventory的插件的开发过程及途中遇到的问题。

开发过程

数据准备

MongoDB中创建一个名为hosts的表(这个可以自定义,跟下面的配置里面的collection对应起来就行),插入如下的示例数据:

{
    "name" : "server1",
    "vars" : {
        "ansible_ssh_host" : "1.1.1.1",
        "ansible_ssh_port" : "12345",
        "ansible_ssh_user" : "user",
        "ansible_ssh_private_key_file" : "/path/to/private/key",
        "ansible_ssh_common_args" : "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
    }
}

配置部分

对应的inventory文件mongodb.yaml(这里需要指定一个固定的yml文件来让ansible识别使用哪个插件来读取配置以及获取必要的参数):

# mongodb.yaml

plugin: mongodb_inventory
mongodb_uri: mongodb://localhost:27017
database: ansible
collection: hosts

ansible.cfg文件里面需要指明一下去哪个目录下搜索插件:

[defaults]
inventory_plugins = /root/inventory_plugins

插件开发

mongodb_inventory.py代码

# mongodb_inventory.py

from ansible.plugins.inventory import BaseInventoryPlugin

try:
    from pymongo import MongoClient
except ImportError:
    raise Exception("The 'pymongo' python module is required.")

DOCUMENTATION = '''
    name: mongodb_inventory
    plugin_type: inventory
    short_description: Returns Ansible inventory from MongoDB
    options:
        mongodb_uri:
            description: MongoDB URI
            required: True
        database:
            description: Database name
            required: True
        collection:
            description: Collection name
            required: True
    requirements:
        - pymongo
'''
    
class InventoryModule(BaseInventoryPlugin):
    NAME = 'mongodb_inventory'

    def verify_file(self, path):
        return path.endswith(('mongodb.yaml', 'mongodb.yml'))

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

        self._read_config_data(path)

        client = MongoClient(self.get_option('mongodb_uri'))
        db = client[self.get_option('database')]
        collection = db[self.get_option('collection')]

        results = collection.find()

        for item in results:
            host_name = item.get('host')
            group_name = item.get('group', 'ungrouped')
            host_vars = item.get('vars', {})

            self.inventory.add_host(host_name)
            self.inventory.add_group(group_name)
            self.inventory.add_host(host_name, group_name)

            for var, value in host_vars.items():
                self.inventory.set_variable(host_name, var, value)

使用示例

ansible -i mongodb.yaml all -m ping

如果能正常执行ping脚本,那么说明我们的插件开发以及ok了。至此,这个小插件就开发完成了。通过这个插件,我们就可以将inventory数据定义在mongodb里面了。如果别的接口或者数据库也是类似的思路,只是里面的verify和parse函数稍作调整即可。

小结

个人觉得这里比较关键的三个点是:

  1. 要了解如inventory插件的生效机制,需要通过ansible.cfg(也可以在默认插件文件存放插件文件,但是个人觉得不太好做版本管理)来指定对应的插件搜索路径;
  2. 了解插件开发的范式,需要一个yml文件作为inventory文件来告诉ansible使用哪个插件来解析inventory,并且需要设置DOCUMENT变量值才能让插件正常的解析inventory文件里面自定义的参数;
  3. 最简单的插件需要实现verify_fileparse两个函数,一个是做合法性校验的,另一个则是添加host并设置对应的变量;

踩的几个坑

问题1

运行命令时遇到 specifies unknown plugin 错误,比如这样:

Failed to parse /root/mongodb.yml with auto plugin: inventory config '/root/mongodb.yml' specifies unknown plugin 'mongodb_inventory'

解决:

该错误表示 Ansible 无法找到名为 mongodb_inventory 的库存插件。这可能是因为插件文件未放置在正确的位置,或者 Ansible 的配置未正确指向插件的位置。

以下是解决此问题的步骤:

  1. 确保 mongodb_inventory.py 文件已放置在正确的目录中:Ansible 的库存插件需要放置在 ansible/plugins/inventory/ 目录中,或者你可以创建一个自定义的目录并将其添加到 ansible.cfg 文件的 inventory_plugins 配置项中。
  2. 确保 mongodb_inventory.py 文件有执行权限。你可以通过运行以下命令来设置执行权限:
chmod +x mongodb_inventory.py
  1. 检查你的 ansible.cfg 文件,并确保 inventory_plugins 配置项包含了你的插件文件 mongodb_inventory.py 所在的目录。例如:
[defaults]
inventory_plugins = /path/to/your/inventory_plugins_directory
  1. 确保你的 Ansible 版本支持库存插件。库存插件是在 Ansible 2.4 版本中引入的,因此如果你的 Ansible 版本较旧,你可能需要升级你的 Ansible 版本。

如果你仍然遇到问题,你可能需要检查你的插件代码是否有误,或者检查 MongoDB 的连接信息是否正确。

问题2

命名已经在yml文件里面定义了对应的参数,但是运行报错:

mongodb_inventory setting: mongodb_uri ) was not defined in configuration

解决:

插件里面需要有 DOCUMENTATION 变量定义, 比如这样:

    DOCUMENTATION = '''
        name: mongodb_inventory
        plugin_type: inventory
        short_description: Returns Ansible inventory from MongoDB
        options:
          mongodb_uri:
            description: MongoDB URI
            required: True
          database:
            description: Database name
            required: True
          collection:
            description: Collection name
            required: True
        requirements:
          - pymongo
    '''
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。