<commit_before>package fastping

import (
	"net"
	"sync"
	"testing"
	"time"
)

type addHostTest struct {
	host   string
	addr   *net.IPAddr
	expect bool
}

var addHostTests = []addHostTest{
	{host: "127.0.0.1", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: true},
	{host: "localhost", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: false},
}

func TestAddIP(t *testing.T) {
	p := NewPinger()

	for _, tt := range addHostTests {
		if ok := p.AddIP(tt.host); ok != nil {
			if tt.expect != false {
				t.Errorf("AddIP failed: got %v, expected %v", ok, tt.expect)
			}
		}
	}
	for _, tt := range addHostTests {
		if tt.expect {
			if !p.addrs[tt.host].IP.Equal(tt.addr.IP) {
				t.Errorf("AddIP didn't save IPAddr: %v", tt.host)
			}
		}
	}
}

func TestRun(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	if err := p.AddIP("127.0.0.100"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	found1, found100 := false, false
	called, idle := false, false
	p.AddHandler("receive", func(ip *net.IPAddr, d time.Duration) {
		called = true
		if ip.String() == "127.0.0.1" {
			found1 = true
		} else if ip.String() == "127.0.0.100" {
			found100 = true
		}
	})
	p.AddHandler("idle", func() {
		idle = true
	})
	err := p.Run()
	if err != nil {
		t.Fatalf("Pinger returns error: %v", err)
	}
	if !called {
		t.Fatalf("Pinger didn't get any responses")
	}
	if !idle {
		t.Fatalf("Pinger didn't call OnIdle function")
	}
	if !found1 {
		t.Fatalf("Pinger `127.0.0.1` didn't respond")
	}
	if found100 {
		t.Fatalf("Pinger `127.0.0.100` responded")
	}
}

func TestMultiRun(t *testing.T) {
	p1 := NewPinger()
	p2 := NewPinger()

	if err := p1.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	if err := p2.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	var mu sync.Mutex
	res1 := 0
	p1.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res1++
		mu.Unlock()
	})

	res2 := 0
	p2.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res2++
		mu.Unlock()
	})
	p1.MaxRTT, p2.MaxRTT = time.Millisecond*100, time.Millisecond*100

	if err := p1.Run(); err != nil {
		t.Fatalf("Pinger 1 returns error: %v", err)
	}
	if res1 == 0 {
		t.Fatalf("Pinger 1 didn't get any responses")
	}
	if res2 > 0 {
		t.Fatalf("Pinger 2 got response")
	}

	res1, res2 = 0, 0
	if err := p2.Run(); err != nil {
		t.Fatalf("Pinger 2 returns error: %v", err)
	}
	if res1 > 0 {
		t.Fatalf("Pinger 1 got response")
	}
	if res2 == 0 {
		t.Fatalf("Pinger 2 didn't get any responses")
	}

	res1, res2 = 0, 0
	errch1, errch2 := make(chan error), make(chan error)
	go func(ch chan error) {
		err := p1.Run()
		if err != nil {
			ch <- err
		}
	}(errch1)
	go func(ch chan error) {
		err := p2.Run()
		if err != nil {
			ch <- err
		}
	}(errch2)
	ticker := time.NewTicker(time.Millisecond * 200)
	select {
	case err := <-errch1:
		t.Fatalf("Pinger 1 returns error: %v", err)
	case err := <-errch2:
		t.Fatalf("Pinger 2 returns error: %v", err)
	case <-ticker.C:
		break
	}
	mu.Lock()
	if res1 != 1 {
		t.Fatalf("Pinger 1 didn't get correct response")
	}
	if res2 != 1 {
		t.Fatalf("Pinger 2 didn't get correct response")
	}
	mu.Unlock()
}

func TestRunLoop(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}
	p.MaxRTT = time.Millisecond * 100

	recvCount, idleCount := 0, 0
	p.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		recvCount++
	})
	p.AddHandler("idle", func() {
		idleCount++
	})

	wait := make(chan bool)
	quit, errch := p.RunLoop()
	ticker := time.NewTicker(time.Millisecond * 250)
	select {
	case err := <-errch:
		t.Fatalf("Pinger returns error %v", err)
	case <-ticker.C:
		quit <- wait
	case <-wait:
		break
	}

	if recvCount < 2 {
		t.Fatalf("Pinger receive count less than 2")
	}
	if idleCount < 2 {
		t.Fatalf("Pinger idle count less than 2")
	}
}

func TestTimeToBytes(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	expect := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	for i := 0; i < 8; i++ {
		if b[i] != expect[i] {
			t.Errorf("timeToBytes failed: got %v, expected: %v", b, expect)
			break
		}
	}
}

func TestBytesToTime(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	b := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	expect, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	tm := bytesToTime(b)
	if !tm.Equal(expect) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm.UTC(), expect.UTC())
	}
}

func TestTimeToBytesToTime(t *testing.T) {
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	tm2 := bytesToTime(b)
	if !tm.Equal(tm2) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm2.UTC(), tm.UTC())
	}
}
<commit_msg>Use defer when it calls Mutex Unlock<commit_after>package fastping

import (
	"net"
	"sync"
	"testing"
	"time"
)

type addHostTest struct {
	host   string
	addr   *net.IPAddr
	expect bool
}

var addHostTests = []addHostTest{
	{host: "127.0.0.1", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: true},
	{host: "localhost", addr: &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}, expect: false},
}

func TestAddIP(t *testing.T) {
	p := NewPinger()

	for _, tt := range addHostTests {
		if ok := p.AddIP(tt.host); ok != nil {
			if tt.expect != false {
				t.Errorf("AddIP failed: got %v, expected %v", ok, tt.expect)
			}
		}
	}
	for _, tt := range addHostTests {
		if tt.expect {
			if !p.addrs[tt.host].IP.Equal(tt.addr.IP) {
				t.Errorf("AddIP didn't save IPAddr: %v", tt.host)
			}
		}
	}
}

func TestRun(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	if err := p.AddIP("127.0.0.100"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}

	found1, found100 := false, false
	called, idle := false, false
	p.AddHandler("receive", func(ip *net.IPAddr, d time.Duration) {
		called = true
		if ip.String() == "127.0.0.1" {
			found1 = true
		} else if ip.String() == "127.0.0.100" {
			found100 = true
		}
	})
	p.AddHandler("idle", func() {
		idle = true
	})
	err := p.Run()
	if err != nil {
		t.Fatalf("Pinger returns error: %v", err)
	}
	if !called {
		t.Fatalf("Pinger didn't get any responses")
	}
	if !idle {
		t.Fatalf("Pinger didn't call OnIdle function")
	}
	if !found1 {
		t.Fatalf("Pinger `127.0.0.1` didn't respond")
	}
	if found100 {
		t.Fatalf("Pinger `127.0.0.100` responded")
	}
}

func TestMultiRun(t *testing.T) {
	p1 := NewPinger()
	p2 := NewPinger()

	if err := p1.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	if err := p2.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP 1 failed: %v", err)
	}

	var mu sync.Mutex
	res1 := 0
	p1.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res1++
		mu.Unlock()
	})

	res2 := 0
	p2.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		mu.Lock()
		res2++
		mu.Unlock()
	})
	p1.MaxRTT, p2.MaxRTT = time.Millisecond*100, time.Millisecond*100

	if err := p1.Run(); err != nil {
		t.Fatalf("Pinger 1 returns error: %v", err)
	}
	if res1 == 0 {
		t.Fatalf("Pinger 1 didn't get any responses")
	}
	if res2 > 0 {
		t.Fatalf("Pinger 2 got response")
	}

	res1, res2 = 0, 0
	if err := p2.Run(); err != nil {
		t.Fatalf("Pinger 2 returns error: %v", err)
	}
	if res1 > 0 {
		t.Fatalf("Pinger 1 got response")
	}
	if res2 == 0 {
		t.Fatalf("Pinger 2 didn't get any responses")
	}

	res1, res2 = 0, 0
	errch1, errch2 := make(chan error), make(chan error)
	go func(ch chan error) {
		err := p1.Run()
		if err != nil {
			ch <- err
		}
	}(errch1)
	go func(ch chan error) {
		err := p2.Run()
		if err != nil {
			ch <- err
		}
	}(errch2)
	ticker := time.NewTicker(time.Millisecond * 200)
	select {
	case err := <-errch1:
		t.Fatalf("Pinger 1 returns error: %v", err)
	case err := <-errch2:
		t.Fatalf("Pinger 2 returns error: %v", err)
	case <-ticker.C:
		break
	}
	mu.Lock()
	defer mu.Unlock()
	if res1 != 1 {
		t.Fatalf("Pinger 1 didn't get correct response")
	}
	if res2 != 1 {
		t.Fatalf("Pinger 2 didn't get correct response")
	}
}

func TestRunLoop(t *testing.T) {
	p := NewPinger()

	if err := p.AddIP("127.0.0.1"); err != nil {
		t.Fatalf("AddIP failed: %v", err)
	}
	p.MaxRTT = time.Millisecond * 100

	recvCount, idleCount := 0, 0
	p.AddHandler("receive", func(*net.IPAddr, time.Duration) {
		recvCount++
	})
	p.AddHandler("idle", func() {
		idleCount++
	})

	wait := make(chan bool)
	quit, errch := p.RunLoop()
	ticker := time.NewTicker(time.Millisecond * 250)
	select {
	case err := <-errch:
		t.Fatalf("Pinger returns error %v", err)
	case <-ticker.C:
		quit <- wait
	case <-wait:
		break
	}

	if recvCount < 2 {
		t.Fatalf("Pinger receive count less than 2")
	}
	if idleCount < 2 {
		t.Fatalf("Pinger idle count less than 2")
	}
}

func TestTimeToBytes(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	expect := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	for i := 0; i < 8; i++ {
		if b[i] != expect[i] {
			t.Errorf("timeToBytes failed: got %v, expected: %v", b, expect)
			break
		}
	}
}

func TestBytesToTime(t *testing.T) {
	// 2009-11-10 23:00:00 +0000 UTC = 1257894000000000000
	b := []byte{0x11, 0x74, 0xef, 0xed, 0xab, 0x18, 0x60, 0x00}
	expect, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	tm := bytesToTime(b)
	if !tm.Equal(expect) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm.UTC(), expect.UTC())
	}
}

