gddo-server/dynconfig: add package Copied from https://go.googlesource.com/pkgsite/+/cb9361e611fe25baabab637bc260f48b345bd1da/internal/config/dynconfig with minor modification to remove reference to derrors package. Change-Id: Ib006861369613183ac29eb1456582e34dbd83b22 Reviewed-on: https://go-review.googlesource.com/c/gddo/+/285834 Trust: Julie Qiu <julie@golang.org> Run-TryBot: Julie Qiu <julie@golang.org> Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/gddo-server/dynconfig/dynconfig.go b/gddo-server/dynconfig/dynconfig.go new file mode 100644 index 0000000..d75f8bc --- /dev/null +++ b/gddo-server/dynconfig/dynconfig.go
@@ -0,0 +1,87 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package dynconfig supports dynamic configuration for pkgsite services. +// Dynamic configuration is read from a file and can change over the lifetime of +// the process. +package dynconfig + +import ( + "context" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "strings" + + "cloud.google.com/go/storage" + "github.com/ghodss/yaml" +) + +// DynamicConfig holds configuration that can change over the lifetime of the +// process. It is loaded from a GCS file or other external source. +type DynamicConfig struct { + // Fields can be added at any time, but removing or changing a field + // requires careful coordination with the config file contents. +} + +// Read reads dynamic configuration from the given location. +// Location may be of the form gs://bucket/object, denoting a GCS bucket. +// Otherwise it is interpreted as a filename. +func Read(ctx context.Context, location string) (_ *DynamicConfig, err error) { + defer wrap(&err, "dynconfig.Read(%q)", location) + + log.Printf("reading dynamic config from %s", location) + var r io.ReadCloser + if strings.HasPrefix(location, "gs://") { + parts := strings.SplitN(location[5:], "/", 2) + if len(parts) != 2 { + return nil, errors.New("bad GCS URL") + } + bucket := parts[0] + object := parts[1] + if err != nil { + return nil, err + } + client, err := storage.NewClient(ctx) + if err != nil { + return nil, err + } + defer client.Close() + r, err = client.Bucket(bucket).Object(object).NewReader(ctx) + if err != nil { + return nil, err + } + } else { + r, err = os.Open(location) + if err != nil { + return nil, err + } + } + defer r.Close() + data, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + return Parse(data) +} + +// Parse parses yamlData as a YAML description of DynamicConfig. +func Parse(yamlData []byte) (_ *DynamicConfig, err error) { + defer wrap(&err, "dynconfig.Parse(data)") + + var dc DynamicConfig + if err := yaml.Unmarshal(yamlData, &dc); err != nil { + return nil, err + } + return &dc, nil +} + +func wrap(errp *error, format string, args ...interface{}) { + if *errp != nil { + *errp = fmt.Errorf("%s: %w", fmt.Sprintf(format, args...), *errp) + } +}
diff --git a/go.mod b/go.mod index 8b23dfb..d21b016 100644 --- a/go.mod +++ b/go.mod
@@ -9,6 +9,7 @@ github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc // indirect github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f + github.com/ghodss/yaml v1.0.0 github.com/go-stack/stack v1.6.0 // indirect github.com/golang/lint v0.0.0-20170918230701-e5d664eb928e github.com/golang/snappy v0.0.0-20170215233205-553a64147049
diff --git a/go.sum b/go.sum index 84fd4e3..bf30d80 100644 --- a/go.sum +++ b/go.sum
@@ -11,6 +11,8 @@ github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f h1:Sk0u0gIncQaQD23zAoAZs2DNi2u2l5UTLi4CmCBL5v8= github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-stack/stack v1.6.0 h1:MmJCxYVKTJ0SplGKqFVX3SBnmaUhODHZrrFF6jMbpZk= github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/golang/lint v0.0.0-20170918230701-e5d664eb928e h1:ior8LN6127GsA53E9mD9nH/oP/LVbJplmLH5V8o+/Uk=