forked from jseifeddine/mysql-dynamic-inventory
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmysql-dynamic-inventory.py
96 lines (86 loc) · 3.46 KB
/
mysql-dynamic-inventory.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from ansible.errors import AnsibleError
from ansible.plugins.inventory import BaseInventoryPlugin
from ansible.utils.display import Display
import pymysql
display = Display()
DOCUMENTATION = r"""
name: mysql-dynamic-inventory
plugin_type: inventory
short_description: Returns Ansible inventory from an SQL query
description: Returns Ansible inventory from an SQL query
options:
plugin:
description: Name of the plugin
required: true
choices: ['mysql-dynamic-inventory']
db_host:
description: Database host
required: true
db_user:
description: Database user
required: true
db_pass:
description: Database password
required: true
db_name:
description: Database name
required: true
db_query:
description: Database query
required: true
"""
class InventoryModule(BaseInventoryPlugin):
NAME = "mysql-dynamic-inventory"
def verify_file(self, path):
"""Ensures that the given file is valid for this plugin"""
valid = False
if super(InventoryModule, self).verify_file(path):
if path.endswith(("mysql.yaml", "mysql.yml")):
valid = True
return valid
def parse(self, inventory, loader, path, cache=True):
"""Parses the inventory file"""
super(InventoryModule, self).parse(inventory, loader, path, cache)
self._read_config_data(path)
self.templar.available_variables = self._vars
for option in self._options:
try:
if self.get_option(option):
templated_option = self.templar.template(self.get_option(option))
self.set_option(option, templated_option)
except Exception as e:
raise AnsibleError(
f"Error processing templating for {option}: {str(e)}"
)
self._fetch_hosts()
def _fetch_hosts(self):
"""Fetches hosts from the database and populates the inventory"""
group_init = {}
try:
connection = pymysql.connect(
host=self.get_option("db_host"),
user=self.get_option("db_user"),
password=self.get_option("db_pass"),
database=self.get_option("db_name"),
cursorclass=pymysql.cursors.DictCursor,
)
with connection.cursor() as cursor:
cursor.execute(self.get_option("db_query"))
for row in cursor.fetchall():
group = row.get("inventory_group")
if group and group not in group_init:
self.inventory.add_group(group)
group_init[group] = True
hostname = row.get("inventory_hostname")
if hostname:
self.inventory.add_host(hostname, group=group)
# Dynamically set ansible host variables for each column returned
for key, value in row.items():
# Skip inventory_hostname and group as they're already used
if key not in ["inventory_hostname", "inventory_group"]:
self.inventory.set_variable(hostname, key, value)
except Exception as e:
raise AnsibleError(f"Database query failed: {e}")
finally:
if connection:
connection.close()