Files
ansible-freeipa/plugins/inventory/freeipa.py
Rafael Guterres Jeffman fdd45cc475 pylint: Fix pylint 3.3.8 issues
With the latest pylint version, an issue is raised by inheriting from
BaseInventoryPlugin, as the class has too many ancestors
(too-many-ancestors). This is caused by a class hierarchy that is too
deep, and is not under ansible-freeipa's control.
2025-11-10 11:38:52 -03:00

192 lines
6.1 KiB
Python

# -*- coding: utf-8 -*-
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# Copyright (C) 2024 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.0",
"supported_by": "community",
"status": ["preview"],
}
DOCUMENTATION = """
---
name: freeipa
version_added: "1.13.0"
short_description: Compiles a dynamic inventory from IPA domain
description: |
Compiles a dynamic inventory from IPA domain, filters servers by role(s).
options:
plugin:
description: Marks this as an instance of the "freeipa" plugin.
required: True
choices: ["freeipa"]
ipaadmin_principal:
description: The admin principal.
default: admin
type: str
ipaadmin_password:
description: The admin password.
required: true
type: str
server:
description: FQDN of server to start the scan.
type: str
required: true
verify:
description: |
The server TLS certificate file for verification (/etc/ipa/ca.crt).
Turned off if not set.
type: str
required: false
role:
description: |
The role(s) of the server. If several roles are given, only servers
that have all the roles are returned.
type: list
elements: str
choices: ["IPA master", "CA server", "KRA server", "DNS server",
"AD trust controller", "AD trust agent"]
required: false
inventory_group:
description: |
The inventory group to create. The default group name is "ipaservers".
type: str
default: ipaservers
author:
- Thomas Woerner (@t-woerner)
"""
EXAMPLES = """
# inventory.config file in YAML format
plugin: freeipa
server: ipaserver-01.ipa.local
ipaadmin_password: SomeADMINpassword
# inventory.config file in YAML format with server TLS certificate verification
plugin: freeipa
server: ipaserver-01.ipa.local
ipaadmin_password: SomeADMINpassword
verify: ca.crt
"""
import os
try:
import requests
except ImportError:
requests = None
try:
import urllib3
except ImportError:
urllib3 = None
from ansible import constants
from ansible.errors import AnsibleParserError
from ansible.module_utils.common.text.converters import to_native
from ansible.plugins.inventory import BaseInventoryPlugin
from ansible.module_utils.six.moves.urllib.parse import quote
class InventoryModule(BaseInventoryPlugin): # pylint: disable=R0901
NAME = 'freeipa'
def verify_file(self, path):
# pylint: disable=super-with-arguments
if super(InventoryModule, self).verify_file(path):
_name, ext = os.path.splitext(path)
if ext in constants.YAML_FILENAME_EXTENSIONS:
return True
return False
def parse(self, inventory, loader, path, cache=False):
# pylint: disable=super-with-arguments
super(InventoryModule, self).parse(inventory, loader, path,
cache=cache)
self._read_config_data(path) # This also loads the cache
self.get_option("plugin")
if requests is None:
raise AnsibleParserError("The required Python library "
"'requests' could not be imported.")
ipaadmin_principal = self.get_option("ipaadmin_principal")
ipaadmin_password = self.get_option("ipaadmin_password")
server = self.get_option("server")
verify = self.get_option("verify")
role = self.get_option("role")
inventory_group = self.get_option("inventory_group")
if verify is not None:
if not os.path.exists(verify):
raise AnsibleParserError("ERROR: Could not load %s" % verify)
else:
verify = False
# Disable certificate verification warning without certificate
# as long as urllib3 could have been loaded.
if urllib3 is not None:
urllib3.disable_warnings(
urllib3.exceptions.InsecureRequestWarning)
self.inventory.add_group(inventory_group)
ipa_url = "https://%s/ipa" % server
s = requests.Session()
s.headers.update({"referer": ipa_url})
s.headers.update({"Content-Type":
"application/x-www-form-urlencoded"})
s.headers.update({"Accept": "text/plain"})
data = 'user=%s&password=%s' % (quote(ipaadmin_principal, safe=''),
quote(ipaadmin_password, safe=''))
response = s.post("%s/session/login_password" % ipa_url,
data=data, verify=verify)
# Now use json API
s.headers.update({"Content-Type": "application/json"})
kw_args = {}
if role is not None:
kw_args["servrole"] = role
json_data = {
"method" : "server_find",
"params": [[], kw_args],
"id": 0
}
response = s.post("%s/session/json" % ipa_url, json=json_data,
verify=verify)
json_res = response.json()
error = json_res.get("error")
if error is not None:
raise AnsibleParserError("ERROR: %s" % to_native(error))
if "result" in json_res and "result" in json_res["result"]:
res = json_res["result"].get("result")
if isinstance(res, list):
for server in res:
self.inventory.add_host(server["cn"][0],
group=inventory_group)