Skip to content

Commit ef38e70

Browse files
committed
MB-70103 Add backup-service repo-archive command
Duplicates the functionality of backup-service repository --archive which will be deprecated. Change-Id: If4da8a31b0e64bec4b26e2295440b9bcf4fc89d4 Reviewed-on: https://review.couchbase.org/c/couchbase-cli/+/238412 Reviewed-by: Safian Ali <safian.ali@couchbase.com> Tested-by: Build Bot <build@couchbase.com>
1 parent 8276a92 commit ef38e70

8 files changed

Lines changed: 174 additions & 3 deletions

cbmgr.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6999,11 +6999,13 @@ def __init__(self):
69996999
self.repo_list_cmd = BackupServiceRepoList(self.subparser)
70007000
self.repo_get_cmd = BackupServiceRepoGet(self.subparser)
70017001
self.repo_add_cmd = BackupServiceRepoAdd(self.subparser)
7002+
self.repo_archive_cmd = BackupServiceRepoArchive(self.subparser)
70027003
self.plan_cmd = BackupServicePlan(self.subparser)
70037004
self.nodeThreads_cmd = BackupServiceNodeThreadsMap(self.subparser)
70047005

70057006
def execute(self, opts):
7006-
subcommands = ['settings', 'repository', 'repo-list', 'repo-get', 'repo-add', 'plan', 'node-threads']
7007+
subcommands = ['settings', 'repository', 'repo-list', 'repo-get', 'repo-add', 'repo-archive', 'plan',
7008+
'node-threads']
70077009

70087010
if opts.sub_cmd is None or opts.sub_cmd not in subcommands:
70097011
_exit_if_errors([f'<subcommand> must be one of {subcommands}'])
@@ -7018,6 +7020,8 @@ def execute(self, opts):
70187020
self.repo_get_cmd.execute(opts)
70197021
elif opts.sub_cmd == 'repo-add':
70207022
self.repo_add_cmd.execute(opts)
7023+
elif opts.sub_cmd == 'repo-archive':
7024+
self.repo_archive_cmd.execute(opts)
70217025
elif opts.sub_cmd == 'plan':
70227026
self.plan_cmd.execute(opts)
70237027
elif opts.sub_cmd == 'node-threads':
@@ -7400,6 +7404,37 @@ def get_description():
74007404
return 'Adds a new active repository'
74017405

74027406

