diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-12-04 09:00:36 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-12-04 09:00:36 +0100 |
| commit | f5e771b2001534be1ba5066cbeefc8e6b77e2739 (patch) | |
| tree | a53ebee5671fb9d7ec5b07560761088ea37e4e02 | |
| parent | 96ca35f4c7ac6fecc3f129eb340cfd29f18cfdf1 (diff) | |
dashboard/app: add drop namespace functionality
dropNamespace drops all entities related to a single namespace.
Use with care. There is no undo.
This functionality is intentionally not connected to any handler.
To use it, first make a backup of the datastore. Then, specify the target
namespace in the ns variable, connect the function to a handler, invoke it
and double check the output. Finally, set dryRun to false and invoke again.
| -rw-r--r-- | dashboard/app/admin.go | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/dashboard/app/admin.go b/dashboard/app/admin.go new file mode 100644 index 000000000..74b9a4591 --- /dev/null +++ b/dashboard/app/admin.go @@ -0,0 +1,120 @@ +// Copyright 2017 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package dash + +import ( + "fmt" + "net/http" + + "golang.org/x/net/context" + "google.golang.org/appengine/datastore" + "google.golang.org/appengine/log" +) + +// dropNamespace drops all entities related to a single namespace. +// Use with care. There is no undo. +// This functionality is intentionally not connected to any handler. +// To use it, first make a backup of the datastore. Then, specify the target +// namespace in the ns variable, connect the function to a handler, invoke it +// and double check the output. Finally, set dryRun to false and invoke again. +func dropNamespace(c context.Context, w http.ResponseWriter, r *http.Request) error { + ns := "non-existent" + dryRun := true + if !dryRun { + log.Criticalf(c, "dropping namespace %v", ns) + } + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + fmt.Fprintf(w, "dropping namespace %v\n", ns) + if err := dropNamespaceReportingState(c, w, ns, dryRun); err != nil { + return err + } + type Entity struct { + name string + child string + } + entities := []Entity{ + {"Patch", ""}, + {"ReproC", ""}, + {"ReproSyz", ""}, + {"KernelConfig", ""}, + {"Job", ""}, + {"Error", ""}, + {"CrashLog", ""}, + {"CrashReport", ""}, + {"Build", ""}, + {"Manager", "ManagerStats"}, + {"Bug", "Crash"}, + } + for _, entity := range entities { + keys, err := datastore.NewQuery(entity.name). + Filter("Namespace=", ns). + KeysOnly(). + GetAll(c, nil) + if err != nil { + return err + } + fmt.Fprintf(w, "%v: %v\n", entity.name, len(keys)) + if entity.child != "" { + var childKeys []*datastore.Key + for _, key := range keys { + keys1, err := datastore.NewQuery(entity.child). + Ancestor(key). + KeysOnly(). + GetAll(c, nil) + if err != nil { + return err + } + childKeys = append(childKeys, keys1...) + } + fmt.Fprintf(w, " %v: %v\n", entity.child, len(childKeys)) + if err := dropEntities(c, childKeys, dryRun); err != nil { + return err + } + } + if err := dropEntities(c, keys, dryRun); err != nil { + return err + } + } + return nil +} + +func dropNamespaceReportingState(c context.Context, w http.ResponseWriter, ns string, dryRun bool) error { + tx := func(c context.Context) error { + state, err := loadReportingState(c) + if err != nil { + return err + } + newState := new(ReportingState) + for _, ent := range state.Entries { + if ent.Namespace != ns { + newState.Entries = append(newState.Entries, ent) + } + } + if !dryRun { + if err := saveReportingState(c, newState); err != nil { + return err + } + } + fmt.Fprintf(w, "ReportingState: %v\n", len(state.Entries)-len(newState.Entries)) + return nil + } + return datastore.RunInTransaction(c, tx, nil) +} + +func dropEntities(c context.Context, keys []*datastore.Key, dryRun bool) error { + if dryRun { + return nil + } + for len(keys) != 0 { + batch := 100 + if batch > len(keys) { + batch = len(keys) + } + if err := datastore.DeleteMulti(c, keys[:batch]); err != nil { + return err + } + keys = keys[batch:] + } + return nil +} |
