install: re-introduce option groups

Re-introduce option groups in ipa-client-install, ipa-server-install and
ipa-replica-install.

https://pagure.io/freeipa/issue/6392

Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
This commit is contained in:
Jan Cholasta 2017-03-08 08:03:13 +00:00 committed by Martin Basti
parent 774d8d0a5d
commit 2fc9feddd0
12 changed files with 310 additions and 249 deletions

View File

@ -8,9 +8,10 @@ Automount installer module
from ipalib.install import service
from ipalib.install.service import enroll_only
from ipapython.install.core import knob
from ipapython.install.core import group, knob
@group
class AutomountInstallInterface(service.ServiceInstallInterface):
"""
Interface of the automount installer
@ -19,9 +20,10 @@ class AutomountInstallInterface(service.ServiceInstallInterface):
* ipa-client-install
* ipa-client-automount
"""
description = "Automount"
automount_location = knob(
str, 'default',
str, None,
description="Automount location",
)
automount_location = enroll_only(automount_location)

View File

@ -50,7 +50,7 @@ from ipapython import certdb, kernel_keyring, ipaldap, ipautil
from ipapython.admintool import ScriptError
from ipapython.dn import DN
from ipapython.install import typing
from ipapython.install.core import knob
from ipapython.install.core import group, knob, extend_knob
from ipapython.install.common import step
from ipapython.ipa_log_manager import log_mgr, root_logger
from ipapython.ipautil import (
@ -3355,6 +3355,7 @@ def init(installer):
installer.sssd = not installer.no_sssd
@group
class ClientInstallInterface(hostname_.HostNameInstallInterface,
service.ServiceAdminInstallInterface,
sssd.SSSDInstallInterface):
@ -3367,9 +3368,10 @@ class ClientInstallInterface(hostname_.HostNameInstallInterface,
* ipa-replica-prepare
* ipa-replica-install
"""
description = "Client"
principal = knob(
bases=service.ServiceAdminInstallInterface.principal,
principal = extend_knob(
service.ServiceAdminInstallInterface.principal,
description="principal to use to join the IPA realm",
)
principal = enroll_only(principal)
@ -3518,8 +3520,8 @@ class ClientInstall(ClientInstallInterface,
replica_file = None
dm_password = None
ca_cert_files = knob(
bases=ClientInstallInterface.ca_cert_files,
ca_cert_files = extend_knob(
ClientInstallInterface.ca_cert_files,
)
@ca_cert_files.validator
@ -3544,11 +3546,6 @@ class ClientInstall(ClientInstallInterface,
def prompt_password(self):
return self.interactive
automount_location = knob(
bases=automount.AutomountInstallInterface.automount_location,
default=None,
)
no_ac = knob(
None,
description="do not modify the nsswitch.conf and PAM configuration",

View File

@ -5,16 +5,17 @@
from ipaclient.install import client
from ipaplatform.paths import paths
from ipapython.install import cli
from ipapython.install.core import knob
from ipapython.install.core import knob, extend_knob
class StandaloneClientInstall(client.ClientInstall):
no_host_dns = False
no_wait_for_dns = False
principal = knob(
bases=client.ClientInstall.principal,
cli_names=list(client.ClientInstall.principal.cli_names) + ['-p'],
principal = client.ClientInstall.principal
principal = extend_knob(
principal,
cli_names=list(principal.cli_names) + ['-p'],
)
password = knob(

View File

@ -8,7 +8,7 @@ Base service installer module
from ipalib.util import validate_domain_name
from ipapython.install import common, core, typing
from ipapython.install.core import knob
from ipapython.install.core import group, knob
def prepare_only(obj):
@ -94,12 +94,14 @@ def installs_replica(cls):
return _does(cls, 'replica_install')
@group
class ServiceInstallInterface(common.Installable,
common.Interactive,
core.Composite):
"""
Interface common to all service installers
"""
description = "Basic"
domain_name = knob(
str, None,

View File

@ -11,6 +11,7 @@ import collections
import functools
import itertools
import sys
import types
import six
@ -122,6 +123,10 @@ class KnobBase(PropertyBase):
def validate(self, value):
pass
@classmethod
def group(cls):
return cls.__outer_class__.group()
@classmethod
def is_cli_positional(cls):
return all(n is not None and not n.startswith('-')
@ -146,15 +151,16 @@ class KnobBase(PropertyBase):
return cls
def knob(type_=_missing, default=_missing, bases=_missing, sensitive=_missing,
deprecated=_missing, description=_missing, cli_names=_missing,
cli_deprecated_names=_missing, cli_metavar=_missing):
if type_ is None:
type_ = NoneType
def _knob(type=_missing, default=_missing, bases=_missing, _order=_missing,
sensitive=_missing, deprecated=_missing, description=_missing,
group=_missing, cli_names=_missing, cli_deprecated_names=_missing,
cli_metavar=_missing):
if type is None:
type = NoneType
if bases is _missing:
bases = (KnobBase,)
elif isinstance(bases, type):
elif isinstance(bases, types.TypeType):
bases = (bases,)
if cli_names is None or isinstance(cli_names, str):
@ -168,17 +174,20 @@ def knob(type_=_missing, default=_missing, bases=_missing, sensitive=_missing,
cli_deprecated_names = tuple(cli_deprecated_names)
class_dict = {}
class_dict['_order'] = next(_counter)
if type_ is not _missing:
class_dict['type'] = type_
if type is not _missing:
class_dict['type'] = type
if default is not _missing:
class_dict['default'] = default
if _order is not _missing:
class_dict['_order'] = _order
if sensitive is not _missing:
class_dict['sensitive'] = sensitive
if deprecated is not _missing:
class_dict['deprecated'] = deprecated
if description is not _missing:
class_dict['description'] = description
if group is not _missing:
class_dict['group'] = group
if cli_names is not _missing:
class_dict['cli_names'] = cli_names
if cli_deprecated_names is not _missing:
@ -189,6 +198,37 @@ def knob(type_=_missing, default=_missing, bases=_missing, sensitive=_missing,
return util.InnerClassMeta('Knob', bases, class_dict)
def knob(type, default=_missing, **kwargs):
"""
Define a new knob.
"""
return _knob(
type, default,
_order=next(_counter),
**kwargs
)
def extend_knob(base, default=_missing, bases=_missing, group=_missing,
**kwargs):
"""
Extend an existing knob.
"""
if bases is _missing:
bases = (base,)
if group is _missing:
group = staticmethod(base.group)
return _knob(
_missing, default,
bases=bases,
_order=_missing,
group=group,
**kwargs
)
class Configurable(six.with_metaclass(abc.ABCMeta, object)):
"""
Base class of all configurables.

View File

@ -15,11 +15,12 @@ import six
from ipalib.constants import DOMAIN_LEVEL_0
from ipalib import errors
from ipalib.install.service import ServiceAdminInstallInterface
from ipalib.install.service import replica_install_only
from ipaplatform.paths import paths
from ipapython.admintool import ScriptError
from ipapython import ipaldap, ipautil
from ipapython.dn import DN
from ipapython.install.core import knob
from ipapython.install.core import group, knob
from ipapython.ipa_log_manager import root_logger
from ipaserver.install import adtrustinstance
from ipaserver.install import service
@ -430,6 +431,7 @@ def install(standalone, options, fstore, api):
add_new_adtrust_agents(api, options)
@group
class ADTrustInstallInterface(ServiceAdminInstallInterface):
"""
Interface for the AD trust installer
@ -439,6 +441,7 @@ class ADTrustInstallInterface(ServiceAdminInstallInterface):
* ipa-replica-install
* ipa-adtrust-install
"""
description = "AD trust"
# the following knobs are provided on top of those specified for
# admin credentials
@ -451,6 +454,7 @@ class ADTrustInstallInterface(ServiceAdminInstallInterface):
description="Add IPA masters to a list of hosts allowed to "
"serve information about users from trusted forests"
)
add_agents = replica_install_only(add_agents)
enable_compat = knob(
None,
description="Enable support for trusted domains for old clients"

View File

@ -18,7 +18,7 @@ from ipalib.install import certstore
from ipalib.install.service import enroll_only, master_install_only, replica_install_only
from ipaserver.install import sysupgrade
from ipapython.install import typing
from ipapython.install.core import knob
from ipapython.install.core import group, knob, extend_knob
from ipaserver.install import (cainstance,
custodiainstance,
dsinstance,
@ -367,6 +367,7 @@ class CASigningAlgorithm(enum.Enum):
SHA_512_WITH_RSA = 'SHA512withRSA'
@group
class CAInstallInterface(dogtag.DogtagInstallInterface,
conncheck.ConnCheckInterface):
"""
@ -378,22 +379,22 @@ class CAInstallInterface(dogtag.DogtagInstallInterface,
* ipa-replica-install
* ipa-ca-install
"""
description = "Certificate system"
principal = knob(
bases=conncheck.ConnCheckInterface.principal,
principal = conncheck.ConnCheckInterface.principal
principal = extend_knob(
principal,
description="User allowed to manage replicas",
cli_names=(
list(conncheck.ConnCheckInterface.principal.cli_names) + ['-P']),
cli_names=list(principal.cli_names) + ['-P'],
)
principal = enroll_only(principal)
principal = replica_install_only(principal)
admin_password = knob(
bases=conncheck.ConnCheckInterface.admin_password,
admin_password = conncheck.ConnCheckInterface.admin_password
admin_password = extend_knob(
admin_password,
description="Admin user Kerberos password used for connection check",
cli_names=(
list(conncheck.ConnCheckInterface.admin_password.cli_names) +
['-w']),
cli_names=list(admin_password.cli_names) + ['-w'],
)
admin_password = enroll_only(admin_password)

View File

@ -32,7 +32,7 @@ from ipapython import dnsutil
from ipapython.dn import DN
from ipapython.dnsutil import check_zone_overlap
from ipapython.install import typing
from ipapython.install.core import knob
from ipapython.install.core import group, knob
from ipapython.ipa_log_manager import root_logger
from ipapython.admintool import ScriptError
from ipapython.ipautil import user_input
@ -414,6 +414,7 @@ class DNSForwardPolicy(enum.Enum):
FIRST = 'first'
@group
class DNSInstallInterface(hostname.HostNameInstallInterface):
"""
Interface of the DNS installer
@ -424,6 +425,7 @@ class DNSInstallInterface(hostname.HostNameInstallInterface):
* ipa-replica-install
* ipa-dns-install
"""
description = "DNS"
allow_zone_overlap = knob(
None,

View File

@ -3,7 +3,7 @@
#
from ipapython.install import cli
from ipapython.install.core import knob
from ipapython.install.core import knob, extend_knob
from ipaplatform.paths import paths
from ipaserver.install.server import ServerReplicaInstall
@ -19,9 +19,8 @@ class CompatServerReplicaInstall(ServerReplicaInstall):
ca_file = None
zonemgr = None
replica_file = knob(
# pylint: disable=no-member
bases=ServerReplicaInstall.replica_file,
replica_file = extend_knob(
ServerReplicaInstall.replica_file, # pylint: disable=no-member
cli_names='replica_file',
)
@ -52,17 +51,18 @@ class CompatServerReplicaInstall(ServerReplicaInstall):
def dm_password(self, value):
self.__dm_password = value
ip_addresses = knob(
# pylint: disable=no-member
bases=ServerReplicaInstall.ip_addresses,
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 = knob(
# pylint: disable=no-member
bases=ServerReplicaInstall.admin_password,
cli_names=list(ServerReplicaInstall.admin_password.cli_names) + ['-w'],
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

View File

@ -3,7 +3,7 @@
#
from ipapython.install import cli
from ipapython.install.core import knob
from ipapython.install.core import extend_knob
from ipaplatform.paths import paths
from ipaserver.install.server import ServerMasterInstall
@ -15,22 +15,20 @@ class CompatServerMasterInstall(ServerMasterInstall):
no_sudo = False
request_cert = False
dm_password = knob(
# pylint: disable=no-member
bases=ServerMasterInstall.dm_password,
dm_password = extend_knob(
ServerMasterInstall.dm_password, # pylint: disable=no-member
cli_names=['--ds-password', '-p'],
)
admin_password = knob(
admin_password = ServerMasterInstall.admin_password
admin_password = extend_knob(
admin_password,
# pylint: disable=no-member
bases=ServerMasterInstall.admin_password,
cli_names=(list(ServerMasterInstall.admin_password.cli_names) +
['-a']),
cli_names=list(admin_password.cli_names) + ['-a'],
)
ip_addresses = knob(
# pylint: disable=no-member
bases=ServerMasterInstall.ip_addresses,
ip_addresses = extend_knob(
ServerMasterInstall.ip_addresses, # pylint: disable=no-member
description="Master Server IP Address. This option can be used "
"multiple times",
)

View File

@ -15,6 +15,7 @@ from ipaplatform.paths import paths
from ipapython import certdb
from ipapython import ipautil
from ipapython.dn import DN
from ipapython.install.core import group
from ipaserver.install import custodiainstance
from ipaserver.install import cainstance
from ipaserver.install import krainstance
@ -141,6 +142,7 @@ def uninstall(standalone):
kra.uninstall()
@group
class KRAInstallInterface(dogtag.DogtagInstallInterface):
"""
Interface of the KRA installer
@ -151,3 +153,4 @@ class KRAInstallInterface(dogtag.DogtagInstallInterface):
* ipa-replica-install
* ipa-kra-install
"""
description = "KRA"

View File

@ -14,6 +14,7 @@ import random
from ipaclient.install import client
from ipalib import constants
from ipalib.install import service
from ipalib.install.service import (enroll_only,
installs_master,
installs_replica,
@ -24,7 +25,7 @@ from ipalib.install.service import (enroll_only,
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.core import group, knob, extend_knob
from ipapython.install.common import step
from .install import validate_admin_password, validate_dm_password
@ -41,159 +42,9 @@ from .upgrade import upgrade_check, upgrade
from .. import adtrust, ca, conncheck, dns, kra
class ServerInstallInterface(client.ClientInstallInterface,
ca.CAInstallInterface,
kra.KRAInstallInterface,
dns.DNSInstallInterface,
adtrust.ADTrustInstallInterface,
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']),
)
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)
dm_password = knob(
bases=client.ClientInstallInterface.dm_password,
description="Directory Manager password",
)
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 = 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)
@group
class ServerUninstallInterface(service.ServiceInstallInterface):
description = "Uninstall"
ignore_topology_disconnect = knob(
None,
@ -209,31 +60,10 @@ class ServerInstallInterface(client.ClientInstallInterface,
)
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)
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)
@group
class ServerCertificateInstallInterface(service.ServiceInstallInterface):
description = "SSL certificate"
dirsrv_cert_files = knob(
# pylint: disable=invalid-sequence-index
@ -316,10 +146,191 @@ class ServerInstallInterface(client.ClientInstallInterface,
)
pkinit_cert_name = prepare_only(pkinit_cert_name)
add_agents = knob(
bases=adtrust.ADTrustInstallInterface.add_agents
@group
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"
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
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'],
)
add_agents = replica_install_only(add_agents)
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 __init__(self, **kwargs):
super(ServerInstallInterface, self).__init__(**kwargs)
@ -514,8 +525,8 @@ class ServerMasterInstall(ServerMasterInstallInterface):
keytab = None
setup_ca = True
domain_name = knob(
bases=ServerMasterInstallInterface.domain_name,
domain_name = extend_knob(
ServerMasterInstallInterface.domain_name,
)
@domain_name.validator
@ -525,16 +536,16 @@ class ServerMasterInstall(ServerMasterInstallInterface):
print("Checking DNS domain %s, please wait ..." % value)
check_zone_overlap(value, False)
dm_password = knob(
bases=ServerMasterInstallInterface.dm_password,
dm_password = extend_knob(
ServerMasterInstallInterface.dm_password,
)
@dm_password.validator
def dm_password(self, value):
validate_dm_password(value)
admin_password = knob(
bases=ServerMasterInstallInterface.admin_password,
admin_password = extend_knob(
ServerMasterInstallInterface.admin_password,
description="admin user kerberos password",
)
@ -574,8 +585,8 @@ class ServerReplicaInstall(ServerReplicaInstallInterface):
subject_base = None
ca_subject = None
admin_password = knob(
bases=ServerReplicaInstallInterface.admin_password,
admin_password = extend_knob(
ServerReplicaInstallInterface.admin_password,
description="Kerberos password for the specified admin principal",
)