Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 5971 - CLI - Fix password prompt for repl status #5972

Merged
merged 1 commit into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/lib389/lib389/agreement.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
"""
Expand All @@ -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:
Expand Down
54 changes: 26 additions & 28 deletions src/lib389/lib389/cli_conf/replication.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
droideck marked this conversation as resolved.
Show resolved Hide resolved
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:
Expand All @@ -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)
tbordaz marked this conversation as resolved.
Show resolved Hide resolved
if args.json:
log.info(json.dumps({"type": "list", "items": status}, indent=4))
else:
Expand Down Expand Up @@ -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)


Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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')
Expand Down
4 changes: 2 additions & 2 deletions src/lib389/lib389/replica.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading