diff --git a/src/lib389/lib389/agreement.py b/src/lib389/lib389/agreement.py index c7d90544a5..170ab9050d 100644 --- a/src/lib389/lib389/agreement.py +++ b/src/lib389/lib389/agreement.py @@ -13,6 +13,7 @@ import datetime from lib389._constants import * from lib389.properties import * +from lib389.cli_base import _get_arg from lib389._entry import FormatDict from lib389.utils import normalizeDN, ensure_bytes, ensure_str, ensure_dict_str, ensure_list_str from lib389 import Entry, DirSrv, NoSuchEntryError, InvalidArgumentError @@ -305,7 +306,7 @@ def get_lag_time(self, suffix, agmt_name, binddn=None, bindpw=None): # Return a nice formated timestamp return "{:0>8}".format(str(lag)) - def status(self, winsync=False, just_status=False, use_json=False, binddn=None, bindpw=None): + def status(self, winsync=False, just_status=False, use_json=False, binddn=None, bindpw=None, pwprompt=False): """Get the status of a replication agreement :param winsync: Specifies if the the agreement is a winsync replication agreement :type winsync: boolean @@ -317,6 +318,8 @@ def status(self, winsync=False, just_status=False, use_json=False, binddn=None, :type binddn: str :param bindpw: Password for the bind DN :type bindpw: str + :param pwprompt: If binddn or bindpw is None, ask for them interactively + :type pwprompt: boolean :returns: A status message :raises: ValueError - if failing to get agmt status """ @@ -328,6 +331,14 @@ def status(self, winsync=False, just_status=False, use_json=False, binddn=None, # RUV entry under the suffix, then we can't get the status. So in this case we # need to provide a DN and password. if not winsync: + if pwprompt: + host = self.get_attr_val_utf8(AGMT_HOST) + port = self.get_attr_val_utf8(AGMT_PORT) + suffix = self.get_attr_val_utf8(REPL_ROOT) + if binddn is None: + binddn = _get_arg(None, msg=f"Enter bind DN for the replicated suffix ({suffix}) on {host}:{port}") + if bindpw is None: + bindpw = _get_arg(None, msg=f"Enter password for ({binddn}) to the replicated suffix ({suffix}) on {host}:{port}", hidden=True) try: status = self.get_agmt_status(binddn=binddn, bindpw=bindpw) except ldap.INVALID_CREDENTIALS as e: diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py index f2d55c8dcf..35233c5f50 100644 --- a/src/lib389/lib389/cli_conf/replication.py +++ b/src/lib389/lib389/cli_conf/replication.py @@ -317,13 +317,12 @@ def list_suffixes(inst, basedn, log, args): def get_repl_status(inst, basedn, log, args): replicas = Replicas(inst) replica = replicas.get(args.suffix) + pw_and_dn_prompt = False if args.bind_passwd_file is not None: - passwd = get_passwd_from_file(args.bind_passwd_file) - elif args.bind_passwd_prompt: - passwd = _get_arg(None, msg=f"Enter password for ({args.bind_dn})", hidden=True, confirm=True) - else: - passwd = args.bind_passwd - status = replica.status(binddn=args.bind_dn, bindpw=passwd) + args.bind_passwd = get_passwd_from_file(args.bind_passwd_file) + if args.bind_passwd_prompt or args.bind_dn is None or args.bind_passwd is None: + pw_and_dn_prompt = True + status = replica.status(binddn=args.bind_dn, bindpw=args.bind_passwd, pwprompt=pw_and_dn_prompt) if args.json: log.info(json.dumps({"type": "list", "items": status}, indent=4)) else: @@ -334,14 +333,12 @@ def get_repl_status(inst, basedn, log, args): def get_repl_winsync_status(inst, basedn, log, args): replicas = Replicas(inst) replica = replicas.get(args.suffix) + pw_and_dn_prompt = False if args.bind_passwd_file is not None: - passwd = get_passwd_from_file(args.bind_passwd_file) - elif args.bind_passwd_prompt: - passwd = _get_arg(None, msg=f"Enter password for ({args.bind_dn})", hidden=True, confirm=True) - else: - passwd = args.bind_passwd - - status = replica.status(binddn=args.bind_dn, bindpw=passwd, winsync=True) + args.bind_passwd = get_passwd_from_file(args.bind_passwd_file) + if args.bind_passwd_prompt or args.bind_dn is None or args.bind_passwd is None: + pw_and_dn_prompt = True + status = replica.status(binddn=args.bind_dn, bindpw=args.bind_passwd, winsync=True, pwprompt=pw_and_dn_prompt) if args.json: log.info(json.dumps({"type": "list", "items": status}, indent=4)) else: @@ -927,11 +924,12 @@ def poke_agmt(inst, basedn, log, args): def get_agmt_status(inst, basedn, log, args): agmt = get_agmt(inst, args) + pw_and_dn_prompt = False if args.bind_passwd_file is not None: args.bind_passwd = get_passwd_from_file(args.bind_passwd_file) - if (args.bind_dn is not None and args.bind_passwd is None) or args.bind_passwd_prompt: - args.bind_passwd = _get_arg(None, msg=f"Enter password for \"{args.bind_dn}\"", hidden=True, confirm=True) - status = agmt.status(use_json=args.json, binddn=args.bind_dn, bindpw=args.bind_passwd) + if args.bind_passwd_prompt or args.bind_dn is None or args.bind_passwd is None: + pw_and_dn_prompt = True + status = agmt.status(use_json=args.json, binddn=args.bind_dn, bindpw=args.bind_passwd, pwprompt=pw_and_dn_prompt) log.info(status) @@ -1321,19 +1319,19 @@ def create_parser(subparsers): repl_status_parser = repl_subcommands.add_parser('status', help='Display the current status of all the replication agreements') repl_status_parser.set_defaults(func=get_repl_status) repl_status_parser.add_argument('--suffix', required=True, help="Sets the DN of the replication suffix") - repl_status_parser.add_argument('--bind-dn', help="Sets the DN to use to authenticate to the consumer") - repl_status_parser.add_argument('--bind-passwd', help="Sets the password for the bind DN") - repl_status_parser.add_argument('--bind-passwd-file', help="File containing the password") - repl_status_parser.add_argument('--bind-passwd-prompt', action='store_true', help="Prompt for password") + repl_status_parser.add_argument('--bind-dn', help="Sets the DN to use to authenticate to the consumer. If not set, current instance's root DN will be used. It will be used for all agreements") + repl_status_parser.add_argument('--bind-passwd', help="Sets the password for the bind DN. It will be used for all agreements") + repl_status_parser.add_argument('--bind-passwd-file', help="File containing the password. It will be used for all agreements") + repl_status_parser.add_argument('--bind-passwd-prompt', action='store_true', help="Prompt for passwords for each agreement's instance separately") repl_winsync_status_parser = repl_subcommands.add_parser('winsync-status', help='Display the current status of all ' 'the replication agreements') repl_winsync_status_parser.set_defaults(func=get_repl_winsync_status) repl_winsync_status_parser.add_argument('--suffix', required=True, help="Sets the DN of the replication suffix") - repl_winsync_status_parser.add_argument('--bind-dn', help="Sets the DN to use to authenticate to the consumer") - repl_winsync_status_parser.add_argument('--bind-passwd', help="Sets the password of the bind DN") - repl_winsync_status_parser.add_argument('--bind-passwd-file', help="File containing the password") - repl_winsync_status_parser.add_argument('--bind-passwd-prompt', action='store_true', help="Prompt for password") + repl_winsync_status_parser.add_argument('--bind-dn', help="Sets the DN to use to authenticate to the consumer. Currectly not used") + repl_winsync_status_parser.add_argument('--bind-passwd', help="Sets the password of the bind DN. Currectly not used") + repl_winsync_status_parser.add_argument('--bind-passwd-file', help="File containing the password. Currectly not used") + repl_winsync_status_parser.add_argument('--bind-passwd-prompt', action='store_true', help="Prompt for password. Currectly not used") repl_promote_parser = repl_subcommands.add_parser('promote', help='Promote a replica to a hub or supplier') repl_promote_parser.set_defaults(func=promote_replica) @@ -1510,10 +1508,10 @@ def create_parser(subparsers): agmt_status_parser.set_defaults(func=get_agmt_status) agmt_status_parser.add_argument('AGMT_NAME', nargs=1, help='The name of the replication agreement') agmt_status_parser.add_argument('--suffix', required=True, help="Sets the DN of the replication suffix") - agmt_status_parser.add_argument('--bind-dn', help="Sets the DN to use to authenticate to the consumer") - agmt_status_parser.add_argument('--bind-passwd', help="Sets the password for the bind DN") - agmt_status_parser.add_argument('--bind-passwd-file', help="File containing the password") - agmt_status_parser.add_argument('--bind-passwd-prompt', action='store_true', help="Prompt for password") + agmt_status_parser.add_argument('--bind-dn', help="Sets the DN to use to authenticate to the consumer. If not set, current instance's root DN will be used. It will be used for all agreements") + agmt_status_parser.add_argument('--bind-passwd', help="Sets the password for the bind DN. It will be used for all agreements") + agmt_status_parser.add_argument('--bind-passwd-file', help="File containing the password. It will be used for all agreements") + agmt_status_parser.add_argument('--bind-passwd-prompt', action='store_true', help="Prompt for passwords for each agreement's instance separately") # Delete agmt_del_parser = agmt_subcommands.add_parser('delete', help='Delete replication agreement') diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py index e89664eeff..177128202a 100644 --- a/src/lib389/lib389/replica.py +++ b/src/lib389/lib389/replica.py @@ -1734,13 +1734,13 @@ def get_suffix(self): return self._suffix - def status(self, binddn=None, bindpw=None, winsync=False): + def status(self, binddn=None, bindpw=None, winsync=False, pwprompt=False): """Get a list of the status for every agreement """ agmtList = [] agmts = Agreements(self._instance, self.dn, winsync=winsync).list() for agmt in agmts: - raw_status = agmt.status(binddn=binddn, bindpw=bindpw, use_json=True, winsync=winsync) + raw_status = agmt.status(binddn=binddn, bindpw=bindpw, use_json=True, winsync=winsync, pwprompt=pwprompt) agmtList.append(json.loads(raw_status)) # sort the list of agreements by the lag time