aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-03-15 15:21:21 +0100
committerDmitry Vyukov <dvyukov@google.com>2019-03-17 18:06:44 +0100
commit03efedc6d1ffa8d8f76696875571b908cfe2fea1 (patch)
treefeb302a493671c533b7adff32e88938c27d8e22e
parentc1fd2f3b4aa8dc263c14ecc1c5bee9e721600407 (diff)
dashboard/app: add handler for config migration
updateBugReporting adds missing reporting stages to bugs in a single namespace. Use with care. There is no undo. This can be used to migrate datastore to a new config with more reporting stages. This functionality is intentionally not connected to any handler. Before invoking it is recommented to stop all connected instances just in case.
-rw-r--r--dashboard/app/admin.go69
-rw-r--r--dashboard/app/api.go17
2 files changed, 78 insertions, 8 deletions
diff --git a/dashboard/app/admin.go b/dashboard/app/admin.go
index db122297a..ce14a067c 100644
--- a/dashboard/app/admin.go
+++ b/dashboard/app/admin.go
@@ -80,8 +80,6 @@ func dropNamespace(c context.Context, w http.ResponseWriter, r *http.Request) er
return nil
}
-var _ = dropNamespace // prevent warnings about dead code
-
func dropNamespaceReportingState(c context.Context, w http.ResponseWriter, ns string, dryRun bool) error {
tx := func(c context.Context) error {
state, err := loadReportingState(c)
@@ -121,3 +119,70 @@ func dropEntities(c context.Context, keys []*datastore.Key, dryRun bool) error {
}
return nil
}
+
+// updateBugReporting adds missing reporting stages to bugs in a single namespace.
+// Use with care. There is no undo.
+// This can be used to migrate datastore to a new config with more reporting stages.
+// This functionality is intentionally not connected to any handler.
+// Before invoking it is recommended to stop all connected instances just in case.
+func updateBugReporting(c context.Context, w http.ResponseWriter, r *http.Request) error {
+ if accessLevel(c, r) != AccessAdmin {
+ return fmt.Errorf("admin only")
+ }
+ ns := r.FormValue("ns")
+ if ns == "" {
+ return fmt.Errorf("no ns parameter")
+ }
+ var bugs []*Bug
+ keys, err := datastore.NewQuery("Bug").
+ Filter("Namespace=", ns).
+ GetAll(c, &bugs)
+ if err != nil {
+ return err
+ }
+ log.Warningf(c, "fetched %v bugs for namespce %v", len(bugs), ns)
+ cfg := config.Namespaces[ns]
+ var batchKeys []*datastore.Key
+ const batchSize = 20
+ for i, bug := range bugs {
+ if len(bug.Reporting) >= len(cfg.Reporting) {
+ continue
+ }
+ batchKeys = append(batchKeys, keys[i])
+ if len(batchKeys) == batchSize {
+ if err := updateBugReportingBatch(c, cfg, batchKeys); err != nil {
+ return err
+ }
+ batchKeys = nil
+ }
+ }
+ if len(batchKeys) != 0 {
+ if err := updateBugReportingBatch(c, cfg, batchKeys); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func updateBugReportingBatch(c context.Context, cfg *Config, keys []*datastore.Key) error {
+ tx := func(c context.Context) error {
+ bugs := make([]*Bug, len(keys))
+ if err := datastore.GetMulti(c, keys, bugs); err != nil {
+ return err
+ }
+ for _, bug := range bugs {
+ createBugReporting(bug, cfg)
+ }
+ _, err := datastore.PutMulti(c, keys, bugs)
+ return err
+ }
+ err := datastore.RunInTransaction(c, tx, &datastore.TransactionOptions{XG: true})
+ log.Warningf(c, "updated %v bugs: %v", len(keys), err)
+ return err
+}
+
+// Prevent warnings about dead code.
+var (
+ _ = dropNamespace
+ _ = updateBugReporting
+)
diff --git a/dashboard/app/api.go b/dashboard/app/api.go
index 32cab3871..1f4fea5dd 100644
--- a/dashboard/app/api.go
+++ b/dashboard/app/api.go
@@ -988,12 +988,7 @@ func createBugForCrash(c context.Context, ns string, req *dashapi.Crash) (*Bug,
FirstTime: now,
LastTime: now,
}
- for _, rep := range config.Namespaces[ns].Reporting {
- bug.Reporting = append(bug.Reporting, BugReporting{
- Name: rep.Name,
- ID: bugReportingHash(bugHash, rep.Name),
- })
- }
+ createBugReporting(bug, config.Namespaces[ns])
if bugKey, err = datastore.Put(c, bugKey, bug); err != nil {
return fmt.Errorf("failed to put new bug: %v", err)
}
@@ -1018,6 +1013,16 @@ func createBugForCrash(c context.Context, ns string, req *dashapi.Crash) (*Bug,
return bug, bugKey, nil
}
+func createBugReporting(bug *Bug, cfg *Config) {
+ for len(bug.Reporting) < len(cfg.Reporting) {
+ rep := &cfg.Reporting[len(bug.Reporting)]
+ bug.Reporting = append(bug.Reporting, BugReporting{
+ Name: rep.Name,
+ ID: bugReportingHash(bug.keyHash(), rep.Name),
+ })
+ }
+}
+
func isActiveBug(c context.Context, bug *Bug) (bool, error) {
if bug == nil {
return false, nil