github.com/resonatecoop/id@v1.1.0-43/config/etcd.go (about)

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