class ServerMasterInstall(ServerMasterInstallInterface): """ Server master installer """ force_join = False servers = None no_wait_for_dns = True host_password = None keytab = None setup_ca = True domain_name = extend_knob(ServerMasterInstallInterface.domain_name, ) @domain_name.validator def domain_name(self, value): # There might be an overlap but at this point we don't have # complete installer object to verify that DNS is hosted # by the same machine (i.e. we are already installed). # Later, DNS.install_check will do its zone overlap check # and will make sure to fail if overlap does really exist. # At this point we only verify that value is a valid DNS syntax. validate_domain_name(value) dm_password = extend_knob(ServerMasterInstallInterface.dm_password, ) @dm_password.validator def dm_password(self, value): validate_dm_password(value) admin_password = extend_knob( ServerMasterInstallInterface.admin_password, description="admin user kerberos password", ) @admin_password.validator def admin_password(self, value): validate_admin_password(value) # always run sidgen task and do not allow adding agents on first master add_sids = True add_agents = 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 ServerMasterInstall(ServerMasterInstallInterface): """ Server master installer """ force_join = False servers = None no_wait_for_dns = True host_password = None keytab = None setup_ca = True domain_name = extend_knob(ServerMasterInstallInterface.domain_name, ) @domain_name.validator def domain_name(self, value): if (self.setup_dns and not self.allow_zone_overlap): print("Checking DNS domain %s, please wait ..." % value) check_zone_overlap(value, False) dm_password = extend_knob(ServerMasterInstallInterface.dm_password, ) @dm_password.validator def dm_password(self, value): validate_dm_password(value) admin_password = extend_knob( ServerMasterInstallInterface.admin_password, description="admin user kerberos password", ) @admin_password.validator def admin_password(self, value): validate_admin_password(value) # always run sidgen task and do not allow adding agents on first master add_sids = True add_agents = False def _is_promote(self): return self.domain_level > constants.DOMAIN_LEVEL_0 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(ServerReplicaInstallInterface): """ Server replica installer """ subject_base = None ca_subject = None admin_password = extend_knob( ServerReplicaInstallInterface.admin_password, description="Kerberos password for the specified admin principal", ) def _is_promote(self): return self.replica_file is 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)
class CompatServerMasterInstall(ServerMasterInstall): all_ip_addresses = False nisdomain = None no_nisdomain = False no_sudo = False request_cert = False dm_password = extend_knob( ServerMasterInstall.dm_password, cli_names=['--ds-password', '-p'], ) admin_password = ServerMasterInstall.admin_password admin_password = extend_knob( admin_password, cli_names=list(admin_password.cli_names) + ['-a'], ) ip_addresses = extend_knob( ServerMasterInstall.ip_addresses, description="Master Server IP Address. This option can be used " "multiple times", )
class StandaloneClientInstall(client.ClientInstall): no_host_dns = False no_wait_for_dns = False principal = client.ClientInstall.principal principal = extend_knob( principal, cli_names=list(principal.cli_names) + ['-p'], ) password = knob( str, None, sensitive=True, description="password to join the IPA realm (assumes bulk password " "unless principal is also set)", cli_names=[None, '-w'], ) @property def admin_password(self): if self.principal: return self.password return super(StandaloneClientInstall, self).admin_password @property def host_password(self): if not self.principal: return self.password return super(StandaloneClientInstall, self).host_password prompt_password = knob( None, description="Prompt for a password to join the IPA realm", cli_names='-W', ) on_master = knob( None, deprecated=True, )
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_install = True # Used in ServerInstallInterface.__init__ 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 return super(CompatServerReplicaInstall, self).dm_password @dm_password.setter def dm_password(self, value): self.__dm_password = value ip_addresses = extend_knob( ServerReplicaInstall.ip_addresses, # pylint: disable=no-member description="Replica server IP Address. This option can be used " "multiple times", ) admin_password = ( ServerReplicaInstall.admin_password # pylint: disable=no-member ) admin_password = extend_knob( admin_password, cli_names=list(admin_password.cli_names) + ['-w'], ) @admin_password.default_getter def admin_password(self): if 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 not self.principal or admin_password: return self.auto_password return super(CompatServerReplicaInstall, self).host_password
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 """ description = "Certificate system" principal = conncheck.ConnCheckInterface.principal principal = extend_knob( principal, description="User allowed to manage replicas", cli_names=list(principal.cli_names) + ['-P'], ) principal = enroll_only(principal) principal = replica_install_only(principal) admin_password = conncheck.ConnCheckInterface.admin_password admin_password = extend_knob( admin_password, description="Admin user Kerberos password used for connection check", cli_names=list(admin_password.cli_names) + ['-w'], ) admin_password = enroll_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(x509.ExternalCAType, None, description="Type of the external CA") external_ca_type = master_install_only(external_ca_type) external_ca_profile = knob( type=x509.ExternalCAProfile, default=None, description=("Specify the certificate profile/template to use at the " "external CA"), ) external_ca_profile = master_install_only(external_ca_profile) external_cert_files = knob( 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_base = knob( str, None, description=("The certificate subject base (default O=<realm-name>). " "RDNs are in LDAP order (most specific RDN first)."), cli_deprecated_names=['--subject'], ) subject_base = master_install_only(subject_base) @subject_base.validator def subject_base(self, value): subject_validator(VALID_SUBJECT_BASE_ATTRS, value) ca_subject = knob( str, None, description=("The CA certificate subject DN " "(default CN=Certificate Authority,O=<realm-name>). " "RDNs are in LDAP order (most specific RDN first)."), ) ca_subject = master_install_only(ca_subject) @ca_subject.validator def ca_subject(self, value): subject_validator(VALID_SUBJECT_ATTRS, value) 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)
class ServerInstallInterface( ServerCertificateInstallInterface, client.ClientInstallInterface, ca.CAInstallInterface, kra.KRAInstallInterface, dns.DNSInstallInterface, adtrust.ADTrustInstallInterface, conncheck.ConnCheckInterface, ServerUninstallInterface): """ Interface of server installers Knobs defined here will be available in: * ipa-server-install * ipa-replica-prepare * ipa-replica-install """ description = "Server" kinit_attempts = 1 fixed_primary = True permit = False enable_dns_updates = False no_krb5_offline_passwords = False preserve_sssd = False no_sssd = False domain_name = client.ClientInstallInterface.domain_name domain_name = extend_knob( domain_name, # pylint: disable=no-member cli_names=list(domain_name.cli_names) + ['-n'], ) servers = extend_knob( client.ClientInstallInterface.servers, description="fully qualified name of IPA server to enroll to", ) servers = enroll_only(servers) realm_name = client.ClientInstallInterface.realm_name realm_name = extend_knob( realm_name, cli_names=list(realm_name.cli_names) + ['-r'], ) host_name = extend_knob( client.ClientInstallInterface.host_name, description="fully qualified name of this host", ) ca_cert_files = extend_knob( 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) dm_password = extend_knob( client.ClientInstallInterface.dm_password, description="Directory Manager password", ) ip_addresses = extend_knob( client.ClientInstallInterface.ip_addresses, description="Server IP Address. This option can be used multiple " "times", ) principal = client.ClientInstallInterface.principal principal = extend_knob( principal, description="User Principal allowed to promote replicas and join IPA " "realm", cli_names=list(principal.cli_names) + ['-P'], ) principal = replica_install_only(principal) admin_password = extend_knob( client.ClientInstallInterface.admin_password, ) 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_adtrust = knob(None, description="configure AD trust capability") 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) 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) 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) def _is_promote(self): """ :returns: True if domain level options correspond to domain level > 0 """ raise NotImplementedError() def __init__(self, **kwargs): super(ServerInstallInterface, self).__init__(**kwargs) # pkinit is not supported on DL0, don't allow related options if not self._is_promote(): if (self.no_pkinit or self.pkinit_cert_files is not None or self.pkinit_pin is not None): raise RuntimeError( "pkinit on domain level 0 is not supported. Please " "don't use any pkinit-related options.") self.no_pkinit = True # 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 not self.no_pkinit: cert_file_req += cert_file_opt if self.no_pkinit and self.pkinit_cert_files: raise RuntimeError( "--no-pkinit and --pkinit-cert-file cannot be specified " "together") if any(cert_file_req + cert_file_opt) and not all(cert_file_req): raise RuntimeError( "--dirsrv-cert-file, --http-cert-file, and --pkinit-cert-file " "or --no-pkinit 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 self.setup_adtrust: if self.add_agents: raise RuntimeError( "You cannot specify an --add-agents option without the " "--setup-adtrust option") if self.enable_compat: raise RuntimeError( "You cannot specify an --enable-compat option without the " "--setup-adtrust option") if self.netbios_name: raise RuntimeError( "You cannot specify a --netbios-name option without the " "--setup-adtrust option") if self.no_msdcs: raise RuntimeError( "You cannot specify a --no-msdcs option without the " "--setup-adtrust option") 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.external_ca_profile and not self.external_ca: raise RuntimeError( "You cannot specify --external-ca-profile without " "--external-ca") 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.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: # replica installers if self.replica_file is None: 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 os.path.isfile(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")