purge restored load test folders (#1059)
## Description purge restored folders for all users in the tenant following a load test to ensure we don't over- produce data that causes future tests to time out. ## Type of change - [x] 🤖 Test ## Issue(s) * #1048 ## Test Plan - [x] 💪 Manual - [x] 💚 E2E
This commit is contained in:
parent
b9e33901f4
commit
30f35709be
15
.github/workflows/load_test.yml
vendored
15
.github/workflows/load_test.yml
vendored
@ -78,3 +78,18 @@ jobs:
|
|||||||
path: src/test_results/*
|
path: src/test_results/*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
|
|
||||||
|
# cleanup folders produced by load test
|
||||||
|
- name: Restored Folder Purge
|
||||||
|
if: always()
|
||||||
|
working-directory: ./src
|
||||||
|
env:
|
||||||
|
CLIENT_ID: ${{ secrets.CLIENT_ID }}
|
||||||
|
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
|
||||||
|
DELETE_FOLDER_PREFIX: "Corso_Restore_"
|
||||||
|
TENANT_ID: ${{ secrets.TENANT_ID }}
|
||||||
|
run: >
|
||||||
|
go run ./cmd/purge/purge.go
|
||||||
|
--user '*'
|
||||||
|
--prefix ${{ env.DELETE_FOLDER_PREFIX }}
|
||||||
|
|
||||||
|
|||||||
@ -50,6 +50,8 @@ var (
|
|||||||
prefix string
|
prefix string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrPurging = errors.New("not all items were successfully purged")
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
// CLI command handlers
|
// CLI command handlers
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
@ -69,7 +71,6 @@ func main() {
|
|||||||
purgeCmd.AddCommand(contactsCmd)
|
purgeCmd.AddCommand(contactsCmd)
|
||||||
|
|
||||||
if err := purgeCmd.ExecuteContext(ctx); err != nil {
|
if err := purgeCmd.ExecuteContext(ctx); err != nil {
|
||||||
Info(purgeCmd.Context(), "Error: ", err.Error())
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,29 +82,19 @@ func handleAllFolderPurge(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
gc, err := getGC(ctx)
|
gc, t, err := getGCAndBoundaryTime(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := getBoundaryTime(ctx)
|
err = runPurgeForEachUser(
|
||||||
|
ctx, gc, t,
|
||||||
|
purgeMailFolders,
|
||||||
|
purgeCalendarFolders,
|
||||||
|
purgeContactFolders,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return Only(ctx, ErrPurging)
|
||||||
}
|
|
||||||
|
|
||||||
err = purgeMailFolders(ctx, gc, t)
|
|
||||||
if err != nil {
|
|
||||||
return Only(ctx, errors.Wrap(err, "purging mail folders"))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = purgeCalendarFolders(ctx, gc, t)
|
|
||||||
if err != nil {
|
|
||||||
return Only(ctx, errors.Wrap(err, "purging event calendars"))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = purgeContactFolders(ctx, gc, t)
|
|
||||||
if err != nil {
|
|
||||||
return Only(ctx, errors.Wrap(err, "purging contacts folders"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -116,18 +107,13 @@ func handleMailFolderPurge(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
gc, err := getGC(ctx)
|
gc, t, err := getGCAndBoundaryTime(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := getBoundaryTime(ctx)
|
if err := runPurgeForEachUser(ctx, gc, t, purgeMailFolders); err != nil {
|
||||||
if err != nil {
|
return Only(ctx, errors.Wrap(ErrPurging, "mail folders"))
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := purgeMailFolders(ctx, gc, t); err != nil {
|
|
||||||
return Only(ctx, errors.Wrap(err, "purging mail folders"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -136,18 +122,17 @@ func handleMailFolderPurge(cmd *cobra.Command, args []string) error {
|
|||||||
func handleCalendarFolderPurge(cmd *cobra.Command, args []string) error {
|
func handleCalendarFolderPurge(cmd *cobra.Command, args []string) error {
|
||||||
ctx := cmd.Context()
|
ctx := cmd.Context()
|
||||||
|
|
||||||
gc, err := getGC(ctx)
|
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gc, t, err := getGCAndBoundaryTime(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := getBoundaryTime(ctx)
|
if err := runPurgeForEachUser(ctx, gc, t, purgeCalendarFolders); err != nil {
|
||||||
if err != nil {
|
return Only(ctx, errors.Wrap(ErrPurging, "event calendars"))
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := purgeCalendarFolders(ctx, gc, t); err != nil {
|
|
||||||
return Only(ctx, errors.Wrap(err, "purging event calendars"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -156,18 +141,17 @@ func handleCalendarFolderPurge(cmd *cobra.Command, args []string) error {
|
|||||||
func handleContactsFolderPurge(cmd *cobra.Command, args []string) error {
|
func handleContactsFolderPurge(cmd *cobra.Command, args []string) error {
|
||||||
ctx := cmd.Context()
|
ctx := cmd.Context()
|
||||||
|
|
||||||
gc, err := getGC(ctx)
|
if utils.HasNoFlagsAndShownHelp(cmd) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gc, t, err := getGCAndBoundaryTime(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t, err := getBoundaryTime(ctx)
|
if err := runPurgeForEachUser(ctx, gc, t, purgeContactFolders); err != nil {
|
||||||
if err != nil {
|
return Only(ctx, errors.Wrap(ErrPurging, "contact folders"))
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := purgeContactFolders(ctx, gc, t); err != nil {
|
|
||||||
return Only(ctx, errors.Wrap(err, "purging contacts folders"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -182,9 +166,37 @@ type purgable interface {
|
|||||||
GetId() *string
|
GetId() *string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type purger func(context.Context, *connector.GraphConnector, time.Time, string) error
|
||||||
|
|
||||||
|
func runPurgeForEachUser(
|
||||||
|
ctx context.Context,
|
||||||
|
gc *connector.GraphConnector,
|
||||||
|
boundary time.Time,
|
||||||
|
ps ...purger,
|
||||||
|
) error {
|
||||||
|
var errs error
|
||||||
|
|
||||||
|
for pn, uid := range userOrUsers(user, gc.Users) {
|
||||||
|
Infof(ctx, "\nUser: %s - %s", pn, uid)
|
||||||
|
|
||||||
|
for _, p := range ps {
|
||||||
|
if err := p(ctx, gc, boundary, pn); err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
// ----- mail
|
// ----- mail
|
||||||
|
|
||||||
func purgeMailFolders(ctx context.Context, gc *connector.GraphConnector, boundary time.Time) error {
|
func purgeMailFolders(
|
||||||
|
ctx context.Context,
|
||||||
|
gc *connector.GraphConnector,
|
||||||
|
boundary time.Time,
|
||||||
|
uid string,
|
||||||
|
) error {
|
||||||
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
|
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
|
||||||
mfs, err := exchange.GetAllMailFolders(ctx, gs, uid, prefix)
|
mfs, err := exchange.GetAllMailFolders(ctx, gs, uid, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -204,12 +216,17 @@ func purgeMailFolders(ctx context.Context, gc *connector.GraphConnector, boundar
|
|||||||
return exchange.DeleteMailFolder(ctx, gs, uid, fid)
|
return exchange.DeleteMailFolder(ctx, gs, uid, fid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return purgeFolders(ctx, gc, boundary, "mail", getter, deleter)
|
return purgeFolders(ctx, gc, boundary, "Mail Folders", uid, getter, deleter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- calendars
|
// ----- calendars
|
||||||
|
|
||||||
func purgeCalendarFolders(ctx context.Context, gc *connector.GraphConnector, boundary time.Time) error {
|
func purgeCalendarFolders(
|
||||||
|
ctx context.Context,
|
||||||
|
gc *connector.GraphConnector,
|
||||||
|
boundary time.Time,
|
||||||
|
uid string,
|
||||||
|
) error {
|
||||||
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
|
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
|
||||||
cfs, err := exchange.GetAllCalendars(ctx, gs, uid, prefix)
|
cfs, err := exchange.GetAllCalendars(ctx, gs, uid, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -229,12 +246,17 @@ func purgeCalendarFolders(ctx context.Context, gc *connector.GraphConnector, bou
|
|||||||
return exchange.DeleteCalendar(ctx, gs, uid, fid)
|
return exchange.DeleteCalendar(ctx, gs, uid, fid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return purgeFolders(ctx, gc, boundary, "calendar", getter, deleter)
|
return purgeFolders(ctx, gc, boundary, "Event Calendars", uid, getter, deleter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- contacts
|
// ----- contacts
|
||||||
|
|
||||||
func purgeContactFolders(ctx context.Context, gc *connector.GraphConnector, boundary time.Time) error {
|
func purgeContactFolders(
|
||||||
|
ctx context.Context,
|
||||||
|
gc *connector.GraphConnector,
|
||||||
|
boundary time.Time,
|
||||||
|
uid string,
|
||||||
|
) error {
|
||||||
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
|
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
|
||||||
cfs, err := exchange.GetAllContactFolders(ctx, gs, uid, prefix)
|
cfs, err := exchange.GetAllContactFolders(ctx, gs, uid, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -254,7 +276,7 @@ func purgeContactFolders(ctx context.Context, gc *connector.GraphConnector, boun
|
|||||||
return exchange.DeleteContactFolder(ctx, gs, uid, fid)
|
return exchange.DeleteContactFolder(ctx, gs, uid, fid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return purgeFolders(ctx, gc, boundary, "contact", getter, deleter)
|
return purgeFolders(ctx, gc, boundary, "Contact Folders", uid, getter, deleter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- controller
|
// ----- controller
|
||||||
@ -263,26 +285,33 @@ func purgeFolders(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
gc *connector.GraphConnector,
|
gc *connector.GraphConnector,
|
||||||
boundary time.Time,
|
boundary time.Time,
|
||||||
data string,
|
data, uid string,
|
||||||
getter func(graph.Service, string, string) ([]purgable, error),
|
getter func(graph.Service, string, string) ([]purgable, error),
|
||||||
deleter func(graph.Service, string, string) error,
|
deleter func(graph.Service, string, string) error,
|
||||||
) error {
|
) error {
|
||||||
|
Infof(ctx, "\nContainer: %s", data)
|
||||||
|
|
||||||
// get them folders
|
// get them folders
|
||||||
fs, err := getter(gc.Service(), user, prefix)
|
fs, err := getter(gc.Service(), uid, prefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Only(ctx, errors.Wrapf(err, "retrieving %s folders", data))
|
return Only(ctx, errors.Wrapf(err, "retrieving %s folders", data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(fs) == 0 {
|
||||||
|
Info(ctx, "None Matched")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var errs error
|
var errs error
|
||||||
|
|
||||||
// delete any that don't meet the boundary
|
// delete any containers that don't pass the boundary
|
||||||
for _, fld := range fs {
|
for _, fld := range fs {
|
||||||
// compare the folder time to the deletion boundary time first
|
// compare the folder time to the deletion boundary time first
|
||||||
displayName := *fld.GetDisplayName()
|
displayName := *fld.GetDisplayName()
|
||||||
|
|
||||||
dnTime, err := common.ExtractTime(displayName)
|
dnTime, err := common.ExtractTime(displayName)
|
||||||
if err != nil && !errors.Is(err, common.ErrNoTimeString) {
|
if err != nil && !errors.Is(err, common.ErrNoTimeString) {
|
||||||
err = errors.Wrapf(err, "Error: parsing %s folder name [%s]", data, displayName)
|
err = errors.Wrapf(err, "!! Error: parsing container named [%s]", displayName)
|
||||||
errs = multierror.Append(errs, err)
|
errs = multierror.Append(errs, err)
|
||||||
Info(ctx, err)
|
Info(ctx, err)
|
||||||
|
|
||||||
@ -293,11 +322,11 @@ func purgeFolders(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
Infof(ctx, "Deleting %s folder: %s", data, displayName)
|
Infof(ctx, "Deleting [%s]", displayName)
|
||||||
|
|
||||||
err = deleter(gc.Service(), user, *fld.GetId())
|
err = deleter(gc.Service(), uid, *fld.GetId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrapf(err, "Error: deleting %s folder [%s]", data, displayName)
|
err = errors.Wrapf(err, "!! Error")
|
||||||
errs = multierror.Append(errs, err)
|
errs = multierror.Append(errs, err)
|
||||||
Info(ctx, err)
|
Info(ctx, err)
|
||||||
}
|
}
|
||||||
@ -347,3 +376,29 @@ func getBoundaryTime(ctx context.Context) (time.Time, error) {
|
|||||||
|
|
||||||
return boundaryTime, nil
|
return boundaryTime, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getGCAndBoundaryTime(ctx context.Context) (*connector.GraphConnector, time.Time, error) {
|
||||||
|
gc, err := getGC(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, time.Time{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := getBoundaryTime(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, time.Time{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gc, t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func userOrUsers(u string, us map[string]string) map[string]string {
|
||||||
|
if len(u) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if u == "*" {
|
||||||
|
return us
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{u: u}
|
||||||
|
}
|
||||||
|
|||||||
@ -136,11 +136,6 @@ func (gc *GraphConnector) setTenantUsers(ctx context.Context) error {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if response == nil {
|
|
||||||
err = support.WrapAndAppend("general access", errors.New("connector failed: No access"), err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
userIterator, err := msgraphgocore.NewPageIterator(
|
userIterator, err := msgraphgocore.NewPageIterator(
|
||||||
response,
|
response,
|
||||||
&gc.graphService.adapter,
|
&gc.graphService.adapter,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user