func TestTimeToBytesToTime(t *testing.T) {
	tm, err := time.Parse(time.RFC3339, "2009-11-10T23:00:00Z")
	if err != nil {
		t.Errorf("time.Parse failed: %v", err)
	}
	b := timeToBytes(tm)
	tm2 := bytesToTime(b)
	if !tm.Equal(tm2) {
		t.Errorf("bytesToTime failed: got %v, expected: %v", tm2.UTC(), tm.UTC())
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"

	"github.com/premkit/premkit/certs"
	"github.com/premkit/premkit/log"
	"github.com/premkit/premkit/server"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	defaultHTTPPort               = 80
	defaultHTTPSPort              = 443
	defaultTLSKeyFile             = ""
	defaultTLSCertFile            = ""
	defaultGenerateSelfSignedCert = true

	defaultDataFile = "/data/premkit.db"
	defaultTLSStore = "/data/premkit.db"
)

var daemonCmd = &cobra.Command{
	Use:   "daemon",
	Short: "A high performance reverse proxy",
	Long: `PremKit is built around this high performance reverse proxy which supports
backend service automatic registration with namespacing.

'premkit daemon' will start this reverse proxy and listen for requests for registrations
and for requests to forward to backend services.`,
}

func init() {
	viper.SetEnvPrefix("premkit")
	viper.AutomaticEnv()

	daemonCmd.Flags().Int("bind-http", defaultHTTPPort, "port on which the reverse proxy will bind and listen for http connections")
	daemonCmd.Flags().Int("bind-https", defaultHTTPSPort, "port on which the reverse proxy will bind and listen for https (tls) connections")
	daemonCmd.Flags().String("key-file", defaultTLSKeyFile, "path to private key to use when serving tls connections")
	daemonCmd.Flags().String("cert-file", defaultTLSCertFile, "path to cert to use when serving tls connections")
	daemonCmd.Flags().Bool("self-signed", defaultGenerateSelfSignedCert, "true to have premkit generate a new self-signed keypair to use for tls connections")
	daemonCmd.Flags().String("data-file", defaultDataFile, "location of the database file")
	daemonCmd.Flags().String("tls-store", defaultTLSStore, "location to store generated tls certs and keys in")

	viper.BindPFlag("bind_http", daemonCmd.Flags().Lookup("bind-http"))
	viper.BindPFlag("bind_https", daemonCmd.Flags().Lookup("bind-https"))
	viper.BindPFlag("key_file", daemonCmd.Flags().Lookup("key-file"))
	viper.BindPFlag("cert_file", daemonCmd.Flags().Lookup("cert-file"))
	viper.BindPFlag("self_signed", daemonCmd.Flags().Lookup("self-signed"))
	viper.BindPFlag("data_file", daemonCmd.Flags().Lookup("data-file"))
	viper.BindPFlag("tls_store", daemonCmd.Flags().Lookup("tls-store"))

	daemonCmd.RunE = daemon
}

func daemon(cmd *cobra.Command, args []string) error {
	if err := InitializeConfig(daemonCmd); err != nil {
		return err
	}

	config, err := buildConfig()
	if err != nil {
		return err
	}

	showAppliedSettings()

	server.Run(config)
	return nil
}

func buildConfig() (*server.Config, error) {
	keyFile := ""
	certFile := ""

	if viper.GetInt("bind_https") != 0 {
		if viper.GetBool("self_signed") {
			k, c, err := certs.GenerateSelfSigned(viper.GetString("tls_store"))
			if err != nil {
				log.Error(err)
				return nil, err
			}
			keyFile = k
			certFile = c
		} else if viper.GetString("key_file") != "" && viper.GetString("cert_file") != "" {
			if err := certs.ParseKeyPair(viper.GetString("key_file"), viper.GetString("cert_file")); err != nil {
				log.Error(err)
				return nil, err
			}

			keyFile = viper.GetString("key_file")
			certFile = viper.GetString("cert_file")
		}
	}

	config := server.Config{
		HTTPPort:  viper.GetInt("bind_http"),
		HTTPSPort: viper.GetInt("bind_https"),

		TLSKeyFile:  keyFile,
		TLSCertFile: certFile,
	}

	return &config, nil
}

func showAppliedSettings() {
	var nonDefault []string

	if viper.GetInt("bind_http") != defaultHTTPPort {
		nonDefault = append(nonDefault, fmt.Sprintf("HTTP Bind Port set to %d", viper.GetInt("bind_http")))
	}
	if viper.GetInt("bind_https") != defaultHTTPSPort {
		nonDefault = append(nonDefault, fmt.Sprintf("HTTPS Bind Port set to %d", viper.GetInt("bind_https")))
	}

	if viper.GetString("key_file") != defaultTLSKeyFile {
		nonDefault = append(nonDefault, fmt.Sprintf("TLS Key File set to %s", viper.GetString("key_file")))
	}
	if viper.GetString("cert_file") != defaultTLSCertFile {
		nonDefault = append(nonDefault, fmt.Sprintf("TLS Cert File set to %s", viper.GetString("cert_file")))
	}
	if viper.GetBool("self_signed") != defaultGenerateSelfSignedCert {
		nonDefault = append(nonDefault, fmt.Sprintf("Generate Self Signed Cert set to %v", viper.GetBool("self_signed")))
	}

	if viper.GetString("data_file") != defaultDataFile {
		nonDefault = append(nonDefault, fmt.Sprintf("DataFile set to %s", viper.GetString("data_file")))
	}
	if viper.GetString("tls_store") != defaultTLSStore {
		nonDefault = append(nonDefault, fmt.Sprintf("TLS Store set to %s", viper.GetString("tls_store")))
	}

	if len(nonDefault) == 0 {
		log.Infof("Using default settings")
		return
	}

	log.Infof("Overridden settings: ")
	for _, n := range nonDefault {
		log.Infof("\t%s", n)
	}
}
<commit_msg>These must be different because one is a dir, one is a file<commit_after>package commands

import (
	"fmt"

	"github.com/premkit/premkit/certs"
	"github.com/premkit/premkit/log"
	"github.com/premkit/premkit/server"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	defaultHTTPPort               = 80
	defaultHTTPSPort              = 443
	defaultTLSKeyFile             = ""
	defaultTLSCertFile            = ""
	defaultGenerateSelfSignedCert = true

	defaultDataFile = "/data/premkit.db"
	defaultTLSStore = "/data/tls"
)

var daemonCmd = &cobra.Command{
	Use:   "daemon",
	Short: "A high performance reverse proxy",
	Long: `PremKit is built around this high performance reverse proxy which supports
backend service automatic registration with namespacing.

'premkit daemon' will start this reverse proxy and listen for requests for registrations
and for requests to forward to backend services.`,
}

func init() {
	viper.SetEnvPrefix("premkit")
	viper.AutomaticEnv()

	daemonCmd.Flags().Int("bind-http", defaultHTTPPort, "port on which the reverse proxy will bind and listen for http connections")
	daemonCmd.Flags().Int("bind-https", defaultHTTPSPort, "port on which the reverse proxy will bind and listen for https (tls) connections")
	daemonCmd.Flags().String("key-file", defaultTLSKeyFile, "path to private key to use when serving tls connections")
	daemonCmd.Flags().String("cert-file", defaultTLSCertFile, "path to cert to use when serving tls connections")
	daemonCmd.Flags().Bool("self-signed", defaultGenerateSelfSignedCert, "true to have premkit generate a new self-signed keypair to use for tls connections")
	daemonCmd.Flags().String("data-file", defaultDataFile, "location of the database file")
	daemonCmd.Flags().String("tls-store", defaultTLSStore, "location to store generated tls certs and keys in")

	viper.BindPFlag("bind_http", daemonCmd.Flags().Lookup("bind-http"))
	viper.BindPFlag("bind_https", daemonCmd.Flags().Lookup("bind-https"))
	viper.BindPFlag("key_file", daemonCmd.Flags().Lookup("key-file"))
	viper.BindPFlag("cert_file", daemonCmd.Flags().Lookup("cert-file"))
	viper.BindPFlag("self_signed", daemonCmd.Flags().Lookup("self-signed"))
	viper.BindPFlag("data_file", daemonCmd.Flags().Lookup("data-file"))
	viper.BindPFlag("tls_store", daemonCmd.Flags().Lookup("tls-store"))

	daemonCmd.RunE = daemon
}

func daemon(cmd *cobra.Command, args []string) error {
	if err := InitializeConfig(daemonCmd); err != nil {
		return err
	}

	config, err := buildConfig()
	if err != nil {
		return err
	}

	showAppliedSettings()

	server.Run(config)
	return nil
}

func buildConfig() (*server.Config, error) {
	keyFile := ""
	certFile := ""

	if viper.GetInt("bind_https") != 0 {
		if viper.GetBool("self_signed") {
			k, c, err := certs.GenerateSelfSigned(viper.GetString("tls_store"))
			if err != nil {
				log.Error(err)
				return nil, err
			}
			keyFile = k
			certFile = c
		} else if viper.GetString("key_file") != "" && viper.GetString("cert_file") != "" {
			if err := certs.ParseKeyPair(viper.GetString("key_file"), viper.GetString("cert_file")); err != nil {
				log.Error(err)
				return nil, err
			}

			keyFile = viper.GetString("key_file")
			certFile = viper.GetString("cert_file")
		}
	}

	config := server.Config{
		HTTPPort:  viper.GetInt("bind_http"),
		HTTPSPort: viper.GetInt("bind_https"),

		TLSKeyFile:  keyFile,
		TLSCertFile: certFile,
	}

	return &config, nil
}

func showAppliedSettings() {
	var nonDefault []string

	if viper.GetInt("bind_http") != defaultHTTPPort {
		nonDefault = append(nonDefault, fmt.Sprintf("HTTP Bind Port set to %d", viper.GetInt("bind_http")))
	}
	if viper.GetInt("bind_https") != defaultHTTPSPort {
		nonDefault = append(nonDefault, fmt.Sprintf("HTTPS Bind Port set to %d", viper.GetInt("bind_https")))
	}

	if viper.GetString("key_file") != defaultTLSKeyFile {
		nonDefault = append(nonDefault, fmt.Sprintf("TLS Key File set to %s", viper.GetString("key_file")))
	}
	if viper.GetString("cert_file") != defaultTLSCertFile {
		nonDefault = append(nonDefault, fmt.Sprintf("TLS Cert File set to %s", viper.GetString("cert_file")))
	}
	if viper.GetBool("self_signed") != defaultGenerateSelfSignedCert {
		nonDefault = append(nonDefault, fmt.Sprintf("Generate Self Signed Cert set to %v", viper.GetBool("self_signed")))
	}

	if viper.GetString("data_file") != defaultDataFile {
		nonDefault = append(nonDefault, fmt.Sprintf("DataFile set to %s", viper.GetString("data_file")))
	}
	if viper.GetString("tls_store") != defaultTLSStore {
		nonDefault = append(nonDefault, fmt.Sprintf("TLS Store set to %s", viper.GetString("tls_store")))
	}

	if len(nonDefault) == 0 {
		log.Infof("Using default settings")
		return
	}

	log.Infof("Overridden settings: ")
	for _, n := range nonDefault {
		log.Infof("\t%s", n)
	}
}
<|endoftext|>


<commit_before>package gl

// #include <GLES2/gl2.h>
// #include <stdlib.h>
import "C"
import (
	"fmt"
	"unsafe"
)

type Shader C.GLuint
type ShaderType C.GLint

type Program struct {
	id C.GLuint

	shadersValid bool
	shaders      []Shader

	Uniforms   map[string]Uniform
	Attributes map[string]VertexAttrib
}

func CreateProgram() Program {
	return Program{id: C.glCreateProgram()}
}

func CreateShader(stype ShaderType) Shader {
	return Shader(C.glCreateShader(C.GLenum(stype)))
}

func (program *Program) Shaders() []Shader {
	if !program.shadersValid {
		nshaders := C.GLint(0)
		C.glGetProgramiv(program.id, C.GL_ATTACHED_SHADERS, &nshaders)
		program.shaders = make([]Shader, nshaders)
		C.glGetAttachedShaders(program.id, C.GLsizei(nshaders), nil, (*C.GLuint)(&program.shaders[0]))
		program.shadersValid = true
	}
	return program.shaders
}

func (program *Program) AttachShader(shader Shader) {
	C.glAttachShader(program.id, C.GLuint(shader))
	program.shadersValid = false
}

func (program *Program) BindAttribLocation(attrib VertexAttrib, name string) {

	cstr := C.CString(name)
	defer C.free(unsafe.Pointer(cstr))

	C.glBindAttribLocation(program.id, attrib.Index(), (*C.GLchar)(cstr))
}

func (program *Program) DeleteProgram() {
	C.glDeleteProgram(program.id)
}

func (shader Shader) DeleteShader() {
	C.glDeleteShader(C.GLuint(shader))
}

func (program *Program) DetachShader(shader Shader) {
	C.glDetachShader(program.id, C.GLuint(shader))
	program.shadersValid = false
}

// func (program *Program) GetActiveAttrib(index uint) (size int, atype int, name string) {

// 	nameBuf := make([]byte, MAX_ATTRIBUTE_LENGTH)
// 	sizeBuf := C.GLint(0)
// 	typeBuf := C.GLenum(0)

// 	C.glGetActiveAttrib(program.id, C.GLuint(index), C.GLsizei(len(nameBuf)), C.NULL, &sizeBuf, &typeBuf, (*C.GLchar)(&nameBuf[0]))

// 	size = int(sizeBuf)
// 	atype = int(typeBuf)
// 	name = string(nameBuf)
// }

// func (program *Program) GetActiveUniform(index uint) (size int, utype int, name string) {

// 	nameBuf := make([]byte, MAX_UNIFORM_LENGTH)
// 	sizeBuf := C.GLint(0)
// 	typeBuf := C.GLenum(0)

// 	C.glGetActiveUniform(program.id, C.GLuint(index), C.GLsizei(len(nameBuf)), C.NULL, &sizeBuf, &typeBuf, (*C.GLchar)(&nameBuf[0]))

// 	size = int(sizeBuf)
// 	utype = int(typeBuf)
// 	name = string(nameBuf)
// }

// func (program *Program) GetAttachedShaders(GLsizei maxcount, GLsizei* count) []uint {
// 	C.glGetAttachedShaders(program.id, GLsizei maxcount, GLsizei* count, GLuint* shaders)
// }

// func (program *Program) GetProgramiv(pname int,  params int) {
// 	C.glGetProgramiv(program.id, GLenum pname, GLint* params)
// }

// func (program *Program) InfoLog(GLsizei bufsize, GLsizei* length, GLchar* infolog) {
// 	C.glGetProgramInfoLog(program.id, GLsizei bufsize, GLsizei* length, GLchar* infolog)
// }

// func GetShaderiv(shader Shader, pname int, params int) {
// 	C.glGetShaderiv(C.GLuint(shader), GLenum pname, GLint* params)
// }

// func GetShaderInfoLog(shader Shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) {
// 	C.glGetShaderInfoLog(C.GLuint(shader), GLsizei bufsize, GLsizei* length, GLchar* infolog)
// }

// func GetShaderPrecisionFormat(shadertype ShaderType, precisiontype int, GLint* range,  precision int) {
// 	C.glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
// }

// func GetShaderSource(shader Shader, GLsizei bufsize, GLsizei* length, GLchar* source) {
// 	C.glGetShaderSource(C.GLuint(shader), GLsizei bufsize, GLsizei* length, GLchar* source)
// }

// func (program *Program) GetUniformfv(location int, GLfloat* params) {
// 	C.glGetUniformfv(program.id, GLint location, GLfloat* params)
// }

// func (program *Program) GetUniformiv(GLint location,  params int) {
// 	C.glGetUniformiv(program.id, GLint location, GLint* params)
// }

// GL_APICALL int          GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
// GL_APICALL int          GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);

// func ShaderBinary(GLsizei n, shaders []uint, binaryformat int, const GLvoid* binary, GLsizei length) {
// 	C.glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
// }

func (shader Shader) Source(src string) {
	cstr := (*C.GLchar)(C.CString(src))
	defer C.free(unsafe.Pointer(cstr))
	slen := C.GLint(len(src))
	C.glShaderSource(C.GLuint(shader), 1, &cstr, &slen)
}

func (shader Shader) Compile() {
	C.glCompileShader(C.GLuint(shader))

	status := C.GLint(0)
	C.glGetShaderiv(C.GLuint(shader), C.GL_COMPILE_STATUS, &status)

	if status != C.GL_TRUE {
		loglen := C.GLint(0)
		C.glGetShaderiv(C.GLuint(shader), C.GL_INFO_LOG_LENGTH, &loglen)
		log := (*C.GLchar)(C.malloc(C.size_t(loglen)))
		defer C.free(unsafe.Pointer(log))
		C.glGetShaderInfoLog(C.GLuint(shader), C.GLsizei(loglen), nil, log)
		panic(fmt.Errorf("Failed to compile shader: %s", C.GoString((*C.char)(log))))
	}
}

func setupProgramAttributes(program *Program) {
	nattribs := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_ACTIVE_ATTRIBUTES, &nattribs)
	maxattriblen := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxattriblen)
	program.Attributes = make(map[string]VertexAttrib, nattribs)

	for i := 0; i < int(nattribs); i++ {
		name := make([]C.char, maxattriblen)
		namelen := C.GLsizei(0)
		datatype := C.GLenum(0)
		C.glGetActiveAttrib(program.id, C.GLuint(i), C.GLsizei(len(name)), &namelen, nil, &datatype, (*C.GLchar)(&name[0]))

		switch datatype {
		case C.GL_FLOAT:
			program.Attributes[C.GoString(&name[0])] = FloatAttrib{C.GLuint(i)}
		case C.GL_FLOAT_VEC2:
			program.Attributes[C.GoString(&name[0])] = Vec2Attrib{FloatAttrib{C.GLuint(i)}}
		case C.GL_FLOAT_VEC3:
			program.Attributes[C.GoString(&name[0])] = Vec3Attrib{FloatAttrib{C.GLuint(i)}}
		case C.GL_FLOAT_VEC4:
			program.Attributes[C.GoString(&name[0])] = Vec4Attrib{FloatAttrib{C.GLuint(i)}}
		}
	}
}

