Skip to content

Commit b33be6f

Browse files
CLOUDP-285951: add support for flex clusters to "atlas backup restores start"
1 parent 7db2572 commit b33be6f

File tree

4 files changed

+104
-12
lines changed

4 files changed

+104
-12
lines changed

docs/command/atlas-backups-restores-start.txt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ Start a restore job for your project and cluster.
1717
If you create an automated or pointInTime restore job, Atlas removes all existing data on the target cluster prior to the restore.
1818

1919
To use this command, you must authenticate with a user account or an API key with the Project Owner role.
20-
Atlas supports this command only for M10+ clusters.
20+
Atlas supports this command only for Flex and M10+ clusters.
21+
Flex clusters support only automated restore jobs.
2122

2223
Syntax
2324
------
@@ -137,6 +138,17 @@ Examples
137138
--targetProjectId 1a2345b67c8e9a12f3456de7
138139

139140

141+
.. code-block::
142+
:copyable: false
143+
144+
# Create an automated restore for a Flex Cluster:
145+
atlas backup restore start automated \
146+
--clusterName myFlexSource \
147+
--snapshotId 5e7e00128f8ce03996a47179 \
148+
--targetClusterName myFlexCluster \
149+
--targetProjectId 1a2345b67c8e9a12f3456de7
150+
151+
140152
.. code-block::
141153
:copyable: false
142154

internal/cli/backup/restores/restores.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ import (
1919
"github.com/spf13/cobra"
2020
)
2121