7407+
class BackupServiceRepoArchive:
7408+
"""Archive a repository. The archived repository will have a new id.
7409+
"""
7410+
7411+
def __init__(self, subparser):
7412+
"""setup the parser"""
7413+
self.rest = None
7414+
repository_parser = subparser.add_parser('repo-archive', help='Archive a repository', add_help=False,
7415+
allow_abbrev=False)
7416+
7417+
group = repository_parser.add_argument_group('Backup service repository configuration')
7418+
group.add_argument('--id', metavar='<id>', help='The repository id', required=True)
7419+
group.add_argument('--new-id', metavar='<id>', help='The new repository id', required=True)
7420+
7421+
@rest_initialiser(version_check=True, enterprise_check=True, cluster_init_check=True)
7422+
def execute(self, opts):
7423+
"""Run the backup-service repo-archive subcommand"""
7424+
7425+
_, errors = self.rest.archive_backup_repository(opts.id, opts.new_id)
7426+
_exit_if_errors(errors)
7427+
_success('Repository was archived')
7428+
7429+
@staticmethod
7430+
def get_man_page_name():
7431+
return get_doc_page_name("couchbase-cli-backup-service-repo-archive")
7432+
7433+
@staticmethod
7434+
def get_description():
7435+
return 'Archive a repository'
7436+
7437+
74037438
class BackupServiceRepository:
74047439
"""This command manages backup services repositories.
74057440

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
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]
77
** xref:cli:cbcli/couchbase-cli-backup-service-repo-add.adoc[backup-service repo-add]
8+
** xref:cli:cbcli/couchbase-cli-backup-service-repo-archive.adoc[backup-service repo-archive]
89
** xref:cli:cbcli/couchbase-cli-backup-service-repo-get.adoc[backup-service repo-get]
910
** xref:cli:cbcli/couchbase-cli-backup-service-repo-list.adoc[backup-service repo-list]
1011
** xref:cli:cbcli/couchbase-cli-backup-service-repository.adoc[backup-service repository]

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,9 @@ include::{partialsdir}/cbcli/part-common-env.adoc[]
184184
man:couchbase-cli-backup-service[1],
185185
man:couchbase-cli-backup-service-repo-get[1],
186186
man:couchbase-cli-backup-service-repo-list[1],
187+
man:couchbase-cli-backup-service-repo-archive[1],
187188
man:couchbase-cli-backup-service-plan[1]
188189

190+
189191
include::{partialsdir}/cbcli/part-footer.adoc[]
190192

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
= couchbase-cli-backup-service-repo-archive(1)
2+
:description: Archive a backup service repository
3+
ifndef::doctype-manpage[:doctitle: backup-service repo-archive]
4+
5+
ifdef::doctype-manpage[]
6+
== NAME
7+
8+
couchbase-cli-backup-service-repo-archive -
9+
endif::[]
10+
Archive a 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-archive_ [--id <id>]
19+
[--new-id <new_id>]
20+
21+
== DESCRIPTION
22+
23+
Archives an active backup repository. When a repository is archived, it is
24+
moved from the active state to the archived state and is assigned a new ID.
25+
This action is not reversible. Archived repositories no longer run scheduled
26+
backup tasks but their data remains accessible for restore operations.
27+
28+
This command is useful when you want to stop scheduled backups for a repository
29+
while keeping the backup data available.
30+
31+
== OPTIONS
32+
33+
--id <id>::
34+
The ID of the active repository to archive. This argument is required.
35+
36+
--new-id <new_id>::
37+
The new ID to assign to the archived repository. This argument is required.
38+
The new ID must be unique and cannot conflict with existing repository IDs.
39+
40+
include::{partialsdir}/cbcli/part-common-options.adoc[]
41+
42+
include::{partialsdir}/cbcli/part-host-formats.adoc[]
43+
44+
include::{partialsdir}/cbcli/part-certificate-authentication.adoc[]
45+
46+
== EXAMPLES
47+
48+
To archive an active repository with ID 'weekly-backup' and assign it a new
49+
ID of 'weekly-backup-archived', run the following command.
50+
51+
----
52+
$ couchbase-cli backup-service -c 127.0.0.1:8091 -u Administrator -p password \
53+
repo-archive --id weekly-backup --new-id weekly-backup-archived
54+
----
55+
56+
After archiving, the repository will no longer run scheduled backup tasks.
57+
You can verify the repository has been archived using the `repo-get` command
58+
with the `--state archived` flag.
59+
60+
----
61+
$ couchbase-cli backup-service -c 127.0.0.1:8091 -u Administrator -p password \
62+
repo-get --id weekly-backup-archived --state archived
63+
64+
ID: weekly-backup-archived
65+
State: archived
66+
Healthy: True
67+
Archive: /path/to/archive
68+
Repository: 179a36cc-2ad9-4360-a080-42ddc98e53c7
69+
plan: _daily_backups
70+
Creation time: 2025-12-19T14:15:02.29496Z
71+
----
72+
73+
== ENVIRONMENT AND CONFIGURATION VARIABLES
74+
75+
include::{partialsdir}/cbcli/part-common-env.adoc[]
76+
77+
== SEE ALSO
78+
79+
man:couchbase-cli-backup-service[1],
80+
man:couchbase-cli-backup-service-repo-add[1],
81+
man:couchbase-cli-backup-service-repo-get[1],
82+
man:couchbase-cli-backup-service-repo-list[1]
83+
84+
include::{partialsdir}/cbcli/part-footer.adoc[]
85+

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ 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]
126+
man:couchbase-cli-backup-service-repo-add[1],
127+
man:couchbase-cli-backup-service-repo-archive[1]
127128
128129
include::{partialsdir}/cbcli/part-footer.adoc[]
129130

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
@@ -113,7 +113,8 @@ include::{partialsdir}/cbcli/part-common-env.adoc[]
113113

114114
man:couchbase-cli-backup-service[1],
115115
man:couchbase-cli-backup-service-repo-get[1],
116-
man:couchbase-cli-backup-service-repo-add[1]
116+
man:couchbase-cli-backup-service-repo-add[1],
117+
man:couchbase-cli-backup-service-repo-archive[1]
117118

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

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ man:couchbase-cli-backup-service-repo-get[1]::
4646
man:couchbase-cli-backup-service-repo-add[1]::
4747
Add a new backup service repository.
4848

49+
man:couchbase-cli-backup-service-repo-archive[1]::
50+
Archive a backup service repository.
51+
4952
include::{partialsdir}/cbcli/part-host-formats.adoc[]
5053

5154
include::{partialsdir}/cbcli/part-certificate-authentication.adoc[]

test/test_cli.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5304,6 +5304,49 @@ def test_add_repository_with_refresh_token(self):
53045304
self.assertEqual('refresh-token-value', body['cloud_credentials_refresh_token'])
53055305

53065306

5307+
class TestBackupServiceRepoArchive(CommandTest):
5308+
"""Test the backup-service repo-archive subcommand"""
5309+
5310+
def setUp(self):
5311+
self.server_args = {'enterprise': True, 'init': True, 'is_admin': True,
5312+
'/pools/default/nodeServices': {'nodesExt': [{
5313+
'hostname': host,
5314+
'services': {
5315+
'backupAPI': port,
5316+
},
5317+
}]}}
5318+
self.command = ['couchbase-cli', 'backup-service'] + cluster_connect_args + ['repo-archive']
5319+
super(TestBackupServiceRepoArchive, self).setUp()
5320+
5321+
def test_missing_id(self):
5322+
"""Test that the command fails if --id is not provided"""
5323+
self.system_exit_run(self.command + ['--new-id', 'archivedrepo'], self.server_args)
5324+
self.assertIn('--id', self.str_error)
5325+
self.assertIn('required', self.str_error)
5326+
5327+
def test_missing_new_id(self):
5328+
"""Test that the command fails if --new-id is not provided"""
5329+
self.system_exit_run(self.command + ['--id', 'activerepo'], self.server_args)
5330+
self.assertIn('--new-id', self.str_error)
5331+
self.assertIn('required', self.str_error)
5332+
5333+
def test_archive_repository_success(self):
5334+
"""Test that the command successfully archives a repository with both required parameters"""
5335+
self.no_error_run(self.command + ['--id', 'activerepo', '--new-id', 'archivedrepo'], self.server_args)
5336+
self.assertIn('POST:/api/v1/cluster/self/repository/active/activerepo/archive', self.server.trace)
5337+
self.assertIn('Repository was archived', self.str_output)
5338+
5339+
def test_archive_repository_request_body(self):
5340+
"""Test that the correct JSON body is sent in the archive request"""
5341+
self.no_error_run(self.command + ['--id', 'weeklybackup', '--new-id', 'weeklybackup_archived'],
5342+
self.server_args)
5343+
self.assertIn('POST:/api/v1/cluster/self/repository/active/weeklybackup/archive', self.server.trace)
5344+
# Verify JSON body contains expected parameters
5345+
self.assertEqual(1, len(self.server.rest_params))
5346+
body = json.loads(self.server.rest_params[0])
5347+
self.assertEqual('weeklybackup_archived', body['id'])
5348+
5349+
53075350
class TestBackupServiceSettings(CommandTest):
53085351
"""Test the backup-service settings subcommand"""
53095352

0 commit comments

Comments
 (0)