mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-26 21:33:05 +00:00
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.
192 lines
6.1 KiB
Python
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)
|