22+
const (
23+
cannotUseNotFlexWithFlexApisErrorCode = "CANNOT_USE_NON_FLEX_CLUSTER_IN_FLEX_API"
24+
)
25+
2226
func Builder() *cobra.Command {
2327
const use = "restores"
2428
cmd := &cobra.Command{

internal/cli/backup/restores/start.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,37 @@ func (opts *StartOpts) initStore(ctx context.Context) func() error {
6060
var startTemplate = "Restore job '{{.Id}}' successfully started\n"
6161

6262
func (opts *StartOpts) Run() error {
63+
r, err := opts.store.CreateRestoreFlexClusterJobs(opts.ConfigProjectID(), opts.clusterName, opts.newFlexBackupRestoreJobCreate())
64+
if err == nil {
65+
return opts.Print(r)
66+
}
67+
68+
apiError, ok := admin.AsError(err)
69+
if !ok {
70+
return commonerrors.Check(err)
71+
}
72+
73+
if apiError.ErrorCode != cannotUseNotFlexWithFlexApisErrorCode {
74+
return commonerrors.Check(err)
75+
}
76+
6377
request := opts.newCloudProviderSnapshotRestoreJob()
64-
r, err := opts.store.CreateRestoreJobs(opts.ConfigProjectID(), opts.clusterName, request)
78+
restoreJob, err := opts.store.CreateRestoreJobs(opts.ConfigProjectID(), opts.clusterName, request)
6579

6680
if err != nil {
6781
return commonerrors.Check(err)
6882
}
6983

70-
return opts.Print(r)
84+
return opts.Print(restoreJob)
85+
}
86+
87+
func (opts *StartOpts) newFlexBackupRestoreJobCreate() *admin.FlexBackupRestoreJobCreate20241113 {
88+
return &admin.FlexBackupRestoreJobCreate20241113{
89+
SnapshotId: opts.snapshotID,
90+
TargetDeploymentItemName: opts.targetClusterName,
91+
TargetProjectId: &opts.targetProjectID,
92+
InstanceName: &opts.clusterName,
93+
}
7194
}
7295

7396
func (opts *StartOpts) newCloudProviderSnapshotRestoreJob() *admin.DiskBackupSnapshotRestoreJob {
@@ -134,6 +157,7 @@ func markRequiredPointInTimeRestoreFlags(cmd *cobra.Command) error {
134157
return cmd.MarkFlagRequired(flag.TargetClusterName)
135158
}
136159

160+
// StartBuilder builds a cobra.Command that can run as:
137161
// atlas backup(s) restore(s) job(s) start <automated|download|pointInTime>.
138162
func StartBuilder() *cobra.Command {
139163
opts := new(StartOpts)
@@ -142,7 +166,8 @@ func StartBuilder() *cobra.Command {
142166
Short: "Start a restore job for your project and cluster.",
143167
Long: `If you create an automated or pointInTime restore job, Atlas removes all existing data on the target cluster prior to the restore.
144168
145-
` + fmt.Sprintf("%s\n%s", fmt.Sprintf(usage.RequiredRole, "Project Owner"), "Atlas supports this command only for M10+ clusters."),
169+
` + fmt.Sprintf("%s\n%s\n%s", fmt.Sprintf(usage.RequiredRole, "Project Owner"), "Atlas supports this command only for Flex and M10+ clusters.",
170+
"Flex clusters support only automated restore jobs."),
146171
Args: require.ExactValidArgs(1),
147172
ValidArgs: []string{automatedRestore, downloadRestore, pointInTimeRestore},
148173
Annotations: map[string]string{
@@ -156,6 +181,13 @@ func StartBuilder() *cobra.Command {
156181
--targetClusterName myDemo2 \
157182
--targetProjectId 1a2345b67c8e9a12f3456de7
158183
184+
# Create an automated restore for a Flex Cluster:
185+
atlas backup restore start automated \
186+
--clusterName myFlexSource \
187+
--snapshotId 5e7e00128f8ce03996a47179 \
188+
--targetClusterName myFlexCluster \
189+
--targetProjectId 1a2345b67c8e9a12f3456de7
190+
159191
# Create a point-in-time restore:
160192
atlas backup restore start pointInTime \
161193
--clusterName myDemo \

internal/cli/backup/restores/start_test.go

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/golang/mock/gomock"
2323
"github.com/mongodb/mongodb-atlas-cli/atlascli/internal/mocks"
24+
"github.com/stretchr/testify/require"
2425
atlasv2 "go.mongodb.org/atlas-sdk/v20241113002/admin"
2526
)
2627

@@ -39,15 +40,44 @@ func TestStart_Run(t *testing.T) {
3940
targetProjectID: "1",
4041
}
4142

43+
expectedError := &atlasv2.GenericOpenAPIError{}
44+
expectedError.SetModel(atlasv2.ApiError{ErrorCode: cannotUseNotFlexWithFlexApisErrorCode})
45+
46+
mockStore.
47+
EXPECT().
48+
CreateRestoreFlexClusterJobs(listOpts.ProjectID, "Cluster0", listOpts.newFlexBackupRestoreJobCreate()).
49+
Return(nil, expectedError).
50+
Times(1)
51+
4252
mockStore.
4353
EXPECT().
4454
CreateRestoreJobs(listOpts.ProjectID, "Cluster0", listOpts.newCloudProviderSnapshotRestoreJob()).
4555
Return(expected, nil).
4656
Times(1)
4757

48-
if err := listOpts.Run(); err != nil {
49-
t.Fatalf("Run() unexpected error: %v", err)
58+
require.NoError(t, listOpts.Run())
59+
})
60+
61+
t.Run("Flex Cluster automated restore job", func(t *testing.T) {
62+
listOpts := &StartOpts{
63+
store: mockStore,
64+
method: automatedRestore,
65+
clusterName: "Cluster0",
66+
targetClusterName: "Cluster1",
67+
targetProjectID: "1",
5068
}
69+
70+
expectedFlex := &atlasv2.FlexBackupRestoreJob20241113{}
71+
expectedError := &atlasv2.GenericOpenAPIError{}
72+
expectedError.SetModel(atlasv2.ApiError{ErrorCode: cannotUseNotFlexWithFlexApisErrorCode})
73+
74+
mockStore.
75+
EXPECT().
76+
CreateRestoreFlexClusterJobs(listOpts.ProjectID, "Cluster0", listOpts.newFlexBackupRestoreJobCreate()).
77+
Return(expectedFlex, nil).
78+
Times(1)
79+
80+
require.NoError(t, listOpts.Run())
5181
})
5282

5383
t.Run(pointInTimeRestore, func(t *testing.T) {
@@ -59,15 +89,22 @@ func TestStart_Run(t *testing.T) {
5989
targetProjectID: "1",
6090
}
6191

92+
expectedError := &atlasv2.GenericOpenAPIError{}
93+
expectedError.SetModel(atlasv2.ApiError{ErrorCode: cannotUseNotFlexWithFlexApisErrorCode})
94+
95+
mockStore.
96+
EXPECT().
97+
CreateRestoreFlexClusterJobs(listOpts.ProjectID, "Cluster0", listOpts.newFlexBackupRestoreJobCreate()).
98+
Return(nil, expectedError).
99+
Times(1)
100+
62101
mockStore.
63102
EXPECT().
64103
CreateRestoreJobs(listOpts.ProjectID, "Cluster0", listOpts.newCloudProviderSnapshotRestoreJob()).
65104
Return(expected, nil).
66105
Times(1)
67106

68-
if err := listOpts.Run(); err != nil {
69-
t.Fatalf("Run() unexpected error: %v", err)
70-
}
107+
require.NoError(t, listOpts.Run())
71108
})
72109

73110
t.Run(downloadRestore, func(t *testing.T) {
@@ -77,14 +114,21 @@ func TestStart_Run(t *testing.T) {
77114
clusterName: "Cluster0",
78115
}
79116

117+
expectedError := &atlasv2.GenericOpenAPIError{}
118+
expectedError.SetModel(atlasv2.ApiError{ErrorCode: cannotUseNotFlexWithFlexApisErrorCode})
119+
120+
mockStore.
121+
EXPECT().
122+
CreateRestoreFlexClusterJobs(listOpts.ProjectID, "Cluster0", listOpts.newFlexBackupRestoreJobCreate()).
123+
Return(nil, expectedError).
124+
Times(1)
125+
80126
mockStore.
81127
EXPECT().
82128
CreateRestoreJobs(listOpts.ProjectID, "Cluster0", listOpts.newCloudProviderSnapshotRestoreJob()).
83129
Return(expected, nil).
84130
Times(1)
85131

86-
if err := listOpts.Run(); err != nil {
87-
t.Fatalf("Run() unexpected error: %v", err)
88-
}
132+
require.NoError(t, listOpts.Run())
89133
})
90134
}

0 commit comments

Comments
 (0)