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  }