mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
install: introduce installer class hierarchy
Add class hierarchy which allows inherting knob definitions between the various client and server install scripts. https://fedorahosted.org/freeipa/ticket/6392 Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
parent
08a446a6bc
commit
a8fdb8de82
@ -1311,7 +1311,9 @@ fi
|
||||
%dir %{python_sitelib}/ipapython/secrets
|
||||
%{python_sitelib}/ipapython/secrets/*.py*
|
||||
%dir %{python_sitelib}/ipalib
|
||||
%{python_sitelib}/ipalib/*
|
||||
%{python_sitelib}/ipalib/*.py*
|
||||
%dir %{python_sitelib}/ipalib/install
|
||||
%{python_sitelib}/ipalib/install/*.py*
|
||||
%dir %{python_sitelib}/ipaplatform
|
||||
%{python_sitelib}/ipaplatform/*
|
||||
%{python_sitelib}/ipapython-*.egg-info
|
||||
|
27
ipaclient/install/automount.py
Normal file
27
ipaclient/install/automount.py
Normal file
@ -0,0 +1,27 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Automount installer module
|
||||
"""
|
||||
|
||||
from ipalib.install import service
|
||||
from ipalib.install.service import enroll_only
|
||||
from ipapython.install.core import knob
|
||||
|
||||
|
||||
class AutomountInstallInterface(service.ServiceInstallInterface):
|
||||
"""
|
||||
Interface of the automount installer
|
||||
|
||||
Knobs defined here will be available in:
|
||||
* ipa-client-install
|
||||
* ipa-client-automount
|
||||
"""
|
||||
|
||||
automount_location = knob(
|
||||
str, 'default',
|
||||
description="Automount location",
|
||||
)
|
||||
automount_location = enroll_only(automount_location)
|
@ -43,6 +43,9 @@ from ipalib import (
|
||||
x509,
|
||||
)
|
||||
from ipalib.constants import CACERT
|
||||
from ipalib.install import hostname as hostname_
|
||||
from ipalib.install import service
|
||||
from ipalib.install.service import enroll_only, prepare_only
|
||||
from ipalib.rpc import delete_persistent_client_session_data
|
||||
from ipalib.util import (
|
||||
broadcast_ip_address_warning,
|
||||
@ -62,6 +65,8 @@ from ipapython import (
|
||||
)
|
||||
from ipapython.admintool import ScriptError
|
||||
from ipapython.dn import DN
|
||||
from ipapython.install import typing
|
||||
from ipapython.install.core import knob
|
||||
from ipapython.ipa_log_manager import root_logger
|
||||
from ipapython.ipautil import (
|
||||
CalledProcessError,
|
||||
@ -74,6 +79,10 @@ from ipapython.ipautil import (
|
||||
)
|
||||
from ipapython.ssh import SSHPublicKey
|
||||
|
||||
from . import automount
|
||||
|
||||
NoneType = type(None)
|
||||
|
||||
SUCCESS = 0
|
||||
CLIENT_INSTALL_ERROR = 1
|
||||
CLIENT_NOT_CONFIGURED = 2
|
||||
@ -3298,3 +3307,188 @@ def uninstall(options):
|
||||
|
||||
if rv:
|
||||
raise ScriptError(rval=rv)
|
||||
|
||||
|
||||
class ClientInstallInterface(hostname_.HostNameInstallInterface,
|
||||
service.ServiceAdminInstallInterface):
|
||||
"""
|
||||
Interface of the client installer
|
||||
|
||||
Knobs defined here will be available in:
|
||||
* ipa-client-install
|
||||
* ipa-server-install
|
||||
* ipa-replica-prepare
|
||||
* ipa-replica-install
|
||||
"""
|
||||
|
||||
fixed_primary = knob(
|
||||
None,
|
||||
description="Configure sssd to use fixed server as primary IPA server",
|
||||
)
|
||||
fixed_primary = enroll_only(fixed_primary)
|
||||
|
||||
principal = knob(
|
||||
bases=service.ServiceAdminInstallInterface.principal,
|
||||
description="principal to use to join the IPA realm",
|
||||
)
|
||||
principal = enroll_only(principal)
|
||||
|
||||
host_password = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
)
|
||||
host_password = enroll_only(host_password)
|
||||
|
||||
keytab = knob(
|
||||
str, None,
|
||||
description="path to backed up keytab from previous enrollment",
|
||||
cli_names=[None, '-k'],
|
||||
)
|
||||
keytab = enroll_only(keytab)
|
||||
|
||||
mkhomedir = knob(
|
||||
None,
|
||||
description="create home directories for users on their first login",
|
||||
)
|
||||
mkhomedir = enroll_only(mkhomedir)
|
||||
|
||||
force_join = knob(
|
||||
None,
|
||||
description="Force client enrollment even if already enrolled",
|
||||
)
|
||||
force_join = enroll_only(force_join)
|
||||
|
||||
ntp_servers = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[str], None,
|
||||
description="ntp server to use. This option can be used multiple "
|
||||
"times",
|
||||
cli_names='--ntp-server',
|
||||
cli_metavar='NTP_SERVER',
|
||||
)
|
||||
ntp_servers = enroll_only(ntp_servers)
|
||||
|
||||
no_ntp = knob(
|
||||
None,
|
||||
description="do not configure ntp",
|
||||
cli_names=[None, '-N'],
|
||||
)
|
||||
no_ntp = enroll_only(no_ntp)
|
||||
|
||||
force_ntpd = knob(
|
||||
None,
|
||||
description="Stop and disable any time&date synchronization services "
|
||||
"besides ntpd",
|
||||
)
|
||||
force_ntpd = enroll_only(force_ntpd)
|
||||
|
||||
nisdomain = knob(
|
||||
str, None,
|
||||
description="NIS domain name",
|
||||
)
|
||||
nisdomain = enroll_only(nisdomain)
|
||||
|
||||
no_nisdomain = knob(
|
||||
None,
|
||||
description="do not configure NIS domain name",
|
||||
)
|
||||
no_nisdomain = enroll_only(no_nisdomain)
|
||||
|
||||
ssh_trust_dns = knob(
|
||||
None,
|
||||
description="configure OpenSSH client to trust DNS SSHFP records",
|
||||
)
|
||||
ssh_trust_dns = enroll_only(ssh_trust_dns)
|
||||
|
||||
no_ssh = knob(
|
||||
None,
|
||||
description="do not configure OpenSSH client",
|
||||
)
|
||||
no_ssh = enroll_only(no_ssh)
|
||||
|
||||
no_sshd = knob(
|
||||
None,
|
||||
description="do not configure OpenSSH server",
|
||||
)
|
||||
no_sshd = enroll_only(no_sshd)
|
||||
|
||||
no_sudo = knob(
|
||||
None,
|
||||
description="do not configure SSSD as data source for sudo",
|
||||
)
|
||||
no_sudo = enroll_only(no_sudo)
|
||||
|
||||
no_dns_sshfp = knob(
|
||||
None,
|
||||
description="do not automatically create DNS SSHFP records",
|
||||
)
|
||||
no_dns_sshfp = enroll_only(no_dns_sshfp)
|
||||
|
||||
kinit_attempts = knob(
|
||||
int, 5,
|
||||
description="number of attempts to obtain host TGT (defaults to 5).",
|
||||
)
|
||||
kinit_attempts = enroll_only(kinit_attempts)
|
||||
|
||||
@kinit_attempts.validator
|
||||
def kinit_attempts(self, value):
|
||||
if value < 1:
|
||||
raise ValueError("expects an integer greater than 0.")
|
||||
|
||||
request_cert = knob(
|
||||
None,
|
||||
description="request certificate for the machine",
|
||||
)
|
||||
request_cert = prepare_only(request_cert)
|
||||
|
||||
permit = knob(
|
||||
None,
|
||||
description="disable access rules by default, permit all access.",
|
||||
)
|
||||
permit = enroll_only(permit)
|
||||
|
||||
enable_dns_updates = knob(
|
||||
None,
|
||||
description="Configures the machine to attempt dns updates when the "
|
||||
"ip address changes.",
|
||||
)
|
||||
enable_dns_updates = enroll_only(enable_dns_updates)
|
||||
|
||||
no_krb5_offline_passwords = knob(
|
||||
None,
|
||||
description="Configure SSSD not to store user password when the "
|
||||
"server is offline",
|
||||
)
|
||||
no_krb5_offline_passwords = enroll_only(no_krb5_offline_passwords)
|
||||
|
||||
preserve_sssd = knob(
|
||||
None,
|
||||
description="Preserve old SSSD configuration if possible",
|
||||
)
|
||||
preserve_sssd = enroll_only(preserve_sssd)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(ClientInstallInterface, self).__init__(**kwargs)
|
||||
|
||||
if self.servers and not self.domain_name:
|
||||
raise RuntimeError(
|
||||
"--server cannot be used without providing --domain")
|
||||
|
||||
if self.force_ntpd and self.no_ntp:
|
||||
raise RuntimeError(
|
||||
"--force-ntpd cannot be used together with --no-ntp")
|
||||
|
||||
if self.no_nisdomain and self.nisdomain:
|
||||
raise RuntimeError(
|
||||
"--no-nisdomain cannot be used together with --nisdomain")
|
||||
|
||||
if self.ip_addresses:
|
||||
if self.enable_dns_updates:
|
||||
raise RuntimeError(
|
||||
"--ip-address cannot be used together with"
|
||||
" --enable-dns-updates")
|
||||
|
||||
if self.all_ip_addresses:
|
||||
raise RuntimeError(
|
||||
"--ip-address cannot be used together with"
|
||||
"--all-ip-addresses")
|
||||
|
3
ipalib/install/__init__.py
Normal file
3
ipalib/install/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
||||
#
|
59
ipalib/install/hostname.py
Normal file
59
ipalib/install/hostname.py
Normal file
@ -0,0 +1,59 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Host name installer module
|
||||
"""
|
||||
|
||||
from ipapython.install import typing
|
||||
from ipapython.install.core import knob
|
||||
from ipapython.ipautil import CheckedIPAddress
|
||||
|
||||
from . import service
|
||||
from .service import prepare_only
|
||||
|
||||
|
||||
class HostNameInstallInterface(service.ServiceInstallInterface):
|
||||
"""
|
||||
Interface common to all service installers which create DNS address
|
||||
records for `host_name`
|
||||
"""
|
||||
|
||||
ip_addresses = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[CheckedIPAddress], None,
|
||||
description="Specify IP address that should be added to DNS. This "
|
||||
"option can be used multiple times",
|
||||
cli_names='--ip-address',
|
||||
cli_metavar='IP_ADDRESS',
|
||||
)
|
||||
ip_addresses = prepare_only(ip_addresses)
|
||||
|
||||
@ip_addresses.validator
|
||||
def ip_addresses(self, values):
|
||||
for value in values:
|
||||
try:
|
||||
CheckedIPAddress(value, match_local=True)
|
||||
except Exception as e:
|
||||
raise ValueError("invalid IP address {0}: {1}".format(
|
||||
value, e))
|
||||
|
||||
all_ip_addresses = knob(
|
||||
None,
|
||||
description="All routable IP addresses configured on any inteface "
|
||||
"will be added to DNS",
|
||||
)
|
||||
all_ip_addresses = prepare_only(all_ip_addresses)
|
||||
|
||||
no_host_dns = knob(
|
||||
None,
|
||||
description="Do not use DNS for hostname lookup during installation",
|
||||
)
|
||||
no_host_dns = prepare_only(no_host_dns)
|
||||
|
||||
no_wait_for_dns = knob(
|
||||
None,
|
||||
description="do not wait until the host is resolvable in DNS",
|
||||
)
|
||||
no_wait_for_dns = prepare_only(no_wait_for_dns)
|
178
ipalib/install/service.py
Normal file
178
ipalib/install/service.py
Normal file
@ -0,0 +1,178 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Base service installer module
|
||||
"""
|
||||
|
||||
from ipalib.util import validate_domain_name
|
||||
from ipapython.install import common, core, typing
|
||||
from ipapython.install.core import knob
|
||||
|
||||
|
||||
def prepare_only(obj):
|
||||
"""
|
||||
Decorator which makes an installer attribute appear only in the prepare
|
||||
phase of the install
|
||||
"""
|
||||
obj.__exclude__ = getattr(obj, '__exclude__', set()) | {'enroll'}
|
||||
return obj
|
||||
|
||||
|
||||
def enroll_only(obj):
|
||||
"""
|
||||
Decorator which makes an installer attribute appear only in the enroll
|
||||
phase of the install
|
||||
"""
|
||||
obj.__exclude__ = getattr(obj, '__exclude__', set()) | {'prepare'}
|
||||
return obj
|
||||
|
||||
|
||||
def master_install_only(obj):
|
||||
"""
|
||||
Decorator which makes an installer attribute appear only in master install
|
||||
"""
|
||||
obj.__exclude__ = getattr(obj, '__exclude__', set()) | {'replica_install'}
|
||||
return obj
|
||||
|
||||
|
||||
def replica_install_only(obj):
|
||||
"""
|
||||
Decorator which makes an installer attribute appear only in replica install
|
||||
"""
|
||||
obj.__exclude__ = getattr(obj, '__exclude__', set()) | {'master_install'}
|
||||
return obj
|
||||
|
||||
|
||||
def _does(cls, arg):
|
||||
def remove(name):
|
||||
def removed(self):
|
||||
raise AttributeError(name)
|
||||
|
||||
return property(removed)
|
||||
|
||||
return type(
|
||||
cls.__name__,
|
||||
(cls,),
|
||||
{
|
||||
n: remove(n) for n in dir(cls)
|
||||
if arg in getattr(getattr(cls, n), '__exclude__', set())
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def prepares(cls):
|
||||
"""
|
||||
Returns installer class stripped of attributes not related to the prepare
|
||||
phase of the install
|
||||
"""
|
||||
return _does(cls, 'prepare')
|
||||
|
||||
|
||||
def enrolls(cls):
|
||||
"""
|
||||
Returns installer class stripped of attributes not related to the enroll
|
||||
phase of the install
|
||||
"""
|
||||
return _does(cls, 'enroll')
|
||||
|
||||
|
||||
def installs_master(cls):
|
||||
"""
|
||||
Returns installer class stripped of attributes not related to master
|
||||
install
|
||||
"""
|
||||
return _does(cls, 'master_install')
|
||||
|
||||
|
||||
def installs_replica(cls):
|
||||
"""
|
||||
Returns installer class stripped of attributes not related to replica
|
||||
install
|
||||
"""
|
||||
return _does(cls, 'replica_install')
|
||||
|
||||
|
||||
class ServiceInstallInterface(common.Installable,
|
||||
common.Interactive,
|
||||
core.Composite):
|
||||
"""
|
||||
Interface common to all service installers
|
||||
"""
|
||||
|
||||
domain_name = knob(
|
||||
str, None,
|
||||
description="domain name",
|
||||
cli_names='--domain',
|
||||
)
|
||||
|
||||
@domain_name.validator
|
||||
def domain_name(self, value):
|
||||
validate_domain_name(value)
|
||||
|
||||
servers = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[str], None,
|
||||
description="FQDN of IPA server",
|
||||
cli_names='--server',
|
||||
cli_metavar='SERVER',
|
||||
)
|
||||
|
||||
realm_name = knob(
|
||||
str, None,
|
||||
description="realm name",
|
||||
cli_names='--realm',
|
||||
)
|
||||
|
||||
host_name = knob(
|
||||
str, None,
|
||||
description="The hostname of this machine (FQDN). If specified, the "
|
||||
"hostname will be set and the system configuration will "
|
||||
"be updated to persist over reboot. By default the result "
|
||||
"of getfqdn() call from Python's socket module is used.",
|
||||
cli_names='--hostname',
|
||||
)
|
||||
|
||||
ca_cert_files = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[str], None,
|
||||
description="load the CA certificate from this file",
|
||||
cli_names='--ca-cert-file',
|
||||
cli_metavar='FILE',
|
||||
)
|
||||
|
||||
replica_file = knob(
|
||||
str, None,
|
||||
description="a file generated by ipa-replica-prepare",
|
||||
)
|
||||
replica_file = enroll_only(replica_file)
|
||||
replica_file = replica_install_only(replica_file)
|
||||
|
||||
dm_password = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
description="Directory Manager password (for the existing master)",
|
||||
)
|
||||
dm_password = enroll_only(dm_password)
|
||||
dm_password = replica_install_only(dm_password)
|
||||
|
||||
|
||||
class ServiceAdminInstallInterface(ServiceInstallInterface):
|
||||
"""
|
||||
Interface common to all service installers which require admin user
|
||||
authentication
|
||||
"""
|
||||
|
||||
principal = knob(
|
||||
str, None,
|
||||
)
|
||||
principal = enroll_only(principal)
|
||||
principal = replica_install_only(principal)
|
||||
|
||||
admin_password = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
)
|
||||
admin_password = enroll_only(admin_password)
|
||||
admin_password = replica_install_only(admin_password)
|
@ -34,5 +34,6 @@ if __name__ == '__main__':
|
||||
package_dir={'ipalib': ''},
|
||||
packages=[
|
||||
"ipalib",
|
||||
"ipalib.install",
|
||||
],
|
||||
)
|
||||
|
@ -2,11 +2,24 @@
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
CA installer module
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import enum
|
||||
import os.path
|
||||
|
||||
from ipaserver.install import cainstance, custodiainstance, dsinstance, bindinstance
|
||||
import six
|
||||
|
||||
from ipalib.install.service import enroll_only, master_install_only, replica_install_only
|
||||
from ipapython.install import typing
|
||||
from ipapython.install.core import knob
|
||||
from ipaserver.install import (cainstance,
|
||||
custodiainstance,
|
||||
dsinstance,
|
||||
bindinstance)
|
||||
from ipapython import ipautil, certdb
|
||||
from ipapython.admintool import ScriptError
|
||||
from ipaplatform import services
|
||||
@ -17,6 +30,19 @@ from ipalib import api, certstore, x509
|
||||
from ipapython.dn import DN
|
||||
from ipapython.ipa_log_manager import root_logger
|
||||
|
||||
from . import conncheck, dogtag
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c',
|
||||
'serialnumber', 'l', 'title', 'sn', 'givenname',
|
||||
'initials', 'generationqualifier', 'dc', 'mail',
|
||||
'uid', 'postaladdress', 'postalcode', 'postofficebox',
|
||||
'houseidentifier', 'e', 'street', 'pseudonym',
|
||||
'incorporationlocality', 'incorporationstate',
|
||||
'incorporationcountry', 'businesscategory']
|
||||
|
||||
external_cert_file = None
|
||||
external_ca_file = None
|
||||
|
||||
@ -270,3 +296,109 @@ def uninstall():
|
||||
ca_instance.stop_tracking_certificates()
|
||||
if ca_instance.is_configured():
|
||||
ca_instance.uninstall()
|
||||
|
||||
|
||||
class ExternalCAType(enum.Enum):
|
||||
GENERIC = 'generic'
|
||||
MS_CS = 'ms-cs'
|
||||
|
||||
|
||||
class CASigningAlgorithm(enum.Enum):
|
||||
SHA1_WITH_RSA = 'SHA1withRSA'
|
||||
SHA_256_WITH_RSA = 'SHA256withRSA'
|
||||
SHA_512_WITH_RSA = 'SHA512withRSA'
|
||||
|
||||
|
||||
class CAInstallInterface(dogtag.DogtagInstallInterface,
|
||||
conncheck.ConnCheckInterface):
|
||||
"""
|
||||
Interface of the CA installer
|
||||
|
||||
Knobs defined here will be available in:
|
||||
* ipa-server-install
|
||||
* ipa-replica-prepare
|
||||
* ipa-replica-install
|
||||
* ipa-ca-install
|
||||
"""
|
||||
|
||||
principal = knob(
|
||||
bases=conncheck.ConnCheckInterface.principal,
|
||||
description="User allowed to manage replicas",
|
||||
cli_names=(
|
||||
list(conncheck.ConnCheckInterface.principal.cli_names) + ['-P']),
|
||||
)
|
||||
principal = enroll_only(principal)
|
||||
principal = replica_install_only(principal)
|
||||
|
||||
admin_password = knob(
|
||||
bases=conncheck.ConnCheckInterface.admin_password,
|
||||
description="Admin user Kerberos password used for connection check",
|
||||
cli_names=(
|
||||
list(conncheck.ConnCheckInterface.admin_password.cli_names) +
|
||||
['-w']),
|
||||
)
|
||||
admin_password = enroll_only(admin_password)
|
||||
admin_password = replica_install_only(admin_password)
|
||||
|
||||
external_ca = knob(
|
||||
None,
|
||||
description=("Generate a CSR for the IPA CA certificate to be signed "
|
||||
"by an external CA"),
|
||||
)
|
||||
external_ca = master_install_only(external_ca)
|
||||
|
||||
external_ca_type = knob(
|
||||
ExternalCAType, None,
|
||||
description="Type of the external CA",
|
||||
)
|
||||
external_ca_type = master_install_only(external_ca_type)
|
||||
|
||||
external_cert_files = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[str], None,
|
||||
description=("File containing the IPA CA certificate and the external "
|
||||
"CA certificate chain"),
|
||||
cli_names='--external-cert-file',
|
||||
cli_deprecated_names=['--external_cert_file', '--external_ca_file'],
|
||||
cli_metavar='FILE',
|
||||
)
|
||||
external_cert_files = master_install_only(external_cert_files)
|
||||
|
||||
@external_cert_files.validator
|
||||
def external_cert_files(self, value):
|
||||
if any(not os.path.isabs(path) for path in value):
|
||||
raise ValueError("must use an absolute path")
|
||||
|
||||
subject = knob(
|
||||
str, None,
|
||||
description="The certificate subject base (default O=<realm-name>)",
|
||||
)
|
||||
subject = master_install_only(subject)
|
||||
|
||||
@subject.validator
|
||||
def subject(self, value):
|
||||
v = unicode(value, 'utf-8')
|
||||
if any(ord(c) < 0x20 for c in v):
|
||||
raise ValueError("must not contain control characters")
|
||||
if '&' in v:
|
||||
raise ValueError("must not contain an ampersand (\"&\")")
|
||||
try:
|
||||
dn = DN(v)
|
||||
for rdn in dn:
|
||||
if rdn.attr.lower() not in VALID_SUBJECT_ATTRS:
|
||||
raise ValueError("invalid attribute: \"%s\"" % rdn.attr)
|
||||
except ValueError as e:
|
||||
raise ValueError("invalid subject base format: %s" % e)
|
||||
|
||||
ca_signing_algorithm = knob(
|
||||
CASigningAlgorithm, None,
|
||||
description="Signing algorithm of the IPA CA certificate",
|
||||
)
|
||||
ca_signing_algorithm = master_install_only(ca_signing_algorithm)
|
||||
|
||||
skip_schema_check = knob(
|
||||
None,
|
||||
description="skip check for updated CA DS schema on the remote master",
|
||||
)
|
||||
skip_schema_check = enroll_only(skip_schema_check)
|
||||
skip_schema_check = replica_install_only(skip_schema_check)
|
||||
|
25
ipaserver/install/conncheck.py
Normal file
25
ipaserver/install/conncheck.py
Normal file
@ -0,0 +1,25 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Connection check module
|
||||
"""
|
||||
|
||||
from ipalib.install import service
|
||||
from ipalib.install.service import enroll_only, replica_install_only
|
||||
from ipapython.install.core import knob
|
||||
|
||||
|
||||
class ConnCheckInterface(service.ServiceAdminInstallInterface):
|
||||
"""
|
||||
Interface common to all installers which perform connection check to the
|
||||
remote master.
|
||||
"""
|
||||
|
||||
skip_conncheck = knob(
|
||||
None,
|
||||
description="skip connection check to remote master",
|
||||
)
|
||||
skip_conncheck = enroll_only(skip_conncheck)
|
||||
skip_conncheck = replica_install_only(skip_conncheck)
|
@ -2,11 +2,19 @@
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
DNS installer module
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import enum
|
||||
|
||||
# absolute import is necessary because IPA module dns clashes with python-dns
|
||||
from dns import resolver
|
||||
import six
|
||||
|
||||
import sys
|
||||
|
||||
from subprocess import CalledProcessError
|
||||
@ -14,6 +22,8 @@ from subprocess import CalledProcessError
|
||||
from ipalib import api
|
||||
from ipalib import errors
|
||||
from ipalib import util
|
||||
from ipalib.install import hostname
|
||||
from ipalib.install.service import enroll_only, prepare_only
|
||||
from ipaplatform.paths import paths
|
||||
from ipaplatform.constants import constants
|
||||
from ipaplatform import services
|
||||
@ -21,6 +31,9 @@ from ipapython import ipautil
|
||||
from ipapython import sysrestore
|
||||
from ipapython import dnsutil
|
||||
from ipapython.dn import DN
|
||||
from ipapython.dnsutil import check_zone_overlap
|
||||
from ipapython.install import typing
|
||||
from ipapython.install.core import knob
|
||||
from ipapython.ipa_log_manager import root_logger
|
||||
from ipapython.admintool import ScriptError
|
||||
from ipapython.ipautil import user_input
|
||||
@ -32,6 +45,9 @@ from ipaserver.install import dnskeysyncinstance
|
||||
from ipaserver.install import odsexporterinstance
|
||||
from ipaserver.install import opendnssecinstance
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
ip_addresses = []
|
||||
reverse_zones = []
|
||||
|
||||
@ -392,3 +408,119 @@ def uninstall():
|
||||
dnskeysync = dnskeysyncinstance.DNSKeySyncInstance(fstore)
|
||||
if dnskeysync.is_configured():
|
||||
dnskeysync.uninstall()
|
||||
|
||||
|
||||
class DNSForwardPolicy(enum.Enum):
|
||||
ONLY = 'only'
|
||||
FIRST = 'first'
|
||||
|
||||
|
||||
class DNSInstallInterface(hostname.HostNameInstallInterface):
|
||||
"""
|
||||
Interface of the DNS installer
|
||||
|
||||
Knobs defined here will be available in:
|
||||
* ipa-server-install
|
||||
* ipa-replica-prepare
|
||||
* ipa-replica-install
|
||||
* ipa-dns-install
|
||||
"""
|
||||
|
||||
allow_zone_overlap = knob(
|
||||
None,
|
||||
description="Create DNS zone even if it already exists",
|
||||
)
|
||||
allow_zone_overlap = prepare_only(allow_zone_overlap)
|
||||
|
||||
reverse_zones = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[str], [],
|
||||
description=("The reverse DNS zone to use. This option can be used "
|
||||
"multiple times"),
|
||||
cli_names='--reverse-zone',
|
||||
cli_metavar='REVERSE_ZONE',
|
||||
)
|
||||
reverse_zones = prepare_only(reverse_zones)
|
||||
|
||||
@reverse_zones.validator
|
||||
def reverse_zones(self, values):
|
||||
if not self.allow_zone_overlap:
|
||||
for zone in values:
|
||||
check_zone_overlap(zone)
|
||||
|
||||
no_reverse = knob(
|
||||
None,
|
||||
description="Do not create new reverse DNS zone",
|
||||
)
|
||||
no_reverse = prepare_only(no_reverse)
|
||||
|
||||
auto_reverse = knob(
|
||||
None,
|
||||
description="Create necessary reverse zones",
|
||||
)
|
||||
auto_reverse = prepare_only(auto_reverse)
|
||||
|
||||
zonemgr = knob(
|
||||
str, None,
|
||||
description=("DNS zone manager e-mail address. Defaults to "
|
||||
"hostmaster@DOMAIN"),
|
||||
)
|
||||
zonemgr = prepare_only(zonemgr)
|
||||
|
||||
@zonemgr.validator
|
||||
def zonemgr(self, value):
|
||||
# validate the value first
|
||||
try:
|
||||
# IDNA support requires unicode
|
||||
encoding = getattr(sys.stdin, 'encoding', None)
|
||||
if encoding is None:
|
||||
encoding = 'utf-8'
|
||||
value = value.decode(encoding)
|
||||
bindinstance.validate_zonemgr_str(value)
|
||||
except ValueError as e:
|
||||
# FIXME we can do this in better way
|
||||
# https://fedorahosted.org/freeipa/ticket/4804
|
||||
# decode to proper stderr encoding
|
||||
stderr_encoding = getattr(sys.stderr, 'encoding', None)
|
||||
if stderr_encoding is None:
|
||||
stderr_encoding = 'utf-8'
|
||||
error = unicode(e).encode(stderr_encoding)
|
||||
raise ValueError(error)
|
||||
|
||||
forwarders = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[ipautil.CheckedIPAddress], None,
|
||||
description=("Add a DNS forwarder. This option can be used multiple "
|
||||
"times"),
|
||||
cli_names='--forwarder',
|
||||
)
|
||||
forwarders = enroll_only(forwarders)
|
||||
|
||||
no_forwarders = knob(
|
||||
None,
|
||||
description="Do not add any DNS forwarders, use root servers instead",
|
||||
)
|
||||
no_forwarders = enroll_only(no_forwarders)
|
||||
|
||||
auto_forwarders = knob(
|
||||
None,
|
||||
description="Use DNS forwarders configured in /etc/resolv.conf",
|
||||
)
|
||||
auto_forwarders = enroll_only(auto_forwarders)
|
||||
|
||||
forward_policy = knob(
|
||||
DNSForwardPolicy, None,
|
||||
description=("DNS forwarding policy for global forwarders"),
|
||||
)
|
||||
forward_policy = enroll_only(forward_policy)
|
||||
|
||||
no_dnssec_validation = knob(
|
||||
None,
|
||||
description="Disable DNSSEC validation",
|
||||
)
|
||||
no_dnssec_validation = enroll_only(no_dnssec_validation)
|
||||
|
||||
dnssec_master = False
|
||||
disable_dnssec_master = False
|
||||
kasp_db_file = None
|
||||
force = False
|
||||
|
25
ipaserver/install/dogtag.py
Normal file
25
ipaserver/install/dogtag.py
Normal file
@ -0,0 +1,25 @@
|
||||
#
|
||||
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Dogtag-based service installer module
|
||||
"""
|
||||
|
||||
from ipalib.install import service
|
||||
from ipalib.install.service import prepare_only, replica_install_only
|
||||
from ipapython.install.core import knob
|
||||
|
||||
|
||||
class DogtagInstallInterface(service.ServiceInstallInterface):
|
||||
"""
|
||||
Interface common to all Dogtag-based service installers
|
||||
"""
|
||||
|
||||
ca_file = knob(
|
||||
str, None,
|
||||
description="location of CA PKCS#12 file",
|
||||
cli_metavar='FILE',
|
||||
)
|
||||
ca_file = prepare_only(ca_file)
|
||||
ca_file = replica_install_only(ca_file)
|
@ -2,6 +2,10 @@
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
KRA installer module
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
@ -15,7 +19,9 @@ from ipaserver.install import custodiainstance
|
||||
from ipaserver.install import cainstance
|
||||
from ipaserver.install import krainstance
|
||||
from ipaserver.install import dsinstance
|
||||
from ipaserver.install import service
|
||||
from ipaserver.install import service as _service
|
||||
|
||||
from . import dogtag
|
||||
|
||||
|
||||
def install_check(api, replica_config, options):
|
||||
@ -109,7 +115,7 @@ def install(api, replica_config, options):
|
||||
ra_only=ra_only,
|
||||
promote=promote)
|
||||
|
||||
service.print_msg("Restarting the directory server")
|
||||
_service.print_msg("Restarting the directory server")
|
||||
ds = dsinstance.DsInstance()
|
||||
ds.restart()
|
||||
|
||||
@ -134,3 +140,15 @@ def uninstall(standalone):
|
||||
kra.stop_tracking_certificates(stop_certmonger=not standalone)
|
||||
if kra.is_installed():
|
||||
kra.uninstall()
|
||||
|
||||
|
||||
class KRAInstallInterface(dogtag.DogtagInstallInterface):
|
||||
"""
|
||||
Interface of the KRA installer
|
||||
|
||||
Knobs defined here will be available in:
|
||||
* ipa-server-install
|
||||
* ipa-replica-prepare
|
||||
* ipa-replica-install
|
||||
* ipa-kra-install
|
||||
"""
|
||||
|
@ -2,7 +2,539 @@
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
"""
|
||||
Server installer module
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import collections
|
||||
import os.path
|
||||
import random
|
||||
|
||||
from ipaclient.install import client
|
||||
from ipalib import constants
|
||||
from ipalib.install.service import (enroll_only,
|
||||
master_install_only,
|
||||
prepare_only,
|
||||
replica_install_only)
|
||||
from ipalib.util import validate_domain_name
|
||||
from ipapython import ipautil
|
||||
from ipapython.dnsutil import check_zone_overlap
|
||||
from ipapython.install import typing
|
||||
from ipapython.install.core import knob
|
||||
|
||||
from .install import validate_admin_password, validate_dm_password
|
||||
from .install import Server
|
||||
from .replicainstall import Replica
|
||||
|
||||
from .upgrade import upgrade_check, upgrade
|
||||
|
||||
from .. import ca, conncheck, dns, kra
|
||||
|
||||
|
||||
class ServerInstallInterface(client.ClientInstallInterface,
|
||||
ca.CAInstallInterface,
|
||||
kra.KRAInstallInterface,
|
||||
dns.DNSInstallInterface,
|
||||
conncheck.ConnCheckInterface):
|
||||
"""
|
||||
Interface of server installers
|
||||
|
||||
Knobs defined here will be available in:
|
||||
* ipa-server-install
|
||||
* ipa-replica-prepare
|
||||
* ipa-replica-install
|
||||
"""
|
||||
|
||||
force_join = False
|
||||
kinit_attempts = 1
|
||||
fixed_primary = True
|
||||
ntp_servers = None
|
||||
force_ntpd = False
|
||||
permit = False
|
||||
enable_dns_updates = False
|
||||
no_krb5_offline_passwords = False
|
||||
preserve_sssd = False
|
||||
|
||||
domain_name = knob(
|
||||
bases=client.ClientInstallInterface.domain_name,
|
||||
# pylint: disable=no-member
|
||||
cli_names=(list(client.ClientInstallInterface.domain_name.cli_names) +
|
||||
['-n']),
|
||||
)
|
||||
domain_name = replica_install_only(domain_name)
|
||||
|
||||
new_domain_name = knob(
|
||||
bases=client.ClientInstallInterface.domain_name,
|
||||
cli_names=['--domain', '-n'],
|
||||
cli_metavar='DOMAIN_NAME',
|
||||
)
|
||||
new_domain_name = master_install_only(new_domain_name)
|
||||
|
||||
@new_domain_name.validator
|
||||
def new_domain_name(self, value):
|
||||
validate_domain_name(value)
|
||||
if (self.setup_dns and
|
||||
not self.allow_zone_overlap): # pylint: disable=no-member
|
||||
print("Checking DNS domain %s, please wait ..." % value)
|
||||
check_zone_overlap(value, False)
|
||||
|
||||
servers = knob(
|
||||
bases=client.ClientInstallInterface.servers,
|
||||
description="fully qualified name of IPA server to enroll to",
|
||||
)
|
||||
servers = enroll_only(servers)
|
||||
|
||||
realm_name = knob(
|
||||
bases=client.ClientInstallInterface.realm_name,
|
||||
cli_names=(list(client.ClientInstallInterface.realm_name.cli_names) +
|
||||
['-r']),
|
||||
)
|
||||
|
||||
host_name = knob(
|
||||
bases=client.ClientInstallInterface.host_name,
|
||||
description="fully qualified name of this host",
|
||||
)
|
||||
|
||||
ca_cert_files = knob(
|
||||
bases=client.ClientInstallInterface.ca_cert_files,
|
||||
description="File containing CA certificates for the service "
|
||||
"certificate files",
|
||||
cli_deprecated_names='--root-ca-file',
|
||||
)
|
||||
ca_cert_files = prepare_only(ca_cert_files)
|
||||
|
||||
new_dm_password = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
description="Directory Manager password",
|
||||
cli_names='--dm-password',
|
||||
cli_metavar='DM_PASSWORD',
|
||||
)
|
||||
new_dm_password = master_install_only(new_dm_password)
|
||||
|
||||
@new_dm_password.validator
|
||||
def new_dm_password(self, value):
|
||||
validate_dm_password(value)
|
||||
|
||||
ip_addresses = knob(
|
||||
bases=client.ClientInstallInterface.ip_addresses,
|
||||
description="Server IP Address. This option can be used multiple "
|
||||
"times",
|
||||
)
|
||||
|
||||
principal = knob(
|
||||
bases=client.ClientInstallInterface.principal,
|
||||
description="User Principal allowed to promote replicas and join IPA "
|
||||
"realm",
|
||||
cli_names=(list(client.ClientInstallInterface.principal.cli_names) +
|
||||
['-P']),
|
||||
)
|
||||
principal = replica_install_only(principal)
|
||||
|
||||
admin_password = knob(
|
||||
bases=client.ClientInstallInterface.admin_password,
|
||||
description="Kerberos password for the specified admin principal",
|
||||
)
|
||||
admin_password = replica_install_only(admin_password)
|
||||
|
||||
new_admin_password = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
description="admin user kerberos password",
|
||||
cli_names='--admin-password',
|
||||
cli_metavar='ADMIN_PASSWORD',
|
||||
)
|
||||
new_admin_password = master_install_only(new_admin_password)
|
||||
|
||||
@new_admin_password.validator
|
||||
def new_admin_password(self, value):
|
||||
validate_admin_password(value)
|
||||
|
||||
master_password = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
deprecated=True,
|
||||
description="kerberos master password (normally autogenerated)",
|
||||
)
|
||||
master_password = master_install_only(master_password)
|
||||
|
||||
domain_level = knob(
|
||||
int, constants.MAX_DOMAIN_LEVEL,
|
||||
description="IPA domain level",
|
||||
deprecated=True,
|
||||
)
|
||||
domain_level = master_install_only(domain_level)
|
||||
|
||||
@domain_level.validator
|
||||
def domain_level(self, value):
|
||||
# Check that Domain Level is within the allowed range
|
||||
if value < constants.MIN_DOMAIN_LEVEL:
|
||||
raise ValueError(
|
||||
"Domain Level cannot be lower than {0}".format(
|
||||
constants.MIN_DOMAIN_LEVEL))
|
||||
elif value > constants.MAX_DOMAIN_LEVEL:
|
||||
raise ValueError(
|
||||
"Domain Level cannot be higher than {0}".format(
|
||||
constants.MAX_DOMAIN_LEVEL))
|
||||
|
||||
setup_ca = knob(
|
||||
None,
|
||||
description="configure a dogtag CA",
|
||||
)
|
||||
setup_ca = enroll_only(setup_ca)
|
||||
|
||||
setup_kra = knob(
|
||||
None,
|
||||
description="configure a dogtag KRA",
|
||||
)
|
||||
setup_kra = enroll_only(setup_kra)
|
||||
|
||||
setup_dns = knob(
|
||||
None,
|
||||
description="configure bind with our zone",
|
||||
)
|
||||
setup_dns = enroll_only(setup_dns)
|
||||
|
||||
idstart = knob(
|
||||
int, random.randint(1, 10000) * 200000,
|
||||
description="The starting value for the IDs range (default random)",
|
||||
)
|
||||
idstart = master_install_only(idstart)
|
||||
|
||||
idmax = knob(
|
||||
int,
|
||||
description=("The max value for the IDs range (default: "
|
||||
"idstart+199999)"),
|
||||
)
|
||||
idmax = master_install_only(idmax)
|
||||
|
||||
@idmax.default_getter
|
||||
def idmax(self):
|
||||
return self.idstart + 200000 - 1
|
||||
|
||||
no_hbac_allow = knob(
|
||||
None,
|
||||
description="Don't install allow_all HBAC rule",
|
||||
cli_deprecated_names='--no_hbac_allow',
|
||||
)
|
||||
no_hbac_allow = master_install_only(no_hbac_allow)
|
||||
|
||||
ignore_topology_disconnect = knob(
|
||||
None,
|
||||
description="do not check whether server uninstall disconnects the "
|
||||
"topology (domain level 1+)",
|
||||
)
|
||||
ignore_topology_disconnect = master_install_only(ignore_topology_disconnect)
|
||||
|
||||
ignore_last_of_role = knob(
|
||||
None,
|
||||
description="do not check whether server uninstall removes last "
|
||||
"CA/DNS server or DNSSec master (domain level 1+)",
|
||||
)
|
||||
ignore_last_of_role = master_install_only(ignore_last_of_role)
|
||||
|
||||
no_pkinit = knob(
|
||||
None,
|
||||
description="disables pkinit setup steps",
|
||||
)
|
||||
no_pkinit = prepare_only(no_pkinit)
|
||||
|
||||
no_ui_redirect = knob(
|
||||
None,
|
||||
description="Do not automatically redirect to the Web UI",
|
||||
)
|
||||
no_ui_redirect = enroll_only(no_ui_redirect)
|
||||
|
||||
ssh_trust_dns = knob(
|
||||
None,
|
||||
description="configure OpenSSH client to trust DNS SSHFP records",
|
||||
)
|
||||
ssh_trust_dns = enroll_only(ssh_trust_dns)
|
||||
|
||||
no_ssh = knob(
|
||||
None,
|
||||
description="do not configure OpenSSH client",
|
||||
)
|
||||
no_ssh = enroll_only(no_ssh)
|
||||
|
||||
no_sshd = knob(
|
||||
None,
|
||||
description="do not configure OpenSSH server",
|
||||
)
|
||||
no_sshd = enroll_only(no_sshd)
|
||||
|
||||
no_dns_sshfp = knob(
|
||||
None,
|
||||
description="Do not automatically create DNS SSHFP records",
|
||||
)
|
||||
no_dns_sshfp = enroll_only(no_dns_sshfp)
|
||||
|
||||
dirsrv_config_file = knob(
|
||||
str, None,
|
||||
description="The path to LDIF file that will be used to modify "
|
||||
"configuration of dse.ldif during installation of the "
|
||||
"directory server instance",
|
||||
cli_metavar='FILE',
|
||||
)
|
||||
dirsrv_config_file = enroll_only(dirsrv_config_file)
|
||||
|
||||
@dirsrv_config_file.validator
|
||||
def dirsrv_config_file(self, value):
|
||||
if not os.path.exists(value):
|
||||
raise ValueError("File %s does not exist." % value)
|
||||
|
||||
dirsrv_cert_files = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[str], None,
|
||||
description=("File containing the Directory Server SSL certificate "
|
||||
"and private key"),
|
||||
cli_names='--dirsrv-cert-file',
|
||||
cli_deprecated_names='--dirsrv_pkcs12',
|
||||
cli_metavar='FILE',
|
||||
)
|
||||
dirsrv_cert_files = prepare_only(dirsrv_cert_files)
|
||||
|
||||
http_cert_files = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[str], None,
|
||||
description=("File containing the Apache Server SSL certificate and "
|
||||
"private key"),
|
||||
cli_names='--http-cert-file',
|
||||
cli_deprecated_names='--http_pkcs12',
|
||||
cli_metavar='FILE',
|
||||
)
|
||||
http_cert_files = prepare_only(http_cert_files)
|
||||
|
||||
pkinit_cert_files = knob(
|
||||
# pylint: disable=invalid-sequence-index
|
||||
typing.List[str], None,
|
||||
description=("File containing the Kerberos KDC SSL certificate and "
|
||||
"private key"),
|
||||
cli_names='--pkinit-cert-file',
|
||||
cli_deprecated_names='--pkinit_pkcs12',
|
||||
cli_metavar='FILE',
|
||||
)
|
||||
pkinit_cert_files = prepare_only(pkinit_cert_files)
|
||||
|
||||
dirsrv_pin = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
description="The password to unlock the Directory Server private key",
|
||||
cli_deprecated_names='--dirsrv_pin',
|
||||
cli_metavar='PIN',
|
||||
)
|
||||
dirsrv_pin = prepare_only(dirsrv_pin)
|
||||
|
||||
http_pin = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
description="The password to unlock the Apache Server private key",
|
||||
cli_deprecated_names='--http_pin',
|
||||
cli_metavar='PIN',
|
||||
)
|
||||
http_pin = prepare_only(http_pin)
|
||||
|
||||
pkinit_pin = knob(
|
||||
str, None,
|
||||
sensitive=True,
|
||||
description="The password to unlock the Kerberos KDC private key",
|
||||
cli_deprecated_names='--pkinit_pin',
|
||||
cli_metavar='PIN',
|
||||
)
|
||||
pkinit_pin = prepare_only(pkinit_pin)
|
||||
|
||||
dirsrv_cert_name = knob(
|
||||
str, None,
|
||||
description="Name of the Directory Server SSL certificate to install",
|
||||
cli_metavar='NAME',
|
||||
)
|
||||
dirsrv_cert_name = prepare_only(dirsrv_cert_name)
|
||||
|
||||
http_cert_name = knob(
|
||||
str, None,
|
||||
description="Name of the Apache Server SSL certificate to install",
|
||||
cli_metavar='NAME',
|
||||
)
|
||||
http_cert_name = prepare_only(http_cert_name)
|
||||
|
||||
pkinit_cert_name = knob(
|
||||
str, None,
|
||||
description="Name of the Kerberos KDC SSL certificate to install",
|
||||
cli_metavar='NAME',
|
||||
)
|
||||
pkinit_cert_name = prepare_only(pkinit_cert_name)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(ServerInstallInterface, self).__init__(**kwargs)
|
||||
|
||||
# If any of the key file options are selected, all are required.
|
||||
cert_file_req = (self.dirsrv_cert_files, self.http_cert_files)
|
||||
cert_file_opt = (self.pkinit_cert_files,)
|
||||
if any(cert_file_req + cert_file_opt) and not all(cert_file_req):
|
||||
raise RuntimeError(
|
||||
"--dirsrv-cert-file and --http-cert-file are required if any "
|
||||
"key file options are used.")
|
||||
|
||||
if not self.interactive:
|
||||
if self.dirsrv_cert_files and self.dirsrv_pin is None:
|
||||
raise RuntimeError(
|
||||
"You must specify --dirsrv-pin with --dirsrv-cert-file")
|
||||
if self.http_cert_files and self.http_pin is None:
|
||||
raise RuntimeError(
|
||||
"You must specify --http-pin with --http-cert-file")
|
||||
if self.pkinit_cert_files and self.pkinit_pin is None:
|
||||
raise RuntimeError(
|
||||
"You must specify --pkinit-pin with --pkinit-cert-file")
|
||||
|
||||
if not self.setup_dns:
|
||||
if self.forwarders:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --forwarder option without the "
|
||||
"--setup-dns option")
|
||||
if self.auto_forwarders:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --auto-forwarders option without "
|
||||
"the --setup-dns option")
|
||||
if self.no_forwarders:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --no-forwarders option without the "
|
||||
"--setup-dns option")
|
||||
if self.forward_policy:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --forward-policy option without the "
|
||||
"--setup-dns option")
|
||||
if self.reverse_zones:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --reverse-zone option without the "
|
||||
"--setup-dns option")
|
||||
if self.auto_reverse:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --auto-reverse option without the "
|
||||
"--setup-dns option")
|
||||
if self.no_reverse:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --no-reverse option without the "
|
||||
"--setup-dns option")
|
||||
if self.no_dnssec_validation:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --no-dnssec-validation option "
|
||||
"without the --setup-dns option")
|
||||
elif self.forwarders and self.no_forwarders:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --forwarder option together with "
|
||||
"--no-forwarders")
|
||||
elif self.auto_forwarders and self.no_forwarders:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --auto-forwarders option together with "
|
||||
"--no-forwarders")
|
||||
elif self.reverse_zones and self.no_reverse:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --reverse-zone option together with "
|
||||
"--no-reverse")
|
||||
elif self.auto_reverse and self.no_reverse:
|
||||
raise RuntimeError(
|
||||
"You cannot specify a --auto-reverse option together with "
|
||||
"--no-reverse")
|
||||
|
||||
if not hasattr(self, 'replica_file'):
|
||||
if self.external_cert_files and self.dirsrv_cert_files:
|
||||
raise RuntimeError(
|
||||
"Service certificate file options cannot be used with the "
|
||||
"external CA options.")
|
||||
|
||||
if self.external_ca_type and not self.external_ca:
|
||||
raise RuntimeError(
|
||||
"You cannot specify --external-ca-type without "
|
||||
"--external-ca")
|
||||
|
||||
if self.uninstalling:
|
||||
if (self.realm_name or self.new_admin_password or
|
||||
self.master_password):
|
||||
raise RuntimeError(
|
||||
"In uninstall mode, -a, -r and -P options are not "
|
||||
"allowed")
|
||||
elif not self.interactive:
|
||||
if (not self.realm_name or not self.new_dm_password or
|
||||
not self.new_admin_password):
|
||||
raise RuntimeError(
|
||||
"In unattended mode you need to provide at least -r, "
|
||||
"-p and -a options")
|
||||
if self.setup_dns:
|
||||
if (not self.forwarders and
|
||||
not self.no_forwarders and
|
||||
not self.auto_forwarders):
|
||||
raise RuntimeError(
|
||||
"You must specify at least one of --forwarder, "
|
||||
"--auto-forwarders, or --no-forwarders options")
|
||||
|
||||
any_ignore_option_true = any(
|
||||
[self.ignore_topology_disconnect, self.ignore_last_of_role])
|
||||
if any_ignore_option_true and not self.uninstalling:
|
||||
raise RuntimeError(
|
||||
"'--ignore-topology-disconnect/--ignore-last-of-role' "
|
||||
"options can be used only during uninstallation")
|
||||
|
||||
if self.idmax < self.idstart:
|
||||
raise RuntimeError(
|
||||
"idmax (%s) cannot be smaller than idstart (%s)" %
|
||||
(self.idmax, self.idstart))
|
||||
else:
|
||||
cert_file_req = (self.dirsrv_cert_files, self.http_cert_files)
|
||||
cert_file_opt = (self.pkinit_cert_files,)
|
||||
|
||||
if self.replica_file is None:
|
||||
# If any of the PKCS#12 options are selected, all are required.
|
||||
if any(cert_file_req + cert_file_opt) and not all(cert_file_req):
|
||||
raise RuntimeError(
|
||||
"--dirsrv-cert-file and --http-cert-file are required "
|
||||
"if any PKCS#12 options are used")
|
||||
|
||||
if self.servers and not self.domain_name:
|
||||
raise RuntimeError(
|
||||
"The --server option cannot be used without providing "
|
||||
"domain via the --domain option")
|
||||
|
||||
else:
|
||||
if not ipautil.file_exists(self.replica_file):
|
||||
raise RuntimeError(
|
||||
"Replica file %s does not exist" % self.replica_file)
|
||||
|
||||
if any(cert_file_req + cert_file_opt):
|
||||
raise RuntimeError(
|
||||
"You cannot specify any of --dirsrv-cert-file, "
|
||||
"--http-cert-file, or --pkinit-cert-file together "
|
||||
"with replica file")
|
||||
|
||||
CLIKnob = collections.namedtuple('CLIKnob', ('value', 'name'))
|
||||
|
||||
conflicting_knobs = (
|
||||
CLIKnob(self.realm_name, '--realm'),
|
||||
CLIKnob(self.domain_name, '--domain'),
|
||||
CLIKnob(self.host_name, '--hostname'),
|
||||
CLIKnob(self.servers, '--server'),
|
||||
CLIKnob(self.principal, '--principal'),
|
||||
)
|
||||
|
||||
if any([k.value is not None for k in conflicting_knobs]):
|
||||
conflicting_knob_names = [
|
||||
knob.name for knob in conflicting_knobs
|
||||
if knob.value is not None
|
||||
]
|
||||
|
||||
raise RuntimeError(
|
||||
"You cannot specify '{0}' option(s) with replica file."
|
||||
.format(", ".join(conflicting_knob_names))
|
||||
)
|
||||
|
||||
if self.setup_dns:
|
||||
if (not self.forwarders and
|
||||
not self.no_forwarders and
|
||||
not self.auto_forwarders):
|
||||
raise RuntimeError(
|
||||
"You must specify at least one of --forwarder, "
|
||||
"--auto-forwarders, or --no-forwarders options")
|
||||
|
||||
# Automatically disable pkinit w/ dogtag until that is supported
|
||||
self.no_pkinit = True
|
||||
|
Loading…
Reference in New Issue
Block a user