gddo-server: collect GCE metadata configuration in Viper
Remove the gaAccount global variable in favor of reading from
configuration.
Minor behavior changes:
- The GA_ACCOUNT environment variable will override the GCE metadata
ga-account, where before it was not being read on GCE.
- The project ID across the program defaults to the one from GCE
metadata, overridden by the GCLOUD_PROJECT environment variable or the
command-line flag. The GCE logger now uses this project ID instead of
just considering the GCE metadata.
- The GCE log name can now be set using the gddo_gce_log_name
environment variable.
Change-Id: I0ed2ae7a5130d63146e9bf2746f22980c8a782b9
Reviewed-on: https://go-review.googlesource.com/67050
Reviewed-by: Tuo Shan <shantuo@google.com>
diff --git a/gddo-server/config.go b/gddo-server/config.go
index 5f07548..a246bd3 100644
--- a/gddo-server/config.go
+++ b/gddo-server/config.go
@@ -8,14 +8,16 @@
"strings"
"time"
- "github.com/golang/gddo/log"
-
+ "cloud.google.com/go/compute/metadata"
"github.com/spf13/pflag"
"github.com/spf13/viper"
+
+ "github.com/golang/gddo/log"
)
const (
gaeProjectEnvVar = "GCLOUD_PROJECT"
+ gaAccountEnvVar = "GA_ACCOUNT"
)
const (
@@ -25,6 +27,7 @@
ConfigBindAddress = "http"
ConfigAssetsDir = "assets"
ConfigRobotThreshold = "robot"
+ ConfigGCELogName = "gce_log_name"
// Database Config
ConfigDBServer = "db-server"
@@ -36,6 +39,7 @@
ConfigSidebar = "sidebar"
ConfigSourcegraphURL = "sourcegraph_url"
ConfigDefaultGOOS = "default_goos"
+ ConfigGAAccount = "ga_account"
// Crawl Config
ConfigMaxAge = "max_age"
@@ -52,12 +56,21 @@
func init() {
ctx := context.Background()
- // Automatically detect if we are on App Engine.
+ // Gather information from execution environment.
if os.Getenv(gaeProjectEnvVar) != "" {
viper.Set("on_appengine", true)
} else {
viper.Set("on_appengine", false)
}
+ if metadata.OnGCE() {
+ gceProjectAttributeDefault(ctx, viper.GetViper(), ConfigGAAccount, "ga-account")
+ gceProjectAttributeDefault(ctx, viper.GetViper(), ConfigGCELogName, "gce-log-name")
+ if id, err := metadata.ProjectID(); err != nil {
+ log.Warn(ctx, "failed to retrieve project ID", "error", err)
+ } else {
+ viper.SetDefault(ConfigProject, id)
+ }
+ }
// Setup command line flags
flags := buildFlags()
@@ -70,9 +83,8 @@
viper.SetEnvPrefix("gddo")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.AutomaticEnv()
-
- // Automatically get project ID from env on Google App Engine
viper.BindEnv(ConfigProject, gaeProjectEnvVar)
+ viper.BindEnv(ConfigGAAccount, gaAccountEnvVar)
// Read from config.
readViperConfig(ctx)
@@ -83,6 +95,17 @@
log.Info(ctx, "config values loaded", "values", viper.AllSettings())
}
+func gceProjectAttributeDefault(ctx context.Context, v *viper.Viper, cfg, attr string) {
+ val, err := metadata.ProjectAttributeValue(attr)
+ if err != nil {
+ if _, undef := err.(metadata.NotDefinedError); !undef {
+ log.Warn(ctx, "failed to query metadata", "key", attr, "error", err)
+ }
+ return
+ }
+ v.SetDefault(cfg, val)
+}
+
// setDefaults sets defaults for configuration options that depend on other
// configuration options. This allows for smart defaults but allows for
// overrides.
@@ -99,7 +122,7 @@
flags := pflag.NewFlagSet("default", pflag.ExitOnError)
flags.StringP("config", "c", "", "path to motd config file")
- flags.String("project", "", "Google Cloud Platform project used for Google services")
+ flags.String(ConfigProject, "", "Google Cloud Platform project used for Google services")
// TODO(stephenmw): flags.Bool("enable-admin-pages", false, "When true, enables /admin pages")
flags.Float64(ConfigRobotThreshold, 100, "Request counter threshold for robots.")
flags.String(ConfigAssetsDir, filepath.Join(defaultBase("github.com/golang/gddo/gddo-server"), "assets"), "Base directory for templates and static files.")
diff --git a/gddo-server/main.go b/gddo-server/main.go
index 8ac09ad..9e94ef5 100644
--- a/gddo-server/main.go
+++ b/gddo-server/main.go
@@ -19,7 +19,6 @@
"io"
"log"
"net/http"
- "os"
"path"
"regexp"
"runtime/debug"
@@ -28,7 +27,6 @@
"strings"
"time"
- "cloud.google.com/go/compute/metadata"
"cloud.google.com/go/logging"
"github.com/spf13/viper"
@@ -848,35 +846,6 @@
doc.SetDefaultGOOS(viper.GetString(ConfigDefaultGOOS))
httpClient = newHTTPClient(viper.GetViper())
- var (
- gceLogName string
- projID string
- )
-
- // TODO(stephenmw): merge into viper config infrastructure.
- if metadata.OnGCE() {
- acct, err := metadata.ProjectAttributeValue("ga-account")
- if err != nil {
- log.Printf("querying metadata for ga-account: %v", err)
- } else {
- gaAccount = acct
- }
-
- // Get the log name on GCE and setup context for creating a GCE log client.
- if name, err := metadata.ProjectAttributeValue("gce-log-name"); err != nil {
- log.Printf("querying metadata for gce-log-name: %v", err)
- } else {
- gceLogName = name
- if id, err := metadata.ProjectID(); err != nil {
- log.Printf("querying metadata for project ID: %v", err)
- } else {
- projID = id
- }
- }
- } else {
- gaAccount = os.Getenv("GA_ACCOUNT")
- }
-
if err := parseHTMLTemplates([][]string{
{"about.html", "common.html", "layout.html"},
{"bot.html", "common.html", "layout.html"},
@@ -1011,10 +980,10 @@
{"talks.godoc.org", otherDomainHandler{"https", "go-talks.appspot.com"}},
{"", httpsRedirectHandler{mux}},
}
- if gceLogName != "" {
+ if gceLogName := viper.GetString(ConfigGCELogName); gceLogName != "" {
ctx := context.Background()
- logc, err := logging.NewClient(ctx, projID)
+ logc, err := logging.NewClient(ctx, viper.GetString(ConfigProject))
if err != nil {
log.Fatalf("Failed to create cloud logging client: %v", err)
}
diff --git a/gddo-server/template.go b/gddo-server/template.go
index 819e58c..3aefd5b 100644
--- a/gddo-server/template.go
+++ b/gddo-server/template.go
@@ -472,12 +472,6 @@
return isInterfacePat.MatchString(t.Decl.Text)
}
-var gaAccount string
-
-func gaAccountFn() string {
- return gaAccount
-}
-
func noteTitleFn(s string) string {
return strings.Title(strings.ToLower(s))
}
@@ -531,7 +525,7 @@
"code": codeFn,
"comment": commentFn,
"equal": reflect.DeepEqual,
- "gaAccount": gaAccountFn,
+ "gaAccount": func() string { return viper.GetString(ConfigGAAccount) },
"host": hostFn,
"htmlComment": htmlCommentFn,
"importPath": importPathFn,