internal/cmdconfig: use dynamic config for experiments on env var

If the GO_DISCOVERY_EXPERIMENTS_FROM_CONFIG env var is "true", read
experiments from dynamic config instead of the database.

Temporary, until we switch over completely to dynamic config.

For golang/go#41483

Change-Id: Icf6038fb9f2322eba24bedf60450cd9fce84bd6c
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/256380
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/cmd/frontend/main.go b/cmd/frontend/main.go
index d4cbc7b..62027c8 100644
--- a/cmd/frontend/main.go
+++ b/cmd/frontend/main.go
@@ -175,7 +175,7 @@
 		log.Fatal(ctx, err)
 	}
 	rc := cmdconfig.ReportingClient(ctx, cfg)
-	experimenter := cmdconfig.Experimenter(ctx, expg, rc)
+	experimenter := cmdconfig.Experimenter(ctx, cfg, expg, rc)
 	ermw := middleware.Identity()
 	if rc != nil {
 		ermw = middleware.ErrorReporting(rc.Report)
diff --git a/cmd/internal/cmdconfig/cmdconfig.go b/cmd/internal/cmdconfig/cmdconfig.go
index 272410a..1315813 100644
--- a/cmd/internal/cmdconfig/cmdconfig.go
+++ b/cmd/internal/cmdconfig/cmdconfig.go
@@ -7,9 +7,11 @@
 
 import (
 	"context"
+	"os"
 	"time"
 
 	"cloud.google.com/go/errorreporting"
+	"golang.org/x/pkgsite/internal"
 	"golang.org/x/pkgsite/internal/config"
 	"golang.org/x/pkgsite/internal/log"
 	"golang.org/x/pkgsite/internal/middleware"
@@ -45,7 +47,26 @@
 }
 
 // Experimenter configures a middleware.Experimenter.
-func Experimenter(ctx context.Context, getter middleware.ExperimentGetter, reportingClient *errorreporting.Client) *middleware.Experimenter {
+func Experimenter(ctx context.Context, cfg *config.Config, getter middleware.ExperimentGetter, reportingClient *errorreporting.Client) *middleware.Experimenter {
+	if os.Getenv("GO_DISCOVERY_EXPERIMENTS_FROM_CONFIG") == "true" {
+		// Ignore getter, use dynamic config.
+		log.Infof(ctx, "using dynamic config for experiments")
+		getter = func(ctx context.Context) ([]*internal.Experiment, error) {
+			var exps []*internal.Experiment
+			dc, err := cfg.ReadDynamic(ctx)
+			if err != nil {
+				return nil, err
+			}
+			for _, cexp := range dc.Experiments {
+				exps = append(exps, &internal.Experiment{
+					Name:        cexp.Name,
+					Description: cexp.Description,
+					Rollout:     cexp.Rollout,
+				})
+			}
+			return exps, nil
+		}
+	}
 	e, err := middleware.NewExperimenter(ctx, 1*time.Minute, getter, reportingClient)
 	if err != nil {
 		log.Fatal(ctx, err)
diff --git a/cmd/worker/main.go b/cmd/worker/main.go
index dbe25ed..46565a4 100644
--- a/cmd/worker/main.go
+++ b/cmd/worker/main.go
@@ -105,7 +105,7 @@
 	reportingClient := cmdconfig.ReportingClient(ctx, cfg)
 	redisHAClient := getHARedis(ctx, cfg)
 	redisCacheClient := getCacheRedis(ctx, cfg)
-	experimenter := cmdconfig.Experimenter(ctx, db.GetExperiments, reportingClient)
+	experimenter := cmdconfig.Experimenter(ctx, cfg, db.GetExperiments, reportingClient)
 	server, err := worker.NewServer(cfg, worker.ServerConfig{
 		DB:                   db,
 		IndexClient:          indexClient,
diff --git a/internal/config/dynamic.go b/internal/config/dynamic.go
index 2344e50..cd46296 100644
--- a/internal/config/dynamic.go
+++ b/internal/config/dynamic.go
@@ -7,6 +7,7 @@
 import (
 	"context"
 	"io/ioutil"
+	"log"
 
 	"cloud.google.com/go/storage"
 	"github.com/ghodss/yaml"
@@ -40,6 +41,7 @@
 func ReadDynamic(ctx context.Context, bucket, object string) (_ *DynamicConfig, err error) {
 	defer derrors.Wrap(&err, "ReadDynamic(%q, %q)", bucket, object)
 
+	log.Printf("reading experiments from gs://%s/%s", bucket, object)
 	client, err := storage.NewClient(ctx)
 	if err != nil {
 		return nil, err