summaryrefslogtreecommitdiffstats
path: root/ipaserver/install/server
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2016-11-09 12:44:22 +0100
committerJan Cholasta <jcholast@redhat.com>2016-11-11 12:17:25 +0100
commita8fdb8de8248fe24f382e44b05293405b0b309ac (patch)
tree01054c439fb2d64506951f18d163bf341ef869a7 /ipaserver/install/server
parent08a446a6bc516936497c1e0f278a699148f6330c (diff)
downloadfreeipa-a8fdb8de8248fe24f382e44b05293405b0b309ac.tar.gz
freeipa-a8fdb8de8248fe24f382e44b05293405b0b309ac.tar.xz
freeipa-a8fdb8de8248fe24f382e44b05293405b0b309ac.zip
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>
Diffstat (limited to 'ipaserver/install/server')
-rw-r--r--ipaserver/install/server/__init__.py532
1 files changed, 532 insertions, 0 deletions
diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py
index da2ceec9c..a8b56d6fe 100644
--- a/ipaserver/install/server/__init__.py
+++ b/ipaserver/install/server/__init__.py
@@ -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