add cli commands to delete backups (#641)
This commit is contained in:
parent
db2c1ec8e2
commit
f1370b36e4
@ -4,21 +4,28 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var backupCommands = []func(parent *cobra.Command) *cobra.Command{
|
||||
var subCommands = []*cobra.Command{
|
||||
createCmd,
|
||||
listCmd,
|
||||
detailsCmd,
|
||||
deleteCmd,
|
||||
}
|
||||
|
||||
var serviceCommands = []func(parent *cobra.Command) *cobra.Command{
|
||||
addExchangeCommands,
|
||||
}
|
||||
|
||||
// AddCommands attaches all `corso backup * *` commands to the parent.
|
||||
func AddCommands(parent *cobra.Command) {
|
||||
parent.AddCommand(backupCmd)
|
||||
backupCmd.AddCommand(createCmd)
|
||||
backupCmd.AddCommand(listCmd)
|
||||
backupCmd.AddCommand(detailsCmd)
|
||||
for _, sc := range subCommands {
|
||||
backupCmd.AddCommand(sc)
|
||||
}
|
||||
|
||||
for _, addBackupTo := range backupCommands {
|
||||
addBackupTo(createCmd)
|
||||
addBackupTo(listCmd)
|
||||
addBackupTo(detailsCmd)
|
||||
for _, addBackupTo := range serviceCommands {
|
||||
for _, sc := range subCommands {
|
||||
addBackupTo(sc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,7 +82,7 @@ func handleListCmd(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// The backup details subcommand.
|
||||
// `corso backup list <service> [<flag>...]`
|
||||
// `corso backup details <service> [<flag>...]`
|
||||
var (
|
||||
detailsCommand = "details"
|
||||
detailsCmd = &cobra.Command{
|
||||
@ -91,3 +98,21 @@ var (
|
||||
func handleDetailsCmd(cmd *cobra.Command, args []string) error {
|
||||
return cmd.Help()
|
||||
}
|
||||
|
||||
// The backup delete subcommand.
|
||||
// `corso backup delete <service> [<flag>...]`
|
||||
var (
|
||||
deleteCommand = "delete"
|
||||
deleteCmd = &cobra.Command{
|
||||
Use: deleteCommand,
|
||||
Short: "Deletes a backup for a service",
|
||||
RunE: handleDeleteCmd,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
)
|
||||
|
||||
// Handler for calls to `corso backup delete`.
|
||||
// Produces the same output as `corso backup delete --help`.
|
||||
func handleDeleteCmd(cmd *cobra.Command, args []string) error {
|
||||
return cmd.Help()
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"github.com/alcionai/corso/cli/options"
|
||||
. "github.com/alcionai/corso/cli/print"
|
||||
"github.com/alcionai/corso/cli/utils"
|
||||
"github.com/alcionai/corso/internal/model"
|
||||
"github.com/alcionai/corso/pkg/backup"
|
||||
"github.com/alcionai/corso/pkg/logger"
|
||||
"github.com/alcionai/corso/pkg/repository"
|
||||
@ -134,6 +135,11 @@ func addExchangeCommands(parent *cobra.Command) *cobra.Command {
|
||||
"",
|
||||
"Select backup details where the email subject lines contain this value",
|
||||
)
|
||||
|
||||
case deleteCommand:
|
||||
c, fs = utils.AddCommand(parent, exchangeDeleteCmd())
|
||||
fs.StringVar(&backupID, "backup", "", "ID of the backup containing the details to be shown")
|
||||
cobra.CheckErr(c.MarkFlagRequired("backup"))
|
||||
}
|
||||
|
||||
return c
|
||||
@ -506,3 +512,54 @@ func validateExchangeBackupDetailFlags(
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// backup delete
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
// `corso backup delete exchange [<flag>...]`
|
||||
func exchangeDeleteCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: exchangeServiceCommand,
|
||||
Short: "Delete backed-up M365 Exchange service data",
|
||||
RunE: deleteExchangeCmd,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
}
|
||||
|
||||
// deletes an exchange service backup.
|
||||
func deleteExchangeCmd(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, acct, err := config.GetStorageAndAccount(ctx, true, nil)
|
||||
if err != nil {
|
||||
return Only(ctx, err)
|
||||
}
|
||||
|
||||
m365, err := acct.M365Config()
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrap(err, "Failed to parse m365 account config"))
|
||||
}
|
||||
|
||||
logger.Ctx(ctx).Debugw(
|
||||
"Called - "+cmd.CommandPath(),
|
||||
"tenantID", m365.TenantID,
|
||||
"clientID", m365.ClientID,
|
||||
"hasClientSecret", len(m365.ClientSecret) > 0)
|
||||
|
||||
r, err := repository.Connect(ctx, acct, s)
|
||||
if err != nil {
|
||||
return Only(ctx, errors.Wrapf(err, "Failed to connect to the %s repository", s.Provider))
|
||||
}
|
||||
defer utils.CloseRepo(ctx, r)
|
||||
|
||||
if err := r.DeleteBackup(ctx, model.StableID(backupID)); err != nil {
|
||||
return Only(ctx, errors.Wrapf(err, "Deleting backup %s", backupID))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -217,3 +218,106 @@ func (suite *PreparedBackupExchangeIntegrationSuite) TestExchangeDetailsCmd() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// tests for deleting backups
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type BackupDeleteExchangeIntegrationSuite struct {
|
||||
suite.Suite
|
||||
acct account.Account
|
||||
st storage.Storage
|
||||
vpr *viper.Viper
|
||||
cfgFP string
|
||||
repo *repository.Repository
|
||||
backupOp operations.BackupOperation
|
||||
}
|
||||
|
||||
func TestBackupDeleteExchangeIntegrationSuite(t *testing.T) {
|
||||
if err := tester.RunOnAny(
|
||||
tester.CorsoCITests,
|
||||
tester.CorsoCLITests,
|
||||
tester.CorsoCLIBackupTests,
|
||||
); err != nil {
|
||||
t.Skip(err)
|
||||
}
|
||||
suite.Run(t, new(BackupDeleteExchangeIntegrationSuite))
|
||||
}
|
||||
|
||||
func (suite *BackupDeleteExchangeIntegrationSuite) SetupSuite() {
|
||||
t := suite.T()
|
||||
_, err := tester.GetRequiredEnvSls(
|
||||
tester.AWSStorageCredEnvs,
|
||||
tester.M365AcctCredEnvs)
|
||||
require.NoError(t, err)
|
||||
|
||||
// prepare common details
|
||||
suite.acct = tester.NewM365Account(t)
|
||||
suite.st = tester.NewPrefixedS3Storage(t)
|
||||
|
||||
cfg, err := suite.st.S3Config()
|
||||
require.NoError(t, err)
|
||||
|
||||
force := map[string]string{
|
||||
tester.TestCfgAccountProvider: "M365",
|
||||
tester.TestCfgStorageProvider: "S3",
|
||||
tester.TestCfgPrefix: cfg.Prefix,
|
||||
}
|
||||
suite.vpr, suite.cfgFP, err = tester.MakeTempTestConfigClone(t, force)
|
||||
require.NoError(t, err)
|
||||
ctx := config.SetViper(tester.NewContext(), suite.vpr)
|
||||
|
||||
// init the repo first
|
||||
suite.repo, err = repository.Initialize(ctx, suite.acct, suite.st)
|
||||
require.NoError(t, err)
|
||||
|
||||
m365UserID := tester.M365UserID(t)
|
||||
|
||||
// some tests require an existing backup
|
||||
sel := selectors.NewExchangeBackup()
|
||||
sel.Include(sel.MailFolders([]string{m365UserID}, []string{"Inbox"}))
|
||||
|
||||
suite.backupOp, err = suite.repo.NewBackup(
|
||||
ctx,
|
||||
sel.Selector,
|
||||
control.NewOptions(false))
|
||||
require.NoError(t, suite.backupOp.Run(ctx))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func (suite *BackupDeleteExchangeIntegrationSuite) TestExchangeBackupDeleteCmd() {
|
||||
ctx := config.SetViper(tester.NewContext(), suite.vpr)
|
||||
t := suite.T()
|
||||
|
||||
cmd := tester.StubRootCmd(
|
||||
"backup", "delete", "exchange",
|
||||
"--config-file", suite.cfgFP,
|
||||
"--backup", string(suite.backupOp.Results.BackupID))
|
||||
cli.BuildCommandTree(cmd)
|
||||
|
||||
// run the command
|
||||
require.NoError(t, cmd.ExecuteContext(ctx))
|
||||
|
||||
// a follow-up details call should fail, due to the backup ID being deleted
|
||||
cmd = tester.StubRootCmd(
|
||||
"backup", "details", "exchange",
|
||||
"--config-file", suite.cfgFP,
|
||||
"--backup", string(suite.backupOp.Results.BackupID))
|
||||
cli.BuildCommandTree(cmd)
|
||||
|
||||
require.Error(t, cmd.ExecuteContext(ctx))
|
||||
}
|
||||
|
||||
func (suite *BackupDeleteExchangeIntegrationSuite) TestExchangeBackupDeleteCmd_UnknownID() {
|
||||
ctx := config.SetViper(tester.NewContext(), suite.vpr)
|
||||
t := suite.T()
|
||||
|
||||
cmd := tester.StubRootCmd(
|
||||
"backup", "delete", "exchange",
|
||||
"--config-file", suite.cfgFP,
|
||||
"--backup", uuid.NewString())
|
||||
cli.BuildCommandTree(cmd)
|
||||
|
||||
// unknown backupIDs should error since the modelStore can't find the backup
|
||||
require.Error(t, cmd.ExecuteContext(ctx))
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ func (suite *ExchangeSuite) TestAddExchangeCommands() {
|
||||
{"create exchange", createCommand, expectUse, exchangeCreateCmd().Short, createExchangeCmd},
|
||||
{"list exchange", listCommand, expectUse, exchangeListCmd().Short, listExchangeCmd},
|
||||
{"details exchange", detailsCommand, expectUse, exchangeDetailsCmd().Short, detailsExchangeCmd},
|
||||
{"delete exchange", deleteCommand, expectUse, exchangeDeleteCmd().Short, deleteExchangeCmd},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user