func setupProgramUniforms(program *Program) {
	nuniforms := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_ACTIVE_UNIFORMS, &nuniforms)
	maxuniformlen := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxuniformlen)
	program.Uniforms = make(map[string]Uniform, nuniforms)

	for i := 0; i < int(nuniforms); i++ {
		name := make([]C.char, maxuniformlen)
		namelen := C.GLsizei(0)
		datatype := C.GLenum(0)
		size := C.GLint(0)
		C.glGetActiveUniform(program.id, C.GLuint(i), C.GLsizei(len(name)), &namelen, &size, &datatype, (*C.GLchar)(&name[0]))

		switch datatype {
		case C.GL_FLOAT:
			program.Uniforms[C.GoString(&name[0])] = Uniform1f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_VEC2:
			program.Uniforms[C.GoString(&name[0])] = Uniform2f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_VEC3:
			program.Uniforms[C.GoString(&name[0])] = Uniform3f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_VEC4:
			program.Uniforms[C.GoString(&name[0])] = Uniform4f{uniformBase{C.GLint(i)}}
		case C.GL_INT:
			program.Uniforms[C.GoString(&name[0])] = Uniform1i{uniformBase{C.GLint(i)}}
		case C.GL_INT_VEC2:
			program.Uniforms[C.GoString(&name[0])] = Uniform2i{uniformBase{C.GLint(i)}}
		case C.GL_INT_VEC3:
			program.Uniforms[C.GoString(&name[0])] = Uniform3i{uniformBase{C.GLint(i)}}
		case C.GL_INT_VEC4:
			program.Uniforms[C.GoString(&name[0])] = Uniform4i{uniformBase{C.GLint(i)}}
		case C.GL_BOOL:
			program.Uniforms[C.GoString(&name[0])] = Uniform1i{uniformBase{C.GLint(i)}}
		case C.GL_BOOL_VEC2:
			program.Uniforms[C.GoString(&name[0])] = Uniform2i{uniformBase{C.GLint(i)}}
		case C.GL_BOOL_VEC3:
			program.Uniforms[C.GoString(&name[0])] = Uniform3i{uniformBase{C.GLint(i)}}
		case C.GL_BOOL_VEC4:
			program.Uniforms[C.GoString(&name[0])] = Uniform4i{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_MAT2:
			program.Uniforms[C.GoString(&name[0])] = UniformMatrix2f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_MAT3:
			program.Uniforms[C.GoString(&name[0])] = UniformMatrix3f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_MAT4:
			program.Uniforms[C.GoString(&name[0])] = UniformMatrix4f{uniformBase{C.GLint(i)}}
		case C.GL_SAMPLER_2D:
			program.Uniforms[C.GoString(&name[0])] = Uniform1i{uniformBase{C.GLint(i)}}
		case C.GL_SAMPLER_CUBE:
			program.Uniforms[C.GoString(&name[0])] = Uniform1i{uniformBase{C.GLint(i)}}
		}
	}
}

func (program *Program) Link() {
	C.glLinkProgram(program.id)

	status := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_LINK_STATUS, &status)

	if status != C.GL_TRUE {
		loglen := C.GLint(0)
		C.glGetProgramiv(program.id, C.GL_INFO_LOG_LENGTH, &loglen)
		log := (*C.GLchar)(C.malloc(C.size_t(loglen)))
		defer C.free(unsafe.Pointer(log))
		C.glGetProgramInfoLog(program.id, C.GLsizei(loglen), nil, log)
		panic(fmt.Errorf("Failed to link shader: %s", C.GoString((*C.char)(log))))
	} else {
		setupProgramAttributes(program)
		setupProgramUniforms(program)
	}
}

func (program *Program) Use() {
	C.glUseProgram(program.id)
}

func (program *Program) Validate() {
	C.glValidateProgram(program.id)
}

func ReleaseShaderCompiler() {
	C.glReleaseShaderCompiler()
}
<commit_msg>rename DeleteProgram and DeleteShader<commit_after>package gl

// #include <GLES2/gl2.h>
// #include <stdlib.h>
import "C"
import (
	"fmt"
	"unsafe"
)

type Shader C.GLuint
type ShaderType C.GLint

type Program struct {
	id C.GLuint

	shadersValid bool
	shaders      []Shader

	Uniforms   map[string]Uniform
	Attributes map[string]VertexAttrib
}

func CreateProgram() Program {
	return Program{id: C.glCreateProgram()}
}

func CreateShader(stype ShaderType) Shader {
	return Shader(C.glCreateShader(C.GLenum(stype)))
}

func (program *Program) Shaders() []Shader {
	if !program.shadersValid {
		nshaders := C.GLint(0)
		C.glGetProgramiv(program.id, C.GL_ATTACHED_SHADERS, &nshaders)
		program.shaders = make([]Shader, nshaders)
		C.glGetAttachedShaders(program.id, C.GLsizei(nshaders), nil, (*C.GLuint)(&program.shaders[0]))
		program.shadersValid = true
	}
	return program.shaders
}

func (program *Program) AttachShader(shader Shader) {
	C.glAttachShader(program.id, C.GLuint(shader))
	program.shadersValid = false
}

func (program *Program) BindAttribLocation(attrib VertexAttrib, name string) {

	cstr := C.CString(name)
	defer C.free(unsafe.Pointer(cstr))

	C.glBindAttribLocation(program.id, attrib.Index(), (*C.GLchar)(cstr))
}

func (program *Program) Delete() {
	C.glDeleteProgram(program.id)
}

func (shader Shader) Delete() {
	C.glDeleteShader(C.GLuint(shader))
}

func (program *Program) DetachShader(shader Shader) {
	C.glDetachShader(program.id, C.GLuint(shader))
	program.shadersValid = false
}

// func (program *Program) GetActiveAttrib(index uint) (size int, atype int, name string) {

// 	nameBuf := make([]byte, MAX_ATTRIBUTE_LENGTH)
// 	sizeBuf := C.GLint(0)
// 	typeBuf := C.GLenum(0)

// 	C.glGetActiveAttrib(program.id, C.GLuint(index), C.GLsizei(len(nameBuf)), C.NULL, &sizeBuf, &typeBuf, (*C.GLchar)(&nameBuf[0]))

// 	size = int(sizeBuf)
// 	atype = int(typeBuf)
// 	name = string(nameBuf)
// }

// func (program *Program) GetActiveUniform(index uint) (size int, utype int, name string) {

// 	nameBuf := make([]byte, MAX_UNIFORM_LENGTH)
// 	sizeBuf := C.GLint(0)
// 	typeBuf := C.GLenum(0)

// 	C.glGetActiveUniform(program.id, C.GLuint(index), C.GLsizei(len(nameBuf)), C.NULL, &sizeBuf, &typeBuf, (*C.GLchar)(&nameBuf[0]))

// 	size = int(sizeBuf)
// 	utype = int(typeBuf)
// 	name = string(nameBuf)
// }

// func (program *Program) GetAttachedShaders(GLsizei maxcount, GLsizei* count) []uint {
// 	C.glGetAttachedShaders(program.id, GLsizei maxcount, GLsizei* count, GLuint* shaders)
// }

// func (program *Program) GetProgramiv(pname int,  params int) {
// 	C.glGetProgramiv(program.id, GLenum pname, GLint* params)
// }

// func (program *Program) InfoLog(GLsizei bufsize, GLsizei* length, GLchar* infolog) {
// 	C.glGetProgramInfoLog(program.id, GLsizei bufsize, GLsizei* length, GLchar* infolog)
// }

// func GetShaderiv(shader Shader, pname int, params int) {
// 	C.glGetShaderiv(C.GLuint(shader), GLenum pname, GLint* params)
// }

// func GetShaderInfoLog(shader Shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) {
// 	C.glGetShaderInfoLog(C.GLuint(shader), GLsizei bufsize, GLsizei* length, GLchar* infolog)
// }

// func GetShaderPrecisionFormat(shadertype ShaderType, precisiontype int, GLint* range,  precision int) {
// 	C.glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
// }

// func GetShaderSource(shader Shader, GLsizei bufsize, GLsizei* length, GLchar* source) {
// 	C.glGetShaderSource(C.GLuint(shader), GLsizei bufsize, GLsizei* length, GLchar* source)
// }

// func (program *Program) GetUniformfv(location int, GLfloat* params) {
// 	C.glGetUniformfv(program.id, GLint location, GLfloat* params)
// }

// func (program *Program) GetUniformiv(GLint location,  params int) {
// 	C.glGetUniformiv(program.id, GLint location, GLint* params)
// }

// GL_APICALL int          GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
// GL_APICALL int          GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);

// func ShaderBinary(GLsizei n, shaders []uint, binaryformat int, const GLvoid* binary, GLsizei length) {
// 	C.glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
// }

func (shader Shader) Source(src string) {
	cstr := (*C.GLchar)(C.CString(src))
	defer C.free(unsafe.Pointer(cstr))
	slen := C.GLint(len(src))
	C.glShaderSource(C.GLuint(shader), 1, &cstr, &slen)
}

func (shader Shader) Compile() {
	C.glCompileShader(C.GLuint(shader))

	status := C.GLint(0)
	C.glGetShaderiv(C.GLuint(shader), C.GL_COMPILE_STATUS, &status)

	if status != C.GL_TRUE {
		loglen := C.GLint(0)
		C.glGetShaderiv(C.GLuint(shader), C.GL_INFO_LOG_LENGTH, &loglen)
		log := (*C.GLchar)(C.malloc(C.size_t(loglen)))
		defer C.free(unsafe.Pointer(log))
		C.glGetShaderInfoLog(C.GLuint(shader), C.GLsizei(loglen), nil, log)
		panic(fmt.Errorf("Failed to compile shader: %s", C.GoString((*C.char)(log))))
	}
}

func setupProgramAttributes(program *Program) {
	nattribs := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_ACTIVE_ATTRIBUTES, &nattribs)
	maxattriblen := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxattriblen)
	program.Attributes = make(map[string]VertexAttrib, nattribs)

	for i := 0; i < int(nattribs); i++ {
		name := make([]C.char, maxattriblen)
		namelen := C.GLsizei(0)
		datatype := C.GLenum(0)
		C.glGetActiveAttrib(program.id, C.GLuint(i), C.GLsizei(len(name)), &namelen, nil, &datatype, (*C.GLchar)(&name[0]))

		switch datatype {
		case C.GL_FLOAT:
			program.Attributes[C.GoString(&name[0])] = FloatAttrib{C.GLuint(i)}
		case C.GL_FLOAT_VEC2:
			program.Attributes[C.GoString(&name[0])] = Vec2Attrib{FloatAttrib{C.GLuint(i)}}
		case C.GL_FLOAT_VEC3:
			program.Attributes[C.GoString(&name[0])] = Vec3Attrib{FloatAttrib{C.GLuint(i)}}
		case C.GL_FLOAT_VEC4:
			program.Attributes[C.GoString(&name[0])] = Vec4Attrib{FloatAttrib{C.GLuint(i)}}
		}
	}
}

func setupProgramUniforms(program *Program) {
	nuniforms := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_ACTIVE_UNIFORMS, &nuniforms)
	maxuniformlen := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxuniformlen)
	program.Uniforms = make(map[string]Uniform, nuniforms)

	for i := 0; i < int(nuniforms); i++ {
		name := make([]C.char, maxuniformlen)
		namelen := C.GLsizei(0)
		datatype := C.GLenum(0)
		size := C.GLint(0)
		C.glGetActiveUniform(program.id, C.GLuint(i), C.GLsizei(len(name)), &namelen, &size, &datatype, (*C.GLchar)(&name[0]))

		switch datatype {
		case C.GL_FLOAT:
			program.Uniforms[C.GoString(&name[0])] = Uniform1f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_VEC2:
			program.Uniforms[C.GoString(&name[0])] = Uniform2f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_VEC3:
			program.Uniforms[C.GoString(&name[0])] = Uniform3f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_VEC4:
			program.Uniforms[C.GoString(&name[0])] = Uniform4f{uniformBase{C.GLint(i)}}
		case C.GL_INT:
			program.Uniforms[C.GoString(&name[0])] = Uniform1i{uniformBase{C.GLint(i)}}
		case C.GL_INT_VEC2:
			program.Uniforms[C.GoString(&name[0])] = Uniform2i{uniformBase{C.GLint(i)}}
		case C.GL_INT_VEC3:
			program.Uniforms[C.GoString(&name[0])] = Uniform3i{uniformBase{C.GLint(i)}}
		case C.GL_INT_VEC4:
			program.Uniforms[C.GoString(&name[0])] = Uniform4i{uniformBase{C.GLint(i)}}
		case C.GL_BOOL:
			program.Uniforms[C.GoString(&name[0])] = Uniform1i{uniformBase{C.GLint(i)}}
		case C.GL_BOOL_VEC2:
			program.Uniforms[C.GoString(&name[0])] = Uniform2i{uniformBase{C.GLint(i)}}
		case C.GL_BOOL_VEC3:
			program.Uniforms[C.GoString(&name[0])] = Uniform3i{uniformBase{C.GLint(i)}}
		case C.GL_BOOL_VEC4:
			program.Uniforms[C.GoString(&name[0])] = Uniform4i{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_MAT2:
			program.Uniforms[C.GoString(&name[0])] = UniformMatrix2f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_MAT3:
			program.Uniforms[C.GoString(&name[0])] = UniformMatrix3f{uniformBase{C.GLint(i)}}
		case C.GL_FLOAT_MAT4:
			program.Uniforms[C.GoString(&name[0])] = UniformMatrix4f{uniformBase{C.GLint(i)}}
		case C.GL_SAMPLER_2D:
			program.Uniforms[C.GoString(&name[0])] = Uniform1i{uniformBase{C.GLint(i)}}
		case C.GL_SAMPLER_CUBE:
			program.Uniforms[C.GoString(&name[0])] = Uniform1i{uniformBase{C.GLint(i)}}
		}
	}
}

