install: migrate server installers to the new class hierarchy

Migrate ipa-server-install and ipa-replica-install from the old installer
classes to the new installer class hierarchy classes.

https://fedorahosted.org/freeipa/ticket/6392

Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
Jan Cholasta 2016-11-09 12:49:25 +01:00
parent a8fdb8de82
commit 225fae8418
8 changed files with 255 additions and 907 deletions

View File

@ -18,17 +18,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from ipapython.install import cli from ipaserver.install import ipa_replica_install
from ipaplatform.paths import paths
from ipaserver.install.server import Replica
ipa_replica_install.run()
ReplicaInstall = cli.install_tool(
Replica,
command_name='ipa-replica-install',
log_file_name=paths.IPAREPLICA_INSTALL_LOG,
debug_option=True,
)
ReplicaInstall.run_cli()

View File

@ -20,18 +20,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from ipapython.install import cli from ipaserver.install import ipa_server_install
from ipaplatform.paths import paths
from ipaserver.install.server import Server
ipa_server_install.run()
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()

View File

@ -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()

View File

@ -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()

View File

@ -15,7 +15,10 @@ import random
from ipaclient.install import client from ipaclient.install import client
from ipalib import constants from ipalib import constants
from ipalib.install.service import (enroll_only, from ipalib.install.service import (enroll_only,
installs_master,
installs_replica,
master_install_only, master_install_only,
prepares,
prepare_only, prepare_only,
replica_install_only) replica_install_only)
from ipalib.util import validate_domain_name from ipalib.util import validate_domain_name
@ -23,11 +26,17 @@ from ipapython import ipautil
from ipapython.dnsutil import check_zone_overlap from ipapython.dnsutil import check_zone_overlap
from ipapython.install import typing from ipapython.install import typing
from ipapython.install.core import knob from ipapython.install.core import knob
from ipapython.install.common import step
from .install import validate_admin_password, validate_dm_password from .install import validate_admin_password, validate_dm_password
from .install import Server from .install import init as master_init
from .replicainstall import Replica 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 .upgrade import upgrade_check, upgrade
from .. import ca, conncheck, dns, kra from .. import ca, conncheck, dns, kra
@ -538,3 +547,56 @@ class ServerInstallInterface(client.ClientInstallInterface,
# Automatically disable pkinit w/ dogtag until that is supported # Automatically disable pkinit w/ dogtag until that is supported
self.no_pkinit = True 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)

View File

@ -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=<realm-name>)",
)
@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)

View File

@ -6,7 +6,6 @@ from __future__ import print_function
import os import os
import pickle import pickle
import random
import shutil import shutil
import sys import sys
import tempfile import tempfile
@ -16,10 +15,6 @@ import six
from ipapython import certmonger, ipautil, sysrestore from ipapython import certmonger, ipautil, sysrestore
from ipapython.dn import DN 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.ipa_log_manager import root_logger
from ipapython.ipautil import ( from ipapython.ipautil import (
decrypt_file, format_netloc, ipa_generate_password, run, user_input, decrypt_file, format_netloc, ipa_generate_password, run, user_input,
@ -56,7 +51,7 @@ try:
except ImportError: except ImportError:
_server_trust_ad_installed = False _server_trust_ad_installed = False
from .common import BaseServer, BaseServerCA NoneType = type(None)
SYSRESTORE_DIR_PATH = paths.SYSRESTORE SYSRESTORE_DIR_PATH = paths.SYSRESTORE
@ -1137,216 +1132,24 @@ def uninstall(installer):
sys.exit(rv) sys.exit(rv)
class ServerCA(BaseServerCA): def init(installer):
external_ca = Knob(BaseServerCA.external_ca) installer.unattended = not installer.interactive
external_ca_type = Knob(BaseServerCA.external_ca_type)
external_cert_files = Knob(BaseServerCA.external_cert_files)
dirsrv_cert_files = Knob( installer.domain_name = installer.new_domain_name
BaseServerCA.dirsrv_cert_files, installer.dm_password = installer.new_dm_password
cli_aliases=['dirsrv_pkcs12'], installer.admin_password = installer.new_admin_password
) installer.domainlevel = installer.domain_level
http_cert_files = Knob( installer._installation_cleanup = True
BaseServerCA.http_cert_files, installer._ds = None
cli_aliases=['http_pkcs12'],
)
pkinit_cert_files = Knob( installer._dirsrv_pkcs12_file = None
BaseServerCA.pkinit_cert_files, installer._http_pkcs12_file = None
cli_aliases=['pkinit_pkcs12'], installer._pkinit_pkcs12_file = None
) installer._dirsrv_pkcs12_info = None
installer._http_pkcs12_info = None
dirsrv_pin = Knob( installer._pkinit_pkcs12_info = None
BaseServerCA.dirsrv_pin, installer._external_cert_file = None
cli_aliases=['dirsrv_pin'], installer._external_ca_file = None
) installer._ca_cert = None
installer._update_hosts_file = False
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)

View File

@ -4,7 +4,6 @@
from __future__ import print_function from __future__ import print_function
import collections
from distutils.version import LooseVersion from distutils.version import LooseVersion
import dns.exception as dnsexception import dns.exception as dnsexception
import dns.name as dnsname import dns.name as dnsname
@ -20,8 +19,6 @@ import six
from ipapython import ipaldap, ipautil, sysrestore from ipapython import ipaldap, ipautil, sysrestore
from ipapython.dn import DN 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.ipa_log_manager import root_logger
from ipapython.admintool import ScriptError from ipapython.admintool import ScriptError
from ipaplatform import services from ipaplatform import services
@ -48,11 +45,11 @@ import SSSDConfig
from subprocess import CalledProcessError from subprocess import CalledProcessError
from binascii import hexlify from binascii import hexlify
from .common import BaseServer
if six.PY3: if six.PY3:
unicode = str unicode = str
NoneType = type(None)
def get_dirman_password(): def get_dirman_password():
return installutils.read_password("Directory Manager (existing master)", return installutils.read_password("Directory Manager (existing master)",
@ -1440,173 +1437,27 @@ def install(installer):
services.knownservices.ipa.enable() services.knownservices.ipa.enable()
class Replica(BaseServer): def init(installer):
replica_file = Knob( installer.unattended = not installer.interactive
str, None, installer.promote = installer.replica_file is None
description="a file generated by ipa-replica-prepare",
cli_positional=True,
cli_name='replica_file',
)
setup_ca = Knob(BaseServer.setup_ca)
setup_kra = Knob(BaseServer.setup_kra)
setup_dns = Knob(BaseServer.setup_dns)
ip_addresses = Knob(
BaseServer.ip_addresses,
description=("Replica server IP Address. This option can be used "
"multiple times"),
)
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")
if installer.servers:
installer.server = installer.servers[0]
else: else:
if not ipautil.file_exists(self.replica_file): installer.server = None
raise RuntimeError("Replica file %s does not exist" if installer.replica_file is None:
% self.replica_file) installer.password = installer.host_password
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: else:
install_check(self) installer.password = installer.dm_password
yield
install(self) installer._ccache = os.environ.get('KRB5CCNAME')
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