Merge pull request #508 from nitzmahone/workaround_import

workaround 2.9 controller import issues
This commit is contained in:
Thomas Woerner
2021-05-12 11:48:41 +02:00
committed by GitHub
4 changed files with 1581 additions and 1569 deletions

View File

@@ -22,20 +22,36 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys __all__ = ["gssapi", "netaddr", "api", "ipalib_errors", "Env",
import operator "DEFAULT_CONFIG", "LDAP_GENERALIZED_TIME_FORMAT",
import os "kinit_password", "kinit_keytab", "run", "DN", "VERSION",
import uuid "paths", "get_credentials_if_valid", "Encoding",
import tempfile "load_pem_x509_certificate"]
import shutil
import netaddr
import gssapi
from datetime import datetime
from pprint import pformat
try: import sys
# HACK: workaround for Ansible 2.9
# https://github.com/ansible/ansible/issues/68361
if 'ansible.executor' in sys.modules:
for attr in __all__:
setattr(sys.modules[__name__], attr, None)
else:
import operator
import os
import uuid
import tempfile
import shutil
import netaddr
import gssapi
from datetime import datetime
from pprint import pformat
# ansible-freeipa requires locale to be C, IPA requires utf-8.
os.environ["LANGUAGE"] = "C"
try:
from packaging import version from packaging import version
except ImportError: except ImportError:
# If `packaging` not found, split version string for creating version # If `packaging` not found, split version string for creating version
# object. Although it is not PEP 440 compliant, it will work for stable # object. Although it is not PEP 440 compliant, it will work for stable
# FreeIPA releases. # FreeIPA releases.
@@ -51,53 +67,48 @@ except ImportError:
""" """
return tuple(re.split("[-_\.]", version_str)) # noqa: W605 return tuple(re.split("[-_\.]", version_str)) # noqa: W605
from ipalib import api from ipalib import api
from ipalib import errors as ipalib_errors # noqa from ipalib import errors as ipalib_errors # noqa
from ipalib.config import Env from ipalib.config import Env
from ipalib.constants import DEFAULT_CONFIG, LDAP_GENERALIZED_TIME_FORMAT from ipalib.constants import DEFAULT_CONFIG, LDAP_GENERALIZED_TIME_FORMAT
try: try:
from ipalib.install.kinit import kinit_password, kinit_keytab from ipalib.install.kinit import kinit_password, kinit_keytab
except ImportError: except ImportError:
from ipapython.ipautil import kinit_password, kinit_keytab from ipapython.ipautil import kinit_password, kinit_keytab
from ipapython.ipautil import run from ipapython.ipautil import run
from ipapython.dn import DN from ipapython.dn import DN
from ipapython.version import VERSION from ipapython.version import VERSION
from ipaplatform.paths import paths from ipaplatform.paths import paths
from ipalib.krb_utils import get_credentials_if_valid from ipalib.krb_utils import get_credentials_if_valid
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text from ansible.module_utils._text import to_text
from ansible.module_utils.common.text.converters import jsonify from ansible.module_utils.common.text.converters import jsonify
try: try:
from ipalib.x509 import Encoding from ipalib.x509 import Encoding
except ImportError: except ImportError:
from cryptography.hazmat.primitives.serialization import Encoding from cryptography.hazmat.primitives.serialization import Encoding
try: try:
from ipalib.x509 import load_pem_x509_certificate from ipalib.x509 import load_pem_x509_certificate
except ImportError: except ImportError:
from ipalib.x509 import load_certificate from ipalib.x509 import load_certificate
load_pem_x509_certificate = None load_pem_x509_certificate = None
import socket import socket
import base64 import base64
import six import six
try: try:
from collections.abc import Mapping # noqa from collections.abc import Mapping # noqa
except ImportError: except ImportError:
from collections import Mapping # noqa from collections import Mapping # noqa
if six.PY3:
if six.PY3:
unicode = str unicode = str
# ansible-freeipa requires locale to be C, IPA requires utf-8. def valid_creds(module, principal): # noqa
os.environ["LANGUAGE"] = "C"
def valid_creds(module, principal): # noqa
"""Get valid credentials matching the princial, try GSSAPI first.""" """Get valid credentials matching the princial, try GSSAPI first."""
if "KRB5CCNAME" in os.environ: if "KRB5CCNAME" in os.environ:
ccache = os.environ["KRB5CCNAME"] ccache = os.environ["KRB5CCNAME"]
@@ -134,8 +145,7 @@ def valid_creds(module, principal): # noqa
return True return True
return False return False
def temp_kinit(principal, password):
def temp_kinit(principal, password):
"""Kinit with password using a temporary ccache.""" """Kinit with password using a temporary ccache."""
if not password: if not password:
raise RuntimeError("The password is not set") raise RuntimeError("The password is not set")
@@ -153,8 +163,7 @@ def temp_kinit(principal, password):
os.environ["KRB5CCNAME"] = ccache_name os.environ["KRB5CCNAME"] = ccache_name
return ccache_dir, ccache_name return ccache_dir, ccache_name
def temp_kdestroy(ccache_dir, ccache_name):
def temp_kdestroy(ccache_dir, ccache_name):
"""Destroy temporary ticket and remove temporary ccache.""" """Destroy temporary ticket and remove temporary ccache."""
if ccache_name is not None: if ccache_name is not None:
run([paths.KDESTROY, '-c', ccache_name], raiseonerr=False) run([paths.KDESTROY, '-c', ccache_name], raiseonerr=False)
@@ -162,8 +171,7 @@ def temp_kdestroy(ccache_dir, ccache_name):
if ccache_dir is not None: if ccache_dir is not None:
shutil.rmtree(ccache_dir, ignore_errors=True) shutil.rmtree(ccache_dir, ignore_errors=True)
def api_connect(context=None):
def api_connect(context=None):
""" """
Initialize IPA API with the provided context. Initialize IPA API with the provided context.
@@ -176,7 +184,9 @@ def api_connect(context=None):
env._bootstrap() env._bootstrap()
env._finalize_core(**dict(DEFAULT_CONFIG)) env._finalize_core(**dict(DEFAULT_CONFIG))
# available contexts are 'server', 'ansible-freeipa' and 'cli_installer' # available contexts are 'server', 'ansible-freeipa' and
# 'cli_installer'
if context is None: if context is None:
context = 'server' context = 'server'
@@ -191,28 +201,23 @@ def api_connect(context=None):
if not backend.isconnected(): if not backend.isconnected():
backend.connect(ccache=os.environ.get('KRB5CCNAME', None)) backend.connect(ccache=os.environ.get('KRB5CCNAME', None))
def api_command(module, command, name, args):
def api_command(module, command, name, args):
"""Call ipa.Command.""" """Call ipa.Command."""
return api.Command[command](name, **args) return api.Command[command](name, **args)
def api_command_no_name(module, command, args):
def api_command_no_name(module, command, args):
"""Call ipa.Command without a name.""" """Call ipa.Command without a name."""
return api.Command[command](**args) return api.Command[command](**args)
def api_check_command(command):
def api_check_command(command):
"""Return if command exists in command list.""" """Return if command exists in command list."""
return command in api.Command return command in api.Command
def api_check_param(command, name):
def api_check_param(command, name):
"""Check if param exists in command param list.""" """Check if param exists in command param list."""
return name in api.Command[command].params return name in api.Command[command].params
def api_check_ipa_version(oper, requested_version):
def api_check_ipa_version(oper, requested_version):
""" """
Compare the installed IPA version against a requested version. Compare the installed IPA version against a requested version.
@@ -229,10 +234,10 @@ def api_check_ipa_version(oper, requested_version):
operation = oper_map.get(oper) operation = oper_map.get(oper)
if not(operation): if not(operation):
raise NotImplementedError("Invalid operator: %s" % oper) raise NotImplementedError("Invalid operator: %s" % oper)
return operation(version.parse(VERSION), version.parse(requested_version)) return operation(version.parse(VERSION),
version.parse(requested_version))
def execute_api_command(module, principal, password, command, name, args):
def execute_api_command(module, principal, password, command, name, args):
""" """
Execute an API command. Execute an API command.
@@ -253,8 +258,7 @@ def execute_api_command(module, principal, password, command, name, args):
finally: finally:
temp_kdestroy(ccache_dir, ccache_name) temp_kdestroy(ccache_dir, ccache_name)
def date_format(value):
def date_format(value):
accepted_date_formats = [ accepted_date_formats = [
LDAP_GENERALIZED_TIME_FORMAT, # generalized time LDAP_GENERALIZED_TIME_FORMAT, # generalized time
'%Y-%m-%dT%H:%M:%SZ', # ISO 8601, second precision '%Y-%m-%dT%H:%M:%SZ', # ISO 8601, second precision
@@ -271,8 +275,7 @@ def date_format(value):
pass pass
raise ValueError("Invalid date '%s'" % value) raise ValueError("Invalid date '%s'" % value)
def compare_args_ipa(module, args, ipa): # noqa
def compare_args_ipa(module, args, ipa): # noqa
"""Compare IPA obj attrs with the command args. """Compare IPA obj attrs with the command args.
This function compares IPA objects attributes with the args the This function compares IPA objects attributes with the args the
@@ -293,7 +296,8 @@ def compare_args_ipa(module, args, ipa): # noqa
if args is None or ipa is None: if args is None or ipa is None:
module.debug( module.debug(
base_debug_msg + "args is%s None an ipa is%s None" % ( base_debug_msg + "args is%s None an ipa is%s None" % (
"" if args is None else " not", "" if ipa is None else " not", "" if args is None else " not",
"" if ipa is None else " not",
) )
) )
return False return False
@@ -328,7 +332,8 @@ def compare_args_ipa(module, args, ipa): # noqa
return False return False
if isinstance(ipa_arg[0], str) and isinstance(arg[0], int): if isinstance(ipa_arg[0], str) and isinstance(arg[0], int):
arg = [to_text(_arg) for _arg in arg] arg = [to_text(_arg) for _arg in arg]
if isinstance(ipa_arg[0], unicode) and isinstance(arg[0], int): if isinstance(ipa_arg[0], unicode) \
and isinstance(arg[0], int):
arg = [to_text(_arg) for _arg in arg] arg = [to_text(_arg) for _arg in arg]
try: try:
arg_set = set(arg) arg_set = set(arg)
@@ -350,13 +355,13 @@ def compare_args_ipa(module, args, ipa): # noqa
return False return False
return True return True
def _afm_convert(value):
def _afm_convert(value):
if value is not None: if value is not None:
if isinstance(value, list): if isinstance(value, list):
return [_afm_convert(x) for x in value] return [_afm_convert(x) for x in value]
elif isinstance(value, dict): elif isinstance(value, dict):
return {_afm_convert(k): _afm_convert(v) for k, v in value.items()} return {_afm_convert(k): _afm_convert(v)
for k, v in value.items()}
elif isinstance(value, str): elif isinstance(value, str):
return to_text(value) return to_text(value)
else: else:
@@ -364,16 +369,13 @@ def _afm_convert(value):
else: else:
return value return value
def module_params_get(module, name):
def module_params_get(module, name):
return _afm_convert(module.params.get(name)) return _afm_convert(module.params.get(name))
def api_get_realm():
def api_get_realm():
return api.env.realm return api.env.realm
def gen_add_del_lists(user_list, res_list):
def gen_add_del_lists(user_list, res_list):
"""Generate the lists for the addition and removal of members.""" """Generate the lists for the addition and removal of members."""
# The user list is None, therefore the parameter should not be touched # The user list is None, therefore the parameter should not be touched
if user_list is None: if user_list is None:
@@ -384,8 +386,7 @@ def gen_add_del_lists(user_list, res_list):
return add_list, del_list return add_list, del_list
def encode_certificate(cert):
def encode_certificate(cert):
""" """
Encode a certificate using base64. Encode a certificate using base64.
@@ -399,8 +400,7 @@ def encode_certificate(cert):
encoded = encoded.decode('ascii') encoded = encoded.decode('ascii')
return encoded return encoded
def load_cert_from_str(cert):
def load_cert_from_str(cert):
cert = cert.strip() cert = cert.strip()
if not cert.startswith("-----BEGIN CERTIFICATE-----"): if not cert.startswith("-----BEGIN CERTIFICATE-----"):
cert = "-----BEGIN CERTIFICATE-----\n" + cert cert = "-----BEGIN CERTIFICATE-----\n" + cert
@@ -413,8 +413,7 @@ def load_cert_from_str(cert):
cert = load_certificate(cert.encode('utf-8')) cert = load_certificate(cert.encode('utf-8'))
return cert return cert
def DN_x500_text(text):
def DN_x500_text(text):
if hasattr(DN, "x500_text"): if hasattr(DN, "x500_text"):
return DN(text).x500_text() return DN(text).x500_text()
else: else:
@@ -423,8 +422,7 @@ def DN_x500_text(text):
dn.rdns = reversed(dn.rdns) dn.rdns = reversed(dn.rdns)
return str(dn) return str(dn)
def is_valid_port(port):
def is_valid_port(port):
if not isinstance(port, int): if not isinstance(port, int):
return False return False
@@ -433,8 +431,7 @@ def is_valid_port(port):
return False return False
def is_ip_address(ipaddr):
def is_ip_address(ipaddr):
"""Test if given IP address is a valid IPv4 or IPv6 address.""" """Test if given IP address is a valid IPv4 or IPv6 address."""
try: try:
netaddr.IPAddress(str(ipaddr)) netaddr.IPAddress(str(ipaddr))
@@ -442,8 +439,7 @@ def is_ip_address(ipaddr):
return False return False
return True return True
def is_ip_network_address(ipaddr):
def is_ip_network_address(ipaddr):
"""Test if given IP address is a valid IPv4 or IPv6 address.""" """Test if given IP address is a valid IPv4 or IPv6 address."""
try: try:
netaddr.IPNetwork(str(ipaddr)) netaddr.IPNetwork(str(ipaddr))
@@ -451,8 +447,7 @@ def is_ip_network_address(ipaddr):
return False return False
return True return True
def is_ipv4_addr(ipaddr):
def is_ipv4_addr(ipaddr):
"""Test if given IP address is a valid IPv4 address.""" """Test if given IP address is a valid IPv4 address."""
try: try:
socket.inet_pton(socket.AF_INET, ipaddr) socket.inet_pton(socket.AF_INET, ipaddr)
@@ -460,8 +455,7 @@ def is_ipv4_addr(ipaddr):
return False return False
return True return True
def is_ipv6_addr(ipaddr):
def is_ipv6_addr(ipaddr):
"""Test if given IP address is a valid IPv6 address.""" """Test if given IP address is a valid IPv6 address."""
try: try:
socket.inet_pton(socket.AF_INET6, ipaddr) socket.inet_pton(socket.AF_INET6, ipaddr)
@@ -469,8 +463,7 @@ def is_ipv6_addr(ipaddr):
return False return False
return True return True
def exit_raw_json(module, **kwargs):
def exit_raw_json(module, **kwargs):
""" """
Print the raw parameters in JSON format, without masking. Print the raw parameters in JSON format, without masking.
@@ -489,8 +482,7 @@ def exit_raw_json(module, **kwargs):
print(jsonify(kwargs)) print(jsonify(kwargs))
sys.exit(0) sys.exit(0)
class AnsibleFreeIPAParams(Mapping):
class AnsibleFreeIPAParams(Mapping):
def __init__(self, ansible_module): def __init__(self, ansible_module):
self.mapping = ansible_module.params self.mapping = ansible_module.params
self.ansible_module = ansible_module self.ansible_module = ansible_module
@@ -513,8 +505,7 @@ class AnsibleFreeIPAParams(Mapping):
def __getattr__(self, name): def __getattr__(self, name):
return self.get(name) return self.get(name)
class FreeIPABaseModule(AnsibleModule):
class FreeIPABaseModule(AnsibleModule):
""" """
Base class for FreeIPA Ansible modules. Base class for FreeIPA Ansible modules.
@@ -528,7 +519,8 @@ class FreeIPABaseModule(AnsibleModule):
2. Implement the method ``define_ipa_commands()`` 2. Implement the method ``define_ipa_commands()``
3. Implement the method ``check_ipa_params()`` (optional) 3. Implement the method ``check_ipa_params()`` (optional)
After instantiating the class the method ``ipa_run()`` should be called. After instantiating the class the method ``ipa_run()`` should be
called.
Example (ansible-freeipa/plugins/modules/ipasomemodule.py): Example (ansible-freeipa/plugins/modules/ipasomemodule.py):
@@ -548,7 +540,8 @@ class FreeIPABaseModule(AnsibleModule):
# Validate your params here # Validate your params here
# Example: # Example:
if not self.ipa_params.module_param in VALID_OPTIONS: if not self.ipa_params.module_param in VALID_OPTIONS:
self.fail_json(msg="Invalid value for argument module_param") self.fail_json(
msg="Invalid value for argument module_param")
def define_ipa_commands(self): def define_ipa_commands(self):
args = self.get_ipa_command_args() args = self.get_ipa_command_args()
@@ -612,7 +605,8 @@ class FreeIPABaseModule(AnsibleModule):
""" """
Return a dict to be passed to an IPA command. Return a dict to be passed to an IPA command.
The keys of ``ipa_param_mapping`` are also the keys of the return dict. The keys of ``ipa_param_mapping`` are also the keys of the return
dict.
The values of ``ipa_param_mapping`` needs to be either: The values of ``ipa_param_mapping`` needs to be either:
* A str with the name of a defined method; or * A str with the name of a defined method; or
@@ -646,8 +640,8 @@ class FreeIPABaseModule(AnsibleModule):
else: else:
self.fail_json( self.fail_json(
msg=( msg=(
"Couldn't get a value for '%s'. Option '%s' is not " "Couldn't get a value for '%s'. Option '%s' is "
"a module argument neither a defined method." "not a module argument neither a defined method."
) )
% (ipa_param_name, param_name) % (ipa_param_name, param_name)
) )
@@ -758,7 +752,8 @@ class FreeIPABaseModule(AnsibleModule):
try: try:
result = self.api_command(command, name, args) result = self.api_command(command, name, args)
except Exception as excpt: except Exception as excpt:
self.fail_json(msg="%s: %s: %s" % (command, name, str(excpt))) self.fail_json(msg="%s: %s: %s" % (command, name,
str(excpt)))
else: else:
self.process_command_result(name, command, args, result) self.process_command_result(name, command, args, result)
self.get_command_errors(command, result) self.get_command_errors(command, result)
@@ -767,7 +762,8 @@ class FreeIPABaseModule(AnsibleModule):
""" """
Process an API command result. Process an API command result.
This method can be overriden in subclasses, and change self.exit_values This method can be overriden in subclasses, and
change self.exit_values
to return data in the result for the controller. to return data in the result for the controller.
""" """
if "completed" in result: if "completed" in result:

View File

@@ -45,17 +45,26 @@ __all__ = ["gssapi", "version", "ipadiscovery", "api", "errors", "x509",
"configure_firefox", "sync_time", "check_ldap_conf", "configure_firefox", "sync_time", "check_ldap_conf",
"sssd_enable_ifp"] "sssd_enable_ifp"]
from ipapython.version import NUM_VERSION, VERSION import sys
# HACK: workaround for Ansible 2.9
# https://github.com/ansible/ansible/issues/68361
if 'ansible.executor' in sys.modules:
for attr in __all__:
setattr(sys.modules[__name__], attr, None)
if NUM_VERSION < 30201:
# See ipapython/version.py
IPA_MAJOR, IPA_MINOR, IPA_RELEASE = [int(x) for x in VERSION.split(".", 2)]
IPA_PYTHON_VERSION = IPA_MAJOR*10000 + IPA_MINOR*100 + IPA_RELEASE
else: else:
from ipapython.version import NUM_VERSION, VERSION
if NUM_VERSION < 30201:
# See ipapython/version.py
IPA_MAJOR, IPA_MINOR, IPA_RELEASE = [int(x) for x in
VERSION.split(".", 2)]
IPA_PYTHON_VERSION = IPA_MAJOR*10000 + IPA_MINOR*100 + IPA_RELEASE
else:
IPA_PYTHON_VERSION = NUM_VERSION IPA_PYTHON_VERSION = NUM_VERSION
class installer_obj(object):
class installer_obj(object):
def __init__(self): def __init__(self):
pass pass
@@ -76,22 +85,22 @@ class installer_obj(object):
# return getattr(self, attr) # return getattr(self, attr)
# def __setattr__(self, attr, value): # def __setattr__(self, attr, value):
# logger.debug(" --> Setting installer.%s to %s" % (attr, repr(value))) # logger.debug(" --> Setting installer.%s to %s" %
# (attr, repr(value)))
# return super(installer_obj, self).__setattr__(attr, value) # return super(installer_obj, self).__setattr__(attr, value)
def knobs(self): def knobs(self):
for name in self.__dict__: for name in self.__dict__:
yield self, name yield self, name
# Initialize installer settings
installer = installer_obj()
# Create options
options = installer
options.interactive = False
options.unattended = not options.interactive
# Initialize installer settings if NUM_VERSION >= 40400:
installer = installer_obj()
# Create options
options = installer
options.interactive = False
options.unattended = not options.interactive
if NUM_VERSION >= 40400:
# IPA version >= 4.4 # IPA version >= 4.4
import sys import sys
@@ -147,9 +156,11 @@ if NUM_VERSION >= 40400:
from ipaclient.install.client import configure_krb5_conf, \ from ipaclient.install.client import configure_krb5_conf, \
get_ca_certs, SECURE_PATH, get_server_connection_interface, \ get_ca_certs, SECURE_PATH, get_server_connection_interface, \
disable_ra, client_dns, \ disable_ra, client_dns, \
configure_certmonger, update_ssh_keys, configure_openldap_conf, \ configure_certmonger, update_ssh_keys, \
configure_openldap_conf, \
hardcode_ldap_server, get_certs_from_ldap, save_state, \ hardcode_ldap_server, get_certs_from_ldap, save_state, \
create_ipa_nssdb, configure_ssh_config, configure_sshd_config, \ create_ipa_nssdb, configure_ssh_config, \
configure_sshd_config, \
configure_automount, configure_firefox, configure_nisdomain, \ configure_automount, configure_firefox, configure_nisdomain, \
CLIENT_INSTALL_ERROR, is_ipa_client_installed, \ CLIENT_INSTALL_ERROR, is_ipa_client_installed, \
CLIENT_ALREADY_CONFIGURED, nssldap_exists, remove_file, \ CLIENT_ALREADY_CONFIGURED, nssldap_exists, remove_file, \
@@ -182,7 +193,8 @@ if NUM_VERSION >= 40400:
shutil.rmtree(temp_dir, ignore_errors=True) shutil.rmtree(temp_dir, ignore_errors=True)
sys.path.remove(temp_dir) sys.path.remove(temp_dir)
argspec = inspect.getargspec(ipa_client_install.configure_krb5_conf) argspec = inspect.getargspec(
ipa_client_install.configure_krb5_conf)
if argspec.keywords is None: if argspec.keywords is None:
def configure_krb5_conf( def configure_krb5_conf(
cli_realm, cli_domain, cli_server, cli_kdc, dnsok, cli_realm, cli_domain, cli_server, cli_kdc, dnsok,
@@ -192,8 +204,8 @@ if NUM_VERSION >= 40400:
options.force = force options.force = force
options.sssd = configure_sssd options.sssd = configure_sssd
return ipa_client_install.configure_krb5_conf( return ipa_client_install.configure_krb5_conf(
cli_realm, cli_domain, cli_server, cli_kdc, dnsok, options, cli_realm, cli_domain, cli_server, cli_kdc, dnsok,
filename, client_domain, client_hostname) options, filename, client_domain, client_hostname)
else: else:
configure_krb5_conf = ipa_client_install.configure_krb5_conf configure_krb5_conf = ipa_client_install.configure_krb5_conf
if NUM_VERSION < 40100: if NUM_VERSION < 40100:
@@ -211,19 +223,22 @@ if NUM_VERSION >= 40400:
client_dns = ipa_client_install.client_dns client_dns = ipa_client_install.client_dns
configure_certmonger = ipa_client_install.configure_certmonger configure_certmonger = ipa_client_install.configure_certmonger
update_ssh_keys = ipa_client_install.update_ssh_keys update_ssh_keys = ipa_client_install.update_ssh_keys
configure_openldap_conf = ipa_client_install.configure_openldap_conf configure_openldap_conf = \
ipa_client_install.configure_openldap_conf
hardcode_ldap_server = ipa_client_install.hardcode_ldap_server hardcode_ldap_server = ipa_client_install.hardcode_ldap_server
get_certs_from_ldap = ipa_client_install.get_certs_from_ldap get_certs_from_ldap = ipa_client_install.get_certs_from_ldap
save_state = ipa_client_install.save_state save_state = ipa_client_install.save_state
create_ipa_nssdb = certdb.create_ipa_nssdb create_ipa_nssdb = certdb.create_ipa_nssdb
argspec = inspect.getargspec(ipa_client_install.configure_nisdomain) argspec = \
inspect.getargspec(ipa_client_install.configure_nisdomain)
if len(argspec.args) == 3: if len(argspec.args) == 3:
configure_nisdomain = ipa_client_install.configure_nisdomain configure_nisdomain = ipa_client_install.configure_nisdomain
else: else:
def configure_nisdomain(options, domain, statestore=None): def configure_nisdomain(options, domain, statestore=None):
return ipa_client_install.configure_nisdomain(options, domain) return ipa_client_install.configure_nisdomain(options,
domain)
configure_ldap_conf = ipa_client_install.configure_ldap_conf configure_ldap_conf = ipa_client_install.configure_ldap_conf
configure_nslcd_conf = ipa_client_install.configure_nslcd_conf configure_nslcd_conf = ipa_client_install.configure_nslcd_conf
@@ -264,7 +279,7 @@ if NUM_VERSION >= 40400:
logger = logging.getLogger("ipa-client-install") logger = logging.getLogger("ipa-client-install")
root_logger = logger root_logger = logger
else: else:
# IPA version < 4.4 # IPA version < 4.4
raise Exception("freeipa version '%s' is too old" % VERSION) raise Exception("freeipa version '%s' is too old" % VERSION)

View File

@@ -46,21 +46,27 @@ __all__ = ["contextlib", "dnsexception", "dnsresolver", "dnsreversename",
"dnsname", "kernel_keyring", "krbinstance"] "dnsname", "kernel_keyring", "krbinstance"]
import sys import sys
import logging
from contextlib import contextmanager as contextlib_contextmanager
# HACK: workaround for Ansible 2.9
from ipapython.version import NUM_VERSION, VERSION # https://github.com/ansible/ansible/issues/68361
if 'ansible.executor' in sys.modules:
if NUM_VERSION < 30201: for attr in __all__:
# See ipapython/version.py setattr(sys.modules[__name__], attr, None)
IPA_MAJOR, IPA_MINOR, IPA_RELEASE = [int(x) for x in VERSION.split(".", 2)]
IPA_PYTHON_VERSION = IPA_MAJOR*10000 + IPA_MINOR*100 + IPA_RELEASE
else: else:
import logging
from contextlib import contextmanager as contextlib_contextmanager
from ipapython.version import NUM_VERSION, VERSION
if NUM_VERSION < 30201:
# See ipapython/version.py
IPA_MAJOR, IPA_MINOR, IPA_RELEASE = [int(x) for x in
VERSION.split(".", 2)]
IPA_PYTHON_VERSION = IPA_MAJOR*10000 + IPA_MINOR*100 + IPA_RELEASE
else:
IPA_PYTHON_VERSION = NUM_VERSION IPA_PYTHON_VERSION = NUM_VERSION
if NUM_VERSION >= 40600:
if NUM_VERSION >= 40600:
# IPA version >= 4.6 # IPA version >= 4.6
import contextlib import contextlib
@@ -77,7 +83,8 @@ if NUM_VERSION >= 40600:
from ipapython.ipautil import ipa_generate_password from ipapython.ipautil import ipa_generate_password
from ipalib.install.kinit import kinit_keytab from ipalib.install.kinit import kinit_keytab
from ipapython import ipaldap, ipautil, kernel_keyring from ipapython import ipaldap, ipautil, kernel_keyring
from ipapython.certdb import IPA_CA_TRUST_FLAGS, EXTERNAL_CA_TRUST_FLAGS from ipapython.certdb import IPA_CA_TRUST_FLAGS, \
EXTERNAL_CA_TRUST_FLAGS
from ipapython.dn import DN from ipapython.dn import DN
from ipapython.admintool import ScriptError from ipapython.admintool import ScriptError
from ipapython.ipa_log_manager import standard_logging_setup from ipapython.ipa_log_manager import standard_logging_setup
@@ -89,7 +96,8 @@ if NUM_VERSION >= 40600:
from ipalib.util import ( from ipalib.util import (
validate_domain_name, validate_domain_name,
no_matching_interface_for_ip_address_warning) no_matching_interface_for_ip_address_warning)
from ipaclient.install.client import configure_krb5_conf, purge_host_keytab from ipaclient.install.client import configure_krb5_conf, \
purge_host_keytab
from ipaserver.install import ( from ipaserver.install import (
adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance, adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance,
installutils, kra, krbinstance, installutils, kra, krbinstance,
@@ -111,7 +119,8 @@ if NUM_VERSION >= 40600:
from ipaserver.install.server.replicainstall import ( from ipaserver.install.server.replicainstall import (
make_pkcs12_info, install_replica_ds, install_krb, install_ca_cert, make_pkcs12_info, install_replica_ds, install_krb, install_ca_cert,
install_http, install_dns_records, create_ipa_conf, check_dirsrv, install_http, install_dns_records, create_ipa_conf, check_dirsrv,
check_dns_resolution, configure_certmonger, remove_replica_info_dir, check_dns_resolution, configure_certmonger,
remove_replica_info_dir,
# common_cleanup, # common_cleanup,
preserve_enrollment_state, uninstall_client, preserve_enrollment_state, uninstall_client,
promote_sssd, promote_openldap_conf, rpc_client, promote_sssd, promote_openldap_conf, rpc_client,
@@ -136,33 +145,28 @@ if NUM_VERSION >= 40600:
from ipaserver.install import ntpinstance from ipaserver.install import ntpinstance
time_service = "ntpd" time_service = "ntpd"
else:
else:
# IPA version < 4.6 # IPA version < 4.6
raise Exception("freeipa version '%s' is too old" % VERSION) raise Exception("freeipa version '%s' is too old" % VERSION)
logger = logging.getLogger("ipa-server-install")
logger = logging.getLogger("ipa-server-install") def setup_logging():
def setup_logging():
# logger.setLevel(logging.DEBUG) # logger.setLevel(logging.DEBUG)
standard_logging_setup( standard_logging_setup(
paths.IPAREPLICA_INSTALL_LOG, verbose=False, debug=False, paths.IPAREPLICA_INSTALL_LOG, verbose=False, debug=False,
filemode='a', console_format='%(message)s') filemode='a', console_format='%(message)s')
@contextlib_contextmanager
@contextlib_contextmanager def redirect_stdout(f):
def redirect_stdout(f):
sys.stdout = f sys.stdout = f
try: try:
yield f yield f
finally: finally:
sys.stdout = sys.__stdout__ sys.stdout = sys.__stdout__
class AnsibleModuleLog():
class AnsibleModuleLog():
def __init__(self, module): def __init__(self, module):
self.module = module self.module = module
_ansible_module_log = self _ansible_module_log = self
@@ -195,8 +199,7 @@ class AnsibleModuleLog():
self.module.debug(msg) self.module.debug(msg)
# self.module.warn(msg) # self.module.warn(msg)
class installer_obj(object):
class installer_obj(object):
def __init__(self): def __init__(self):
# CompatServerReplicaInstall # CompatServerReplicaInstall
self.ca_cert_files = None self.ca_cert_files = None
@@ -234,7 +237,8 @@ class installer_obj(object):
# value = super(installer_obj, self).__getattribute__(attr) # value = super(installer_obj, self).__getattribute__(attr)
# if not attr.startswith("--") and not attr.endswith("--"): # if not attr.startswith("--") and not attr.endswith("--"):
# logger.debug( # logger.debug(
# " <-- Accessing installer.%s (%s)" % (attr, repr(value))) # " <-- Accessing installer.%s (%s)" %
# (attr, repr(value)))
# return value # return value
def __getattr__(self, attr): def __getattr__(self, attr):
@@ -243,33 +247,32 @@ class installer_obj(object):
return getattr(self, attr) return getattr(self, attr)
# def __setattr__(self, attr, value): # def __setattr__(self, attr, value):
# logger.debug(" --> Setting installer.%s to %s" % (attr, repr(value))) # logger.debug(" --> Setting installer.%s to %s" %
# (attr, repr(value)))
# return super(installer_obj, self).__setattr__(attr, value) # return super(installer_obj, self).__setattr__(attr, value)
def knobs(self): def knobs(self):
for name in self.__dict__: for name in self.__dict__:
yield self, name yield self, name
installer = installer_obj()
options = installer
installer = installer_obj() # DNSInstallInterface
options = installer options.dnssec_master = False
options.disable_dnssec_master = False
options.kasp_db_file = None
options.force = False
# DNSInstallInterface # ServerMasterInstall
options.dnssec_master = False options.add_sids = False
options.disable_dnssec_master = False options.add_agents = False
options.kasp_db_file = None
options.force = False
# ServerMasterInstall # ServerReplicaInstall
options.add_sids = False options.subject_base = None
options.add_agents = False options.ca_subject = None
# ServerReplicaInstall def gen_env_boostrap_finalize_core(etc_ipa, default_config):
options.subject_base = None
options.ca_subject = None
def gen_env_boostrap_finalize_core(etc_ipa, default_config):
env = Env() env = Env()
# env._bootstrap(context='installer', confdir=paths.ETC_IPA, log=None) # env._bootstrap(context='installer', confdir=paths.ETC_IPA, log=None)
# env._finalize_core(**dict(constants.DEFAULT_CONFIG)) # env._finalize_core(**dict(constants.DEFAULT_CONFIG))
@@ -277,10 +280,10 @@ def gen_env_boostrap_finalize_core(etc_ipa, default_config):
env._finalize_core(**dict(default_config)) env._finalize_core(**dict(default_config))
return env return env
def api_bootstrap_finalize(env):
def api_bootstrap_finalize(env):
# pylint: disable=no-member # pylint: disable=no-member
xmlrpc_uri = 'https://{}/ipa/xml'.format(ipautil.format_netloc(env.host)) xmlrpc_uri = \
'https://{}/ipa/xml'.format(ipautil.format_netloc(env.host))
api.bootstrap(in_server=True, api.bootstrap(in_server=True,
context='installer', context='installer',
confdir=paths.ETC_IPA, confdir=paths.ETC_IPA,
@@ -289,14 +292,14 @@ def api_bootstrap_finalize(env):
# pylint: enable=no-member # pylint: enable=no-member
api.finalize() api.finalize()
def gen_ReplicaConfig():
def gen_ReplicaConfig():
class ExtendedReplicaConfig(ReplicaConfig): class ExtendedReplicaConfig(ReplicaConfig):
def __init__(self, top_dir=None): def __init__(self, top_dir=None):
super(ExtendedReplicaConfig, self).__init__(top_dir) super(ExtendedReplicaConfig, self).__init__(top_dir)
# def __getattribute__(self, attr): # def __getattribute__(self, attr):
# value = super(ExtendedReplicaConfig, self).__getattribute__(attr) # value = super(ExtendedReplicaConfig, self).__getattribute__(
# attr)
# if attr not in ["__dict__", "knobs"]: # if attr not in ["__dict__", "knobs"]:
# logger.debug(" <== Accessing config.%s (%s)" % # logger.debug(" <== Accessing config.%s (%s)" %
# (attr, repr(value))) # (attr, repr(value)))
@@ -308,8 +311,10 @@ def gen_ReplicaConfig():
return getattr(self, attr) return getattr(self, attr)
# def __setattr__(self, attr, value): # def __setattr__(self, attr, value):
# logger.debug(" ==> Setting config.%s to %s" % (attr, repr(value))) # logger.debug(" ==> Setting config.%s to %s" %
# return super(ExtendedReplicaConfig, self).__setattr__(attr, value) # (attr, repr(value)))
# return super(ExtendedReplicaConfig, self).__setattr__(attr,
# value)
def knobs(self): def knobs(self):
for name in self.__dict__: for name in self.__dict__:
@@ -332,8 +337,7 @@ def gen_ReplicaConfig():
return config return config
def replica_ds_init_info(ansible_log,
def replica_ds_init_info(ansible_log,
config, options, ca_is_configured, remote_api, config, options, ca_is_configured, remote_api,
ds_ca_subject, ca_file, ds_ca_subject, ca_file,
promote=False, pkcs12_info=None): promote=False, pkcs12_info=None):
@@ -352,7 +356,8 @@ def replica_ds_init_info(ansible_log,
# if ca_is_configured: # if ca_is_configured:
# ca_subject = ca.lookup_ca_subject(_api, config.subject_base) # ca_subject = ca.lookup_ca_subject(_api, config.subject_base)
# else: # else:
# ca_subject = installutils.default_ca_subject_dn(config.subject_base) # ca_subject = installutils.default_ca_subject_dn(
# config.subject_base)
ca_subject = ds_ca_subject ca_subject = ds_ca_subject
ds = dsinstance.DsInstance( ds = dsinstance.DsInstance(
@@ -397,20 +402,19 @@ def replica_ds_init_info(ansible_log,
return ds return ds
def ansible_module_get_parsed_ip_addresses(ansible_module,
def ansible_module_get_parsed_ip_addresses(ansible_module,
param='ip_addresses'): param='ip_addresses'):
ip_addrs = [] ip_addrs = []
for ip in ansible_module.params.get(param): for ip in ansible_module.params.get(param):
try: try:
ip_parsed = ipautil.CheckedIPAddress(ip) ip_parsed = ipautil.CheckedIPAddress(ip)
except Exception as e: except Exception as e:
ansible_module.fail_json(msg="Invalid IP Address %s: %s" % (ip, e)) ansible_module.fail_json(
msg="Invalid IP Address %s: %s" % (ip, e))
ip_addrs.append(ip_parsed) ip_addrs.append(ip_parsed)
return ip_addrs return ip_addrs
def gen_remote_api(master_host_name, etc_ipa):
def gen_remote_api(master_host_name, etc_ipa):
ldapuri = 'ldaps://%s' % ipautil.format_netloc(master_host_name) ldapuri = 'ldaps://%s' % ipautil.format_netloc(master_host_name)
xmlrpc_uri = 'https://{}/ipa/xml'.format( xmlrpc_uri = 'https://{}/ipa/xml'.format(
ipautil.format_netloc(master_host_name)) ipautil.format_netloc(master_host_name))

View File

@@ -41,23 +41,31 @@ __all__ = ["IPAChangeConf", "certmonger", "sysrestore", "root_logger",
"check_available_memory"] "check_available_memory"]
import sys import sys
import logging
from contextlib import contextmanager as contextlib_contextmanager
import six
import base64
# HACK: workaround for Ansible 2.9
# https://github.com/ansible/ansible/issues/68361
if 'ansible.executor' in sys.modules:
for attr in __all__:
setattr(sys.modules[__name__], attr, None)
from ipapython.version import NUM_VERSION, VERSION
if NUM_VERSION < 30201:
# See ipapython/version.py
IPA_MAJOR, IPA_MINOR, IPA_RELEASE = [int(x) for x in VERSION.split(".", 2)]
IPA_PYTHON_VERSION = IPA_MAJOR*10000 + IPA_MINOR*100 + IPA_RELEASE
else: else:
import logging
from contextlib import contextmanager as contextlib_contextmanager
import six
import base64
from ipapython.version import NUM_VERSION, VERSION
if NUM_VERSION < 30201:
# See ipapython/version.py
IPA_MAJOR, IPA_MINOR, IPA_RELEASE = [int(x) for x in
VERSION.split(".", 2)]
IPA_PYTHON_VERSION = IPA_MAJOR*10000 + IPA_MINOR*100 + IPA_RELEASE
else:
IPA_PYTHON_VERSION = NUM_VERSION IPA_PYTHON_VERSION = NUM_VERSION
if NUM_VERSION >= 40500:
if NUM_VERSION >= 40500:
# IPA version >= 4.5 # IPA version >= 4.5
from ipaclient.install.ipachangeconf import IPAChangeConf from ipaclient.install.ipachangeconf import IPAChangeConf
@@ -167,32 +175,28 @@ if NUM_VERSION >= 40500:
from ipalib.x509 import load_certificate from ipalib.x509 import load_certificate
load_pem_x509_certificate = None load_pem_x509_certificate = None
else: else:
# IPA version < 4.5 # IPA version < 4.5
raise Exception("freeipa version '%s' is too old" % VERSION) raise Exception("freeipa version '%s' is too old" % VERSION)
logger = logging.getLogger("ipa-server-install")
logger = logging.getLogger("ipa-server-install") def setup_logging():
def setup_logging():
# logger.setLevel(logging.DEBUG) # logger.setLevel(logging.DEBUG)
standard_logging_setup( standard_logging_setup(
paths.IPASERVER_INSTALL_LOG, verbose=False, debug=False, paths.IPASERVER_INSTALL_LOG, verbose=False, debug=False,
filemode='a', console_format='%(message)s') filemode='a', console_format='%(message)s')
@contextlib_contextmanager
@contextlib_contextmanager def redirect_stdout(f):
def redirect_stdout(f):
sys.stdout = f sys.stdout = f
try: try:
yield f yield f
finally: finally:
sys.stdout = sys.__stdout__ sys.stdout = sys.__stdout__
class AnsibleModuleLog():
class AnsibleModuleLog():
def __init__(self, module): def __init__(self, module):
self.module = module self.module = module
_ansible_module_log = self _ansible_module_log = self
@@ -225,8 +229,7 @@ class AnsibleModuleLog():
self.module.debug(msg) self.module.debug(msg)
# self.module.warn(msg) # self.module.warn(msg)
class options_obj(object):
class options_obj(object):
def __init__(self): def __init__(self):
self._replica_install = False self._replica_install = False
self.dnssec_master = False # future unknown self.dnssec_master = False # future unknown
@@ -249,54 +252,51 @@ class options_obj(object):
for name in self.__dict__: for name in self.__dict__:
yield self, name yield self, name
options = options_obj()
installer = options
options = options_obj() # ServerMasterInstall
installer = options options.add_sids = True
options.add_agents = False
# ServerMasterInstall # Installable
options.add_sids = True options.uninstalling = False
options.add_agents = False
# ServerInstallInterface
options.description = "Server"
# Installable options.kinit_attempts = 1
options.uninstalling = False options.fixed_primary = True
options.permit = False
options.enable_dns_updates = False
options.no_krb5_offline_passwords = False
options.preserve_sssd = False
options.no_sssd = False
# ServerInstallInterface # ServerMasterInstall
options.description = "Server" options.force_join = False
options.servers = None
options.no_wait_for_dns = True
options.host_password = None
options.keytab = None
options.setup_ca = True
# always run sidgen task and do not allow adding agents on first master
options.add_sids = True
options.add_agents = False
options.kinit_attempts = 1 # ADTrustInstallInterface
options.fixed_primary = True # no_msdcs is deprecated
options.permit = False options.no_msdcs = False
options.enable_dns_updates = False
options.no_krb5_offline_passwords = False
options.preserve_sssd = False
options.no_sssd = False
# ServerMasterInstall # For pylint
options.force_join = False options.external_cert_files = None
options.servers = None options.dirsrv_cert_files = None
options.no_wait_for_dns = True
options.host_password = None
options.keytab = None
options.setup_ca = True
# always run sidgen task and do not allow adding agents on first master
options.add_sids = True
options.add_agents = False
# ADTrustInstallInterface # Uninstall
# no_msdcs is deprecated options.ignore_topology_disconnect = False
options.no_msdcs = False options.ignore_last_of_role = False
# For pylint def api_Backend_ldap2(host_name, setup_ca, connect=False):
options.external_cert_files = None
options.dirsrv_cert_files = None
# Uninstall
options.ignore_topology_disconnect = False
options.ignore_last_of_role = False
def api_Backend_ldap2(host_name, setup_ca, connect=False):
# we are sure we have the configuration file ready. # we are sure we have the configuration file ready.
cfg = dict(context='installer', confdir=paths.ETC_IPA, in_server=True, cfg = dict(context='installer', confdir=paths.ETC_IPA, in_server=True,
host=host_name) host=host_name)
@@ -309,8 +309,7 @@ def api_Backend_ldap2(host_name, setup_ca, connect=False):
if connect: if connect:
api.Backend.ldap2.connect() api.Backend.ldap2.connect()
def ds_init_info(ansible_log, fstore, domainlevel, dirsrv_config_file,
def ds_init_info(ansible_log, fstore, domainlevel, dirsrv_config_file,
realm_name, host_name, domain_name, dm_password, realm_name, host_name, domain_name, dm_password,
idstart, idmax, subject_base, ca_subject, idstart, idmax, subject_base, ca_subject,
no_hbac_allow, dirsrv_pkcs12_info, no_pkinit): no_hbac_allow, dirsrv_pkcs12_info, no_pkinit):
@@ -341,20 +340,19 @@ def ds_init_info(ansible_log, fstore, domainlevel, dirsrv_config_file,
return ds return ds
def ansible_module_get_parsed_ip_addresses(ansible_module,
def ansible_module_get_parsed_ip_addresses(ansible_module,
param='ip_addresses'): param='ip_addresses'):
ip_addrs = [] ip_addrs = []
for ip in ansible_module.params.get(param): for ip in ansible_module.params.get(param):
try: try:
ip_parsed = ipautil.CheckedIPAddress(ip) ip_parsed = ipautil.CheckedIPAddress(ip)
except Exception as e: except Exception as e:
ansible_module.fail_json(msg="Invalid IP Address %s: %s" % (ip, e)) ansible_module.fail_json(
msg="Invalid IP Address %s: %s" % (ip, e))
ip_addrs.append(ip_parsed) ip_addrs.append(ip_parsed)
return ip_addrs return ip_addrs
def encode_certificate(cert):
def encode_certificate(cert):
""" """
Encode a certificate using base64. Encode a certificate using base64.
@@ -368,13 +366,12 @@ def encode_certificate(cert):
encoded = encoded.decode('ascii') encoded = encoded.decode('ascii')
return encoded return encoded
def decode_certificate(cert):
def decode_certificate(cert):
""" """
Decode a certificate using base64. Decode a certificate using base64.
It also takes FreeIPA versions into account and returns a IPACertificate It also takes FreeIPA versions into account and returns a
for newer IPA versions. IPACertificate for newer IPA versions.
""" """
if hasattr(x509, "IPACertificate"): if hasattr(x509, "IPACertificate"):
cert = cert.strip() cert = cert.strip()