func (program *Program) Link() {
	C.glLinkProgram(program.id)

	status := C.GLint(0)
	C.glGetProgramiv(program.id, C.GL_LINK_STATUS, &status)

	if status != C.GL_TRUE {
		loglen := C.GLint(0)
		C.glGetProgramiv(program.id, C.GL_INFO_LOG_LENGTH, &loglen)
		log := (*C.GLchar)(C.malloc(C.size_t(loglen)))
		defer C.free(unsafe.Pointer(log))
		C.glGetProgramInfoLog(program.id, C.GLsizei(loglen), nil, log)
		panic(fmt.Errorf("Failed to link shader: %s", C.GoString((*C.char)(log))))
	} else {
		setupProgramAttributes(program)
		setupProgramUniforms(program)
	}
}

func (program *Program) Use() {
	C.glUseProgram(program.id)
}

func (program *Program) Validate() {
	C.glValidateProgram(program.id)
}

func ReleaseShaderCompiler() {
	C.glReleaseShaderCompiler()
}
<|endoftext|>


<commit_before>package etcd

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/appc/acserver/Godeps/_workspace/src/github.com/coreos/etcd/client"
	"github.com/appc/acserver/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/appc/acserver/upload"
)

type Backend struct {
	api client.KeysAPI

	namespace string
}

func NewBackend(endpoints []string, namespace string) (*Backend, error) {
	cfg := client.Config{
		Endpoints: endpoints,
		Transport: client.DefaultTransport,
	}

	c, err := client.New(cfg)

	if err != nil {
		return nil, err
	}

	kapi := client.NewKeysAPI(c)

	kapi.Create(context.Background(), fmt.Sprintf("%s/counter", namespace), "0")

	return &Backend{kapi, namespace}, nil
}

func (b *Backend) Get(id uint64) (*upload.Upload, error) {
	n, err := b.api.Get(
		context.Background(),
		fmt.Sprintf("%s/%d", b.namespace, id),
		nil,
	)

	if err != nil {
		return nil, err
	}

	up := upload.Upload{}

	if err := json.Unmarshal([]byte(n.Node.Value), &up); err != nil {
		return nil, err
	}

	return &up, nil
}

func (b *Backend) Create(name string) (*upload.Upload, error) {
	up := upload.NewUpload(name)

	n, err := b.api.Get(
		context.Background(),
		fmt.Sprintf("%s/counter", b.namespace),
		nil,
	)

	if err != nil {
		return nil, err
	}

	v, err := strconv.Atoi(n.Node.Value)

	if err != nil {
		return nil, err
	}

	_, err = b.api.Set(
		context.Background(),
		fmt.Sprintf("%s/counter", b.namespace),
		strconv.Itoa(v+1),
		&client.SetOptions{PrevValue: n.Node.Value},
	)

	if err != nil {
		return nil, err
	}

	up.ID = uint64(v + 1)

	blob, err := json.Marshal(up)

	if err != nil {
		return nil, err
	}

	_, err = b.api.Create(
		context.Background(),
		fmt.Sprintf("%s/%d", b.namespace, v+1),
		string(blob),
	)

	if err != nil {
		return nil, err
	}

	return up, nil
}

func (b *Backend) Update(up *upload.Upload) error {
	blob, err := json.Marshal(up)

	if err != nil {
		return err
	}

	//TODO: Should compare and swap
	_, err = b.api.Set(
		context.Background(),
		fmt.Sprintf("%s/%d", b.namespace, up.ID),
		string(blob),
		nil,
	)

	return err
}

func (b *Backend) Delete(id uint64) error {
	//TODO: Should compare and swap
	_, err := b.api.Delete(
		context.Background(),
		fmt.Sprintf("%s/%d", b.namespace, id),
		nil,
	)

	return err
}
<commit_msg>Raise an error in the constructor if etcd is not available<commit_after>package etcd

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/appc/acserver/Godeps/_workspace/src/github.com/coreos/etcd/client"
	"github.com/appc/acserver/Godeps/_workspace/src/golang.org/x/net/context"
	"github.com/appc/acserver/upload"
)

type Backend struct {
	api client.KeysAPI

	namespace string
}

func NewBackend(endpoints []string, namespace string) (*Backend, error) {
	cfg := client.Config{
		Endpoints: endpoints,
		Transport: client.DefaultTransport,
	}

	c, err := client.New(cfg)

	if err != nil {
		return nil, err
	}

	kapi := client.NewKeysAPI(c)

	_, err = kapi.Create(
		context.Background(),
		fmt.Sprintf("%s/counter", namespace),
		"0",
	)

	if err != nil {
		if e, ok := err.(client.Error); !ok || e.Code != client.ErrorCodeNodeExist {
			return nil, err
		}
	}

	return &Backend{kapi, namespace}, nil
}

func (b *Backend) Get(id uint64) (*upload.Upload, error) {
	n, err := b.api.Get(
		context.Background(),
		fmt.Sprintf("%s/%d", b.namespace, id),
		nil,
	)

	if err != nil {
		return nil, err
	}

	up := upload.Upload{}

	if err := json.Unmarshal([]byte(n.Node.Value), &up); err != nil {
		return nil, err
	}

	return &up, nil
}

func (b *Backend) Create(name string) (*upload.Upload, error) {
	up := upload.NewUpload(name)

	n, err := b.api.Get(
		context.Background(),
		fmt.Sprintf("%s/counter", b.namespace),
		nil,
	)

	if err != nil {
		return nil, err
	}

	v, err := strconv.Atoi(n.Node.Value)

	if err != nil {
		return nil, err
	}

	_, err = b.api.Set(
		context.Background(),
		fmt.Sprintf("%s/counter", b.namespace),
		strconv.Itoa(v+1),
		&client.SetOptions{PrevValue: n.Node.Value},
	)

	if err != nil {
		return nil, err
	}

	up.ID = uint64(v + 1)

	blob, err := json.Marshal(up)

	if err != nil {
		return nil, err
	}

	_, err = b.api.Create(
		context.Background(),
		fmt.Sprintf("%s/%d", b.namespace, v+1),
		string(blob),
	)

	if err != nil {
		return nil, err
	}

	return up, nil
}

func (b *Backend) Update(up *upload.Upload) error {
	blob, err := json.Marshal(up)

	if err != nil {
		return err
	}

	//TODO: Should compare and swap
	_, err = b.api.Set(
		context.Background(),
		fmt.Sprintf("%s/%d", b.namespace, up.ID),
		string(blob),
		nil,
	)

	return err
}

func (b *Backend) Delete(id uint64) error {
	//TODO: Should compare and swap
	_, err := b.api.Delete(
		context.Background(),
		fmt.Sprintf("%s/%d", b.namespace, id),
		nil,
	)

	return err
}
<|endoftext|>


<commit_before>package raft

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"hash"
	"hash/crc64"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

const (
	testPath      = "permTest"
	snapPath      = "snapshots"
	metaFilePath  = "meta.json"
	stateFilePath = "state.bin"
	tmpSuffix     = ".tmp"
)

// FileSnapshotStore implements the SnapshotStore interface and allows
// snapshots to be made on the local disk.
type FileSnapshotStore struct {
	path   string
	retain int
	logger *log.Logger
}

type dirEnts []os.FileInfo

// Implements the SnapshotSink
type FileSnapshotSink struct {
	store  *FileSnapshotStore
	logger *log.Logger
	dir    string
	meta   fileSnapshotMeta

	stateFile *os.File
	stateHash hash.Hash64
	buffered  *bufio.Writer

	closed bool
}

// fileSnapshotMeta is stored on disk. We also put a CRC
// on disk so that we can verify the snapshot
type fileSnapshotMeta struct {
	SnapshotMeta
	CRC []byte
}

// bufferedFile is returned when we open a snapshot. This way
// reads are buffered and the file still gets closed.
type bufferedFile struct {
	bh *bufio.Reader
	fh *os.File
}

func (b *bufferedFile) Read(p []byte) (n int, err error) {
	return b.bh.Read(p)
}

func (b *bufferedFile) Close() error {
	return b.fh.Close()
}

// NewFileSnapshotStore creates a new FileSnapshotStore based
// on a base directory. The `retain` parameter controls how many
// snapshots are retained. Must be at least 1.
func NewFileSnapshotStore(base string, retain int, logOutput io.Writer) (*FileSnapshotStore, error) {
	if retain < 1 {
		return nil, fmt.Errorf("must retain at least one snapshot")
	}
	if logOutput == nil {
		logOutput = os.Stderr
	}

	// Ensure our path exists
	path := filepath.Join(base, snapPath)
	if err := os.Mkdir(path, 0755); err != nil && !os.IsExist(err) {
		return nil, fmt.Errorf("snapshot path not accessible: %v", err)
	}

	// Setup the store
	store := &FileSnapshotStore{
		path:   path,
		retain: retain,
		logger: log.New(logOutput, "", log.LstdFlags),
	}

	// Do a permissions test
	if err := store.testPermissions(); err != nil {
		return nil, fmt.Errorf("permissions test failed: %v", err)
	}
	return store, nil
}

// testPermissions tries to touch a file in our path to see if it works
func (f *FileSnapshotStore) testPermissions() error {
	path := filepath.Join(f.path, testPath)
	fh, err := os.Create(path)
	if err != nil {
		return err
	}
	fh.Close()
	os.Remove(path)
	return nil
}

// Create is used to start a new snapshot
func (f *FileSnapshotStore) Create(index, term uint64, peers []byte) (SnapshotSink, error) {
	// Create a new path
	name := fmt.Sprintf("%s-%d-%d", time.Now().Format(time.RFC3339Nano), index, term)
	path := filepath.Join(f.path, name+tmpSuffix)
	f.logger.Printf("[INFO] snapshot: Creating new snapshot at %s", path)

	// Make the directory
	if err := os.Mkdir(path, 0755); err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to make snapshot directory: %v", err)
		return nil, err
	}

	// Create the sink
	sink := &FileSnapshotSink{
		store:  f,
		logger: f.logger,
		dir:    path,
		meta: fileSnapshotMeta{
			SnapshotMeta: SnapshotMeta{
				ID:    name,
				Index: index,
				Term:  term,
				Peers: peers,
			},
			CRC: nil,
		},
	}

	// Write out the meta data
	if err := sink.writeMeta(); err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to write metadata: %v", err)
		return nil, err
	}

	// Open the state file
	statePath := filepath.Join(path, stateFilePath)
	fh, err := os.Create(statePath)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to create state file: %v", err)
		return nil, err
	}
	sink.stateFile = fh

	// Create a CRC64 hash
	sink.stateHash = crc64.New(crc64.MakeTable(crc64.ECMA))

	// Wrap both the hash and file in a MultiWriter with buffering
	multi := io.MultiWriter(sink.stateFile, sink.stateHash)
	sink.buffered = bufio.NewWriter(multi)

	// Done
	return sink, nil
}

func (f *FileSnapshotStore) List() ([]*SnapshotMeta, error) {
	// Get the eligible snapshots
	snapshots, err := f.getSnapshots()
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get snapshots: %v", err)
		return nil, err
	}

	var snapMeta []*SnapshotMeta
	for _, meta := range snapshots {
		snapMeta = append(snapMeta, &meta.SnapshotMeta)
		if len(snapMeta) == f.retain {
			break
		}
	}
	return snapMeta, nil
}

// getSnapshots returns all the known snapshots
func (f *FileSnapshotStore) getSnapshots() ([]*fileSnapshotMeta, error) {
	// Get the eligible snapshots
	snapshots, err := ioutil.ReadDir(f.path)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to scan snapshot dir: %v", err)
		return nil, err
	}

	// Sort the contents, ensures lexical order
	sort.Sort(dirEnts(snapshots))

	// Populate the metadata, reverse order (newest first)
	var snapMeta []*fileSnapshotMeta
	for i := len(snapshots); i > 0; i-- {
		// Ignore any files
		snap := snapshots[i-1]
		if !snap.IsDir() {
			continue
		}

		// Ignore any temporary snapshots
		dirName := snap.Name()
		if strings.HasSuffix(dirName, tmpSuffix) {
			f.logger.Printf("[WARN] snapshot: Found temporary snapshot: %v", dirName)
			continue
		}

		// Try to read the meta data
		meta, err := f.readMeta(dirName)
		if err != nil {
			f.logger.Printf("[WARN] snapshot: Failed to read metadata for %v: %v", dirName, err)
			continue
		}

		// Append, but only return up to the retain count
		snapMeta = append(snapMeta, meta)
	}
	return snapMeta, nil
}

