Skip to content

Commit 8276a92

Browse files
committed
MB-70103 Add backup-service repo-add command
The names of a few flags have been changed: --s3-force-path-style has been changed to --cloud-force-path-style to make it consistent with the body parameter. --backup-archive has been changed to --location to avoid confusion with the repo-archive command and to allow for the term "archive" to be removed in the future without breaking backwards compatibility. Duplicates the functionality of backup-service repository --add which will be deprecated. Change-Id: I3f462150463907540ab35c2efc55ccbd77a37a02 Reviewed-on: https://review.couchbase.org/c/couchbase-cli/+/238411 Reviewed-by: Safian Ali <safian.ali@couchbase.com> Tested-by: Build Bot <build@couchbase.com>
1 parent 2ee9dd9 commit 8276a92

9 files changed

Lines changed: 550 additions & 5 deletions

cbmgr.py

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""A Couchbase CLI subcommand"""
22

3+
import argparse
34
import dataclasses
45
import getpass
56
import inspect
@@ -6997,11 +6998,12 @@ def __init__(self):
69976998
self.repository_cmd = BackupServiceRepository(self.subparser)
69986999
self.repo_list_cmd = BackupServiceRepoList(self.subparser)
69997000
self.repo_get_cmd = BackupServiceRepoGet(self.subparser)
7001+
self.repo_add_cmd = BackupServiceRepoAdd(self.subparser)
70007002
self.plan_cmd = BackupServicePlan(self.subparser)
70017003
self.nodeThreads_cmd = BackupServiceNodeThreadsMap(self.subparser)
70027004

70037005
def execute(self, opts):
7004-
subcommands = ['settings', 'repository', 'repo-list', 'repo-get', 'plan', 'node-threads']
7006+
subcommands = ['settings', 'repository', 'repo-list', 'repo-get', 'repo-add', 'plan', 'node-threads']
70057007

70067008
if opts.sub_cmd is None or opts.sub_cmd not in subcommands:
70077009
_exit_if_errors([f'<subcommand> must be one of {subcommands}'])
@@ -7014,6 +7016,8 @@ def execute(self, opts):
70147016
self.repo_list_cmd.execute(opts)
70157017
elif opts.sub_cmd == 'repo-get':
70167018
self.repo_get_cmd.execute(opts)
7019+
elif opts.sub_cmd == 'repo-add':
7020+
self.repo_add_cmd.execute(opts)
70177021
elif opts.sub_cmd == 'plan':
70187022
self.plan_cmd.execute(opts)
70197023
elif opts.sub_cmd == 'node-threads':
@@ -7205,6 +7209,32 @@ def human_friendly_print_repositories(repositories_map):
72057209
f" {healthy!s:<7}| {repository['repo']}")
72067210

72077211

7212+
def check_cloud_params(location: str, opts: argparse.Namespace) -> Optional[List[str]]:
7213+
"""Checks that inside kwargs there is a valid set of parameters to add a cloud repository
7214+
Args:
7215+
location (str): The location to use for the repository.
7216+
opts (argparse.Namespace): The options dict containing the cloud params.
7217+
"""
7218+
if not location.startswith('s3://') and not location.startswith('az://') and not location.startswith('gs://'):
7219+
return None
7220+
7221+
creds_name = opts.cloud_credentials_name
7222+
region = opts.cloud_region
7223+
creds_id = opts.cloud_credentials_id
7224+
creds_key = opts.cloud_credentials_key
7225+
staging_dir = opts.cloud_staging_dir
7226+
7227+
if (creds_name and (creds_id or creds_key)) or (not creds_name and not (creds_id or creds_key)):
7228+
return ['must provide either --cloud-credentials-name or --cloud-credentials-key and '
7229+
'--cloud-credentials-id']
7230+
if not staging_dir:
7231+
return ['--cloud-staging-dir is required']
7232+
if not creds_name and not region:
7233+
return ['--cloud-credentials-region is required']
7234+
7235+
return None
7236+
7237+
72087238
class BackupServiceRepoList:
72097239
"""List the backup repositories.
72107240
@@ -7283,6 +7313,93 @@ def get_description():
72837313
return 'Retrieves a repository from the backup service'
72847314

