Skip to content

Commit abddb2a

Browse files
committed
MB-69379 Add --stage to xdcr-setup
Adds secondary credentials for if the primary ones start failing. Change-Id: I6a6a636c9dd61fa63ef6065e46991cd60da6fb73 Reviewed-on: https://review.couchbase.org/c/couchbase-cli/+/236609 Tested-by: Build Bot <build@couchbase.com> Reviewed-by: Safian Ali <safian.ali@couchbase.com>
1 parent a52e39d commit abddb2a

4 files changed

Lines changed: 72 additions & 11 deletions

File tree

cbmgr.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5297,6 +5297,8 @@ def __init__(self):
52975297
default=False, help="Set the local read-only user")
52985298
group.add_argument("--list", dest="list", action="store_true",
52995299
default=False, help="List all XDCR remote references")
5300+
group.add_argument("--stage", dest="stage", action="store_true",
5301+
default=False, help="Set the staged credentials")
53005302
group.add_argument("--xdcr-cluster-name", dest="name", metavar="<name>",
53015303
help="The name for the remote cluster reference")
53025304
group.add_argument("--xdcr-hostname", dest="hostname", metavar="<hostname>",
@@ -5322,13 +5324,16 @@ def __init__(self):
53225324

53235325
@rest_initialiser(cluster_init_check=True, version_check=True)
53245326
def execute(self, opts):
5325-
actions = sum([opts.create, opts.delete, opts.edit, opts.list])
5327+
actions = sum([opts.create, opts.delete, opts.edit, opts.list, opts.stage])
53265328
if actions == 0:
5327-
_exit_if_errors(["Must specify one of --create, --delete, --edit, --list"])
5329+
_exit_if_errors(["Must specify one of --create, --delete, --edit, --stage, --list"])
53285330
elif actions > 1:
5329-
_exit_if_errors(["The --create, --delete, --edit, --list flags may not be specified at the same time"])
5331+
_exit_if_errors(
5332+
["The --create, --delete, --edit, --stage, --list flags may not be specified at the same time"])
53305333
elif opts.create or opts.edit:
53315334
self._set(opts)
5335+
elif opts.stage:
5336+
self._stage(opts)
53325337
elif opts.delete:
53335338
self._delete(opts)
53345339
elif opts.list:
@@ -5397,6 +5402,33 @@ def _set(self, opts):
53975402
_exit_if_errors(errors)
53985403
_success("Cluster reference edited")
53995404

5405+
def _stage(self, opts):
5406+
if opts.name is None:
5407+
_exit_if_errors(['--xdcr-cluster-name is required to stage credentials on a cluster connection'])
5408+
5409+
total = sum(1 if x else 0 for x in [opts.r_username, opts.r_password, opts.r_key, opts.r_certificate])
5410+
if total != 2:
5411+
_exit_if_errors(['exactly one of --xdcr-username/--xdcr-password and ' +
5412+
'--xdcr-user-certificate/--xdcr-user-key must be specified'])
5413+
5414+
if (opts.r_username and opts.r_password is None) or (opts.r_username is None and opts.r_password):
5415+
_exit_if_errors(['-xdcr-username and --xdcr-password must be specified together'])
5416+
5417+
if (opts.r_key and opts.r_certificate is None) or (opts.r_key is None and opts.r_certificate):
5418+
_exit_if_errors(['-xdcr-user-certificate and --xdcr-user-key must be specified together'])
5419+
5420+
raw_user_key = None
5421+
if opts.r_key:
5422+
raw_user_key = _exit_on_file_read_failure(opts.r_key)
5423+
raw_user_cert = None
5424+
if opts.r_certificate:
5425+
raw_user_cert = _exit_on_file_read_failure(opts.r_certificate)
5426+
5427+
_, errors = self.rest.stage_creds_on_xdcr_reference(opts.name, opts.r_username, opts.r_password, raw_user_cert,
5428+
raw_user_key)
5429+
_exit_if_errors(errors)
5430+
_success("Credentials for cluster reference staged")
5431+
54005432
def _delete(self, opts):
54015433
if opts.name is None:
54025434
_exit_if_errors(["--xdcr-cluster-name is required to delete a cluster connection"])

cluster_manager.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ def __init__(self, service):
9292
Exception.__init__(self, f'Service {service} not available in target cluster')
9393

9494

95+
class SetXDCRReferenceMode(Enum):
96+
CREATE = 1
97+
EDIT = 2
98+
STAGE = 3
99+
100+
95101
class ClusterManager(object):
96102
"""A set of REST API's for managing a Couchbase cluster"""
97103

@@ -2104,25 +2110,31 @@ def retrieve_client_cert_auth(self):
21042110

21052111
def create_xdcr_reference(self, name, hostname, hostname_external, username, password, encrypted,
21062112
encryption_type, certificate, client_certificate, client_key):
2107-
return self._set_xdcr_reference(False, name, hostname, hostname_external, username,
2113+
return self._set_xdcr_reference(SetXDCRReferenceMode.CREATE, name, hostname, hostname_external, username,
21082114
password, encrypted, encryption_type,
21092115
certificate, client_certificate, client_key)
21102116

21112117
def edit_xdcr_reference(self, name, hostname, hostname_external, username, password, encrypted,
21122118
encryption_type, certificate, client_certificate, client_key):
2113-
return self._set_xdcr_reference(True, name, hostname, hostname_external, username,
2119+
return self._set_xdcr_reference(SetXDCRReferenceMode.EDIT, name, hostname, hostname_external, username,
21142120
password, encrypted, encryption_type,
21152121
certificate, client_certificate, client_key)
21162122

2117-
def _set_xdcr_reference(self, edit, name, hostname, hostname_external, username, password,
2123+
def stage_creds_on_xdcr_reference(self, name, username, password, client_certificate, client_key):
2124+
return self._set_xdcr_reference(SetXDCRReferenceMode.STAGE, name, None, None, username, password, None, None,
2125+
None, client_certificate, client_key)
2126+
2127+
def _set_xdcr_reference(self, mode, name, hostname, hostname_external, username, password,
21182128
encrypted, encryption_type, certificate, client_certificate, client_key):
21192129
url = f'{self.hostname}/pools/default/remoteClusters'
21202130
params = {}
21212131

2122-
if edit:
2132+
if mode == SetXDCRReferenceMode.EDIT or mode == SetXDCRReferenceMode.STAGE:
21232133
url += f'/{urllib.parse.quote(name)}'
2134+
if mode == SetXDCRReferenceMode.STAGE:
2135+
params["stage"] = 'true'
21242136

2125-
if name is not None:
2137+
if name is not None and mode != SetXDCRReferenceMode.STAGE:
21262138
params["name"] = name
21272139
if hostname is not None:
21282140
params["hostname"] = hostname

docs/modules/cli/pages/cbcli/couchbase-cli-xdcr-setup.adoc

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Manage references to remote clusters
1414
[verse]
1515
_couchbase-cli xdcr-setup_ [--cluster <url>] [--username <user>] [--password <password>]
1616
[--client-cert <path>] [--client-cert-password <password>] [--client-key <path>]
17-
[--client-key-password <password>] [--create] [--delete] [--edit] [--list]
17+
[--client-key-password <password>] [--create] [--delete] [--edit] [--list] [--stage]
1818
[--xdcr-cluster-name <name>] [--xdcr-hostname <hostname>] [--xdcr-hostname-external]
1919
[--xdcr-username <username>] [--xdcr-password <password>]
2020
[--xdcr-user-certificate <path>] [--xdcr-user-key <path>]
@@ -38,6 +38,9 @@ include::{partialsdir}/cbcli/part-common-options.adoc[]
3838
--edit::
3939
Edits an XDCR remote reference.
4040

41+
--stage::
42+
Adds staged credentials to the XDCR remote reference.
43+
4144
--list::
4245
List all XDCR remote references.
4346

@@ -84,7 +87,7 @@ To create a new remote reference to a Couchbase cluster named "east" run the
8487
following command.
8588

8689
$ couchbase-cli xdcr-setup -c 192.168.1.5 -u Administrator \
87-
-p password --create --xdcr-cluster-name east --xdcr-hostname 192.168.1.6
90+
-p password --create --xdcr-cluster-name east --xdcr-hostname 192.168.1.6 \
8891
--xdcr-username Administrator --xdcr-password password
8992

9093
If the new remote reference should always be encrypted then make sure to enable
@@ -104,12 +107,20 @@ If you need to edit a cluster references named "east" and change the password
104107
run the following command.
105108

106109
$ couchbase-cli xdcr-setup -c 192.168.1.5 -u Administrator \
107-
-p password --edit --xdcr-cluster-name east --xdcr-hostname 192.168.1.6
110+
-p password --edit --xdcr-cluster-name east --xdcr-hostname 192.168.1.6 \
108111
--xdcr-username Administrator --xdcr-password new_password
109112

110113
Note in the above example that you need to specify all of the current unchanging
111114
configuration parameters also to avoid them being reset to defaults.
112115

116+
Remote references can have "staged" credentials which are used if the first set
117+
start failing. Username and password or client certificate and key can be passed.
118+
These can be set like so.
119+
120+
$ couchbase-cli xdcr-setup -c 192.168.1.5 -u Administrator \
121+
-p password --stage --xdcr-cluster-name east \
122+
--xdcr-username Admin2 --xdcr-password password
123+
113124
If you no longer need an XDCR remote reference then you can delete it. We should
114125
this below using the "east" remote reference as an example.
115126

test/test_cli.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3133,6 +3133,12 @@ def test_edit_xdcr_cert(self):
31333133
f'clientCertificate={contents}', f'clientKey={contents}', f'certificate={contents}']
31343134
self.rest_parameter_match(expected_params)
31353135

3136+
def test_stage_xdcr(self):
3137+
self.no_error_run(self.command + ['--stage'] + self.cmd_args_without_hostname, self.server_args)
3138+
self.assertIn('POST:/pools/default/remoteClusters/name', self.server.trace)
3139+
expected_params = ['stage=true', 'username=username', 'password=pwd']
3140+
self.rest_parameter_match(expected_params)
3141+
31363142
def test_list_xdcr(self):
31373143
self.server_args['remote-clusters'] = [{'name': 'name', 'uuid': '1', 'hostname': 'host', 'username': 'user',
31383144
'uri': 'uri', 'deleted': False, 'stage': {'username': 'other-user'}}]

0 commit comments

Comments
 (0)