github.com/alpe/etcd@v0.1.2-0.20130915230056-09f31af88aeb/config.go (about)

     1  package main
     2  
     3  import (
     4  	"crypto/tls"
     5  	"crypto/x509"
     6  	"encoding/json"
     7  	"encoding/pem"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  )
    12  
    13  //--------------------------------------
    14  // Config
    15  //--------------------------------------
    16  
    17  // Get the server info from previous conf file
    18  // or from the user
    19  func getInfo(path string) *Info {
    20  
    21  	infoPath := filepath.Join(path, "info")
    22  
    23  	if force {
    24  		// Delete the old configuration if exist
    25  		logPath := filepath.Join(path, "log")
    26  		confPath := filepath.Join(path, "conf")
    27  		snapshotPath := filepath.Join(path, "snapshot")
    28  		os.Remove(infoPath)
    29  		os.Remove(logPath)
    30  		os.Remove(confPath)
    31  		os.RemoveAll(snapshotPath)
    32  	} else if info := readInfo(infoPath); info != nil {
    33  		infof("Found node configuration in '%s'. Ignoring flags", infoPath)
    34  		return info
    35  	}
    36  
    37  	// Read info from command line
    38  	info := &argInfo
    39  
    40  	// Write to file.
    41  	content, _ := json.MarshalIndent(info, "", " ")
    42  	content = []byte(string(content) + "\n")
    43  	if err := ioutil.WriteFile(infoPath, content, 0644); err != nil {
    44  		fatalf("Unable to write info to file: %v", err)
    45  	}
    46  
    47  	infof("Wrote node configuration to '%s'", infoPath)
    48  
    49  	return info
    50  }
    51  
    52  // readInfo reads from info file and decode to Info struct
    53  func readInfo(path string) *Info {
    54  	file, err := os.Open(path)
    55  
    56  	if err != nil {
    57  		if os.IsNotExist(err) {
    58  			return nil
    59  		}
    60  		fatal(err)
    61  	}
    62  	defer file.Close()
    63  
    64  	info := &Info{}
    65  
    66  	content, err := ioutil.ReadAll(file)
    67  	if err != nil {
    68  		fatalf("Unable to read info: %v", err)
    69  		return nil
    70  	}
    71  
    72  	if err = json.Unmarshal(content, &info); err != nil {
    73  		fatalf("Unable to parse info: %v", err)
    74  		return nil
    75  	}
    76  
    77  	return info
    78  }
    79  
    80  func tlsConfigFromInfo(info TLSInfo) (t TLSConfig, ok bool) {
    81  	var keyFile, certFile, CAFile string
    82  	var tlsCert tls.Certificate
    83  	var err error
    84  
    85  	t.Scheme = "http"
    86  
    87  	keyFile = info.KeyFile
    88  	certFile = info.CertFile
    89  	CAFile = info.CAFile
    90  
    91  	// If the user do not specify key file, cert file and
    92  	// CA file, the type will be HTTP
    93  	if keyFile == "" && certFile == "" && CAFile == "" {
    94  		return t, true
    95  	}
    96  
    97  	// both the key and cert must be present
    98  	if keyFile == "" || certFile == "" {
    99  		return t, false
   100  	}
   101  
   102  	tlsCert, err = tls.LoadX509KeyPair(certFile, keyFile)
   103  	if err != nil {
   104  		fatal(err)
   105  	}
   106  
   107  	t.Scheme = "https"
   108  	t.Server.ClientAuth, t.Server.ClientCAs = newCertPool(CAFile)
   109  
   110  	// The client should trust the RootCA that the Server uses since
   111  	// everyone is a peer in the network.
   112  	t.Client.Certificates = []tls.Certificate{tlsCert}
   113  	t.Client.RootCAs = t.Server.ClientCAs
   114  
   115  	return t, true
   116  }
   117  
   118  // newCertPool creates x509 certPool and corresponding Auth Type.
   119  // If the given CAfile is valid, add the cert into the pool and verify the clients'
   120  // certs against the cert in the pool.
   121  // If the given CAfile is empty, do not verify the clients' cert.
   122  // If the given CAfile is not valid, fatal.
   123  func newCertPool(CAFile string) (tls.ClientAuthType, *x509.CertPool) {
   124  	if CAFile == "" {
   125  		return tls.NoClientCert, nil
   126  	}
   127  	pemByte, err := ioutil.ReadFile(CAFile)
   128  	check(err)
   129  
   130  	block, pemByte := pem.Decode(pemByte)
   131  
   132  	cert, err := x509.ParseCertificate(block.Bytes)
   133  	check(err)
   134  
   135  	certPool := x509.NewCertPool()
   136  
   137  	certPool.AddCert(cert)
   138  
   139  	return tls.RequireAndVerifyClientCert, certPool
   140  }