github.com/kafkaliu/etcd@v0.1.2-0.20131007164923-44c16dd30d69/config.go (about)

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