diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index 27be5f8f4..44a9aa3f4 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -18,17 +18,6 @@
# along with this program. If not, see .
#
-from ipapython.install import cli
-from ipaplatform.paths import paths
-from ipaserver.install.server import Replica
+from ipaserver.install import ipa_replica_install
-
-ReplicaInstall = cli.install_tool(
- Replica,
- command_name='ipa-replica-install',
- log_file_name=paths.IPAREPLICA_INSTALL_LOG,
- debug_option=True,
-)
-
-
-ReplicaInstall.run_cli()
+ipa_replica_install.run()
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index 9fc78b538..17be2f4e8 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -20,18 +20,6 @@
# along with this program. If not, see .
#
-from ipapython.install import cli
-from ipaplatform.paths import paths
-from ipaserver.install.server import Server
+from ipaserver.install import ipa_server_install
-
-ServerInstall = cli.install_tool(
- Server,
- command_name='ipa-server-install',
- log_file_name=paths.IPASERVER_INSTALL_LOG,
- debug_option=True,
- uninstall_log_file_name=paths.IPASERVER_UNINSTALL_LOG,
-)
-
-
-ServerInstall.run_cli()
+ipa_server_install.run()
diff --git a/ipaserver/install/ipa_replica_install.py b/ipaserver/install/ipa_replica_install.py
new file mode 100644
index 000000000..39c745643
--- /dev/null
+++ b/ipaserver/install/ipa_replica_install.py
@@ -0,0 +1,95 @@
+#
+# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
+#
+
+from ipapython.install import cli
+from ipapython.install.core import knob
+from ipaplatform.paths import paths
+from ipaserver.install.server import ServerReplicaInstall
+
+
+class CompatServerReplicaInstall(ServerReplicaInstall):
+ ca_cert_files = None
+ all_ip_addresses = False
+ no_wait_for_dns = True
+ nisdomain = None
+ no_nisdomain = False
+ no_sudo = False
+ request_cert = False
+ ca_file = None
+ zonemgr = None
+
+ replica_file = knob(
+ # pylint: disable=no-member
+ bases=ServerReplicaInstall.replica_file,
+ cli_names='replica_file',
+ )
+
+ auto_password = knob(
+ str, None,
+ description="Password to join the IPA realm. Assumes bulk password "
+ "unless principal is also set. (domain level 1+) "
+ "Directory Manager (existing master) password. (domain "
+ "level 0)",
+ sensitive=True,
+ cli_names=['--password', '-p'],
+ cli_metavar='PASSWORD',
+ )
+
+ @property
+ def dm_password(self):
+ try:
+ return self.__dm_password
+ except AttributeError:
+ pass
+
+ if self.replica_file is not None:
+ return self.auto_password
+
+ return super(CompatServerReplicaInstall, self).dm_password
+
+ @dm_password.setter
+ def dm_password(self, value):
+ self.__dm_password = value
+
+ ip_addresses = knob(
+ # pylint: disable=no-member
+ bases=ServerReplicaInstall.ip_addresses,
+ description="Replica server IP Address. This option can be used "
+ "multiple times",
+ )
+
+ admin_password = knob(
+ # pylint: disable=no-member
+ bases=ServerReplicaInstall.admin_password,
+ cli_names=list(ServerReplicaInstall.admin_password.cli_names) + ['-w'],
+ )
+
+ @admin_password.default_getter
+ def admin_password(self):
+ if self.replica_file is None and self.principal:
+ return self.auto_password
+
+ return super(CompatServerReplicaInstall, self).admin_password
+
+ @property
+ def host_password(self):
+ admin_password = (
+ super(CompatServerReplicaInstall, self).admin_password)
+ if (self.replica_file is None and
+ (not self.principal or admin_password)):
+ return self.auto_password
+
+ return super(CompatServerReplicaInstall, self).host_password
+
+
+ReplicaInstall = cli.install_tool(
+ CompatServerReplicaInstall,
+ command_name='ipa-replica-install',
+ log_file_name=paths.IPAREPLICA_INSTALL_LOG,
+ debug_option=True,
+)
+
+
+def run():
+ ReplicaInstall.run_cli()
diff --git a/ipaserver/install/ipa_server_install.py b/ipaserver/install/ipa_server_install.py
new file mode 100644
index 000000000..3b6cb81c7
--- /dev/null
+++ b/ipaserver/install/ipa_server_install.py
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
+#
+
+from ipapython.install import cli
+from ipapython.install.core import knob
+from ipaplatform.paths import paths
+from ipaserver.install.server import ServerMasterInstall
+
+
+class CompatServerMasterInstall(ServerMasterInstall):
+ all_ip_addresses = False
+ nisdomain = None
+ no_nisdomain = False
+ no_sudo = False
+ request_cert = False
+
+ new_dm_password = knob(
+ # pylint: disable=no-member
+ bases=ServerMasterInstall.new_dm_password,
+ cli_names=['--ds-password', '-p'],
+ )
+
+ new_admin_password = knob(
+ # pylint: disable=no-member
+ bases=ServerMasterInstall.new_admin_password,
+ cli_names=(list(ServerMasterInstall.new_admin_password.cli_names) +
+ ['-a']),
+ )
+
+ ip_addresses = knob(
+ # pylint: disable=no-member
+ bases=ServerMasterInstall.ip_addresses,
+ description="Master Server IP Address. This option can be used "
+ "multiple times",
+ )
+
+
+ServerInstall = cli.install_tool(
+ CompatServerMasterInstall,
+ command_name='ipa-server-install',
+ log_file_name=paths.IPASERVER_INSTALL_LOG,
+ debug_option=True,
+ uninstall_log_file_name=paths.IPASERVER_UNINSTALL_LOG,
+)
+
+
+def run():
+ ServerInstall.run_cli()
diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py
index a8b56d6fe..c518ec946 100644
--- a/ipaserver/install/server/__init__.py
+++ b/ipaserver/install/server/__init__.py
@@ -15,7 +15,10 @@ import random
from ipaclient.install import client
from ipalib import constants
from ipalib.install.service import (enroll_only,
+ installs_master,
+ installs_replica,
master_install_only,
+ prepares,
prepare_only,
replica_install_only)
from ipalib.util import validate_domain_name
@@ -23,11 +26,17 @@ from ipapython import ipautil
from ipapython.dnsutil import check_zone_overlap
from ipapython.install import typing
from ipapython.install.core import knob
+from ipapython.install.common import step
from .install import validate_admin_password, validate_dm_password
-from .install import Server
-from .replicainstall import Replica
-
+from .install import init as master_init
+from .install import install as master_install
+from .install import install_check as master_install_check
+from .install import uninstall, uninstall_check
+from .replicainstall import init as replica_init
+from .replicainstall import install as replica_install
+from .replicainstall import install_check as replica_install_check
+from .replicainstall import promote_check as replica_promote_check
from .upgrade import upgrade_check, upgrade
from .. import ca, conncheck, dns, kra
@@ -538,3 +547,56 @@ class ServerInstallInterface(client.ClientInstallInterface,
# Automatically disable pkinit w/ dogtag until that is supported
self.no_pkinit = True
+
+
+class ServerMasterInstall(installs_master(ServerInstallInterface)):
+ """
+ Server master installer
+ """
+
+ domain_name = None
+ servers = None
+ dm_password = None
+ no_wait_for_dns = True
+ admin_password = None
+ host_password = None
+ keytab = None
+ setup_ca = True
+ setup_kra = False
+
+ def __init__(self, **kwargs):
+ super(ServerMasterInstall, self).__init__(**kwargs)
+ master_init(self)
+
+ @step()
+ def main(self):
+ master_install_check(self)
+ yield
+ master_install(self)
+
+ @main.uninstaller
+ def main(self):
+ uninstall_check(self)
+ yield
+ uninstall(self)
+
+
+class ServerReplicaInstall(installs_replica(ServerInstallInterface)):
+ """
+ Server replica installer
+ """
+
+ subject = None
+
+ def __init__(self, **kwargs):
+ super(ServerReplicaInstall, self).__init__(**kwargs)
+ replica_init(self)
+
+ @step()
+ def main(self):
+ if self.replica_file is None:
+ replica_promote_check(self)
+ else:
+ replica_install_check(self)
+ yield
+ replica_install(self)
diff --git a/ipaserver/install/server/common.py b/ipaserver/install/server/common.py
deleted file mode 100644
index 4ee83f15e..000000000
--- a/ipaserver/install/server/common.py
+++ /dev/null
@@ -1,489 +0,0 @@
-#
-# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
-#
-
-from __future__ import print_function
-
-import os
-import sys
-
-import six
-
-from ipapython.dn import DN
-from ipapython.ipautil import CheckedIPAddress
-from ipapython.install import common, core
-from ipapython.install.core import Knob, group
-from ipalib.util import validate_domain_name
-from ipaserver.install import bindinstance
-from ipapython.dnsutil import check_zone_overlap
-
-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']
-
-
-@group
-class BaseServerCA(common.Installable, core.Composite):
- description = "certificate system"
-
- external_ca = Knob(
- bool, False,
- description=("Generate a CSR for the IPA CA certificate to be signed "
- "by an external CA"),
- )
-
- external_ca_type = Knob(
- {'generic', 'ms-cs'}, None,
- description="Type of the external CA",
- )
-
- external_cert_files = Knob(
- (list, str), None,
- description=("File containing the IPA CA certificate and the external "
- "CA certificate chain"),
- cli_name='external-cert-file',
- cli_aliases=['external_cert_file', 'external_ca_file'],
- cli_metavar='FILE',
- )
-
- @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")
-
- dirsrv_cert_files = Knob(
- (list, str), None,
- description=("File containing the Directory Server SSL certificate "
- "and private key"),
- cli_name='dirsrv-cert-file',
- cli_metavar='FILE',
- )
-
- http_cert_files = Knob(
- (list, str), None,
- description=("File containing the Apache Server SSL certificate and "
- "private key"),
- cli_name='http-cert-file',
- cli_metavar='FILE',
- )
-
- pkinit_cert_files = Knob(
- (list, str), None,
- description=("File containing the Kerberos KDC SSL certificate and "
- "private key"),
- cli_name='pkinit-cert-file',
- cli_metavar='FILE',
- )
-
- dirsrv_pin = Knob(
- str, None,
- sensitive=True,
- description="The password to unlock the Directory Server private key",
- cli_metavar='PIN',
- )
-
- http_pin = Knob(
- str, None,
- sensitive=True,
- description="The password to unlock the Apache Server private key",
- cli_metavar='PIN',
- )
-
- pkinit_pin = Knob(
- str, None,
- sensitive=True,
- description="The password to unlock the Kerberos KDC private key",
- cli_metavar='PIN',
- )
-
- dirsrv_cert_name = Knob(
- str, None,
- description="Name of the Directory Server SSL certificate to install",
- cli_metavar='NAME',
- )
-
- http_cert_name = Knob(
- str, None,
- description="Name of the Apache Server SSL certificate to install",
- cli_metavar='NAME',
- )
-
- pkinit_cert_name = Knob(
- str, None,
- description="Name of the Kerberos KDC SSL certificate to install",
- cli_metavar='NAME',
- )
-
- ca_cert_files = Knob(
- (list, str), None,
- description=("File containing CA certificates for the service "
- "certificate files"),
- cli_name='ca-cert-file',
- cli_aliases=['root-ca-file'],
- cli_metavar='FILE',
- )
-
- subject = Knob(
- str, None,
- description="The certificate subject base (default O=)",
- )
-
- @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(
- {'SHA1withRSA', 'SHA256withRSA', 'SHA512withRSA'}, None,
- description="Signing algorithm of the IPA CA certificate",
- )
-
- skip_schema_check = Knob(
- bool, False,
- description="skip check for updated CA DS schema on the remote master",
- )
-
-
-@group
-class BaseServerDNS(common.Installable, core.Composite):
- description = "DNS"
-
- forwarders = Knob(
- (list, 'ip'), None,
- description=("Add a DNS forwarder. This option can be used multiple "
- "times"),
- cli_name='forwarder',
- )
-
- forward_policy = Knob(
- {'only', 'first'}, None,
- description=("DNS forwarding policy for global forwarders"),
- )
-
- auto_forwarders = Knob(
- bool, False,
- description="Use DNS forwarders configured in /etc/resolv.conf",
- )
-
- no_forwarders = Knob(
- bool, False,
- description="Do not add any DNS forwarders, use root servers instead",
- )
-
- allow_zone_overlap = Knob(
- bool, False,
- description="Create DNS zone even if it already exists",
- )
-
- reverse_zones = Knob(
- (list, str), [],
- description=("The reverse DNS zone to use. This option can be used "
- "multiple times"),
- cli_name='reverse-zone',
- cli_metavar='REVERSE_ZONE',
- )
-
- @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(
- bool, False,
- description="Do not create new reverse DNS zone",
- )
-
- auto_reverse = Knob(
- bool, False,
- description="Create necessary reverse zones",
- )
-
- no_dnssec_validation = Knob(
- bool, False,
- description="Disable DNSSEC validation",
- )
-
- dnssec_master = Knob(
- bool, False,
- description="Setup server to be DNSSEC key master",
- )
-
- disable_dnssec_master = Knob(
- bool, False,
- description="Disable the DNSSEC master on this server",
- )
-
- kasp_db_file = Knob(
- str, None,
- description="Copy OpenDNSSEC metadata from the specified file (will "
- "not create a new kasp.db file)",
- )
-
- force = Knob(
- bool, False,
- description="Force install",
- )
-
- zonemgr = Knob(
- str, None,
- description=("DNS zone manager e-mail address. Defaults to "
- "hostmaster@DOMAIN"),
- )
-
- @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)
-
-
-class BaseServer(common.Installable, common.Interactive, core.Composite):
- realm_name = Knob(
- str, None,
- description="realm name",
- cli_name='realm',
- cli_short_name='r',
- )
-
- domain_name = Knob(
- str, None,
- description="domain name",
- cli_name='domain',
- cli_short_name='n',
- )
-
- @domain_name.validator
- def domain_name(self, value):
- validate_domain_name(value)
-
- dm_password = Knob(
- str, None,
- sensitive=True,
- cli_short_name='p',
- )
-
- admin_password = Knob(
- str, None,
- sensitive=True,
- )
-
- mkhomedir = Knob(
- bool, False,
- description="create home directories for users on their first login",
- )
-
- host_name = Knob(
- str, None,
- description="fully qualified name of this host",
- cli_name='hostname',
- )
-
- ip_addresses = Knob(
- (list, 'ip'), None,
- description=("Master Server IP Address. This option can be used "
- "multiple times"),
- cli_name='ip-address',
- cli_metavar='IP_ADDRESS',
- )
-
- @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))
-
- no_host_dns = Knob(
- bool, False,
- description="Do not use DNS for hostname lookup during installation",
- )
-
- setup_ca = Knob(
- bool, False,
- description="configure a dogtag CA",
- )
-
- setup_kra = Knob(
- bool, False,
- description="configure a dogtag KRA",
- )
-
- setup_dns = Knob(
- bool, False,
- description="configure bind with our zone",
- )
-
- no_ntp = Knob(
- bool, False,
- description="do not configure ntp",
- cli_short_name='N',
- )
-
- no_pkinit = Knob(
- bool, False,
- description="disables pkinit setup steps",
- )
-
- no_ui_redirect = Knob(
- bool, False,
- description="Do not automatically redirect to the Web UI",
- )
-
- ssh_trust_dns = Knob(
- bool, False,
- description="configure OpenSSH client to trust DNS SSHFP records",
- )
-
- no_ssh = Knob(
- bool, False,
- description="do not configure OpenSSH client",
- )
-
- no_sshd = Knob(
- bool, False,
- description="do not configure OpenSSH server",
- )
-
- no_dns_sshfp = Knob(
- bool, False,
- description="Do not automatically create DNS SSHFP records",
- )
-
- 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.validator
- def dirsrv_config_file(self, value):
- if not os.path.exists(value):
- raise ValueError("File %s does not exist." % value)
-
-
- def __init__(self, **kwargs):
- super(BaseServer, self).__init__(**kwargs)
-
- #pylint: disable=no-member
-
- # If any of the key file options are selected, all are required.
- cert_file_req = (self.ca.dirsrv_cert_files, self.ca.http_cert_files)
- cert_file_opt = (self.ca.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.ca.dirsrv_cert_files and self.ca.dirsrv_pin is None:
- raise RuntimeError(
- "You must specify --dirsrv-pin with --dirsrv-cert-file")
- if self.ca.http_cert_files and self.ca.http_pin is None:
- raise RuntimeError(
- "You must specify --http-pin with --http-cert-file")
- if self.ca.pkinit_cert_files and self.ca.pkinit_pin is None:
- raise RuntimeError(
- "You must specify --pkinit-pin with --pkinit-cert-file")
-
- if self.ca.external_cert_files and self.ca.dirsrv_cert_files:
- raise RuntimeError(
- "Service certificate file options cannot be used with the "
- "external CA options.")
-
- if self.ca.external_ca_type and not self.ca.external_ca:
- raise RuntimeError(
- "You cannot specify --external-ca-type without --external-ca")
-
- if not self.setup_dns:
- if self.dns.forwarders:
- raise RuntimeError(
- "You cannot specify a --forwarder option without the "
- "--setup-dns option")
- if self.dns.auto_forwarders:
- raise RuntimeError(
- "You cannot specify a --auto-forwarders option without "
- "the --setup-dns option")
- if self.dns.no_forwarders:
- raise RuntimeError(
- "You cannot specify a --no-forwarders option without the "
- "--setup-dns option")
- if self.dns.forward_policy:
- raise RuntimeError(
- "You cannot specify a --forward-policy option without the "
- "--setup-dns option")
- if self.dns.reverse_zones:
- raise RuntimeError(
- "You cannot specify a --reverse-zone option without the "
- "--setup-dns option")
- if self.dns.auto_reverse:
- raise RuntimeError(
- "You cannot specify a --auto-reverse option without the "
- "--setup-dns option")
- if self.dns.no_reverse:
- raise RuntimeError(
- "You cannot specify a --no-reverse option without the "
- "--setup-dns option")
- if self.dns.no_dnssec_validation:
- raise RuntimeError(
- "You cannot specify a --no-dnssec-validation option "
- "without the --setup-dns option")
- elif self.dns.forwarders and self.dns.no_forwarders:
- raise RuntimeError(
- "You cannot specify a --forwarder option together with "
- "--no-forwarders")
- elif self.dns.auto_forwarders and self.dns.no_forwarders:
- raise RuntimeError(
- "You cannot specify a --auto-forwarders option together with "
- "--no-forwarders")
- elif self.dns.reverse_zones and self.dns.no_reverse:
- raise RuntimeError(
- "You cannot specify a --reverse-zone option together with "
- "--no-reverse")
- elif self.dns.auto_reverse and self.dns.no_reverse:
- raise RuntimeError(
- "You cannot specify a --auto-reverse option together with "
- "--no-reverse")
-
- # Automatically disable pkinit w/ dogtag until that is supported
- self.no_pkinit = True
-
- self.unattended = not self.interactive
-
- ca = core.Component(BaseServerCA)
- dns = core.Component(BaseServerDNS)
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
index 22e0cd3d7..091992a27 100644
--- a/ipaserver/install/server/install.py
+++ b/ipaserver/install/server/install.py
@@ -6,7 +6,6 @@ from __future__ import print_function
import os
import pickle
-import random
import shutil
import sys
import tempfile
@@ -16,10 +15,6 @@ import six
from ipapython import certmonger, ipautil, sysrestore
from ipapython.dn import DN
-from ipapython.dnsutil import check_zone_overlap
-from ipapython.install import core
-from ipapython.install.common import step
-from ipapython.install.core import Knob
from ipapython.ipa_log_manager import root_logger
from ipapython.ipautil import (
decrypt_file, format_netloc, ipa_generate_password, run, user_input,
@@ -56,7 +51,7 @@ try:
except ImportError:
_server_trust_ad_installed = False
-from .common import BaseServer, BaseServerCA
+NoneType = type(None)
SYSRESTORE_DIR_PATH = paths.SYSRESTORE
@@ -1137,216 +1132,24 @@ def uninstall(installer):
sys.exit(rv)
-class ServerCA(BaseServerCA):
- external_ca = Knob(BaseServerCA.external_ca)
- external_ca_type = Knob(BaseServerCA.external_ca_type)
- external_cert_files = Knob(BaseServerCA.external_cert_files)
+def init(installer):
+ installer.unattended = not installer.interactive
- dirsrv_cert_files = Knob(
- BaseServerCA.dirsrv_cert_files,
- cli_aliases=['dirsrv_pkcs12'],
- )
+ installer.domain_name = installer.new_domain_name
+ installer.dm_password = installer.new_dm_password
+ installer.admin_password = installer.new_admin_password
+ installer.domainlevel = installer.domain_level
- http_cert_files = Knob(
- BaseServerCA.http_cert_files,
- cli_aliases=['http_pkcs12'],
- )
+ installer._installation_cleanup = True
+ installer._ds = None
- pkinit_cert_files = Knob(
- BaseServerCA.pkinit_cert_files,
- cli_aliases=['pkinit_pkcs12'],
- )
-
- dirsrv_pin = Knob(
- BaseServerCA.dirsrv_pin,
- cli_aliases=['dirsrv_pin'],
- )
-
- http_pin = Knob(
- BaseServerCA.http_pin,
- cli_aliases=['http_pin'],
- )
-
- pkinit_pin = Knob(
- BaseServerCA.pkinit_pin,
- cli_aliases=['pkinit_pin'],
- )
-
- skip_schema_check = None
-
-
-class Server(BaseServer):
- setup_ca = None
- setup_kra = None
- setup_dns = Knob(BaseServer.setup_dns)
-
- realm_name = Knob(BaseServer.realm_name)
- domain_name = Knob(BaseServer.domain_name)
-
- @domain_name.validator
- def domain_name(self, value):
- if (self.setup_dns and
- not self.dns.allow_zone_overlap): # pylint: disable=no-member
- print("Checking DNS domain %s, please wait ..." % value)
- check_zone_overlap(value, False)
-
- dm_password = Knob(
- BaseServer.dm_password,
- description="Directory Manager password",
- cli_name='ds-password',
- )
-
- @dm_password.validator
- def dm_password(self, value):
- validate_dm_password(value)
-
- master_password = Knob(
- str, None,
- sensitive=True,
- deprecated=True,
- description="kerberos master password (normally autogenerated)",
- cli_short_name='P',
- )
-
- admin_password = Knob(
- BaseServer.admin_password,
- description="admin user kerberos password",
- cli_short_name='a',
- )
-
- @admin_password.validator
- def admin_password(self, value):
- validate_admin_password(value)
-
- mkhomedir = Knob(BaseServer.mkhomedir)
- host_name = Knob(BaseServer.host_name)
-
- domainlevel = Knob(
- int, constants.MAX_DOMAIN_LEVEL,
- description="IPA domain level",
- cli_name='domain-level',
- deprecated=True,
- )
-
- @domainlevel.validator
- def domainlevel(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))
-
- ip_addresses = Knob(
- BaseServer.ip_addresses,
- description=("Master Server IP Address. This option can be used "
- "multiple times"),
- )
-
- no_host_dns = Knob(BaseServer.no_host_dns)
- no_ntp = Knob(BaseServer.no_ntp)
-
- idstart = Knob(
- int, random.randint(1, 10000) * 200000,
- description="The starting value for the IDs range (default random)",
- )
-
- idmax = Knob(
- int,
- description=("The max value for the IDs range (default: "
- "idstart+199999)"),
- )
-
- @idmax.default_getter
- def idmax(self):
- return self.idstart + 200000 - 1
-
- no_hbac_allow = Knob(
- bool, False,
- description="Don't install allow_all HBAC rule",
- cli_name='no-hbac-allow',
- cli_aliases=['no_hbac_allow'],
- )
-
- ignore_topology_disconnect = Knob(
- bool, False,
- description="do not check whether server uninstall disconnects the "
- "topology (domain level 1+)",
- )
- ignore_last_of_role = Knob(
- bool, False,
- description="do not check whether server uninstall removes last "
- "CA/DNS server or DNSSec master (domain level 1+)",
- )
-
- # dns
- dnssec_master = None
- disable_dnssec_master = None
- kasp_db_file = None
- force = None
-
- def __init__(self, **kwargs):
- super(Server, self).__init__(**kwargs)
-
- self._installation_cleanup = True
- self._ds = None
-
- self._dirsrv_pkcs12_file = None
- self._http_pkcs12_file = None
- self._pkinit_pkcs12_file = None
- self._dirsrv_pkcs12_info = None
- self._http_pkcs12_info = None
- self._pkinit_pkcs12_info = None
- self._external_cert_file = None
- self._external_ca_file = None
- self._ca_cert = None
- self._update_hosts_file = False
-
- # pylint: disable=no-member
-
- if self.uninstalling:
- if (self.realm_name or self.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.dm_password or
- not self.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.dns.forwarders and not self.dns.no_forwarders
- and not self.dns.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))
-
- ca = core.Component(ServerCA)
-
- @step()
- def main(self):
- install_check(self)
- yield
- install(self)
-
- @main.uninstaller
- def main(self):
- uninstall_check(self)
- yield
- uninstall(self)
+ installer._dirsrv_pkcs12_file = None
+ installer._http_pkcs12_file = None
+ installer._pkinit_pkcs12_file = None
+ installer._dirsrv_pkcs12_info = None
+ installer._http_pkcs12_info = None
+ installer._pkinit_pkcs12_info = None
+ installer._external_cert_file = None
+ installer._external_ca_file = None
+ installer._ca_cert = None
+ installer._update_hosts_file = False
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 537f7dfbd..6d618b6cb 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -4,7 +4,6 @@
from __future__ import print_function
-import collections
from distutils.version import LooseVersion
import dns.exception as dnsexception
import dns.name as dnsname
@@ -20,8 +19,6 @@ import six
from ipapython import ipaldap, ipautil, sysrestore
from ipapython.dn import DN
-from ipapython.install.common import step
-from ipapython.install.core import Knob
from ipapython.ipa_log_manager import root_logger
from ipapython.admintool import ScriptError
from ipaplatform import services
@@ -48,11 +45,11 @@ import SSSDConfig
from subprocess import CalledProcessError
from binascii import hexlify
-from .common import BaseServer
-
if six.PY3:
unicode = str
+NoneType = type(None)
+
def get_dirman_password():
return installutils.read_password("Directory Manager (existing master)",
@@ -1440,173 +1437,27 @@ def install(installer):
services.knownservices.ipa.enable()
-class Replica(BaseServer):
- replica_file = Knob(
- str, None,
- description="a file generated by ipa-replica-prepare",
- cli_positional=True,
- cli_name='replica_file',
- )
+def init(installer):
+ installer.unattended = not installer.interactive
+ installer.promote = installer.replica_file is None
- setup_ca = Knob(BaseServer.setup_ca)
- setup_kra = Knob(BaseServer.setup_kra)
- setup_dns = Knob(BaseServer.setup_dns)
+ if installer.servers:
+ installer.server = installer.servers[0]
+ else:
+ installer.server = None
+ if installer.replica_file is None:
+ installer.password = installer.host_password
+ else:
+ installer.password = installer.dm_password
- ip_addresses = Knob(
- BaseServer.ip_addresses,
- description=("Replica server IP Address. This option can be used "
- "multiple times"),
- )
+ installer._ccache = os.environ.get('KRB5CCNAME')
- dm_password = None
-
- password = Knob(
- BaseServer.dm_password,
- description=("Password to join the IPA realm. Assumes bulk password "
- "unless principal is also set. (domain level 1+)\n"
- "Directory Manager (existing master) password. "
- "(domain level 0)"),
- )
-
- admin_password = Knob(
- BaseServer.admin_password,
- description="Kerberos password for the specified admin principal",
- cli_short_name='w',
- )
-
- server = Knob(
- str, None,
- description="fully qualified name of IPA server to enroll to",
- )
-
- mkhomedir = Knob(BaseServer.mkhomedir)
- no_host_dns = Knob(BaseServer.no_host_dns)
- no_ntp = Knob(BaseServer.no_ntp)
- no_pkinit = Knob(BaseServer.no_pkinit)
- no_ui_redirect = Knob(BaseServer.no_ui_redirect)
- ssh_trust_dns = Knob(BaseServer.ssh_trust_dns)
- no_ssh = Knob(BaseServer.no_ssh)
- no_sshd = Knob(BaseServer.no_sshd)
- no_dns_sshfp = Knob(BaseServer.no_dns_sshfp)
-
- skip_conncheck = Knob(
- bool, False,
- description="skip connection check to remote master",
- )
-
- principal = Knob(
- str, None,
- sensitive=True,
- description="User Principal allowed to promote replicas "
- "and join IPA realm",
- cli_short_name='P',
- )
-
- keytab = Knob(
- str, None,
- description="path to backed up keytab from previous enrollment",
- cli_short_name='k',
- )
-
- promote = False
-
- # ca
- external_ca = None
- external_ca_type = None
- external_cert_files = None
- ca_cert_files = None
- subject = None
- ca_signing_algorithm = None
-
- # dns
- dnssec_master = None
- disable_dnssec_master = None
- kasp_db_file = None
- force = None
- zonemgr = None
-
- def __init__(self, **kwargs):
- super(Replica, self).__init__(**kwargs)
-
- self._ccache = os.environ.get('KRB5CCNAME')
-
- self._top_dir = None
- self._config = None
- self._update_hosts_file = False
- self._dirsrv_pkcs12_file = None
- self._http_pkcs12_file = None
- self._pkinit_pkcs12_file = None
- self._dirsrv_pkcs12_info = None
- self._http_pkcs12_info = None
- self._pkinit_pkcs12_info = None
-
- # pylint: disable=no-member
-
- cert_file_req = (self.ca.dirsrv_cert_files, self.ca.http_cert_files)
- cert_file_opt = (self.ca.pkinit_cert_files,)
-
- if self.replica_file is None:
- self.promote = True
-
- if self.principal and not self.admin_password:
- self.admin_password = self.password
- self.password = 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.server 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.server, '--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.dns.forwarders and not self.dns.no_forwarders
- and not self.dns.auto_forwarders):
- raise RuntimeError(
- "You must specify at least one of --forwarder, "
- "--auto-forwarders, or --no-forwarders options")
-
- @step()
- def main(self):
- if self.promote:
- promote_check(self)
- else:
- install_check(self)
- yield
- install(self)
+ installer._top_dir = None
+ installer._config = None
+ installer._update_hosts_file = False
+ installer._dirsrv_pkcs12_file = None
+ installer._http_pkcs12_file = None
+ installer._pkinit_pkcs12_file = None
+ installer._dirsrv_pkcs12_info = None
+ installer._http_pkcs12_info = None
+ installer._pkinit_pkcs12_info = None