aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-12-04 09:00:36 +0100
committerDmitry Vyukov <dvyukov@google.com>2017-12-04 09:00:36 +0100
commitf5e771b2001534be1ba5066cbeefc8e6b77e2739 (patch)
treea53ebee5671fb9d7ec5b07560761088ea37e4e02
parent96ca35f4c7ac6fecc3f129eb340cfd29f18cfdf1 (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.go120
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
+}