github.com/jxgolibs/go-oauth2-server@v1.0.1/config/etcd.go (about) 1 package config 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "strings" 8 9 "github.com/RichardKnop/go-oauth2-server/log" 10 "github.com/coreos/etcd/clientv3" 11 "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes" 12 "github.com/coreos/etcd/pkg/transport" 13 "golang.org/x/net/context" 14 ) 15 16 var ( 17 etcdEndpoints = "http://localhost:2379" 18 etcdCertFile, etcdKeyFile, etcdCaFile string 19 etcdConfigPath = "/config/go_oauth2_server.json" 20 ) 21 22 type etcdBackend struct{} 23 24 func (b *etcdBackend) InitConfigBackend() { 25 // Overwrite default values with environment variables if they are set 26 if os.Getenv("ETCD_ENDPOINTS") != "" { 27 etcdEndpoints = os.Getenv("ETCD_ENDPOINTS") 28 } 29 if os.Getenv("ETCD_CERT_FILE") != "" { 30 etcdCertFile = os.Getenv("ETCD_CERT_FILE") 31 } 32 if os.Getenv("ETCD_KEY_FILE") != "" { 33 etcdKeyFile = os.Getenv("ETCD_KEY_FILE") 34 } 35 if os.Getenv("ETCD_CA_FILE") != "" { 36 etcdCaFile = os.Getenv("ETCD_CA_FILE") 37 } 38 if os.Getenv("ETCD_CONFIG_PATH") != "" { 39 etcdConfigPath = os.Getenv("ETCD_CONFIG_PATH") 40 } 41 } 42 43 // LoadConfig gets the JSON from ETCD and unmarshals it to the config object 44 func (b *etcdBackend) LoadConfig() (*Config, error) { 45 46 cli, err := newEtcdClient(etcdEndpoints, etcdCertFile, etcdKeyFile, etcdCaFile) 47 if err != nil { 48 return nil, err 49 } 50 defer cli.Close() 51 52 // Read from remote config the first time 53 ctx, cancel := context.WithTimeout(context.Background(), contextTimeout) 54 resp, err := cli.Get(ctx, etcdConfigPath) 55 cancel() 56 if err != nil { 57 switch err { 58 case context.Canceled: 59 return nil, fmt.Errorf("ctx is canceled by another routine: %v", err) 60 case context.DeadlineExceeded: 61 return nil, fmt.Errorf("ctx is attached with a deadline is exceeded: %v", err) 62 case rpctypes.ErrEmptyKey: 63 return nil, fmt.Errorf("client-side error: %v", err) 64 default: 65 return nil, fmt.Errorf("bad cluster endpoints, which are not etcd servers: %v", err) 66 } 67 } 68 69 if len(resp.Kvs) == 0 { 70 return nil, fmt.Errorf("key not found: %s", etcdConfigPath) 71 } 72 73 // Unmarshal the config JSON into the cnf object 74 newCnf := new(Config) 75 76 if err := json.Unmarshal([]byte(resp.Kvs[0].Value), newCnf); err != nil { 77 return nil, err 78 } 79 80 return newCnf, nil 81 } 82 83 // RefreshConfig sets config through the pointer so config actually gets refreshed 84 func (b *etcdBackend) RefreshConfig(newCnf *Config) { 85 *Cnf = *newCnf 86 } 87 88 func newEtcdClient(theEndpoints, certFile, keyFile, caFile string) (*clientv3.Client, error) { 89 // Log the etcd endpoint for debugging purposes 90 log.INFO.Printf("ETCD Endpoints: %s", theEndpoints) 91 92 // ETCD config 93 etcdConfig := clientv3.Config{ 94 Endpoints: strings.Split(theEndpoints, ","), 95 DialTimeout: dialTimeout, 96 } 97 98 // Optionally, configure TLS transport 99 if certFile != "" && keyFile != "" && caFile != "" { 100 // Load client cert 101 tlsInfo := transport.TLSInfo{ 102 CertFile: certFile, 103 KeyFile: keyFile, 104 TrustedCAFile: caFile, 105 } 106 107 // Setup HTTPS client 108 tlsConfig, err := tlsInfo.ClientConfig() 109 if err != nil { 110 return nil, err 111 } 112 // Add TLS config 113 etcdConfig.TLS = tlsConfig 114 } 115 116 // ETCD client 117 return clientv3.New(etcdConfig) 118 }