https://github.com/etcd-io/etcd
Revision 8670e1b7aad03be94f5c22c21b80e179cdc0d99d authored by Ben Johnson on 12 October 2013, 21:56:43 UTC, committed by Ben Johnson on 12 October 2013, 21:56:43 UTC
1 parent bb94015
Raw File
Tip revision: 8670e1b7aad03be94f5c22c21b80e179cdc0d99d authored by Ben Johnson on 12 October 2013, 21:56:43 UTC
Refactored.
Tip revision: 8670e1b
config.go
package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/coreos/etcd/log"
	"github.com/coreos/etcd/server"
)

//--------------------------------------
// Config
//--------------------------------------

// Get the server info from previous conf file
// or from the user
func getInfo(path string) *Info {

	infoPath := filepath.Join(path, "info")

	if force {
		// Delete the old configuration if exist
		logPath := filepath.Join(path, "log")
		confPath := filepath.Join(path, "conf")
		snapshotPath := filepath.Join(path, "snapshot")
		os.Remove(infoPath)
		os.Remove(logPath)
		os.Remove(confPath)
		os.RemoveAll(snapshotPath)
	} else if info := readInfo(infoPath); info != nil {
		log.Infof("Found node configuration in '%s'. Ignoring flags", infoPath)
		return info
	}

	// Read info from command line
	info := &argInfo

	// Write to file.
	content, _ := json.MarshalIndent(info, "", " ")
	content = []byte(string(content) + "\n")
	if err := ioutil.WriteFile(infoPath, content, 0644); err != nil {
		log.Fatalf("Unable to write info to file: %v", err)
	}

	log.Infof("Wrote node configuration to '%s'", infoPath)

	return info
}

// readInfo reads from info file and decode to Info struct
func readInfo(path string) *Info {
	file, err := os.Open(path)

	if err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		log.Fatal(err)
	}
	defer file.Close()

	info := &Info{}

	content, err := ioutil.ReadAll(file)
	if err != nil {
		log.Fatalf("Unable to read info: %v", err)
		return nil
	}

	if err = json.Unmarshal(content, &info); err != nil {
		log.Fatalf("Unable to parse info: %v", err)
		return nil
	}

	return info
}

func tlsConfigFromInfo(info server.TLSInfo) (t server.TLSConfig, ok bool) {
	var keyFile, certFile, CAFile string
	var tlsCert tls.Certificate
	var err error

	t.Scheme = "http"

	keyFile = info.KeyFile
	certFile = info.CertFile
	CAFile = info.CAFile

	// If the user do not specify key file, cert file and
	// CA file, the type will be HTTP
	if keyFile == "" && certFile == "" && CAFile == "" {
		return t, true
	}

	// both the key and cert must be present
	if keyFile == "" || certFile == "" {
		return t, false
	}

	tlsCert, err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		log.Fatal(err)
	}

	t.Scheme = "https"
	t.Server.ClientAuth, t.Server.ClientCAs = newCertPool(CAFile)

	// The client should trust the RootCA that the Server uses since
	// everyone is a peer in the network.
	t.Client.Certificates = []tls.Certificate{tlsCert}
	t.Client.RootCAs = t.Server.ClientCAs

	return t, true
}

// newCertPool creates x509 certPool and corresponding Auth Type.
// If the given CAfile is valid, add the cert into the pool and verify the clients'
// certs against the cert in the pool.
// If the given CAfile is empty, do not verify the clients' cert.
// If the given CAfile is not valid, fatal.
func newCertPool(CAFile string) (tls.ClientAuthType, *x509.CertPool) {
	if CAFile == "" {
		return tls.NoClientCert, nil
	}
	pemByte, err := ioutil.ReadFile(CAFile)
	check(err)

	block, pemByte := pem.Decode(pemByte)

	cert, err := x509.ParseCertificate(block.Bytes)
	check(err)

	certPool := x509.NewCertPool()

	certPool.AddCert(cert)

	return tls.RequireAndVerifyClientCert, certPool
}
back to top