// 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 }