// readMeta is used to read the meta data for a given named backup
func (f *FileSnapshotStore) readMeta(name string) (*fileSnapshotMeta, error) {
	// Open the meta file
	metaPath := filepath.Join(f.path, name, metaFilePath)
	fh, err := os.Open(metaPath)
	if err != nil {
		return nil, err
	}
	defer fh.Close()

	// Buffer the file IO
	buffered := bufio.NewReader(fh)

	// Read in the JSON
	meta := &fileSnapshotMeta{}
	dec := json.NewDecoder(buffered)
	if err := dec.Decode(meta); err != nil {
		return nil, err
	}
	return meta, nil
}

func (f *FileSnapshotStore) Open(id string) (*SnapshotMeta, io.ReadCloser, error) {
	// Get the metadata
	meta, err := f.readMeta(id)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get meta data to open snapshot: %v", err)
		return nil, nil, err
	}

	// Open the state file
	statePath := filepath.Join(f.path, id, stateFilePath)
	fh, err := os.Open(statePath)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to open state file: %v", err)
		return nil, nil, err
	}

	// Create a CRC64 hash
	stateHash := crc64.New(crc64.MakeTable(crc64.ECMA))

	// Compute the hash
	_, err = io.Copy(stateHash, fh)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to read state file: %v", err)
		fh.Close()
		return nil, nil, err
	}

	// Verify the hash
	computed := stateHash.Sum(nil)
	if bytes.Compare(meta.CRC, computed) != 0 {
		f.logger.Printf("[ERR] snapshot: CRC checksum failed (stored: %v computed: %v)",
			meta.CRC, computed)
		fh.Close()
		return nil, nil, fmt.Errorf("CRC mismatch")
	}

	// Seek to the start
	if _, err := fh.Seek(0, 0); err != nil {
		f.logger.Printf("[ERR] snapshot: State file seek failed: %v", err)
		fh.Close()
		return nil, nil, err
	}

	// Return a buffered file
	buffered := &bufferedFile{
		bh: bufio.NewReader(fh),
		fh: fh,
	}

	return &meta.SnapshotMeta, buffered, nil
}

// Used to reap any snapshots beyond the retain count
func (f *FileSnapshotStore) ReapSnapshots() error {
	snapshots, err := f.getSnapshots()
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get snapshots: %v", err)
		return err
	}

	for i := f.retain; i < len(snapshots); i++ {
		path := filepath.Join(f.path, snapshots[i].ID)
		f.logger.Printf("[INFO] snapshot: reaping snapshot %v", path)
		if err := os.RemoveAll(path); err != nil {
			f.logger.Printf("[ERR] snapshot: Failed to reap snapshot %v: %v", path, err)
			return err
		}
	}
	return nil
}

// ID returns the ID of the snapshot, can be used with Open()
// after the snapshot is finalized.
func (s *FileSnapshotSink) ID() string {
	return s.meta.ID
}

// Write is used to append to the state file. We write to the
// buffered IO object to reduce the amount of context switches
func (s *FileSnapshotSink) Write(b []byte) (int, error) {
	return s.buffered.Write(b)
}

// Close is used to indicate a successful end
func (s *FileSnapshotSink) Close() error {
	// Make sure close is idempotent
	if s.closed {
		return nil
	}
	s.closed = true

	// Close the open handles
	if err := s.finalize(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to finalize snapshot: %v", err)
		return err
	}

	// Write out the meta data
	if err := s.writeMeta(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to write metadata: %v", err)
		return err
	}

	// Move the directory into place
	newPath := strings.TrimSuffix(s.dir, tmpSuffix)
	if err := os.Rename(s.dir, newPath); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to move snapshot into place: %v", err)
		return err
	}

	// Reap any old snapshots
	s.store.ReapSnapshots()
	return nil
}

// Cancel is used to indicate an unsuccessful end
func (s *FileSnapshotSink) Cancel() error {
	// Make sure close is idempotent
	if s.closed {
		return nil
	}
	s.closed = true

	// Close the open handles
	if err := s.finalize(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to finalize snapshot: %v", err)
		return err
	}

	// Attempt to remove all artifacts
	return os.RemoveAll(s.dir)
}

// finalize is used to close all of our resources
func (s *FileSnapshotSink) finalize() error {
	// Flush any remaining data
	if err := s.buffered.Flush(); err != nil {
		return err
	}

	// Get the file size
	stat, statErr := s.stateFile.Stat()

	// Close the file
	if err := s.stateFile.Close(); err != nil {
		return err
	}

	// Set the file size, check after we close
	if statErr != nil {
		return statErr
	}
	s.meta.Size = stat.Size()

	// Set the CRC
	s.meta.CRC = s.stateHash.Sum(nil)
	return nil
}

// writeMeta is used to write out the metadata we have
func (s *FileSnapshotSink) writeMeta() error {
	// Open the meta file
	metaPath := filepath.Join(s.dir, metaFilePath)
	fh, err := os.Create(metaPath)
	if err != nil {
		return err
	}
	defer fh.Close()

	// Buffer the file IO
	buffered := bufio.NewWriter(fh)
	defer buffered.Flush()

	// Write out as JSON
	enc := json.NewEncoder(buffered)
	if err := enc.Encode(&s.meta); err != nil {
		return err
	}
	return nil
}

// Implement the sort interface for dirEnts
func (d dirEnts) Len() int {
	return len(d)
}

func (d dirEnts) Less(i, j int) bool {
	return d[i].Name() < d[j].Name()
}

func (d dirEnts) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}
<commit_msg>Change snapshot name to do term-index-time instead of time-index-term<commit_after>package raft

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"hash"
	"hash/crc64"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

const (
	testPath      = "permTest"
	snapPath      = "snapshots"
	metaFilePath  = "meta.json"
	stateFilePath = "state.bin"
	tmpSuffix     = ".tmp"
)

// FileSnapshotStore implements the SnapshotStore interface and allows
// snapshots to be made on the local disk.
type FileSnapshotStore struct {
	path   string
	retain int
	logger *log.Logger
}

type dirEnts []os.FileInfo

// Implements the SnapshotSink
type FileSnapshotSink struct {
	store  *FileSnapshotStore
	logger *log.Logger
	dir    string
	meta   fileSnapshotMeta

	stateFile *os.File
	stateHash hash.Hash64
	buffered  *bufio.Writer

	closed bool
}

// fileSnapshotMeta is stored on disk. We also put a CRC
// on disk so that we can verify the snapshot
type fileSnapshotMeta struct {
	SnapshotMeta
	CRC []byte
}

// bufferedFile is returned when we open a snapshot. This way
// reads are buffered and the file still gets closed.
type bufferedFile struct {
	bh *bufio.Reader
	fh *os.File
}

func (b *bufferedFile) Read(p []byte) (n int, err error) {
	return b.bh.Read(p)
}

func (b *bufferedFile) Close() error {
	return b.fh.Close()
}

// NewFileSnapshotStore creates a new FileSnapshotStore based
// on a base directory. The `retain` parameter controls how many
// snapshots are retained. Must be at least 1.
func NewFileSnapshotStore(base string, retain int, logOutput io.Writer) (*FileSnapshotStore, error) {
	if retain < 1 {
		return nil, fmt.Errorf("must retain at least one snapshot")
	}
	if logOutput == nil {
		logOutput = os.Stderr
	}

	// Ensure our path exists
	path := filepath.Join(base, snapPath)
	if err := os.Mkdir(path, 0755); err != nil && !os.IsExist(err) {
		return nil, fmt.Errorf("snapshot path not accessible: %v", err)
	}

	// Setup the store
	store := &FileSnapshotStore{
		path:   path,
		retain: retain,
		logger: log.New(logOutput, "", log.LstdFlags),
	}

	// Do a permissions test
	if err := store.testPermissions(); err != nil {
		return nil, fmt.Errorf("permissions test failed: %v", err)
	}
	return store, nil
}

// testPermissions tries to touch a file in our path to see if it works
func (f *FileSnapshotStore) testPermissions() error {
	path := filepath.Join(f.path, testPath)
	fh, err := os.Create(path)
	if err != nil {
		return err
	}
	fh.Close()
	os.Remove(path)
	return nil
}

// Create is used to start a new snapshot
func (f *FileSnapshotStore) Create(index, term uint64, peers []byte) (SnapshotSink, error) {
	// Create a new path
	name := fmt.Sprintf("%d-%d-%s", term, index, time.Now().Format(time.RFC3339Nano))
	path := filepath.Join(f.path, name+tmpSuffix)
	f.logger.Printf("[INFO] snapshot: Creating new snapshot at %s", path)

	// Make the directory
	if err := os.Mkdir(path, 0755); err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to make snapshot directory: %v", err)
		return nil, err
	}

	// Create the sink
	sink := &FileSnapshotSink{
		store:  f,
		logger: f.logger,
		dir:    path,
		meta: fileSnapshotMeta{
			SnapshotMeta: SnapshotMeta{
				ID:    name,
				Index: index,
				Term:  term,
				Peers: peers,
			},
			CRC: nil,
		},
	}

	// Write out the meta data
	if err := sink.writeMeta(); err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to write metadata: %v", err)
		return nil, err
	}

	// Open the state file
	statePath := filepath.Join(path, stateFilePath)
	fh, err := os.Create(statePath)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to create state file: %v", err)
		return nil, err
	}
	sink.stateFile = fh

	// Create a CRC64 hash
	sink.stateHash = crc64.New(crc64.MakeTable(crc64.ECMA))

	// Wrap both the hash and file in a MultiWriter with buffering
	multi := io.MultiWriter(sink.stateFile, sink.stateHash)
	sink.buffered = bufio.NewWriter(multi)

	// Done
	return sink, nil
}

func (f *FileSnapshotStore) List() ([]*SnapshotMeta, error) {
	// Get the eligible snapshots
	snapshots, err := f.getSnapshots()
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get snapshots: %v", err)
		return nil, err
	}

	var snapMeta []*SnapshotMeta
	for _, meta := range snapshots {
		snapMeta = append(snapMeta, &meta.SnapshotMeta)
		if len(snapMeta) == f.retain {
			break
		}
	}
	return snapMeta, nil
}

// getSnapshots returns all the known snapshots
func (f *FileSnapshotStore) getSnapshots() ([]*fileSnapshotMeta, error) {
	// Get the eligible snapshots
	snapshots, err := ioutil.ReadDir(f.path)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to scan snapshot dir: %v", err)
		return nil, err
	}

	// Sort the contents, ensures lexical order
	sort.Sort(dirEnts(snapshots))

	// Populate the metadata, reverse order (newest first)
	var snapMeta []*fileSnapshotMeta
	for i := len(snapshots); i > 0; i-- {
		// Ignore any files
		snap := snapshots[i-1]
		if !snap.IsDir() {
			continue
		}

		// Ignore any temporary snapshots
		dirName := snap.Name()
		if strings.HasSuffix(dirName, tmpSuffix) {
			f.logger.Printf("[WARN] snapshot: Found temporary snapshot: %v", dirName)
			continue
		}

		// Try to read the meta data
		meta, err := f.readMeta(dirName)
		if err != nil {
			f.logger.Printf("[WARN] snapshot: Failed to read metadata for %v: %v", dirName, err)
			continue
		}

		// Append, but only return up to the retain count
		snapMeta = append(snapMeta, meta)
	}
	return snapMeta, nil
}

// readMeta is used to read the meta data for a given named backup
func (f *FileSnapshotStore) readMeta(name string) (*fileSnapshotMeta, error) {
	// Open the meta file
	metaPath := filepath.Join(f.path, name, metaFilePath)
	fh, err := os.Open(metaPath)
	if err != nil {
		return nil, err
	}
	defer fh.Close()

	// Buffer the file IO
	buffered := bufio.NewReader(fh)

	// Read in the JSON
	meta := &fileSnapshotMeta{}
	dec := json.NewDecoder(buffered)
	if err := dec.Decode(meta); err != nil {
		return nil, err
	}
	return meta, nil
}

func (f *FileSnapshotStore) Open(id string) (*SnapshotMeta, io.ReadCloser, error) {
	// Get the metadata
	meta, err := f.readMeta(id)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get meta data to open snapshot: %v", err)
		return nil, nil, err
	}

	// Open the state file
	statePath := filepath.Join(f.path, id, stateFilePath)
	fh, err := os.Open(statePath)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to open state file: %v", err)
		return nil, nil, err
	}

	// Create a CRC64 hash
	stateHash := crc64.New(crc64.MakeTable(crc64.ECMA))

	// Compute the hash
	_, err = io.Copy(stateHash, fh)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to read state file: %v", err)
		fh.Close()
		return nil, nil, err
	}

	// Verify the hash
	computed := stateHash.Sum(nil)
	if bytes.Compare(meta.CRC, computed) != 0 {
		f.logger.Printf("[ERR] snapshot: CRC checksum failed (stored: %v computed: %v)",
			meta.CRC, computed)
		fh.Close()
		return nil, nil, fmt.Errorf("CRC mismatch")
	}

	// Seek to the start
	if _, err := fh.Seek(0, 0); err != nil {
		f.logger.Printf("[ERR] snapshot: State file seek failed: %v", err)
		fh.Close()
		return nil, nil, err
	}

	// Return a buffered file
	buffered := &bufferedFile{
		bh: bufio.NewReader(fh),
		fh: fh,
	}

	return &meta.SnapshotMeta, buffered, nil
}

// Used to reap any snapshots beyond the retain count
func (f *FileSnapshotStore) ReapSnapshots() error {
	snapshots, err := f.getSnapshots()
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get snapshots: %v", err)
		return err
	}

	for i := f.retain; i < len(snapshots); i++ {
		path := filepath.Join(f.path, snapshots[i].ID)
		f.logger.Printf("[INFO] snapshot: reaping snapshot %v", path)
		if err := os.RemoveAll(path); err != nil {
			f.logger.Printf("[ERR] snapshot: Failed to reap snapshot %v: %v", path, err)
			return err
		}
	}
	return nil
}

