Skip to content

Commit 88bb493

Browse files
CLOUDP-93398: Allow to reclaim free space for a cluster (#761)
1 parent 9ed3f35 commit 88bb493

File tree

11 files changed

+225
-6
lines changed

11 files changed

+225
-6
lines changed

e2e/E2E-TESTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ Command | E2E Atlas | E2E OM | E2E CM
280280
| `cluster startup` | | N | N | | Y | Y |
281281
| `cluster unmanage` | | Y | Y | | Y | Y |
282282
| `cluster update` | | N | N | | Y | Y |
283+
| `cluster reclaimFreeSpace` | | Y | Y | | Y | Y |
283284
| `cluster index create` | | N | N | | Y | Y |
284285
| `dbuser create` | | N | Y | | Y | Y |
285286
| `dbuser delete` | | N | Y | | Y | Y |

e2e/cloud_manager/deploy_replica_set_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ func TestDeployReplicaSet(t *testing.T) {
114114
}
115115
})
116116

117+
t.Run("Reclaim free space", func(t *testing.T) {
118+
cmd := exec.Command(cliPath,
119+
entity,
120+
clustersEntity,
121+
"reclaimFreeSpace",
122+
clusterName,
123+
"--force",
124+
)
125+
126+
cmd.Env = os.Environ()
127+
if resp, err := cmd.CombinedOutput(); err != nil {
128+
t.Fatalf("unexpected error: %v, resp: %v\n", err, string(resp))
129+
}
130+
})
131+
132+
t.Run("Watch", watchAutomation(cliPath))
133+
117134
t.Run("Restart", func(t *testing.T) {
118135
cmd := exec.Command(cliPath,
119136
entity,

e2e/cloud_manager/deploy_sharded_cluster_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,23 @@ func TestDeployCluster(t *testing.T) {
8080

8181
t.Run("Watch", watchAutomation(cliPath))
8282

83+
t.Run("Reclaim free space", func(t *testing.T) {
84+
cmd := exec.Command(cliPath,
85+
entity,
86+
clustersEntity,
87+
"reclaimFreeSpace",
88+
clusterName,
89+
"--force",
90+
)
91+
92+
cmd.Env = os.Environ()
93+
if resp, err := cmd.CombinedOutput(); err != nil {
94+
t.Fatalf("unexpected error: %v, resp: %v\n", err, string(resp))
95+
}
96+
})
97+
98+
t.Run("Watch", watchAutomation(cliPath))
99+
83100
t.Run("Shutdown", func(t *testing.T) {
84101
cmd := exec.Command(cliPath,
85102
entity,

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ require (
2222
github.com/stretchr/testify v1.7.0
2323
github.com/tangzero/inflector v1.0.0
2424
go.mongodb.org/atlas v0.10.1
25-
go.mongodb.org/ops-manager v0.24.1-0.20210712085958-0820f6a47c22
25+
go.mongodb.org/ops-manager v0.25.0
2626
gopkg.in/yaml.v2 v2.4.0
2727
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,8 @@ go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsX
296296
go.mongodb.org/atlas v0.9.1-0.20210707095538-d4a51579e8e0/go.mod h1:MMWDsc2akjTDSG4tVQrxv/82p3QbBnqeELbtTl45sbg=
297297
go.mongodb.org/atlas v0.10.1 h1:IerzfJ7wqxJpaXen3jewg2+kUBnq2elMz2OPOz7Usas=
298298
go.mongodb.org/atlas v0.10.1/go.mod h1:MMWDsc2akjTDSG4tVQrxv/82p3QbBnqeELbtTl45sbg=
299-
go.mongodb.org/ops-manager v0.24.1-0.20210712085958-0820f6a47c22 h1:t6i0M0UtPU0r0LbU+XKu9sOEX1efB62TM24gccZtyjo=
300-
go.mongodb.org/ops-manager v0.24.1-0.20210712085958-0820f6a47c22/go.mod h1:XgJU31JIcelHxW2ilkAO+R0vsvka9QiUdJOlWWHyKSw=
299+
go.mongodb.org/ops-manager v0.25.0 h1:EtPL2rPG+V6IYsFA75BOo7rm2uIENi1derJ6v6aIY7c=
300+
go.mongodb.org/ops-manager v0.25.0/go.mod h1:XgJU31JIcelHxW2ilkAO+R0vsvka9QiUdJOlWWHyKSw=
301301
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
302302
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
303303
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=

internal/cli/opsmanager/clusters/clusters.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@ func Builder() *cobra.Command {
3131
ListBuilder(),
3232
DescribeBuilder(),
3333
CreateBuilder(),
34-
ShutdownBuilder(),
35-
StartupBuilder(),
3634
UpdateBuilder(),
3735
DeleteBuilder(),
3836
ApplyBuilder(),
3937
IndexesBuilder(),
4038
UnmanageBuilder(),
4139
RestartBuilder(),
40+
StartupBuilder(),
41+
ShutdownBuilder(),
42+
ReclaimFreeSpaceBuilder(),
4243
)
4344

4445
return cmd

internal/cli/opsmanager/clusters/clusters_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestBuilder(t *testing.T) {
2626
test.CmdValidator(
2727
t,
2828
Builder(),
29-
11,
29+
12,
3030
[]string{},
3131
)
3232
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright 2021 MongoDB Inc
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package clusters
16+
17+
import (
18+
"fmt"
19+
"strings"
20+
21+
"github.com/AlecAivazis/survey/v2"
22+
"github.com/mongodb/mongocli/internal/cli"
23+
"github.com/mongodb/mongocli/internal/cli/require"
24+
"github.com/mongodb/mongocli/internal/config"
25+
"github.com/mongodb/mongocli/internal/flag"
26+
"github.com/mongodb/mongocli/internal/store"
27+
"github.com/mongodb/mongocli/internal/usage"
28+
"github.com/spf13/cobra"
29+
"go.mongodb.org/ops-manager/atmcfg"
30+
)
31+
32+
type ReclaimFreeSpaceOpts struct {
33+
cli.GlobalOpts
34+
confirm bool
35+
clusterName string
36+
timestamp string
37+
processes []string
38+
store store.AutomationPatcher
39+
}
40+
41+
func (opts *ReclaimFreeSpaceOpts) initStore() error {
42+
var err error
43+
opts.store, err = store.New(store.AuthenticatedPreset(config.Default()))
44+
return err
45+
}
46+
47+
func (opts *ReclaimFreeSpaceOpts) Run() error {
48+
current, err := opts.store.GetAutomationConfig(opts.ConfigProjectID())
49+
if err != nil {
50+
return err
51+
}
52+
53+
err = atmcfg.ReclaimFreeSpaceForProcessesByClusterName(current, opts.clusterName, opts.timestamp, opts.processes)
54+
if err != nil {
55+
return err
56+
}
57+
58+
if err := opts.store.UpdateAutomationConfig(opts.ConfigProjectID(), current); err != nil {
59+
return err
60+
}
61+
62+
fmt.Print(cli.DeploymentStatus(config.OpsManagerURL(), opts.ConfigProjectID()))
63+
64+
return nil
65+
}
66+
67+
func (opts *ReclaimFreeSpaceOpts) Confirm() error {
68+
if opts.confirm {
69+
return nil
70+
}
71+
72+
process := opts.clusterName
73+
74+
if len(opts.processes) > 0 {
75+
process = fmt.Sprintf("%s (%s)", opts.clusterName, strings.Join(opts.processes, ", "))
76+
}
77+
78+
prompt := &survey.Confirm{
79+
Message: fmt.Sprintf("Are you sure you want to reclaim free space for: %s", process),
80+
}
81+
return survey.AskOne(prompt, &opts.confirm)
82+
}
83+
84+
// mongocli cloud-manager cluster(s) reclaimFreeSpace|rfs <clusterName> [--processName process1,process2...][--timestamp timestamp] [--force].
85+
func ReclaimFreeSpaceBuilder() *cobra.Command {
86+
opts := &ReclaimFreeSpaceOpts{}
87+
cmd := &cobra.Command{
88+
Use: "reclaimFreeSpace <clusterName>",
89+
Short: "Reclaim unused space for a cluster.",
90+
Aliases: []string{"rfs"},
91+
Args: require.ExactArgs(1),
92+
Annotations: map[string]string{
93+
"args": "clusterName",
94+
"clusterNameDesc": "Name of the cluster for which you want to reclaim free space.",
95+
},
96+
PreRunE: func(cmd *cobra.Command, args []string) error {
97+
if err := opts.PreRunE(opts.ValidateProjectID, opts.initStore); err != nil {
98+
return err
99+
}
100+
opts.clusterName = args[0]
101+
return opts.Confirm()
102+
},
103+
RunE: func(cmd *cobra.Command, args []string) error {
104+
return opts.Run()
105+
},
106+
}
107+
108+
cmd.Flags().StringSliceVar(&opts.processes, flag.ProcessName, []string{}, usage.ProcessName)
109+
cmd.Flags().BoolVar(&opts.confirm, flag.Force, false, usage.Force)
110+
cmd.Flags().StringVar(&opts.timestamp, flag.Timestamp, "", usage.ReclaimFreeSpaceTimestamp)
111+
112+
cmd.Flags().StringVar(&opts.ProjectID, flag.ProjectID, "", usage.ProjectID)
113+
114+
return cmd
115+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2021 MongoDB Inc
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// +build unit
16+
17+
package clusters
18+
19+
import (
20+
"testing"
21+
22+
"github.com/golang/mock/gomock"
23+
"github.com/mongodb/mongocli/internal/flag"
24+
"github.com/mongodb/mongocli/internal/mocks"
25+
"github.com/mongodb/mongocli/internal/test"
26+
"github.com/mongodb/mongocli/internal/test/fixture"
27+
)
28+
29+
func TestReclaimFreeSpace_Run(t *testing.T) {
30+
ctrl := gomock.NewController(t)
31+
mockStore := mocks.NewMockAutomationPatcher(ctrl)
32+
defer ctrl.Finish()
33+
34+
expected := fixture.AutomationConfig()
35+
36+
opts := &ReclaimFreeSpaceOpts{
37+
store: mockStore,
38+
confirm: true,
39+
clusterName: "myReplicaSet2",
40+
}
41+
42+
mockStore.
43+
EXPECT().
44+
GetAutomationConfig(opts.ProjectID).
45+
Return(expected, nil).
46+
Times(1)
47+
48+
mockStore.
49+
EXPECT().
50+
UpdateAutomationConfig(opts.ProjectID, expected).
51+
Return(nil).
52+
Times(1)
53+
54+
if err := opts.Run(); err != nil {
55+
t.Fatalf("Run() unexpected error: %v", err)
56+
}
57+
}
58+
59+
func TestReclaimFreeSpaceBuilder(t *testing.T) {
60+
test.CmdValidator(
61+
t,
62+
ReclaimFreeSpaceBuilder(),
63+
0,
64+
[]string{flag.ProjectID, flag.Force, flag.ProcessName},
65+
)
66+
}

internal/flag/flags.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,5 +250,6 @@ const (
250250
Policy = "policy" // Policy flag
251251
SystemID = "systemId" // SystemID flag
252252
Default = "default" // Default flag
253+
Timestamp = "timestamp" // Timestamp flag
253254

254255
)

0 commit comments

Comments
 (0)