Skip to content

Commit cefc417

Browse files
committed
enable/disable snapshot plan
1 parent 7a6e432 commit cefc417

9 files changed

+335
-0
lines changed

docs/reference/manual/hcloud_storage-box.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@ Manage Storage Boxes
3131
* [hcloud storage-box delete](hcloud_storage-box_delete.md) - Delete a Storage Box
3232
* [hcloud storage-box describe](hcloud_storage-box_describe.md) - Describe a Storage Box
3333
* [hcloud storage-box disable-protection](hcloud_storage-box_disable-protection.md) - Disable resource protection for a Storage Box
34+
* [hcloud storage-box disable-snapshot-plan](hcloud_storage-box_disable-snapshot-plan.md) - Disable automatic snapshots for a Storage Box
3435
* [hcloud storage-box enable-protection](hcloud_storage-box_enable-protection.md) - Enable resource protection for a Storage Box
36+
* [hcloud storage-box enable-snapshot-plan](hcloud_storage-box_enable-snapshot-plan.md) - Enable automatic snapshots for a Storage Box
3537
* [hcloud storage-box folders](hcloud_storage-box_folders.md) - List folders of a Storage Box
3638
* [hcloud storage-box list](hcloud_storage-box_list.md) - List Storage Boxes
3739
* [hcloud storage-box remove-label](hcloud_storage-box_remove-label.md) - Remove a label from a Storage Box
3840
* [hcloud storage-box reset-password](hcloud_storage-box_reset-password.md) - Reset the password of a Storage Box
41+
* [hcloud storage-box rollback-snapshot](hcloud_storage-box_rollback-snapshot.md) - Rolls back the Storage Box to the given Snapshot
3942
* [hcloud storage-box update](hcloud_storage-box_update.md) - Update a Storage Box
4043
* [hcloud storage-box update-access-settings](hcloud_storage-box_update-access-settings.md) - Update access settings of the primary Storage Box account
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
## hcloud storage-box disable-snapshot-plan
2+
3+
Disable automatic snapshots for a Storage Box
4+
5+
```
6+
hcloud storage-box disable-snapshot-plan <storage-box>
7+
```
8+
9+
### Options
10+
11+
```
12+
-h, --help help for disable-snapshot-plan
13+
```
14+
15+
### Options inherited from parent commands
16+
17+
```
18+
--config string Config file path (default "~/.config/hcloud/cli.toml")
19+
--context string Currently active context
20+
--debug Enable debug output
21+
--debug-file string File to write debug output to
22+
--endpoint string Hetzner Cloud API endpoint (default "https://api.hetzner.cloud/v1")
23+
--hetzner-endpoint string Hetzner API endpoint (default "https://api.hetzner.com/v1")
24+
--no-experimental-warnings If true, experimental warnings are not shown
25+
--poll-interval duration Interval at which to poll information, for example action progress (default 500ms)
26+
--quiet If true, only print error messages
27+
```
28+
29+
### SEE ALSO
30+
31+
* [hcloud storage-box](hcloud_storage-box.md) - Manage Storage Boxes
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
## hcloud storage-box enable-snapshot-plan
2+
3+
Enable automatic snapshots for a Storage Box
4+
5+
```
6+
hcloud storage-box enable-snapshot-plan [options] <storage-box>
7+
```
8+
9+
### Options
10+
11+
```
12+
--day-of-month int Day of the month the Snapshot Plan should be executed on. Not specified means every day
13+
--day-of-week string Day of the week the Snapshot Plan should be executed on. Not specified means every day
14+
-h, --help help for enable-snapshot-plan
15+
--hour int Hour the Snapshot Plan should be executed on (UTC). Not specified means every hour
16+
--max-snapshots int Maximum amount of Snapshots that should be created by this Snapshot Plan
17+
--minute int Minute the Snapshot Plan should be executed on (UTC). Not specified means every minute
18+
```
19+
20+
### Options inherited from parent commands
21+
22+
```
23+
--config string Config file path (default "~/.config/hcloud/cli.toml")
24+
--context string Currently active context
25+
--debug Enable debug output
26+
--debug-file string File to write debug output to
27+
--endpoint string Hetzner Cloud API endpoint (default "https://api.hetzner.cloud/v1")
28+
--hetzner-endpoint string Hetzner API endpoint (default "https://api.hetzner.com/v1")
29+
--no-experimental-warnings If true, experimental warnings are not shown
30+
--poll-interval duration Interval at which to poll information, for example action progress (default 500ms)
31+
--quiet If true, only print error messages
32+
```
33+
34+
### SEE ALSO
35+
36+
* [hcloud storage-box](hcloud_storage-box.md) - Manage Storage Boxes
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## hcloud storage-box rollback-snapshot
2+
3+
Rolls back the Storage Box to the given Snapshot
4+
5+
```
6+
hcloud storage-box rollback-snapshot --snapshot <snapshot> <storage-box>
7+
```
8+
9+
### Options
10+
11+
```
12+
-h, --help help for rollback-snapshot
13+
--snapshot string The name or ID of the snapshot to roll back to
14+
```
15+
16+
### Options inherited from parent commands
17+
18+
```
19+
--config string Config file path (default "~/.config/hcloud/cli.toml")
20+
--context string Currently active context
21+
--debug Enable debug output
22+
--debug-file string File to write debug output to
23+
--endpoint string Hetzner Cloud API endpoint (default "https://api.hetzner.cloud/v1")
24+
--hetzner-endpoint string Hetzner API endpoint (default "https://api.hetzner.com/v1")
25+
--no-experimental-warnings If true, experimental warnings are not shown
26+
--poll-interval duration Interval at which to poll information, for example action progress (default 500ms)
27+
--quiet If true, only print error messages
28+
```
29+
30+
### SEE ALSO
31+
32+
* [hcloud storage-box](hcloud_storage-box.md) - Manage Storage Boxes
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package storagebox
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
8+
"github.com/hetznercloud/cli/internal/cmd/base"
9+
"github.com/hetznercloud/cli/internal/cmd/cmpl"
10+
"github.com/hetznercloud/cli/internal/hcapi2"
11+
"github.com/hetznercloud/cli/internal/state"
12+
)
13+
14+
var DisableSnapshotPlanCmd = base.Cmd{
15+
BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
16+
cmd := &cobra.Command{
17+
Use: "disable-snapshot-plan <storage-box>",
18+
Short: "Disable automatic snapshots for a Storage Box",
19+
ValidArgsFunction: cmpl.SuggestArgs(
20+
cmpl.SuggestCandidatesF(client.StorageBox().Names),
21+
),
22+
TraverseChildren: true,
23+
DisableFlagsInUseLine: true,
24+
}
25+
return cmd
26+
},
27+
Run: func(s state.State, cmd *cobra.Command, args []string) error {
28+
idOrName := args[0]
29+
30+
storageBox, _, err := s.Client().StorageBox().Get(s, idOrName)
31+
if err != nil {
32+
return err
33+
}
34+
if storageBox == nil {
35+
return fmt.Errorf("Storage Box not found: %s", idOrName)
36+
}
37+
38+
action, _, err := s.Client().StorageBox().DisableSnapshotPlan(s, storageBox)
39+
if err != nil {
40+
return err
41+
}
42+
43+
if err := s.WaitForActions(s, cmd, action); err != nil {
44+
return err
45+
}
46+
47+
cmd.Printf("Snapshot Plan disabled for Storage Box %d\n", storageBox.ID)
48+
return nil
49+
},
50+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package storagebox_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
"go.uber.org/mock/gomock"
9+
10+
"github.com/hetznercloud/cli/internal/cmd/storagebox"
11+
"github.com/hetznercloud/cli/internal/testutil"
12+
"github.com/hetznercloud/hcloud-go/v2/hcloud"
13+
)
14+
15+
func TestDisableSnapshotPlan(t *testing.T) {
16+
fx := testutil.NewFixture(t)
17+
defer fx.Finish()
18+
19+
cmd := storagebox.DisableSnapshotPlanCmd.CobraCommand(fx.State())
20+
fx.ExpectEnsureToken()
21+
22+
sb := &hcloud.StorageBox{ID: 123, Name: "my-storage-box"}
23+
24+
fx.Client.StorageBoxClient.EXPECT().
25+
Get(gomock.Any(), "my-storage-box").
26+
Return(sb, nil, nil)
27+
fx.Client.StorageBoxClient.EXPECT().
28+
DisableSnapshotPlan(gomock.Any(), sb).
29+
Return(&hcloud.Action{ID: 456}, nil, nil)
30+
fx.ActionWaiter.EXPECT().
31+
WaitForActions(gomock.Any(), gomock.Any(), &hcloud.Action{ID: 456}).
32+
Return(nil)
33+
34+
args := []string{"my-storage-box"}
35+
out, errOut, err := fx.Run(cmd, args)
36+
37+
require.NoError(t, err)
38+
assert.Empty(t, errOut)
39+
assert.Equal(t, "Snapshot Plan disabled for Storage Box 123\n", out)
40+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package storagebox
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
8+
"github.com/hetznercloud/cli/internal/cmd/base"
9+
"github.com/hetznercloud/cli/internal/cmd/cmpl"
10+
"github.com/hetznercloud/cli/internal/cmd/util"
11+
"github.com/hetznercloud/cli/internal/hcapi2"
12+
"github.com/hetznercloud/cli/internal/state"
13+
"github.com/hetznercloud/hcloud-go/v2/hcloud"
14+
)
15+
16+
var EnableSnapshotPlanCmd = base.Cmd{
17+
BaseCobraCommand: func(client hcapi2.Client) *cobra.Command {
18+
cmd := &cobra.Command{
19+
Use: "enable-snapshot-plan [options] <storage-box>",
20+
Short: "Enable automatic snapshots for a Storage Box",
21+
ValidArgsFunction: cmpl.SuggestArgs(
22+
cmpl.SuggestCandidatesF(client.StorageBox().Names),
23+
),
24+
TraverseChildren: true,
25+
DisableFlagsInUseLine: true,
26+
}
27+
28+
cmd.Flags().Int("max-snapshots", 0, "Maximum amount of Snapshots that should be created by this Snapshot Plan")
29+
_ = cmd.MarkFlagRequired("max-snapshots")
30+
31+
cmd.Flags().Int("minute", 0, "Minute the Snapshot Plan should be executed on (UTC). Not specified means every minute")
32+
cmd.Flags().Int("hour", 0, "Hour the Snapshot Plan should be executed on (UTC). Not specified means every hour")
33+
cmd.Flags().String("day-of-week", "", "Day of the week the Snapshot Plan should be executed on. Not specified means every day")
34+
cmd.Flags().Int("day-of-month", 0, "Day of the month the Snapshot Plan should be executed on. Not specified means every day")
35+
36+
_ = cmd.RegisterFlagCompletionFunc("day-of-week", cmpl.SuggestCandidates("monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"))
37+
38+
// TODO: should we add some validation here to avoid footguns? (e.g. backing up every minute)
39+
40+
return cmd
41+
},
42+
Run: func(s state.State, cmd *cobra.Command, args []string) error {
43+
idOrName := args[0]
44+
maxSnapshots, _ := cmd.Flags().GetInt("max-snapshots")
45+
minute, _ := cmd.Flags().GetInt("minute")
46+
hour, _ := cmd.Flags().GetInt("hour")
47+
dayOfWeek, _ := cmd.Flags().GetString("day-of-week")
48+
dayOfMonth, _ := cmd.Flags().GetInt("day-of-month")
49+
50+
storageBox, _, err := s.Client().StorageBox().Get(s, idOrName)
51+
if err != nil {
52+
return err
53+
}
54+
if storageBox == nil {
55+
return fmt.Errorf("Storage Box not found: %s", idOrName)
56+
}
57+
58+
opts := hcloud.StorageBoxEnableSnapshotPlanOpts{
59+
MaxSnapshots: maxSnapshots,
60+
}
61+
62+
if cmd.Flags().Changed("minute") {
63+
opts.Minute = &minute
64+
}
65+
if cmd.Flags().Changed("hour") {
66+
opts.Hour = &hour
67+
}
68+
if cmd.Flags().Changed("day-of-week") {
69+
weekday, err := util.WeekdayFromString(dayOfWeek)
70+
if err != nil {
71+
return err
72+
}
73+
if weekday == 0 {
74+
// The API expects 7 for Sunday
75+
weekday = 7
76+
}
77+
opts.DayOfWeek = hcloud.Ptr(int(weekday))
78+
}
79+
if cmd.Flags().Changed("day-of-month") {
80+
opts.DayOfMonth = &dayOfMonth
81+
}
82+
83+
action, _, err := s.Client().StorageBox().EnableSnapshotPlan(s, storageBox, opts)
84+
if err != nil {
85+
return err
86+
}
87+
88+
if err := s.WaitForActions(s, cmd, action); err != nil {
89+
return err
90+
}
91+
92+
cmd.Printf("Snapshot Plan enabled for Storage Box %d\n", storageBox.ID)
93+
return nil
94+
},
95+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package storagebox_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/require"
8+
"go.uber.org/mock/gomock"
9+
10+
"github.com/hetznercloud/cli/internal/cmd/storagebox"
11+
"github.com/hetznercloud/cli/internal/testutil"
12+
"github.com/hetznercloud/hcloud-go/v2/hcloud"
13+
)
14+
15+
func TestEnableSnapshotPlan(t *testing.T) {
16+
fx := testutil.NewFixture(t)
17+
defer fx.Finish()
18+
19+
cmd := storagebox.EnableSnapshotPlanCmd.CobraCommand(fx.State())
20+
fx.ExpectEnsureToken()
21+
22+
sb := &hcloud.StorageBox{ID: 123, Name: "my-storage-box"}
23+
24+
fx.Client.StorageBoxClient.EXPECT().
25+
Get(gomock.Any(), "my-storage-box").
26+
Return(sb, nil, nil)
27+
fx.Client.StorageBoxClient.EXPECT().
28+
EnableSnapshotPlan(gomock.Any(), sb, hcloud.StorageBoxEnableSnapshotPlanOpts{
29+
MaxSnapshots: 10,
30+
Minute: hcloud.Ptr(0),
31+
Hour: hcloud.Ptr(2),
32+
DayOfWeek: hcloud.Ptr(2),
33+
DayOfMonth: nil,
34+
}).
35+
Return(&hcloud.Action{ID: 456}, nil, nil)
36+
fx.ActionWaiter.EXPECT().
37+
WaitForActions(gomock.Any(), gomock.Any(), &hcloud.Action{ID: 456}).
38+
Return(nil)
39+
40+
args := []string{"my-storage-box", "--max-snapshots", "10", "--minute", "0", "--hour", "2", "--day-of-week", "tuesday"}
41+
out, errOut, err := fx.Run(cmd, args)
42+
43+
require.NoError(t, err)
44+
assert.Empty(t, errOut)
45+
assert.Equal(t, "Snapshot Plan enabled for Storage Box 123\n", out)
46+
}

internal/cmd/storagebox/storage_box.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ func NewCommand(s state.State) *cobra.Command {
3131
ResetPasswordCmd.CobraCommand(s),
3232
UpdateAccessSettingsCmd.CobraCommand(s),
3333
RollbackSnapshotCmd.CobraCommand(s),
34+
EnableSnapshotPlanCmd.CobraCommand(s),
35+
DisableSnapshotPlanCmd.CobraCommand(s),
3436
)
3537
return cmd
3638
}

0 commit comments

Comments
 (0)