// ID returns the ID of the snapshot, can be used with Open()
// after the snapshot is finalized.
func (s *FileSnapshotSink) ID() string {
	return s.meta.ID
}

// Write is used to append to the state file. We write to the
// buffered IO object to reduce the amount of context switches
func (s *FileSnapshotSink) Write(b []byte) (int, error) {
	return s.buffered.Write(b)
}

// Close is used to indicate a successful end
func (s *FileSnapshotSink) Close() error {
	// Make sure close is idempotent
	if s.closed {
		return nil
	}
	s.closed = true

	// Close the open handles
	if err := s.finalize(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to finalize snapshot: %v", err)
		return err
	}

	// Write out the meta data
	if err := s.writeMeta(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to write metadata: %v", err)
		return err
	}

	// Move the directory into place
	newPath := strings.TrimSuffix(s.dir, tmpSuffix)
	if err := os.Rename(s.dir, newPath); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to move snapshot into place: %v", err)
		return err
	}

	// Reap any old snapshots
	s.store.ReapSnapshots()
	return nil
}

// Cancel is used to indicate an unsuccessful end
func (s *FileSnapshotSink) Cancel() error {
	// Make sure close is idempotent
	if s.closed {
		return nil
	}
	s.closed = true

	// Close the open handles
	if err := s.finalize(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to finalize snapshot: %v", err)
		return err
	}

	// Attempt to remove all artifacts
	return os.RemoveAll(s.dir)
}

// finalize is used to close all of our resources
func (s *FileSnapshotSink) finalize() error {
	// Flush any remaining data
	if err := s.buffered.Flush(); err != nil {
		return err
	}

	// Get the file size
	stat, statErr := s.stateFile.Stat()

	// Close the file
	if err := s.stateFile.Close(); err != nil {
		return err
	}

	// Set the file size, check after we close
	if statErr != nil {
		return statErr
	}
	s.meta.Size = stat.Size()

	// Set the CRC
	s.meta.CRC = s.stateHash.Sum(nil)
	return nil
}

// writeMeta is used to write out the metadata we have
func (s *FileSnapshotSink) writeMeta() error {
	// Open the meta file
	metaPath := filepath.Join(s.dir, metaFilePath)
	fh, err := os.Create(metaPath)
	if err != nil {
		return err
	}
	defer fh.Close()

	// Buffer the file IO
	buffered := bufio.NewWriter(fh)
	defer buffered.Flush()

	// Write out as JSON
	enc := json.NewEncoder(buffered)
	if err := enc.Encode(&s.meta); err != nil {
		return err
	}
	return nil
}

// Implement the sort interface for dirEnts
func (d dirEnts) Len() int {
	return len(d)
}

func (d dirEnts) Less(i, j int) bool {
	return d[i].Name() < d[j].Name()
}

func (d dirEnts) Swap(i, j int) {
	d[i], d[j] = d[j], d[i]
}
<|endoftext|>


<commit_before>package kubernetes