72857315

7316+
class BackupServiceRepoAdd:
7317+
"""Adds a new active repository identified by a repository ID and that uses a plan as base.
7318+
"""
7319+
7320+
def __init__(self, subparser):
7321+
"""setup the parser"""
7322+
self.rest = None
7323+
repository_parser = subparser.add_parser('repo-add', help='Adds a new active repository', add_help=False,
7324+
allow_abbrev=False)
7325+
7326+
group = repository_parser.add_argument_group('Backup service repository configuration')
7327+
group.add_argument('--id', metavar='<id>', help='The repository id', required=True)
7328+
group.add_argument('--plan', metavar='<plan_name>', help='The plan to use as base for the repository',
7329+
required=True)
7330+
group.add_argument('--location', metavar='<location>', help='The location to store the backups in',
7331+
required=True)
7332+
group.add_argument('--bucket-name', metavar='<bucket_name>', help='The bucket to backup')
7333+
7334+
# the cloud arguments are given the own group so that the short help is a bit more readable
7335+
cloud_group = repository_parser.add_argument_group('Backup repository cloud arguments')
7336+
cloud_group.add_argument('--cloud-credentials-name', metavar='<name>',
7337+
help='The stored clouds credential name to use for the new repository')
7338+
cloud_group.add_argument('--cloud-staging-dir', metavar='<path>', help='The path to the staging directory')
7339+
cloud_group.add_argument('--cloud-credentials-id', metavar='<id>',
7340+
help='The ID to use to communicate with the object store')
7341+
cloud_group.add_argument('--cloud-credentials-key', metavar='<key>',
7342+
help='The key to use to communicate with the object store')
7343+
cloud_group.add_argument('--cloud-credentials-refresh-token', metavar='<token>',
7344+
help='Used to refresh oauth2 tokens when accessing remote storage')
7345+
cloud_group.add_argument('--cloud-region', metavar='<region>',
7346+
help='The region for the object store')
7347+
cloud_group.add_argument('--cloud-endpoint', metavar='<endpoint>',
7348+
help='Overrides the default endpoint used to communicate with the cloud provider. '
7349+
'Use for object store compatible third party solutions')
7350+
cloud_group.add_argument('--cloud-force-path-style', action='store_true',
7351+
help='When using S3 or S3 compatible storage it will use the old path style.')
7352+
7353+
@rest_initialiser(version_check=True, enterprise_check=True, cluster_init_check=True)
7354+
def execute(self, opts):
7355+
"""Run the backup-service repo-add subcommand"""
7356+
_exit_if_errors(check_cloud_params(opts.location, opts))
7357+
7358+
request_body = {
7359+
"plan": opts.plan,
7360+
"archive": opts.location,
7361+
}
7362+
7363+
if opts.bucket_name is not None:
7364+
request_body["bucket_name"] = opts.bucket_name
7365+
7366+
if opts.cloud_credentials_name is not None:
7367+
request_body["cloud_credential_name"] = opts.cloud_credentials_name
7368+
7369+
if opts.cloud_credentials_id is not None:
7370+
request_body["cloud_credentials_id"] = opts.cloud_credentials_id
7371+
7372+
if opts.cloud_credentials_key is not None:
7373+
request_body["cloud_credentials_key"] = opts.cloud_credentials_key
7374+
7375+
if opts.cloud_credentials_refresh_token is not None:
7376+
request_body["cloud_credentials_refresh_token"] = opts.cloud_credentials_refresh_token
7377+
7378+
if opts.cloud_region is not None:
7379+
request_body["cloud_region"] = opts.cloud_region
7380+
7381+
if opts.cloud_endpoint is not None:
7382+
request_body["cloud_endpoint"] = opts.cloud_endpoint
7383+
7384+
if opts.cloud_staging_dir is not None:
7385+
request_body["cloud_staging_dir"] = opts.cloud_staging_dir
7386+
7387+
if opts.cloud_force_path_style is not None:
7388+
request_body["cloud_force_path_style"] = opts.cloud_force_path_style
7389+
7390+
_, errors = self.rest.add_backup_active_repository(opts.id, request_body)
7391+
_exit_if_errors(errors)
7392+
_success('Added repository')
7393+
7394+
@staticmethod
7395+
def get_man_page_name():
7396+
return get_doc_page_name("couchbase-cli-backup-service-repo-add")
7397+
7398+
@staticmethod
7399+
def get_description():
7400+
return 'Adds a new active repository'
7401+
7402+
72867403
class BackupServiceRepository:
72877404
"""This command manages backup services repositories.
72887405

docs/modules/cli/pages/_partials/cbcli/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
** xref:cli:cbcli/couchbase-cli-backup-service.adoc[backup-service]
55
** xref:cli:cbcli/couchbase-cli-backup-service-nodes-threads-map.adoc[backup-service nodes-threads-map]
66
** xref:cli:cbcli/couchbase-cli-backup-service-plan.adoc[backup-service plan]
7+
** xref:cli:cbcli/couchbase-cli-backup-service-repo-add.adoc[backup-service repo-add]
78
** xref:cli:cbcli/couchbase-cli-backup-service-repo-get.adoc[backup-service repo-get]
89
** xref:cli:cbcli/couchbase-cli-backup-service-repo-list.adoc[backup-service repo-list]
910
** xref:cli:cbcli/couchbase-cli-backup-service-repository.adoc[backup-service repository]
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
= couchbase-cli-backup-service-repo-add(1)
2+
:description: Add a new backup service repository
3+
ifndef::doctype-manpage[:doctitle: backup-service repo-add]
4+
5+
ifdef::doctype-manpage[]
6+
== NAME
7+
8+
couchbase-cli-backup-service-repo-add -
9+
endif::[]
10+
Add a new backup service repository
11+
12+
== SYNOPSIS
13+
14+
[verse]
15+
_couchbase-cli backup-service_ [--cluster <url>] [--username <user>]
16+
[--password <password>] [--client-cert <path>]
17+
[--client-cert-password <password>] [--client-key <path>]
18+
[--client-key-password <password>] _repo-add_ [--id <id>]
19+
[--plan <plan_name>] [--location <location>] [--bucket-name <bucket_name>]
20+
[--cloud-credentials-name <name>] [--cloud-staging-dir <path>]
21+
[--cloud-credentials-id <id>] [--cloud-credentials-key <key>]
22+
[--cloud-credentials-refresh-token <token>] [--cloud-region <region>]
23+
[--cloud-endpoint <endpoint>] [--cloud-force-path-style]
24+
25+
== DESCRIPTION
26+
27+
Adds a new active backup repository to the backup service. The repository
28+
will be created with the specified ID and will use the given plan as its base
29+
configuration. The plan defines the backup schedules and which services to
30+
back up. Backups will be stored at the specified location.
31+
32+
This command also supports creating cloud backup repositories that store data
33+
directly in object storage such as S3, Azure, GCP or compatible stores.
34+
35+
== OPTIONS
36+
37+
--id <id>::
38+
The unique identifier for the new repository. This argument is required.
39+
40+
--plan <plan_name>::
41+
The name of the plan to use as the base configuration for this repository.
42+
The plan defines backup schedules and which services to include. This
43+
argument is required.
44+
45+
--location <location>::
46+
The location where backups will be stored. This location should be
47+
accessible by all backup nodes. This argument is required.
48+
49+
--bucket-name <bucket_name>::
50+
Optionally specify a single bucket to back up. If not provided, all
51+
buckets will be included in the backup.
52+
53+
== CLOUD OPTIONS
54+
55+
The following options are used when creating a cloud backup repository that
56+
stores data in object storage.
57+
58+
--cloud-credentials-name <name>::
59+
The name of a stored cloud credential set to use for this repository.
60+
If specified, you do not need to provide `--cloud-credentials-id` and
61+
`--cloud-credentials-key`.
62+
63+
--cloud-staging-dir <path>::
64+
The path to a staging directory used temporarily during cloud backups.
65+
This path must be accessible by all backup nodes and should have enough
66+
space for roughly 10% of the dataset size. Required when using cloud
67+
storage.
68+
69+
--cloud-credentials-id <id>::
70+
The ID used to authenticate with the object store.
71+
72+
--cloud-credentials-key <key>::
73+
The key used to authenticate with the object store.
74+
75+
--cloud-credentials-refresh-token <token>::
76+
A refresh token used to obtain new OAuth2 tokens when accessing remote
77+
storage.
78+
79+
--cloud-region <region>::
80+
The region where the object store bucket is located (e.g., `us-east-1`).
81+
82+
--cloud-endpoint <endpoint>::
83+
Overrides the default endpoint used to communicate with the cloud provider.
84+
Use this for third-party object store solutions.
85+
86+
--cloud-force-path-style::
87+
When using S3 or S3-compatible storage, use the legacy path-style URLs
88+
instead of virtual-hosted-style URLs. Some S3-compatible stores require
89+
this option.
90+
91+
include::{partialsdir}/cbcli/part-common-options.adoc[]
92+
93+
include::{partialsdir}/cbcli/part-host-formats.adoc[]
94+
95+
include::{partialsdir}/cbcli/part-certificate-authentication.adoc[]
96+
97+
== EXAMPLES
98+
99+
=== Adding a basic repository
100+
101+
To add a new backup repository with ID 'weekly-backup' using the '_weekly'
102+
plan and storing backups in '/backup/data', run the following command.
103+
104+
----
105+
$ couchbase-cli backup-service -c 127.0.0.1:8091 -u Administrator -p password \
106+
repo-add --id weekly-backup --plan _weekly --location /backup/data
107+
----
108+
109+
In the command above we are adding a new repository with name `weekly-backup`
110+
that is using a base plan `_weekly`. The base plan defines the schedules of
111+
the tasks that the repository will run as well as what services it will backup.
112+
The location is where the backups will be stored. This location is equivalent
113+
to a cbbackupmgr archive. Also `cbbackupmgr` should *not* be run on the
114+
archives managed by the service directly.
115+
116+
=== Adding a repository for a specific bucket
117+
118+
If you want a repository that only backs up one bucket or want different backup
119+
schedules for each bucket, this can be achieved by using the `--bucket-name`
120+
argument to specify which bucket the repository should backup.
121+
122+
----
123+
$ couchbase-cli backup-service -c 127.0.0.1:8091 -u Administrator -p password \
124+
repo-add --id beer-backup --plan _daily --location /backup/beer \
125+
--bucket-name beer-sample
126+
----
127+
128+
=== Adding a cloud backup repository
129+
130+
The service supports creating cloud backup repositories. These are repositories
131+
that backup directly to object store. Currently supported object stores include
132+
S3, Azure, GCP, and S3-compatible stores. To create a cloud repository you will
133+
need to supply some additional details, as illustrated in the example below.
134+
135+
----
136+
$ couchbase-cli backup-service -c 127.0.0.1:8091 -u Administrator -p password \
137+
repo-add --id cloud-backup --plan _daily --location s3://bucket/archive \
138+
--cloud-staging-dir /backup/staging --cloud-credentials-id id \
139+
--cloud-credentials-key key --cloud-region us-east-1
140+
----
141+
142+
In the command above we can see that the archive supplied for cloud starts
143+
with the schema `s3://` followed by the bucket name, after which the path to
144+
the archive in S3 must be given. A *staging directory* must also be supplied.
145+
This is a location where cbbackupmgr will temporarily store data whilst doing
146+
cloud backups. This path must be available on all backup nodes and should have
147+
space for roughly 10% of the data set size as reported by the UI. In the command
148+
above we have also supplied the cloud credential ID, key and region. These are
149+
the details that will be used to communicate with S3.
150+
151+
=== Using stored cloud credentials
152+
153+
Credentials can be stored and reused in the backup service. If you already have
154+
the correct set of credentials stored you can use `--cloud-credentials-name`
155+
instead of providing the ID, key and region flags.
156+
157+
----
158+
$ couchbase-cli backup-service -c 127.0.0.1:8091 -u Administrator -p password \
159+
repo-add --id cloud-backup --plan _weekly --location s3://bucket/archive \
160+
--cloud-staging-dir /backup/staging --cloud-credentials-name creds
161+
----
162+
163+
=== Using S3-compatible storage
164+
165+
For S3-compatible stores you can use the `--cloud-endpoint` argument to override
166+
the endpoint used to communicate with S3 and point it to your storage solution
167+
address. Some S3-compatible storages only support the old S3 path styles; to use
168+
those supply the `--cloud-force-path-style` argument.
169+
170+
----
171+
$ couchbase-cli backup-service -c 127.0.0.1:8091 -u Administrator -p password \
172+
repo-add --id minio-backup --plan _daily --location s3://bucket/backups \
173+
--cloud-staging-dir /backup/staging --cloud-credentials-id id \
174+
--cloud-credentials-key key --cloud-endpoint http://localhost:9000 \
175+
--cloud-force-path-style
176+
----
177+
178+
== ENVIRONMENT AND CONFIGURATION VARIABLES
179+
180+
include::{partialsdir}/cbcli/part-common-env.adoc[]
181+
182+
== SEE ALSO
183+
184+
man:couchbase-cli-backup-service[1],
185+
man:couchbase-cli-backup-service-repo-get[1],
186+
man:couchbase-cli-backup-service-repo-list[1],
187+
man:couchbase-cli-backup-service-plan[1]
188+
189+
include::{partialsdir}/cbcli/part-footer.adoc[]
190+

docs/modules/cli/pages/cbcli/couchbase-cli-backup-service-repo-get.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ include::{partialsdir}/cbcli/part-common-env.adoc[]
123123
124124
man:couchbase-cli-backup-service[1],
125125
man:couchbase-cli-backup-service-repo-list[1],
126+
man:couchbase-cli-backup-service-repo-add[1]
126127
127128
include::{partialsdir}/cbcli/part-footer.adoc[]
128129

docs/modules/cli/pages/cbcli/couchbase-cli-backup-service-repo-list.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ include::{partialsdir}/cbcli/part-common-env.adoc[]
112112
== SEE ALSO
113113

114114
man:couchbase-cli-backup-service[1],
115-
man:couchbase-cli-backup-service-repo-get[1]
115+
man:couchbase-cli-backup-service-repo-get[1],
116+
man:couchbase-cli-backup-service-repo-add[1]
116117

117118
include::{partialsdir}/cbcli/part-footer.adoc[]
118119

docs/modules/cli/pages/cbcli/couchbase-cli-backup-service-repository.adoc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,7 @@ In the command above we are adding a new repository with name `new-repository` t
158158
base profile `_weekly`. The base profile defines the schedules of the tasks that the
159159
repository will run as well as what services it will backup. Finally the backup archive is the
160160
location where the backups will stored. This location is equivalent to a cbbackupmgr
161-
archive. Two repository should *not* use the same archive. Also `cbbackupmgr` should *not*
162-
be run on the archives managed by the service directly.
161+
archive. Also `cbbackupmgr` should *not* be run on the archives managed by the service directly.
163162

164163
If you want an repository that only backs up one bucket or want different backup schedules
165164
for each bucket this can be achieved by using the `--bucket-name` argument to specify
@@ -192,7 +191,7 @@ by the UI. In the command above we have also supplied the cloud credential ID, k
192191
region. This are the details that will be used to communicate with S3. Note that
193192
credentials can be stored and reused in the backup service so if you already have
194193
the correct set of credentials stored you can replace the id, key and region flags by
195-
`--cloud-credential-name` and give the name of the credential set you want to re-use.
194+
`--cloud-credentials-name` and give the name of the credential set you want to re-use.
196195

197196
Finally, for S3 compatible stores you can use the `--cloud-endpoint` argument to override
198197
the endpoint use to communicate with S3 and point it to your storage solution address.

0 commit comments

Comments
 (0)