in internal/config/config.go [355:529]
func Init(ctx context.Context) (_ *Config, err error) {
defer derrors.Add(&err, "config.Init(ctx)")
// Build a Config from the execution environment, loading some values
// from envvars and others from remote services.
cfg := &Config{
AuthValues: parseCommaList(os.Getenv("GO_DISCOVERY_AUTH_VALUES")),
IndexURL: GetEnv("GO_MODULE_INDEX_URL", "https://index.golang.org/index"),
ProxyURL: GetEnv("GO_MODULE_PROXY_URL", "https://proxy.golang.org"),
Port: os.Getenv("PORT"),
DebugPort: os.Getenv("DEBUG_PORT"),
// Resolve AppEngine identifiers
ProjectID: os.Getenv("GOOGLE_CLOUD_PROJECT"),
ServiceID: GetEnv("GAE_SERVICE", os.Getenv("GO_DISCOVERY_SERVICE")),
// Version ID from either AppEngine, Cloud Run (see
// https://cloud.google.com/run/docs/reference/container-contract) or
// GKE (set by our own config).
VersionID: GetEnv("GAE_VERSION", GetEnv("K_REVISION", os.Getenv("DOCKER_IMAGE"))),
InstanceID: GetEnv("GAE_INSTANCE", os.Getenv("GO_DISCOVERY_INSTANCE")),
GoogleTagManagerID: os.Getenv("GO_DISCOVERY_GOOGLE_TAG_MANAGER_ID"),
QueueURL: os.Getenv("GO_DISCOVERY_QUEUE_URL"),
QueueAudience: os.Getenv("GO_DISCOVERY_QUEUE_AUDIENCE"),
// LocationID is essentially hard-coded until we figure out a good way to
// determine it programmatically, but we check an environment variable in
// case it needs to be overridden.
LocationID: GetEnv("GO_DISCOVERY_GAE_LOCATION_ID", "us-central1"),
// This fallback should only be used when developing locally.
FallbackVersionLabel: time.Now().Format(AppVersionFormat),
DBHost: chooseOne(GetEnv("GO_DISCOVERY_DATABASE_HOST", "localhost")),
DBUser: GetEnv("GO_DISCOVERY_DATABASE_USER", "postgres"),
DBPassword: os.Getenv("GO_DISCOVERY_DATABASE_PASSWORD"),
DBSecondaryHost: chooseOne(os.Getenv("GO_DISCOVERY_DATABASE_SECONDARY_HOST")),
DBPort: GetEnv("GO_DISCOVERY_DATABASE_PORT", "5432"),
DBName: GetEnv("GO_DISCOVERY_DATABASE_NAME", "discovery-db"),
DBSecret: os.Getenv("GO_DISCOVERY_DATABASE_SECRET"),
DBSSL: GetEnv("GO_DISCOVERY_DATABASE_SSL", "disable"),
RedisCacheHost: os.Getenv("GO_DISCOVERY_REDIS_HOST"),
RedisBetaCacheHost: os.Getenv("GO_DISCOVERY_REDIS_BETA_HOST"),
RedisCachePort: GetEnv("GO_DISCOVERY_REDIS_PORT", "6379"),
Quota: QuotaSettings{
Enable: os.Getenv("GO_DISCOVERY_ENABLE_QUOTA") == "true",
QPS: GetEnvInt(ctx, "GO_DISCOVERY_QUOTA_QPS", 10),
Burst: 20, // ignored in redis-based quota implementation
MaxEntries: 1000, // ignored in redis-based quota implementation
RecordOnly: func() *bool {
t := (os.Getenv("GO_DISCOVERY_QUOTA_RECORD_ONLY") != "false")
return &t
}(),
AuthValues: parseCommaList(os.Getenv("GO_DISCOVERY_AUTH_VALUES")),
},
UseProfiler: os.Getenv("GO_DISCOVERY_USE_PROFILER") == "true",
LogLevel: os.Getenv("GO_DISCOVERY_LOG_LEVEL"),
ServeStats: os.Getenv("GO_DISCOVERY_SERVE_STATS") == "true",
DisableErrorReporting: os.Getenv("GO_DISCOVERY_DISABLE_ERROR_REPORTING") == "true",
VulnDB: GetEnv("GO_DISCOVERY_VULN_DB", "https://storage.googleapis.com/go-vulndb"),
}
log.SetLevel(cfg.LogLevel)
bucket := os.Getenv("GO_DISCOVERY_CONFIG_BUCKET")
object := os.Getenv("GO_DISCOVERY_CONFIG_DYNAMIC")
if bucket != "" {
if object == "" {
return nil, errors.New("GO_DISCOVERY_CONFIG_DYNAMIC must be set if GO_DISCOVERY_CONFIG_BUCKET is")
}
cfg.DynamicConfigLocation = fmt.Sprintf("gs://%s/%s", bucket, object)
} else {
cfg.DynamicConfigLocation = object
}
if cfg.OnGCP() {
// Zone is not available in the environment but can be queried via the metadata API.
zone, err := gceMetadata(ctx, "instance/zone")
if err != nil {
return nil, err
}
cfg.ZoneID = zone
sa, err := gceMetadata(ctx, "instance/service-accounts/default/email")
if err != nil {
return nil, err
}
cfg.ServiceAccount = sa
switch {
case cfg.OnAppEngine():
// Use the gae_app monitored resource. It would be better to use the
// gae_instance monitored resource, but that's not currently supported:
// https://cloud.google.com/logging/docs/api/v2/resource-list#resource-types
cfg.MonitoredResource = &mrpb.MonitoredResource{
Type: "gae_app",
Labels: map[string]string{
"project_id": cfg.ProjectID,
"module_id": cfg.ServiceID,
"version_id": cfg.VersionID,
"zone": cfg.ZoneID,
},
}
case cfg.OnCloudRun():
cfg.MonitoredResource = &mrpb.MonitoredResource{
Type: "cloud_run_revision",
Labels: map[string]string{
"project_id": cfg.ProjectID,
"service_name": cfg.ServiceID,
"revision_name": cfg.VersionID,
"configuration_name": os.Getenv("K_CONFIGURATION"),
},
}
case cfg.OnGKE():
cfg.MonitoredResource = &mrpb.MonitoredResource{
Type: "k8s_container",
Labels: map[string]string{
"project_id": cfg.ProjectID,
"location": path.Base(cfg.ZoneID),
"cluster_name": cfg.DeploymentEnvironment() + "-pkgsite",
"namespace_name": "default",
"pod_name": os.Getenv("HOSTNAME"),
"container_name": cfg.Application(),
},
}
default:
return nil, errors.New("on GCP but using an unknown product")
}
if cfg.InstanceID == "" {
id, err := gceMetadata(ctx, "instance/id")
if err != nil {
return nil, fmt.Errorf("getting instance ID: %v", err)
}
cfg.InstanceID = id
}
} else { // running locally, perhaps
cfg.MonitoredResource = &mrpb.MonitoredResource{
Type: "global",
Labels: map[string]string{"project_id": cfg.ProjectID},
}
}
if cfg.DBHost == "" {
panic("DBHost is empty; impossible")
}
if cfg.DBSecret != "" {
var err error
cfg.DBPassword, err = secrets.Get(ctx, cfg.DBSecret)
if err != nil {
return nil, fmt.Errorf("could not get database password secret: %v", err)
}
}
if cfg.Quota.Enable {
s, err := secrets.Get(ctx, "quota-hmac-key")
if err != nil {
return nil, err
}
hmacKey, err := hex.DecodeString(s)
if err != nil {
return nil, err
}
if len(hmacKey) < 16 {
return nil, errors.New("HMAC secret must be at least 16 bytes")
}
cfg.Quota.HMACKey = hmacKey
} else {
log.Debugf(ctx, "quota enforcement disabled")
}
// If the <env>-override.yaml file exists in the configured bucket, it
// should provide overrides for selected configuration.
// Use this when you want to fix something in prod quickly, without waiting
// to re-deploy. (Otherwise, do not use it.)
if cfg.DeploymentEnvironment() != "local" {
overrideObj := fmt.Sprintf("%s-override.yaml", cfg.DeploymentEnvironment())
overrideBytes, err := readOverrideFile(ctx, bucket, overrideObj)
if err != nil {
log.Error(ctx, err)
} else {
log.Infof(ctx, "processing overrides from gs://%s/%s", bucket, overrideObj)
processOverrides(ctx, cfg, overrideBytes)
}
}
return cfg, nil
}