import (
	"errors"
	"os"
	"strings"
	"testing"

	"github.com/hashicorp/terraform/config"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	api "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var testAccProviders map[string]terraform.ResourceProvider
var testAccProvider *schema.Provider

func init() {
	testAccProvider = Provider().(*schema.Provider)
	testAccProviders = map[string]terraform.ResourceProvider{
		"kubernetes": testAccProvider,
	}
}

func TestProvider(t *testing.T) {
	if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestProvider_impl(t *testing.T) {
	var _ terraform.ResourceProvider = Provider()
}

func TestProvider_configure(t *testing.T) {
	resetEnv := unsetEnv(t)
	defer resetEnv()

	//os.Setenv("KUBECONFIG", "test-fixtures/kube-config.yaml")
	//os.Setenv("KUBE_CTX", "gcp")

	c, err := config.NewRawConfig(map[string]interface{}{})
	if err != nil {
		t.Fatal(err)
	}
	rc := terraform.NewResourceConfig(c)
	p := Provider()
	err = p.Configure(rc)
	if err != nil {
		t.Fatal(err)
	}
}

func unsetEnv(t *testing.T) func() {
	e := getEnv()

	if err := os.Unsetenv("KUBECONFIG"); err != nil {
		t.Fatalf("Error unsetting env var KUBECONFIG: %s", err)
	}
	if err := os.Unsetenv("KUBE_CONFIG"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CONFIG: %s", err)
	}
	if err := os.Unsetenv("KUBE_CTX"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CTX: %s", err)
	}
	if err := os.Unsetenv("KUBE_CTX_AUTH_INFO"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CTX_AUTH_INFO: %s", err)
	}
	if err := os.Unsetenv("KUBE_CTX_CLUSTER"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CTX_CLUSTER: %s", err)
	}
	if err := os.Unsetenv("KUBE_HOST"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_HOST: %s", err)
	}
	if err := os.Unsetenv("KUBE_USER"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_USER: %s", err)
	}
	if err := os.Unsetenv("KUBE_PASSWORD"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_PASSWORD: %s", err)
	}
	if err := os.Unsetenv("KUBE_CLIENT_CERT_DATA"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CLIENT_CERT_DATA: %s", err)
	}
	if err := os.Unsetenv("KUBE_CLIENT_KEY_DATA"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CLIENT_KEY_DATA: %s", err)
	}
	if err := os.Unsetenv("KUBE_CLUSTER_CA_CERT_DATA"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CLUSTER_CA_CERT_DATA: %s", err)
	}

	return func() {
		if err := os.Setenv("KUBE_CONFIG", e.Config); err != nil {
			t.Fatalf("Error resetting env var KUBE_CONFIG: %s", err)
		}
		if err := os.Setenv("KUBECONFIG", e.Config); err != nil {
			t.Fatalf("Error resetting env var KUBECONFIG: %s", err)
		}
		if err := os.Setenv("KUBE_CTX", e.Config); err != nil {
			t.Fatalf("Error resetting env var KUBE_CTX: %s", err)
		}
		if err := os.Setenv("KUBE_CTX_AUTH_INFO", e.CtxAuthInfo); err != nil {
			t.Fatalf("Error resetting env var KUBE_CTX_AUTH_INFO: %s", err)
		}
		if err := os.Setenv("KUBE_CTX_CLUSTER", e.CtxCluster); err != nil {
			t.Fatalf("Error resetting env var KUBE_CTX_CLUSTER: %s", err)
		}
		if err := os.Setenv("KUBE_HOST", e.Host); err != nil {
			t.Fatalf("Error resetting env var KUBE_HOST: %s", err)
		}
		if err := os.Setenv("KUBE_USER", e.User); err != nil {
			t.Fatalf("Error resetting env var KUBE_USER: %s", err)
		}
		if err := os.Setenv("KUBE_PASSWORD", e.Password); err != nil {
			t.Fatalf("Error resetting env var KUBE_PASSWORD: %s", err)
		}
		if err := os.Setenv("KUBE_CLIENT_CERT_DATA", e.ClientCertData); err != nil {
			t.Fatalf("Error resetting env var KUBE_CLIENT_CERT_DATA: %s", err)
		}
		if err := os.Setenv("KUBE_CLIENT_KEY_DATA", e.ClientKeyData); err != nil {
			t.Fatalf("Error resetting env var KUBE_CLIENT_KEY_DATA: %s", err)
		}
		if err := os.Setenv("KUBE_CLUSTER_CA_CERT_DATA", e.ClusterCACertData); err != nil {
			t.Fatalf("Error resetting env var KUBE_CLUSTER_CA_CERT_DATA: %s", err)
		}
	}
}

func getEnv() *currentEnv {
	e := &currentEnv{
		Ctx:               os.Getenv("KUBE_CTX_CLUSTER"),
		CtxAuthInfo:       os.Getenv("KUBE_CTX_AUTH_INFO"),
		CtxCluster:        os.Getenv("KUBE_CTX_CLUSTER"),
		Host:              os.Getenv("KUBE_HOST"),
		User:              os.Getenv("KUBE_USER"),
		Password:          os.Getenv("KUBE_PASSWORD"),
		ClientCertData:    os.Getenv("KUBE_CLIENT_CERT_DATA"),
		ClientKeyData:     os.Getenv("KUBE_CLIENT_KEY_DATA"),
		ClusterCACertData: os.Getenv("KUBE_CLUSTER_CA_CERT_DATA"),
	}
	if cfg := os.Getenv("KUBE_CONFIG"); cfg != "" {
		e.Config = cfg
	}
	if cfg := os.Getenv("KUBECONFIG"); cfg != "" {
		e.Config = cfg
	}
	return e
}

func testAccPreCheck(t *testing.T) {
	hasFileCfg := (os.Getenv("KUBE_CTX_AUTH_INFO") != "" && os.Getenv("KUBE_CTX_CLUSTER") != "")
	hasStaticCfg := (os.Getenv("KUBE_HOST") != "" &&
		os.Getenv("KUBE_USER") != "" &&
		os.Getenv("KUBE_PASSWORD") != "" &&
		os.Getenv("KUBE_CLIENT_CERT_DATA") != "" &&
		os.Getenv("KUBE_CLIENT_KEY_DATA") != "" &&
		os.Getenv("KUBE_CLUSTER_CA_CERT_DATA") != "")

	if !hasFileCfg && !hasStaticCfg {
		t.Fatalf("File config (KUBE_CTX_AUTH_INFO and KUBE_CTX_CLUSTER) or static configuration"+
			" (%s) must be set for acceptance tests",
			strings.Join([]string{
				"KUBE_HOST",
				"KUBE_USER",
				"KUBE_PASSWORD",
				"KUBE_CLIENT_CERT_DATA",
				"KUBE_CLIENT_KEY_DATA",
				"KUBE_CLUSTER_CA_CERT_DATA",
			}, ", "))
	}

	err := testAccProvider.Configure(terraform.NewResourceConfig(nil))
	if err != nil {
		t.Fatal(err)
	}
}

func skipIfNoGoogleCloudSettingsFound(t *testing.T) {
	if os.Getenv("GOOGLE_PROJECT") == "" || os.Getenv("GOOGLE_REGION") == "" || os.Getenv("GOOGLE_ZONE") == "" {
		t.Skip("The environment variables GOOGLE_PROJECT, GOOGLE_REGION and GOOGLE_ZONE" +
			" must be set to run Google Cloud tests - skipping")
	}
}

func skipIfNoAwsSettingsFound(t *testing.T) {
	if os.Getenv("AWS_DEFAULT_REGION") == "" || os.Getenv("AWS_ZONE") == "" || os.Getenv("AWS_ACCESS_KEY_ID") == "" || os.Getenv("AWS_SECRET_ACCESS_KEY") == "" {
		t.Skip("The environment variables AWS_DEFAULT_REGION, AWS_ZONE, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY" +
			" must be set to run AWS tests - skipping")
	}
}

func skipIfNoLoadBalancersAvailable(t *testing.T) {
	// TODO: Support AWS ELBs
	isInGke, err := isRunningInGke()
	if err != nil {
		t.Fatal(err)
	}
	if !isInGke {
		t.Skip("The Kubernetes endpoint must come from an environment which supports " +
			"load balancer provisioning for this test to run - skipping")
	}
}

func skipIfNotRunningInGke(t *testing.T) {
	isInGke, err := isRunningInGke()
	if err != nil {
		t.Fatal(err)
	}
	if !isInGke {
		t.Skip("The Kubernetes endpoint must come from GKE for this test to run - skipping")
	}
}

func isRunningInMinikube() (bool, error) {
	node, err := getFirstNode()
	if err != nil {
		return false, err
	}

	labels := node.GetLabels()
	if v, ok := labels["kubernetes.io/hostname"]; ok && v == "minikube" {
		return true, nil
	}
	return false, nil
}

func isRunningInGke() (bool, error) {
	node, err := getFirstNode()
	if err != nil {
		return false, err
	}

	labels := node.GetLabels()
	if _, ok := labels["cloud.google.com/gke-nodepool"]; ok {
		return true, nil
	}
	return false, nil
}

func getFirstNode() (api.Node, error) {
	meta := testAccProvider.Meta()
	if meta == nil {
		return api.Node{}, errors.New("Provider not initialized, unable to get cluster node")
	}
	conn := meta.(*kubernetesProvider).conn
	resp, err := conn.CoreV1().Nodes().List(metav1.ListOptions{})
	if err != nil {
		return api.Node{}, err
	}

	if len(resp.Items) < 1 {
		return api.Node{}, errors.New("Expected at least 1 node, none found")
	}

	return resp.Items[0], nil
}

type currentEnv struct {
	Config            string
	Ctx               string
	CtxAuthInfo       string
	CtxCluster        string
	Host              string
	User              string
	Password          string
	ClientCertData    string
	ClientKeyData     string
	ClusterCACertData string
}
<commit_msg>Re-add Google + AWS test providers. (only Google tested).<commit_after>package kubernetes

import (
	"errors"
	"os"
	"strings"
	"testing"

	"github.com/hashicorp/terraform/config"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/terraform"
	"github.com/terraform-providers/terraform-provider-aws/aws"
	"github.com/terraform-providers/terraform-provider-google/google"
	api "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var testAccProviders map[string]terraform.ResourceProvider
var testAccProvider *schema.Provider

func init() {
	testAccProvider = Provider().(*schema.Provider)
	testAccProviders = map[string]terraform.ResourceProvider{
		"kubernetes": testAccProvider,
		"google":     google.Provider(),
		"aws":        aws.Provider(),
	}
}

func TestProvider(t *testing.T) {
	if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
		t.Fatalf("err: %s", err)
	}
}

func TestProvider_impl(t *testing.T) {
	var _ terraform.ResourceProvider = Provider()
}

func TestProvider_configure(t *testing.T) {
	resetEnv := unsetEnv(t)
	defer resetEnv()

	//os.Setenv("KUBECONFIG", "test-fixtures/kube-config.yaml")
	//os.Setenv("KUBE_CTX", "gcp")

	c, err := config.NewRawConfig(map[string]interface{}{})
	if err != nil {
		t.Fatal(err)
	}
	rc := terraform.NewResourceConfig(c)
	p := Provider()
	err = p.Configure(rc)
	if err != nil {
		t.Fatal(err)
	}
}

func unsetEnv(t *testing.T) func() {
	e := getEnv()

	if err := os.Unsetenv("KUBECONFIG"); err != nil {
		t.Fatalf("Error unsetting env var KUBECONFIG: %s", err)
	}
	if err := os.Unsetenv("KUBE_CONFIG"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CONFIG: %s", err)
	}
	if err := os.Unsetenv("KUBE_CTX"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CTX: %s", err)
	}
	if err := os.Unsetenv("KUBE_CTX_AUTH_INFO"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CTX_AUTH_INFO: %s", err)
	}
	if err := os.Unsetenv("KUBE_CTX_CLUSTER"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CTX_CLUSTER: %s", err)
	}
	if err := os.Unsetenv("KUBE_HOST"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_HOST: %s", err)
	}
	if err := os.Unsetenv("KUBE_USER"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_USER: %s", err)
	}
	if err := os.Unsetenv("KUBE_PASSWORD"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_PASSWORD: %s", err)
	}
	if err := os.Unsetenv("KUBE_CLIENT_CERT_DATA"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CLIENT_CERT_DATA: %s", err)
	}
	if err := os.Unsetenv("KUBE_CLIENT_KEY_DATA"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CLIENT_KEY_DATA: %s", err)
	}
	if err := os.Unsetenv("KUBE_CLUSTER_CA_CERT_DATA"); err != nil {
		t.Fatalf("Error unsetting env var KUBE_CLUSTER_CA_CERT_DATA: %s", err)
	}

	return func() {
		if err := os.Setenv("KUBE_CONFIG", e.Config); err != nil {
			t.Fatalf("Error resetting env var KUBE_CONFIG: %s", err)
		}
		if err := os.Setenv("KUBECONFIG", e.Config); err != nil {
			t.Fatalf("Error resetting env var KUBECONFIG: %s", err)
		}
		if err := os.Setenv("KUBE_CTX", e.Config); err != nil {
			t.Fatalf("Error resetting env var KUBE_CTX: %s", err)
		}
		if err := os.Setenv("KUBE_CTX_AUTH_INFO", e.CtxAuthInfo); err != nil {
			t.Fatalf("Error resetting env var KUBE_CTX_AUTH_INFO: %s", err)
		}
		if err := os.Setenv("KUBE_CTX_CLUSTER", e.CtxCluster); err != nil {
			t.Fatalf("Error resetting env var KUBE_CTX_CLUSTER: %s", err)
		}
		if err := os.Setenv("KUBE_HOST", e.Host); err != nil {
			t.Fatalf("Error resetting env var KUBE_HOST: %s", err)
		}
		if err := os.Setenv("KUBE_USER", e.User); err != nil {
			t.Fatalf("Error resetting env var KUBE_USER: %s", err)
		}
		if err := os.Setenv("KUBE_PASSWORD", e.Password); err != nil {
			t.Fatalf("Error resetting env var KUBE_PASSWORD: %s", err)
		}
		if err := os.Setenv("KUBE_CLIENT_CERT_DATA", e.ClientCertData); err != nil {
			t.Fatalf("Error resetting env var KUBE_CLIENT_CERT_DATA: %s", err)
		}
		if err := os.Setenv("KUBE_CLIENT_KEY_DATA", e.ClientKeyData); err != nil {
			t.Fatalf("Error resetting env var KUBE_CLIENT_KEY_DATA: %s", err)
		}
		if err := os.Setenv("KUBE_CLUSTER_CA_CERT_DATA", e.ClusterCACertData); err != nil {
			t.Fatalf("Error resetting env var KUBE_CLUSTER_CA_CERT_DATA: %s", err)
		}
	}
}

func getEnv() *currentEnv {
	e := &currentEnv{
		Ctx:               os.Getenv("KUBE_CTX_CLUSTER"),
		CtxAuthInfo:       os.Getenv("KUBE_CTX_AUTH_INFO"),
		CtxCluster:        os.Getenv("KUBE_CTX_CLUSTER"),
		Host:              os.Getenv("KUBE_HOST"),
		User:              os.Getenv("KUBE_USER"),
		Password:          os.Getenv("KUBE_PASSWORD"),
		ClientCertData:    os.Getenv("KUBE_CLIENT_CERT_DATA"),
		ClientKeyData:     os.Getenv("KUBE_CLIENT_KEY_DATA"),
		ClusterCACertData: os.Getenv("KUBE_CLUSTER_CA_CERT_DATA"),
	}
	if cfg := os.Getenv("KUBE_CONFIG"); cfg != "" {
		e.Config = cfg
	}
	if cfg := os.Getenv("KUBECONFIG"); cfg != "" {
		e.Config = cfg
	}
	return e
}

func testAccPreCheck(t *testing.T) {
	hasFileCfg := (os.Getenv("KUBE_CTX_AUTH_INFO") != "" && os.Getenv("KUBE_CTX_CLUSTER") != "")
	hasStaticCfg := (os.Getenv("KUBE_HOST") != "" &&
		os.Getenv("KUBE_USER") != "" &&
		os.Getenv("KUBE_PASSWORD") != "" &&
		os.Getenv("KUBE_CLIENT_CERT_DATA") != "" &&
		os.Getenv("KUBE_CLIENT_KEY_DATA") != "" &&
		os.Getenv("KUBE_CLUSTER_CA_CERT_DATA") != "")

	if !hasFileCfg && !hasStaticCfg {
		t.Fatalf("File config (KUBE_CTX_AUTH_INFO and KUBE_CTX_CLUSTER) or static configuration"+
			" (%s) must be set for acceptance tests",
			strings.Join([]string{
				"KUBE_HOST",
				"KUBE_USER",
				"KUBE_PASSWORD",
				"KUBE_CLIENT_CERT_DATA",
				"KUBE_CLIENT_KEY_DATA",
				"KUBE_CLUSTER_CA_CERT_DATA",
			}, ", "))
	}

	err := testAccProvider.Configure(terraform.NewResourceConfig(nil))
	if err != nil {
		t.Fatal(err)
	}
}

func skipIfNoGoogleCloudSettingsFound(t *testing.T) {
	if os.Getenv("GOOGLE_PROJECT") == "" || os.Getenv("GOOGLE_REGION") == "" || os.Getenv("GOOGLE_ZONE") == "" {
		t.Skip("The environment variables GOOGLE_PROJECT, GOOGLE_REGION and GOOGLE_ZONE" +
			" must be set to run Google Cloud tests - skipping")
	}
}

func skipIfNoAwsSettingsFound(t *testing.T) {
	if os.Getenv("AWS_DEFAULT_REGION") == "" || os.Getenv("AWS_ZONE") == "" || os.Getenv("AWS_ACCESS_KEY_ID") == "" || os.Getenv("AWS_SECRET_ACCESS_KEY") == "" {
		t.Skip("The environment variables AWS_DEFAULT_REGION, AWS_ZONE, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY" +
			" must be set to run AWS tests - skipping")
	}
}

func skipIfNoLoadBalancersAvailable(t *testing.T) {
	// TODO: Support AWS ELBs
	isInGke, err := isRunningInGke()
	if err != nil {
		t.Fatal(err)
	}
	if !isInGke {
		t.Skip("The Kubernetes endpoint must come from an environment which supports " +
			"load balancer provisioning for this test to run - skipping")
	}
}

func skipIfNotRunningInGke(t *testing.T) {
	isInGke, err := isRunningInGke()
	if err != nil {
		t.Fatal(err)
	}
	if !isInGke {
		t.Skip("The Kubernetes endpoint must come from GKE for this test to run - skipping")
	}
}

func isRunningInMinikube() (bool, error) {
	node, err := getFirstNode()
	if err != nil {
		return false, err
	}

	labels := node.GetLabels()
	if v, ok := labels["kubernetes.io/hostname"]; ok && v == "minikube" {
		return true, nil
	}
	return false, nil
}

func isRunningInGke() (bool, error) {
	node, err := getFirstNode()
	if err != nil {
		return false, err
	}

	labels := node.GetLabels()
	if _, ok := labels["cloud.google.com/gke-nodepool"]; ok {
		return true, nil
	}
	return false, nil
}

func getFirstNode() (api.Node, error) {
	meta := testAccProvider.Meta()
	if meta == nil {
		return api.Node{}, errors.New("Provider not initialized, unable to get cluster node")
	}
	conn := meta.(*kubernetesProvider).conn
	resp, err := conn.CoreV1().Nodes().List(metav1.ListOptions{})
	if err != nil {
		return api.Node{}, err
	}

	if len(resp.Items) < 1 {
		return api.Node{}, errors.New("Expected at least 1 node, none found")
	}

	return resp.Items[0], nil
}

type currentEnv struct {
	Config            string
	Ctx               string
	CtxAuthInfo       string
	CtxCluster        string
	Host              string
	User              string
	Password          string
	ClientCertData    string
	ClientKeyData     string
	ClusterCACertData string
}
<|endoftext|>


<commit_before>// Copyright 2016 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/gohugoio/hugo/config"
	"github.com/gohugoio/hugo/helpers"
	"github.com/spf13/afero"
	"github.com/spf13/cobra"
	jww "github.com/spf13/jwalterweatherman"
)

var (
	disableLiveReload bool
	navigateToChanged bool
	renderToDisk      bool
	serverAppend      bool
	serverInterface   string
	serverPort        int
	liveReloadPort    int
	serverWatch       bool
	noHTTPCache       bool
)

var serverCmd = &cobra.Command{
	Use:     "server",
	Aliases: []string{"serve"},
	Short:   "A high performance webserver",
	Long: `Hugo provides its own webserver which builds and serves the site.
While hugo server is high performance, it is a webserver with limited options.
Many run it in production, but the standard behavior is for people to use it
in development and use a more full featured server such as Nginx or Caddy.

'hugo server' will avoid writing the rendered and served content to disk,
preferring to store it in memory.

By default hugo will also watch your files for any changes you make and
automatically rebuild the site. It will then live reload any open browser pages
and push the latest content to them. As most Hugo sites are built in a fraction
of a second, you will be able to save and see your changes nearly instantly.`,
	//RunE: server,
}

type filesOnlyFs struct {
	fs http.FileSystem
}

type noDirFile struct {
	http.File
}

func (fs filesOnlyFs) Open(name string) (http.File, error) {
	f, err := fs.fs.Open(name)
	if err != nil {
		return nil, err
	}
	return noDirFile{f}, nil
}

func (f noDirFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, nil
}

func init() {
	initHugoBuilderFlags(serverCmd)

	serverCmd.Flags().IntVarP(&serverPort, "port", "p", 1313, "port on which the server will listen")
	serverCmd.Flags().IntVar(&liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)")
	serverCmd.Flags().StringVarP(&serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind")
	serverCmd.Flags().BoolVarP(&serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
	serverCmd.Flags().BoolVar(&noHTTPCache, "noHTTPCache", true, "prevent HTTP caching")
	serverCmd.Flags().BoolVarP(&serverAppend, "appendPort", "", true, "append port to baseURL")
	serverCmd.Flags().BoolVar(&disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
	serverCmd.Flags().BoolVar(&navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
	serverCmd.Flags().BoolVar(&renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)")
	serverCmd.Flags().String("memstats", "", "log memory usage to this file")
	serverCmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")

	serverCmd.RunE = server

}

func server(cmd *cobra.Command, args []string) error {
	cfg, err := InitializeConfig(serverCmd)
	if err != nil {
		return err
	}

	c, err := newCommandeer(cfg)
	if err != nil {
		return err
	}

	if cmd.Flags().Changed("disableLiveReload") {
		c.Set("disableLiveReload", disableLiveReload)
	}

	if cmd.Flags().Changed("navigateToChanged") {
		c.Set("navigateToChanged", navigateToChanged)
	}

	if serverWatch {
		c.Set("watch", true)
	}

	if c.Cfg.GetBool("watch") {
		serverWatch = true
		c.watchConfig()
	}

	l, err := net.Listen("tcp", net.JoinHostPort(serverInterface, strconv.Itoa(serverPort)))
	if err == nil {
		l.Close()
	} else {
		if serverCmd.Flags().Changed("port") {
			// port set explicitly by user -- he/she probably meant it!
			return newSystemErrorF("Server startup failed: %s", err)
		}
		jww.ERROR.Println("port", serverPort, "already in use, attempting to use an available port")
		sp, err := helpers.FindAvailablePort()
		if err != nil {
			return newSystemError("Unable to find alternative port to use:", err)
		}
		serverPort = sp.Port
	}

	c.Set("port", serverPort)
	if liveReloadPort != -1 {
		c.Set("liveReloadPort", liveReloadPort)
	} else {
		c.Set("liveReloadPort", serverPort)
	}

	baseURL, err = fixURL(c.Cfg, baseURL)
	if err != nil {
		return err
	}
	c.Set("baseURL", baseURL)

	if err := memStats(); err != nil {
		jww.ERROR.Println("memstats error:", err)
	}

	// If a Destination is provided via flag write to disk
	if destination != "" {
		renderToDisk = true
	}

	// Hugo writes the output to memory instead of the disk
	if !renderToDisk {
		cfg.Fs.Destination = new(afero.MemMapFs)
		// Rendering to memoryFS, publish to Root regardless of publishDir.
		c.Set("publishDir", "/")
	}

	if err := c.build(serverWatch); err != nil {
		return err
	}

	for _, s := range Hugo.Sites {
		s.RegisterMediaTypes()
	}

	// Watch runs its own server as part of the routine
	if serverWatch {
		watchDirs := c.getDirList()
		baseWatchDir := c.Cfg.GetString("workingDir")
		for i, dir := range watchDirs {
			watchDirs[i], _ = helpers.GetRelativePath(dir, baseWatchDir)
		}

		rootWatchDirs := strings.Join(helpers.UniqueStrings(helpers.ExtractRootPaths(watchDirs)), ",")

		jww.FEEDBACK.Printf("Watching for changes in %s%s{%s}\n", baseWatchDir, helpers.FilePathSeparator, rootWatchDirs)
		err := c.newWatcher(serverPort)

		if err != nil {
			return err
		}
	}

	c.serve(serverPort)

	return nil
}

func (c *commandeer) serve(port int) {
	if renderToDisk {
		jww.FEEDBACK.Println("Serving pages from " + c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")))
	} else {
		jww.FEEDBACK.Println("Serving pages from memory")
	}

	httpFs := afero.NewHttpFs(c.Fs.Destination)
	fs := filesOnlyFs{httpFs.Dir(c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")))}
	decorate := func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if noHTTPCache {
				w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
				w.Header().Set("Pragma", "no-cache")
			}
			h.ServeHTTP(w, r)
		})
	}

	fileserver := decorate(http.FileServer(fs))

	// We're only interested in the path
	u, err := url.Parse(c.Cfg.GetString("baseURL"))
	if err != nil {
		jww.ERROR.Fatalf("Invalid baseURL: %s", err)
	}
	if u.Path == "" || u.Path == "/" {
		http.Handle("/", fileserver)
	} else {
		http.Handle(u.Path, http.StripPrefix(u.Path, fileserver))
	}

	jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", u.String(), serverInterface)
	jww.FEEDBACK.Println("Press Ctrl+C to stop")

	endpoint := net.JoinHostPort(serverInterface, strconv.Itoa(port))
	err = http.ListenAndServe(endpoint, nil)
	if err != nil {
		jww.ERROR.Printf("Error: %s\n", err.Error())
		os.Exit(1)
	}
}

// fixURL massages the baseURL into a form needed for serving
// all pages correctly.
func fixURL(cfg config.Provider, s string) (string, error) {
	useLocalhost := false
	if s == "" {
		s = cfg.GetString("baseURL")
		useLocalhost = true
	}

	if !strings.HasSuffix(s, "/") {
		s = s + "/"
	}

	// do an initial parse of the input string
	u, err := url.Parse(s)
	if err != nil {
		return "", err
	}

	// if no Host is defined, then assume that no schema or double-slash were
	// present in the url.  Add a double-slash and make a best effort attempt.
	if u.Host == "" && s != "/" {
		s = "//" + s

		u, err = url.Parse(s)
		if err != nil {
			return "", err
		}
	}

	if useLocalhost {
		if u.Scheme == "https" {
			u.Scheme = "http"
		}
		u.Host = "localhost"
	}

	if serverAppend {
		if strings.Contains(u.Host, ":") {
			u.Host, _, err = net.SplitHostPort(u.Host)
			if err != nil {
				return "", fmt.Errorf("Failed to split baseURL hostpost: %s", err)
			}
		}
		u.Host += fmt.Sprintf(":%d", serverPort)
	}

	return u.String(), nil
}

func memStats() error {
	memstats := serverCmd.Flags().Lookup("memstats").Value.String()
	if memstats != "" {
		interval, err := time.ParseDuration(serverCmd.Flags().Lookup("meminterval").Value.String())
		if err != nil {
			interval, _ = time.ParseDuration("100ms")
		}

		fileMemStats, err := os.Create(memstats)
		if err != nil {
			return err
		}

		fileMemStats.WriteString("# Time\tHeapSys\tHeapAlloc\tHeapIdle\tHeapReleased\n")

		go func() {
			var stats runtime.MemStats

			start := time.Now().UnixNano()

			for {
				runtime.ReadMemStats(&stats)
				if fileMemStats != nil {
					fileMemStats.WriteString(fmt.Sprintf("%d\t%d\t%d\t%d\t%d\n",
						(time.Now().UnixNano()-start)/1000000, stats.HeapSys, stats.HeapAlloc, stats.HeapIdle, stats.HeapReleased))
					time.Sleep(interval)
				} else {
					break
				}
			}
		}()
	}
	return nil
}
<commit_msg>commands: Make noHTTPCache default false<commit_after>// Copyright 2016 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package commands

import (
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/gohugoio/hugo/config"
	"github.com/gohugoio/hugo/helpers"
	"github.com/spf13/afero"
	"github.com/spf13/cobra"
	jww "github.com/spf13/jwalterweatherman"
)

var (
	disableLiveReload bool
	navigateToChanged bool
	renderToDisk      bool
	serverAppend      bool
	serverInterface   string
	serverPort        int
	liveReloadPort    int
	serverWatch       bool
	noHTTPCache       bool
)

var serverCmd = &cobra.Command{
	Use:     "server",
	Aliases: []string{"serve"},
	Short:   "A high performance webserver",
	Long: `Hugo provides its own webserver which builds and serves the site.
While hugo server is high performance, it is a webserver with limited options.
Many run it in production, but the standard behavior is for people to use it
in development and use a more full featured server such as Nginx or Caddy.

'hugo server' will avoid writing the rendered and served content to disk,
preferring to store it in memory.

By default hugo will also watch your files for any changes you make and
automatically rebuild the site. It will then live reload any open browser pages
and push the latest content to them. As most Hugo sites are built in a fraction
of a second, you will be able to save and see your changes nearly instantly.`,
	//RunE: server,
}

type filesOnlyFs struct {
	fs http.FileSystem
}

type noDirFile struct {
	http.File
}

func (fs filesOnlyFs) Open(name string) (http.File, error) {
	f, err := fs.fs.Open(name)
	if err != nil {
		return nil, err
	}
	return noDirFile{f}, nil
}

func (f noDirFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, nil
}

func init() {
	initHugoBuilderFlags(serverCmd)

	serverCmd.Flags().IntVarP(&serverPort, "port", "p", 1313, "port on which the server will listen")
	serverCmd.Flags().IntVar(&liveReloadPort, "liveReloadPort", -1, "port for live reloading (i.e. 443 in HTTPS proxy situations)")
	serverCmd.Flags().StringVarP(&serverInterface, "bind", "", "127.0.0.1", "interface to which the server will bind")
	serverCmd.Flags().BoolVarP(&serverWatch, "watch", "w", true, "watch filesystem for changes and recreate as needed")
	serverCmd.Flags().BoolVar(&noHTTPCache, "noHTTPCache", false, "prevent HTTP caching")
	serverCmd.Flags().BoolVarP(&serverAppend, "appendPort", "", true, "append port to baseURL")
	serverCmd.Flags().BoolVar(&disableLiveReload, "disableLiveReload", false, "watch without enabling live browser reload on rebuild")
	serverCmd.Flags().BoolVar(&navigateToChanged, "navigateToChanged", false, "navigate to changed content file on live browser reload")
	serverCmd.Flags().BoolVar(&renderToDisk, "renderToDisk", false, "render to Destination path (default is render to memory & serve from there)")
	serverCmd.Flags().String("memstats", "", "log memory usage to this file")
	serverCmd.Flags().String("meminterval", "100ms", "interval to poll memory usage (requires --memstats), valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\".")

	serverCmd.RunE = server

}

func server(cmd *cobra.Command, args []string) error {
	cfg, err := InitializeConfig(serverCmd)
	if err != nil {
		return err
	}

	c, err := newCommandeer(cfg)
	if err != nil {
		return err
	}

	if cmd.Flags().Changed("disableLiveReload") {
		c.Set("disableLiveReload", disableLiveReload)
	}

	if cmd.Flags().Changed("navigateToChanged") {
		c.Set("navigateToChanged", navigateToChanged)
	}

	if serverWatch {
		c.Set("watch", true)
	}

	if c.Cfg.GetBool("watch") {
		serverWatch = true
		c.watchConfig()
	}

	l, err := net.Listen("tcp", net.JoinHostPort(serverInterface, strconv.Itoa(serverPort)))
	if err == nil {
		l.Close()
	} else {
		if serverCmd.Flags().Changed("port") {
			// port set explicitly by user -- he/she probably meant it!
			return newSystemErrorF("Server startup failed: %s", err)
		}
		jww.ERROR.Println("port", serverPort, "already in use, attempting to use an available port")
		sp, err := helpers.FindAvailablePort()
		if err != nil {
			return newSystemError("Unable to find alternative port to use:", err)
		}
		serverPort = sp.Port
	}

	c.Set("port", serverPort)
	if liveReloadPort != -1 {
		c.Set("liveReloadPort", liveReloadPort)
	} else {
		c.Set("liveReloadPort", serverPort)
	}

	baseURL, err = fixURL(c.Cfg, baseURL)
	if err != nil {
		return err
	}
	c.Set("baseURL", baseURL)

	if err := memStats(); err != nil {
		jww.ERROR.Println("memstats error:", err)
	}

	// If a Destination is provided via flag write to disk
	if destination != "" {
		renderToDisk = true
	}

	// Hugo writes the output to memory instead of the disk
	if !renderToDisk {
		cfg.Fs.Destination = new(afero.MemMapFs)
		// Rendering to memoryFS, publish to Root regardless of publishDir.
		c.Set("publishDir", "/")
	}

	if err := c.build(serverWatch); err != nil {
		return err
	}

	for _, s := range Hugo.Sites {
		s.RegisterMediaTypes()
	}

	// Watch runs its own server as part of the routine
	if serverWatch {
		watchDirs := c.getDirList()
		baseWatchDir := c.Cfg.GetString("workingDir")
		for i, dir := range watchDirs {
			watchDirs[i], _ = helpers.GetRelativePath(dir, baseWatchDir)
		}

		rootWatchDirs := strings.Join(helpers.UniqueStrings(helpers.ExtractRootPaths(watchDirs)), ",")

		jww.FEEDBACK.Printf("Watching for changes in %s%s{%s}\n", baseWatchDir, helpers.FilePathSeparator, rootWatchDirs)
		err := c.newWatcher(serverPort)

		if err != nil {
			return err
		}
	}

	c.serve(serverPort)

	return nil
}

func (c *commandeer) serve(port int) {
	if renderToDisk {
		jww.FEEDBACK.Println("Serving pages from " + c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")))
	} else {
		jww.FEEDBACK.Println("Serving pages from memory")
	}

	httpFs := afero.NewHttpFs(c.Fs.Destination)
	fs := filesOnlyFs{httpFs.Dir(c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")))}
	decorate := func(h http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if noHTTPCache {
				w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0")
				w.Header().Set("Pragma", "no-cache")
			}
			h.ServeHTTP(w, r)
		})
	}

	fileserver := decorate(http.FileServer(fs))

	// We're only interested in the path
	u, err := url.Parse(c.Cfg.GetString("baseURL"))
	if err != nil {
		jww.ERROR.Fatalf("Invalid baseURL: %s", err)
	}
	if u.Path == "" || u.Path == "/" {
		http.Handle("/", fileserver)
	} else {
		http.Handle(u.Path, http.StripPrefix(u.Path, fileserver))
	}

	jww.FEEDBACK.Printf("Web Server is available at %s (bind address %s)\n", u.String(), serverInterface)
	jww.FEEDBACK.Println("Press Ctrl+C to stop")

	endpoint := net.JoinHostPort(serverInterface, strconv.Itoa(port))
	err = http.ListenAndServe(endpoint, nil)
	if err != nil {
		jww.ERROR.Printf("Error: %s\n", err.Error())
		os.Exit(1)
	}
}

// fixURL massages the baseURL into a form needed for serving
// all pages correctly.
func fixURL(cfg config.Provider, s string) (string, error) {
	useLocalhost := false
	if s == "" {
		s = cfg.GetString("baseURL")
		useLocalhost = true
	}

	if !strings.HasSuffix(s, "/") {
		s = s + "/"
	}

	// do an initial parse of the input string
	u, err := url.Parse(s)
	if err != nil {
		return "", err
	}

	// if no Host is defined, then assume that no schema or double-slash were
	// present in the url.  Add a double-slash and make a best effort attempt.
	if u.Host == "" && s != "/" {
		s = "//" + s

		u, err = url.Parse(s)
		if err != nil {
			return "", err
		}
	}

	if useLocalhost {
		if u.Scheme == "https" {
			u.Scheme = "http"
		}
		u.Host = "localhost"
	}

	if serverAppend {
		if strings.Contains(u.Host, ":") {
			u.Host, _, err = net.SplitHostPort(u.Host)
			if err != nil {
				return "", fmt.Errorf("Failed to split baseURL hostpost: %s", err)
			}
		}
		u.Host += fmt.Sprintf(":%d", serverPort)
	}

	return u.String(), nil
}

func memStats() error {
	memstats := serverCmd.Flags().Lookup("memstats").Value.String()
	if memstats != "" {
		interval, err := time.ParseDuration(serverCmd.Flags().Lookup("meminterval").Value.String())
		if err != nil {
			interval, _ = time.ParseDuration("100ms")
		}

		fileMemStats, err := os.Create(memstats)
		if err != nil {
			return err
		}

		fileMemStats.WriteString("# Time\tHeapSys\tHeapAlloc\tHeapIdle\tHeapReleased\n")

		go func() {
			var stats runtime.MemStats

			start := time.Now().UnixNano()

			for {
				runtime.ReadMemStats(&stats)
				if fileMemStats != nil {
					fileMemStats.WriteString(fmt.Sprintf("%d\t%d\t%d\t%d\t%d\n",
						(time.Now().UnixNano()-start)/1000000, stats.HeapSys, stats.HeapAlloc, stats.HeapIdle, stats.HeapReleased))
					time.Sleep(interval)
				} else {
					break
				}
			}
		}()
	}
	return nil
}
<|endoftext|>