<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

// if you fork this package, and it's not under OneOfOne, make sure you change this path
const CMapBase = `github.com/OneOfOne/cmap/internal/cmap`

var (
	pkgName   = flag.String("n", "", "package name")
	keyType   = flag.String("kt", "interface{}", "key type")
	valueType = flag.String("vt", "interface{}", "value type")
	hashFn    = flag.String("hfn", "cmap.DefaultKeyHasher", "hash func")
	pkgPath   = flag.String("p", "", "package path")

	toStdout = flag.Bool("stdout", false, "write the output to stdout rather than creating a package")

	verbose        = flag.Bool("v", false, "verbose")
	debugReplacers = flag.Bool("dr", false, "debug replacers")
	isInternal     = flag.Bool("internal", false, "used to generate the main interface{}/interface{} package")

	cmapBase = execString("go", "list", "-f", "{{ .Dir }}", CMapBase)

	validPackageName = regexp.MustCompile(`^[\w\d]+$`)
)

func main() {
	log.SetFlags(log.Lshortfile)
	flag.Parse()

	if cmapBase == "" {
		log.Fatalf("couldn't find the base package: %s", CMapBase)
	}

	if *pkgName == "" {
		wd, _ := os.Getwd()
		*pkgName = filepath.Base(wd)
	}

	if !validPackageName.MatchString(*pkgName) {
		log.Fatalf("invalid package name: %s", *pkgName)
	}

	if !*toStdout {
		if *pkgPath == "" {
			*pkgPath = "./" + *pkgName
		}

		if err := os.MkdirAll(*pkgPath, 0755); err != nil {
			log.Fatalf("error making package dir: %s", *pkgPath)
		}
	}

	r, closeReaders := multiFileReader(filepath.Join(cmapBase, "cmap.go"), filepath.Join(cmapBase, "lmap.go"))
	var (
		filters = getLineFilters()
		buf     bytes.Buffer
	)

	fmt.Fprintf(&buf, `// AUTO-GENERATED by cmap-gen
// DO NOT EDIT"
// generated from %s

package %s

`, CMapBase, *pkgName)

	for sc := bufio.NewScanner(r); sc.Scan(); {
		if line := filters.apply(sc.Bytes()); len(line) > 0 {
			buf.Write(line)
			buf.WriteByte('\n')
		}
	}
	closeReaders()

	cmd := exec.Command("goimports", "-e")
	cmd.Stdin = bytes.NewReader(buf.Bytes())
	cmd.Stderr = os.Stderr

	src, err := cmd.Output()
	if err != nil {
		log.Fatalf("goimports error: %v\n%s", err, buf.Bytes())
	}

	if errs := verifyOutput(src); len(errs) > 0 {
		log.Fatalf("error compiling code: \n\t%s\n\n%s", strings.Join(errs, "\n\t"), src)
	}

	fp := filepath.Join(*pkgPath, "cmap.go")

	if *verbose {
		log.Printf("writing typed cmap %s.CMap[%s][%s] (using HashFn: %s) to file %s...", *pkgName, *keyType, *valueType, *hashFn, fp)
	}

	if *toStdout {
		os.Stdout.Write(src)
	} else {
		if err = ioutil.WriteFile(fp, src, 0644); err != nil {
			log.Fatalf("error writing file (%s): %v", fp, err)
		}
	}
}

func verifyOutput(src []byte) (errs []string) {
	var s scanner.Scanner
	fset := token.NewFileSet()                      // positions are relative to fset
	file := fset.AddFile("", fset.Base(), len(src)) // register input "file"
	s.Init(file, src, func(pos token.Position, msg string) {
		errs = append(errs, msg)
	}, 0)

	for _, tok, _ := s.Scan(); tok != token.EOF; _, tok, _ = s.Scan() {
	}
	return
}

type filters []func([]byte) []byte

var (
	bPkg     = []byte("package")
	bImports = []byte("import")
)

func (f filters) apply(line []byte) (_ []byte) {
	if line = bytes.TrimSpace(line); len(line) == 0 {
		return
	}

	if bytes.HasPrefix(line, bPkg) {
		return
	}

	if bytes.HasPrefix(line, bImports) && bytes.ContainsRune(line, '"') {
		return
	}

	for _, fn := range f {
		if line = fn(line); len(line) == 0 {
			break
		}
	}

	return line
}

func getLineFilters() filters {
	out := filters{
		replacer(`KT`, *keyType),
		replacer(`VT`, *valueType),
	}

	if *hashFn != "cmap.DefaultKeyHasher" {
		out = append(out,
			replacer(`cm\.HashFn`, *hashFn),
			replacer(`.*HashFn.*|.*DefaultKeyHasher.*`, ""),
		)
	}

	if *isInternal {
		out = append(out,
			replacer(`cmap\.`, ""),
			replacer(`^(?:var||//) Break.*$`, ""),
		)
	}

	return out
}

func replacer(sre, r string) func([]byte) []byte {
	re := regexp.MustCompile(sre)
	bR := []byte(r)
	return func(in []byte) []byte {
		if *debugReplacers {
			log.Printf("re=%q in=%q repl=%q m=%q", re.String(), in, bR, re.ReplaceAll(in, bR))
		}
		return re.ReplaceAll(in, bR)
	}
}

func execString(name string, args ...string) string {
	out, err := exec.Command(name, args...).Output()
	if err != nil {
		log.Printf("exec error: %v", err)
		return ""
	}
	return string(bytes.TrimSpace(out))
}

func multiFileReader(fnames ...string) (io.Reader, func()) {
	files := make([]io.Reader, 0, len(fnames))
	closer := func() {
		for _, f := range files {
			f.(io.Closer).Close()
		}
	}

	for _, fname := range fnames {
		f, err := os.Open(fname)
		if err != nil {
			closer()
			log.Fatalf("couldn't open %q: %v", fname, err)
		}
		files = append(files, f)
	}

	return io.MultiReader(files...), closer
}
<commit_msg>enable outputing lmap only<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

// if you fork this package, and it's not under OneOfOne, make sure you change this path
const CMapBase = `github.com/OneOfOne/cmap/internal/cmap`

var (
	pkgName   = flag.String("n", "", "package name")
	keyType   = flag.String("kt", "interface{}", "key type")
	valueType = flag.String("vt", "interface{}", "value type")
	hashFn    = flag.String("hfn", "cmap.DefaultKeyHasher", "hash func")
	pkgPath   = flag.String("p", "", "package path")
	lmapOnly  = flag.Bool("lmap", false, "generate LMap only")

	toStdout = flag.Bool("stdout", false, "write the output to stdout rather than creating a package")

	verbose        = flag.Bool("v", false, "verbose")
	debugReplacers = flag.Bool("dr", false, "debug replacers")
	isInternal     = flag.Bool("internal", false, "used to generate the main interface{}/interface{} package")

	cmapBase = execString("go", "list", "-f", "{{ .Dir }}", CMapBase)

	validPackageName = regexp.MustCompile(`^[\w\d]+$`)
)

func main() {
	log.SetFlags(log.Lshortfile)
	flag.Parse()

	if cmapBase == "" {
		log.Fatalf("couldn't find the base package: %s", CMapBase)
	}

	if *pkgName == "" {
		wd, _ := os.Getwd()
		*pkgName = filepath.Base(wd)
	}

	if !validPackageName.MatchString(*pkgName) {
		log.Fatalf("invalid package name: %s", *pkgName)
	}

	if !*toStdout {
		if *pkgPath == "" {
			*pkgPath = "./" + *pkgName
		}

		if err := os.MkdirAll(*pkgPath, 0755); err != nil {
			log.Fatalf("error making package dir: %s", *pkgPath)
		}
	}

	files := []string{filepath.Join(cmapBase, "cmap.go"), filepath.Join(cmapBase, "lmap.go")}
	if *lmapOnly {
		files = files[1:]
	}

	r, closeReaders := multiFileReader(files...)
	var (
		filters = getLineFilters()
		buf     bytes.Buffer
	)

	fmt.Fprintf(&buf, `// AUTO-GENERATED by cmap-gen
// DO NOT EDIT"
// generated from %s

package %s

`, CMapBase, *pkgName)

	for sc := bufio.NewScanner(r); sc.Scan(); {
		if line := filters.apply(sc.Bytes()); len(line) > 0 {
			buf.Write(line)
			buf.WriteByte('\n')
		}
	}
	closeReaders()

	cmd := exec.Command("goimports", "-e")
	cmd.Stdin = bytes.NewReader(buf.Bytes())
	cmd.Stderr = os.Stderr

	src, err := cmd.Output()
	if err != nil {
		log.Fatalf("goimports error: %v\n%s", err, buf.Bytes())
	}

	if errs := verifyOutput(src); len(errs) > 0 {
		log.Fatalf("error compiling code: \n\t%s\n\n%s", strings.Join(errs, "\n\t"), src)
	}

	var fp string
	if *lmapOnly {
		fp = filepath.Join(*pkgPath, "lmap.go")
	} else {
		fp = filepath.Join(*pkgPath, "cmap.go")
	}

	if *verbose {
		log.Printf("writing typed cmap %s.CMap[%s][%s] (using HashFn: %s) to file %s...", *pkgName, *keyType, *valueType, *hashFn, fp)
	}

	if *toStdout {
		os.Stdout.Write(src)
	} else {
		if err = ioutil.WriteFile(fp, src, 0644); err != nil {
			log.Fatalf("error writing file (%s): %v", fp, err)
		}
	}
}

func verifyOutput(src []byte) (errs []string) {
	var s scanner.Scanner
	fset := token.NewFileSet()                      // positions are relative to fset
	file := fset.AddFile("", fset.Base(), len(src)) // register input "file"
	s.Init(file, src, func(pos token.Position, msg string) {
		errs = append(errs, msg)
	}, 0)

	for _, tok, _ := s.Scan(); tok != token.EOF; _, tok, _ = s.Scan() {
	}
	return
}

type filters []func([]byte) []byte

var (
	bPkg     = []byte("package")
	bImports = []byte("import")
)

func (f filters) apply(line []byte) (_ []byte) {
	if line = bytes.TrimSpace(line); len(line) == 0 {
		return
	}

	if bytes.HasPrefix(line, bPkg) {
		return
	}

	if bytes.HasPrefix(line, bImports) && bytes.ContainsRune(line, '"') {
		return
	}

	for _, fn := range f {
		if line = fn(line); len(line) == 0 {
			break
		}
	}

	return line
}

func getLineFilters() filters {
	out := filters{
		replacer(`KT`, *keyType),
		replacer(`VT`, *valueType),
	}

	if *hashFn != "cmap.DefaultKeyHasher" {
		out = append(out,
			replacer(`cm\.HashFn`, *hashFn),
			replacer(`.*HashFn.*|.*DefaultKeyHasher.*`, ""),
		)
	}

	if *isInternal {
		out = append(out,
			replacer(`cmap\.`, ""),
			replacer(`^(?:var||//) Break.*$`, ""),
		)
	}

	return out
}

func replacer(sre, r string) func([]byte) []byte {
	re := regexp.MustCompile(sre)
	bR := []byte(r)
	return func(in []byte) []byte {
		if *debugReplacers {
			log.Printf("re=%q in=%q repl=%q m=%q", re.String(), in, bR, re.ReplaceAll(in, bR))
		}
		return re.ReplaceAll(in, bR)
	}
}

func execString(name string, args ...string) string {
	out, err := exec.Command(name, args...).Output()
	if err != nil {
		log.Printf("exec error: %v", err)
		return ""
	}
	return string(bytes.TrimSpace(out))
}

func multiFileReader(fnames ...string) (io.Reader, func()) {
	files := make([]io.Reader, 0, len(fnames))
	closer := func() {
		for _, f := range files {
			f.(io.Closer).Close()
		}
	}

	for _, fname := range fnames {
		f, err := os.Open(fname)
		if err != nil {
			closer()
			log.Fatalf("couldn't open %q: %v", fname, err)
		}
		files = append(files, f)
	}

	return io.MultiReader(files...), closer
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"expvar"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"syscall"
	"time"

	"github.com/ekanite/ekanite"
	"github.com/ekanite/ekanite/input"
	"github.com/ekanite/ekanite/status"
)

var (
	stats = expvar.NewMap("ekanite")
)

// Program parameters
var datadir string
var tcpIface string
var udpIface string
var caPemPath string
var caKeyPath string
var queryIface string
var batchSize int
var batchTimeout int
var indexMaxPending int
var gomaxprocs int
var numShards int
var retentionPeriod string
var cpuProfile string
var memProfile string
var inputFormat string

// Flag set
var fs *flag.FlagSet

// Types
const (
	DefaultDataDir         = "/var/opt/ekanite"
	DefaultBatchSize       = 300
	DefaultBatchTimeout    = 1000
	DefaultIndexMaxPending = 1000
	DefaultNumShards       = 4
	DefaultRetentionPeriod = "168h"
	DefaultQueryAddr       = "localhost:9950"
	DefaultHTTPQueryAddr   = "localhost:8080"
	DefaultDiagsIface      = "localhost:9951"
	DefaultTCPServer       = "localhost:5514"
	DefaultInputFormat     = "syslog"
)

func main() {
	fs = flag.NewFlagSet("", flag.ExitOnError)
	var (
		datadir         = fs.String("datadir", DefaultDataDir, "Set data directory")
		batchSize       = fs.Int("batchsize", DefaultBatchSize, "Indexing batch size")
		batchTimeout    = fs.Int("batchtime", DefaultBatchTimeout, "Indexing batch timeout, in milliseconds")
		indexMaxPending = fs.Int("maxpending", DefaultIndexMaxPending, "Maximum pending index events")
		tcpIface        = fs.String("tcp", DefaultTCPServer, "Syslog server TCP bind address in the form host:port. To disable set to empty string")
		udpIface        = fs.String("udp", "", "Syslog server UDP bind address in the form host:port. If not set, not started")
		diagIface       = fs.String("diag", DefaultDiagsIface, "expvar and pprof bind address in the form host:port. If not set, not started")
		caPemPath       = fs.String("tlspem", "", "path to CA PEM file for TLS-enabled TCP server. If not set, TLS not activated")
		caKeyPath       = fs.String("tlskey", "", "path to CA key file for TLS-enabled TCP server. If not set, TLS not activated")
		queryIface      = fs.String("query", DefaultQueryAddr, "TCP Bind address for query server in the form host:port. To disable set to empty string")
		queryIfaceHttp  = fs.String("queryhttp", DefaultHTTPQueryAddr, "TCP Bind address for http query server in the form host:port. To disable set to empty string")
		numShards       = fs.Int("numshards", DefaultNumShards, "Set number of shards per index")
		retentionPeriod = fs.String("retention", DefaultRetentionPeriod, "Data retention period. Minimum is 24 hours")
		cpuProfile      = fs.String("cpuprof", "", "Where to write CPU profiling data. Not written if not set")
		memProfile      = fs.String("memprof", "", "Where to write memory profiling data. Not written if not set")
		inputFormat     = fs.String("input", DefaultInputFormat, "Message format of input (only syslog supported)")
	)
	fs.Usage = printHelp
	fs.Parse(os.Args[1:])

	absDataDir, err := filepath.Abs(*datadir)
	if err != nil {
		log.Fatalf("failed to get absolute data path for '%s': %s", *datadir, err.Error())
	}

	// Get the retention period.
	retention, err := time.ParseDuration(*retentionPeriod)
	if err != nil {
		log.Fatalf("failed to parse retention period '%s'", *retentionPeriod)
	}

	log.SetFlags(log.LstdFlags)
	log.SetPrefix("[ekanite] ")
	log.Printf("ekanite started using %s for index storage", absDataDir)

	runtime.GOMAXPROCS(runtime.NumCPU())
	log.Println("GOMAXPROCS set to", runtime.GOMAXPROCS(0))

	// Start the expvar handler if requested.
	if *diagIface != "" {
		startDiagServer(*diagIface)
	}

	// Create and open the Engine.
	engine := ekanite.NewEngine(absDataDir)
	if engine == nil {
		log.Fatalf("failed to create indexing engine at %s", absDataDir)
	}
	engine.NumShards = *numShards
	engine.RetentionPeriod = retention

	if err := engine.Open(); err != nil {
		log.Fatalf("failed to open engine: %s", err.Error())
	}
	log.Printf("engine opened with shard number of %d, retention period of %s",
		engine.NumShards, engine.RetentionPeriod)

	// Start the simple query server if requested.
	if *queryIface != "" {
		startQueryServer(*queryIface, engine)
	}

	// Start the http query server if requested.
	if *queryIfaceHttp != "" {
		startHTTPQueryServer(*queryIfaceHttp, engine)
	}

	// Create and start the batcher.
	batcherTimeout := time.Duration(*batchTimeout) * time.Millisecond
	batcher := ekanite.NewBatcher(engine, *batchSize, batcherTimeout, *indexMaxPending)
	if batcher == nil {
		log.Fatal("failed to create indexing batcher")
	}

	errChan := make(chan error)
	if err := batcher.Start(errChan); err != nil {
		log.Fatalf("failed to start indexing batcher: %s", err.Error())
	}
	log.Printf("batching configured with size %d, timeout %s, max pending %d",
		*batchSize, batcherTimeout, *indexMaxPending)

	// Start draining batcher errors.
	go drainLog("error indexing batch", errChan)

	// Start TCP collector if requested.
	if *tcpIface != "" {
		var tlsConfig *tls.Config
		if *caPemPath != "" && *caKeyPath != "" {
			tlsConfig, err = newTLSConfig(*caPemPath, *caKeyPath)
			if err != nil {
				log.Fatalf("failed to configure TLS: %s", err.Error())
			}
			log.Printf("TLS successfully configured")
		}

		if err := startTCPCollector(*tcpIface, *inputFormat, tlsConfig, batcher); err != nil {
			log.Fatalf("failed to start TCP collector: %s", err.Error())
		}
		log.Printf("TCP collector listening to %s", *tcpIface)
	}

	// Start UDP collector if requested.
	if *udpIface != "" {
		if err := startUDPCollector(*udpIface, *inputFormat, batcher); err != nil {
			log.Fatalf("failed to start UDP collector: %s", err.Error())
		}
		log.Printf("UDP collector listening to %s", *udpIface)
	}

	// Start profiling.
	startProfile(*cpuProfile, *memProfile)

	stats.Set("launch", time.Now().UTC())

	// Set up signal handling.
	signalCh := make(chan os.Signal, 1)
	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)

	// Block until one of the signals above is received
	select {
	case <-signalCh:
		log.Println("signal received, shutting down...")
	}

	stopProfile()
}

func startTCPCollector(iface, format string, tls *tls.Config, batcher *ekanite.Batcher) error {
	collector, err := input.NewCollector("tcp", iface, format, tls)
	if err != nil {
		return fmt.Errorf(("failed to create TCP collector: %s"), err.Error())
	}
	if err := collector.Start(batcher.C()); err != nil {
		return fmt.Errorf("failed to start TCP collector: %s", err.Error())
	}

	return nil
}

func startUDPCollector(iface, format string, batcher *ekanite.Batcher) error {
	collector, err := input.NewCollector("udp", iface, format, nil)
	if err != nil {
		return fmt.Errorf("failed to create UDP collector: %s", err.Error())
	}
	if err := collector.Start(batcher.C()); err != nil {
		return fmt.Errorf("failed to start UDP collector: %s", err.Error())
	}

	return nil
}

func startQueryServer(iface string, engine *ekanite.Engine) {
	server := ekanite.NewServer(iface, engine)
	if server == nil {
		log.Fatal("failed to create query server")
	}
	if err := server.Start(); err != nil {
		log.Fatalf("failed to start query server: %s", err.Error())
	}
	log.Printf("query server listening on %s", iface)
}

func startHTTPQueryServer(iface string, engine *ekanite.Engine) {
	server := ekanite.NewHTTPServer(iface, engine)
	if server == nil {
		log.Fatal("failed to create HTTP query server")
	}
	if err := server.Start(); err != nil {
		log.Fatalf("failed to start HTTP query server: %s", err.Error())
	}
	log.Printf("HTTP query server listening on %s", iface)
}

func startDiagServer(iface string) {
	diagServer := status.NewService(iface)
	if err := diagServer.Start(); err != nil {
		log.Fatalf("failed to start status server on %s: %s", iface, err.Error())
	}
	log.Printf("diagnostic server listening on %s", iface)
}

func newTLSConfig(caPemPath, caKeyPath string) (*tls.Config, error) {
	var config *tls.Config

	caPem, err := ioutil.ReadFile(caPemPath)
	if err != nil {
		return nil, err
	}
	ca, err := x509.ParseCertificate(caPem)
	if err != nil {
		return nil, err
	}

	caKey, err := ioutil.ReadFile(caKeyPath)
	if err != nil {
		return nil, err
	}
	key, err := x509.ParsePKCS1PrivateKey(caKey)
	if err != nil {
		return nil, err
	}
	pool := x509.NewCertPool()
	pool.AddCert(ca)

	cert := tls.Certificate{
		Certificate: [][]byte{caPem},
		PrivateKey:  key,
	}

	config = &tls.Config{
		ClientAuth:   tls.RequireAndVerifyClientCert,
		Certificates: []tls.Certificate{cert},
		ClientCAs:    pool,
	}

	config.Rand = rand.Reader

	return config, nil
}

// drainLog drains errors from the channel and simply logs them
func drainLog(msg string, errChan <-chan error) {
	for {
		select {
		case err := <-errChan:
			if err != nil {
				log.Printf("%s: %s", msg, err.Error())
			}
		}
	}
}

// prof stores the file locations of active profiles.
var prof struct {
	cpu *os.File
	mem *os.File
}

// StartProfile initializes the cpu and memory profile, if specified.
func startProfile(cpuprofile, memprofile string) {
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatalf("cpuprofile: %v", err)
		}
		log.Printf("writing CPU profile to: %s\n", cpuprofile)
		prof.cpu = f
		pprof.StartCPUProfile(prof.cpu)
	}

	if memprofile != "" {
		f, err := os.Create(memprofile)
		if err != nil {
			log.Fatalf("memprofile: %v", err)
		}
		log.Printf("writing memory profile to: %s\n", memprofile)
		prof.mem = f
		runtime.MemProfileRate = 4096
	}

}

// StopProfile closes the cpu and memory profiles if they are running.
func stopProfile() {
	if prof.cpu != nil {
		pprof.StopCPUProfile()
		prof.cpu.Close()
		log.Println("CPU profile stopped")
	}
	if prof.mem != nil {
		pprof.Lookup("heap").WriteTo(prof.mem, 0)
		prof.mem.Close()
		log.Println("memory profile stopped")
	}
}

func printHelp() {
	fmt.Println("ekanited [options]")
	fs.PrintDefaults()
}
<commit_msg>NewEngine() cannot fail<commit_after>package main

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"expvar"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"syscall"
	"time"

	"github.com/ekanite/ekanite"
	"github.com/ekanite/ekanite/input"
	"github.com/ekanite/ekanite/status"
)

var (
	stats = expvar.NewMap("ekanite")
)

// Program parameters
var datadir string
var tcpIface string
var udpIface string
var caPemPath string
var caKeyPath string
var queryIface string
var batchSize int
var batchTimeout int
var indexMaxPending int
var gomaxprocs int
var numShards int
var retentionPeriod string
var cpuProfile string
var memProfile string
var inputFormat string

// Flag set
var fs *flag.FlagSet

// Types
const (
	DefaultDataDir         = "/var/opt/ekanite"
	DefaultBatchSize       = 300
	DefaultBatchTimeout    = 1000
	DefaultIndexMaxPending = 1000
	DefaultNumShards       = 4
	DefaultRetentionPeriod = "168h"
	DefaultQueryAddr       = "localhost:9950"
	DefaultHTTPQueryAddr   = "localhost:8080"
	DefaultDiagsIface      = "localhost:9951"
	DefaultTCPServer       = "localhost:5514"
	DefaultInputFormat     = "syslog"
)

func main() {
	fs = flag.NewFlagSet("", flag.ExitOnError)
	var (
		datadir         = fs.String("datadir", DefaultDataDir, "Set data directory")
		batchSize       = fs.Int("batchsize", DefaultBatchSize, "Indexing batch size")
		batchTimeout    = fs.Int("batchtime", DefaultBatchTimeout, "Indexing batch timeout, in milliseconds")
		indexMaxPending = fs.Int("maxpending", DefaultIndexMaxPending, "Maximum pending index events")
		tcpIface        = fs.String("tcp", DefaultTCPServer, "Syslog server TCP bind address in the form host:port. To disable set to empty string")
		udpIface        = fs.String("udp", "", "Syslog server UDP bind address in the form host:port. If not set, not started")
		diagIface       = fs.String("diag", DefaultDiagsIface, "expvar and pprof bind address in the form host:port. If not set, not started")
		caPemPath       = fs.String("tlspem", "", "path to CA PEM file for TLS-enabled TCP server. If not set, TLS not activated")
		caKeyPath       = fs.String("tlskey", "", "path to CA key file for TLS-enabled TCP server. If not set, TLS not activated")
		queryIface      = fs.String("query", DefaultQueryAddr, "TCP Bind address for query server in the form host:port. To disable set to empty string")
		queryIfaceHttp  = fs.String("queryhttp", DefaultHTTPQueryAddr, "TCP Bind address for http query server in the form host:port. To disable set to empty string")
		numShards       = fs.Int("numshards", DefaultNumShards, "Set number of shards per index")
		retentionPeriod = fs.String("retention", DefaultRetentionPeriod, "Data retention period. Minimum is 24 hours")
		cpuProfile      = fs.String("cpuprof", "", "Where to write CPU profiling data. Not written if not set")
		memProfile      = fs.String("memprof", "", "Where to write memory profiling data. Not written if not set")
		inputFormat     = fs.String("input", DefaultInputFormat, "Message format of input (only syslog supported)")
	)
	fs.Usage = printHelp
	fs.Parse(os.Args[1:])

	absDataDir, err := filepath.Abs(*datadir)
	if err != nil {
		log.Fatalf("failed to get absolute data path for '%s': %s", *datadir, err.Error())
	}

	// Get the retention period.
	retention, err := time.ParseDuration(*retentionPeriod)
	if err != nil {
		log.Fatalf("failed to parse retention period '%s'", *retentionPeriod)
	}

	log.SetFlags(log.LstdFlags)
	log.SetPrefix("[ekanite] ")
	log.Printf("ekanite started using %s for index storage", absDataDir)

	runtime.GOMAXPROCS(runtime.NumCPU())
	log.Println("GOMAXPROCS set to", runtime.GOMAXPROCS(0))

	// Start the expvar handler if requested.
	if *diagIface != "" {
		startDiagServer(*diagIface)
	}

	// Create and open the Engine.
	engine := ekanite.NewEngine(absDataDir)
	engine.NumShards = *numShards
	engine.RetentionPeriod = retention

	if err := engine.Open(); err != nil {
		log.Fatalf("failed to open engine: %s", err.Error())
	}
	log.Printf("engine opened with shard number of %d, retention period of %s",
		engine.NumShards, engine.RetentionPeriod)

	// Start the simple query server if requested.
	if *queryIface != "" {
		startQueryServer(*queryIface, engine)
	}

	// Start the http query server if requested.
	if *queryIfaceHttp != "" {
		startHTTPQueryServer(*queryIfaceHttp, engine)
	}

	// Create and start the batcher.
	batcherTimeout := time.Duration(*batchTimeout) * time.Millisecond
	batcher := ekanite.NewBatcher(engine, *batchSize, batcherTimeout, *indexMaxPending)
	if batcher == nil {
		log.Fatal("failed to create indexing batcher")
	}

	errChan := make(chan error)
	if err := batcher.Start(errChan); err != nil {
		log.Fatalf("failed to start indexing batcher: %s", err.Error())
	}
	log.Printf("batching configured with size %d, timeout %s, max pending %d",
		*batchSize, batcherTimeout, *indexMaxPending)

	// Start draining batcher errors.
	go drainLog("error indexing batch", errChan)

	// Start TCP collector if requested.
	if *tcpIface != "" {
		var tlsConfig *tls.Config
		if *caPemPath != "" && *caKeyPath != "" {
			tlsConfig, err = newTLSConfig(*caPemPath, *caKeyPath)
			if err != nil {
				log.Fatalf("failed to configure TLS: %s", err.Error())
			}
			log.Printf("TLS successfully configured")
		}

		if err := startTCPCollector(*tcpIface, *inputFormat, tlsConfig, batcher); err != nil {
			log.Fatalf("failed to start TCP collector: %s", err.Error())
		}
		log.Printf("TCP collector listening to %s", *tcpIface)
	}

	// Start UDP collector if requested.
	if *udpIface != "" {
		if err := startUDPCollector(*udpIface, *inputFormat, batcher); err != nil {
			log.Fatalf("failed to start UDP collector: %s", err.Error())
		}
		log.Printf("UDP collector listening to %s", *udpIface)
	}

	// Start profiling.
	startProfile(*cpuProfile, *memProfile)

	stats.Set("launch", time.Now().UTC())

	// Set up signal handling.
	signalCh := make(chan os.Signal, 1)
	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)

	// Block until one of the signals above is received
	select {
	case <-signalCh:
		log.Println("signal received, shutting down...")
	}

	stopProfile()
}

func startTCPCollector(iface, format string, tls *tls.Config, batcher *ekanite.Batcher) error {
	collector, err := input.NewCollector("tcp", iface, format, tls)
	if err != nil {
		return fmt.Errorf(("failed to create TCP collector: %s"), err.Error())
	}
	if err := collector.Start(batcher.C()); err != nil {
		return fmt.Errorf("failed to start TCP collector: %s", err.Error())
	}

	return nil
}

func startUDPCollector(iface, format string, batcher *ekanite.Batcher) error {
	collector, err := input.NewCollector("udp", iface, format, nil)
	if err != nil {
		return fmt.Errorf("failed to create UDP collector: %s", err.Error())
	}
	if err := collector.Start(batcher.C()); err != nil {
		return fmt.Errorf("failed to start UDP collector: %s", err.Error())
	}

	return nil
}

func startQueryServer(iface string, engine *ekanite.Engine) {
	server := ekanite.NewServer(iface, engine)
	if server == nil {
		log.Fatal("failed to create query server")
	}
	if err := server.Start(); err != nil {
		log.Fatalf("failed to start query server: %s", err.Error())
	}
	log.Printf("query server listening on %s", iface)
}

func startHTTPQueryServer(iface string, engine *ekanite.Engine) {
	server := ekanite.NewHTTPServer(iface, engine)
	if server == nil {
		log.Fatal("failed to create HTTP query server")
	}
	if err := server.Start(); err != nil {
		log.Fatalf("failed to start HTTP query server: %s", err.Error())
	}
	log.Printf("HTTP query server listening on %s", iface)
}

func startDiagServer(iface string) {
	diagServer := status.NewService(iface)
	if err := diagServer.Start(); err != nil {
		log.Fatalf("failed to start status server on %s: %s", iface, err.Error())
	}
	log.Printf("diagnostic server listening on %s", iface)
}

func newTLSConfig(caPemPath, caKeyPath string) (*tls.Config, error) {
	var config *tls.Config

	caPem, err := ioutil.ReadFile(caPemPath)
	if err != nil {
		return nil, err
	}
	ca, err := x509.ParseCertificate(caPem)
	if err != nil {
		return nil, err
	}

	caKey, err := ioutil.ReadFile(caKeyPath)
	if err != nil {
		return nil, err
	}
	key, err := x509.ParsePKCS1PrivateKey(caKey)
	if err != nil {
		return nil, err
	}
	pool := x509.NewCertPool()
	pool.AddCert(ca)

	cert := tls.Certificate{
		Certificate: [][]byte{caPem},
		PrivateKey:  key,
	}

	config = &tls.Config{
		ClientAuth:   tls.RequireAndVerifyClientCert,
		Certificates: []tls.Certificate{cert},
		ClientCAs:    pool,
	}

	config.Rand = rand.Reader

	return config, nil
}

// drainLog drains errors from the channel and simply logs them
func drainLog(msg string, errChan <-chan error) {
	for {
		select {
		case err := <-errChan:
			if err != nil {
				log.Printf("%s: %s", msg, err.Error())
			}
		}
	}
}

// prof stores the file locations of active profiles.
var prof struct {
	cpu *os.File
	mem *os.File
}

// StartProfile initializes the cpu and memory profile, if specified.
func startProfile(cpuprofile, memprofile string) {
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatalf("cpuprofile: %v", err)
		}
		log.Printf("writing CPU profile to: %s\n", cpuprofile)
		prof.cpu = f
		pprof.StartCPUProfile(prof.cpu)
	}

	if memprofile != "" {
		f, err := os.Create(memprofile)
		if err != nil {
			log.Fatalf("memprofile: %v", err)
		}
		log.Printf("writing memory profile to: %s\n", memprofile)
		prof.mem = f
		runtime.MemProfileRate = 4096
	}

}

// StopProfile closes the cpu and memory profiles if they are running.
func stopProfile() {
	if prof.cpu != nil {
		pprof.StopCPUProfile()
		prof.cpu.Close()
		log.Println("CPU profile stopped")
	}
	if prof.mem != nil {
		pprof.Lookup("heap").WriteTo(prof.mem, 0)
		prof.mem.Close()
		log.Println("memory profile stopped")
	}
}

func printHelp() {
	fmt.Println("ekanited [options]")
	fs.PrintDefaults()
}
<|endoftext|>


<commit_before>package games

import (
	"context"
	"errors"
	"fmt"
	"path/filepath"

	"github.com/danielkrainas/gobag/cmd"

	"github.com/danielkrainas/shex/cmd/cmdutils"
	"github.com/danielkrainas/shex/manager"
	"github.com/danielkrainas/shex/mods"
)

func init() {
	cmd.Register("games", Info)
}

var (
	Info = &cmd.Info{
		Use:   "games",
		Short: "game folder operations",
		Long:  "Perform operations on game folders.",
		SubCommands: []*cmd.Info{
			{
				Use:   "add <name> <path>",
				Short: "add a game folder",
				Long:  "Add the game folder at <path> with the name <name>",
				Run:   cmd.ExecutorFunc(addGame),
			},

			{
				Use:   "remove <name>",
				Short: "remove a game folder",
				Long:  "Remove the game folder with the name <name>",
				Run:   cmd.ExecutorFunc(removeGame),
			},
			{
				Use:   "list",
				Short: "list available game folders",
				Long:  "List available game folders.",
				Run:   cmd.ExecutorFunc(listGames),
			},
		},
	}
)

/* Add Game Command */
func addGame(ctx context.Context, args []string) error {
	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	if len(args) < 1 {
		return errors.New("invalid game path")
	}

	alias := args[0]
	var gamePath string
	if len(args) < 2 {
		gamePath = alias
		alias = manager.DefaultGameName
		fmt.Println(`No alias specified, assuming "default"`)
	} else {
		gamePath, err = filepath.Abs(args[1])
		if err != nil {
			return errors.New("couldn't resolve path: " + args[1])
		}
	}

	if err := m.AddGame(alias, mods.GameDir(gamePath)); err != nil {
		fmt.Printf("error adding game: %v", err)
		return nil
	}

	if err := m.SaveConfig(); err != nil {
		fmt.Printf("error saving config: %v", err)
		return nil
	}

	fmt.Printf("added %s as %q", gamePath, alias)
	return nil
}

/* Remove Game Command */
func removeGame(ctx context.Context, args []string) error {
	if len(args) < 0 {
		return errors.New("you must specify a game alias")
	}

	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	alias := args[0]
	if err := m.RemoveGame(alias); err != nil {
		fmt.Printf("error removing game: %v", err)
		return nil
	}

	if err := m.SaveConfig(); err != nil {
		fmt.Printf("error saving config: %v", err)
		return nil
	}

	fmt.Printf("game removed: %s", alias)
	return nil
}

/* List Games Command */
func listGames(ctx context.Context, _ []string) error {
	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	if m.Config().Games.Len() < 1 {
		fmt.Printf("no games found.\n")
		return nil
	}

	fmt.Printf("%12s   %s\n", "ALIAS", "FOLDER")
	for alias, gameFolder := range m.Config().Games {
		fmt.Printf("%12s   %s\n", alias, gameFolder)
	}

	return nil
}
<commit_msg>cleanup games commands output<commit_after>package games

import (
	"context"
	"errors"
	"fmt"
	"path/filepath"

	"github.com/danielkrainas/gobag/cmd"

	"github.com/danielkrainas/shex/cmd/cmdutils"
	"github.com/danielkrainas/shex/manager"
	"github.com/danielkrainas/shex/mods"
)

func init() {
	cmd.Register("games", Info)
}

var (
	Info = &cmd.Info{
		Use:   "games",
		Short: "game folder operations",
		Long:  "Perform operations on game folders.",
		SubCommands: []*cmd.Info{
			{
				Use:   "add [alias] <path>",
				Short: "add a game folder",
				Long:  "Add the game folder at <path> with the alias <alias>",
				Run:   cmd.ExecutorFunc(addGame),
			},

			{
				Use:   "remove <alias>",
				Short: "remove a game folder",
				Long:  "Remove the game folder with the alias <alias>",
				Run:   cmd.ExecutorFunc(removeGame),
			},
			{
				Use:   "list",
				Short: "list available game folders",
				Long:  "List available game folders.",
				Run:   cmd.ExecutorFunc(listGames),
			},
		},
	}
)

/* Add Game Command */
func addGame(ctx context.Context, args []string) error {
	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	if len(args) < 1 {
		return errors.New("argument missing: path")
	}

	alias := args[0]
	var gamePath string
	if len(args) < 2 {
		gamePath = alias
		alias = manager.DefaultGameName
		fmt.Println(`No alias specified, assuming "default"`)
	} else {
		gamePath, err = filepath.Abs(args[1])
		if err != nil {
			return errors.New("couldn't resolve path: " + args[1])
		}
	}

	if err := m.AddGame(alias, mods.GameDir(gamePath)); err != nil {
		fmt.Printf("error adding game: %v\n", err)
		return nil
	}

	if err := m.SaveConfig(); err != nil {
		fmt.Printf("error saving config: %v\n", err)
		return nil
	}

	fmt.Printf("added %s as %q\n", gamePath, alias)
	return nil
}

/* Remove Game Command */
func removeGame(ctx context.Context, args []string) error {
	if len(args) < 0 {
		return errors.New("argument missing: alias")
	}

	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	alias := args[0]
	if err := m.RemoveGame(alias); err != nil {
		fmt.Printf("error removing game: %v\n", err)
		return nil
	}

	if err := m.SaveConfig(); err != nil {
		fmt.Printf("error saving config: %v\n", err)
		return nil
	}

	fmt.Printf("game removed: %s\n", alias)
	return nil
}

/* List Games Command */
func listGames(ctx context.Context, _ []string) error {
	m, err := cmdutils.LoadManager(ctx)
	if err != nil {
		return err
	}

	if m.Config().Games.Len() < 1 {
		fmt.Printf("no games found.\n")
		return nil
	}

	fmt.Printf("%12s   %s\n", "ALIAS", "FOLDER")
	for alias, gameFolder := range m.Config().Games {
		fmt.Printf("%12s   %s\n", alias, gameFolder)
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012, Muhammed Uluyol <uluyol0@gmail.com>
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"bytes"
	"github.com/mattn/go-gtk/gtk"
	"github.com/mattn/go-gtk/glib"
	"os"
)

const (
	TIMEOUT = 3000
	NEWLINE = byte(10)
	STATUS_CHARGING = "Charging"
	STATUS_DISCHARGING = "Discharging"
)

var (
	status_icon *gtk.GtkStatusIcon
	full int64
)

func main() {
	gtk.Init(&os.Args)
	glib.SetApplicationName("zzcleanbattery")

	buf, err := ioutil.ReadFile("/sys/class/power_supply/BAT0/energy_full")
	if err != nil { panic(err) }
	str := string(bytes.Split(buf, []byte{NEWLINE})[0])
	full, err = strconv.ParseInt(str, 10, 64)
	if err != nil { panic(err) }

	status_icon = gtk.StatusIcon()
	status_icon.SetTitle("zzcleanbattery")

	update_icon()

	glib.TimeoutAdd(TIMEOUT, update_icon)
	gtk.Main()
}

func update_icon() bool {

	var (
		hours int64
		minutes int64
		seconds int64
		pfull int64
		rate int64
		now int64
		status string
		text string
	)

	buf, err := ioutil.ReadFile("/sys/class/power_supply/BAT0/energy_now")
	if err != nil { panic(err) }
	str := string(bytes.Split(buf, []byte{NEWLINE})[0])
	now, err = strconv.ParseInt(str, 10, 64)
	if err != nil { panic(err) }

	buf, err = ioutil.ReadFile("/sys/class/power_supply/BAT0/power_now")
	if err != nil { panic(err) }
	str = string(bytes.Split(buf, []byte{NEWLINE})[0])
	rate, err = strconv.ParseInt(str, 10, 64)
	if err != nil { panic(err) }

	buf, err = ioutil.ReadFile("/sys/class/power_supply/BAT0/status")
	if err != nil { panic(err) }
	status = string(bytes.Split(buf, []byte{NEWLINE})[0])

	pfull = now * 100 / full

	if rate > 0 {
		switch status {
		case STATUS_CHARGING:
			seconds = 3600 * (full - now) / rate
		case STATUS_DISCHARGING:
			seconds = 3600 * now / rate
		default:
			seconds = 0
		}
	} else {
		seconds = 0
	}
	hours = seconds / 3600
	seconds -= hours * 3600
	minutes = seconds / 60
	seconds -= minutes * 60
	if seconds == 0 {
		text = fmt.Sprintf("%s, %d%%\n", status, pfull)
	} else {
		text = fmt.Sprintf("%s, %d%%, %d:%d remaining\n",
		           status,
		           pfull,
		           hours,
		           minutes)
	}

	status_icon.SetTooltipText(text)
	status_icon.SetFromIconName(get_icon_name(status, pfull))
	return true
}

func get_icon_name(status string, pfull int64) string {
	if status == STATUS_DISCHARGING {
		switch {
		case pfull < 10:
			return "battery_empty"
		case pfull < 20:
			return "battery_caution"
		case pfull < 40:
			return "battery_low"
		case pfull < 60:
			return "battery_two_thirds"
		case pfull < 75:
			return "battery_third_fourth"
		default:
			return "battery_full"
		}
	} else if status == STATUS_CHARGING {
		return "battery_charged"
	}
	return "battery_plugged"
}<commit_msg>Fix tooltip output<commit_after>/*
 *  Copyright (c) 2012, Muhammed Uluyol <uluyol0@gmail.com>
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

package main

import (
	"fmt"
	"io/ioutil"
	"strconv"
	"bytes"
	"github.com/mattn/go-gtk/gtk"
	"github.com/mattn/go-gtk/glib"
	"os"
)

const (
	TIMEOUT = 3000
	NEWLINE = byte(10)
	STATUS_CHARGING = "Charging"
	STATUS_DISCHARGING = "Discharging"
)

var (
	status_icon *gtk.GtkStatusIcon
	full int64
)

func main() {
	gtk.Init(&os.Args)
	glib.SetApplicationName("zzcleanbattery")

	buf, err := ioutil.ReadFile("/sys/class/power_supply/BAT0/energy_full")
	if err != nil { panic(err) }
	str := string(bytes.Split(buf, []byte{NEWLINE})[0])
	full, err = strconv.ParseInt(str, 10, 64)
	if err != nil { panic(err) }

	status_icon = gtk.StatusIcon()
	status_icon.SetTitle("zzcleanbattery")

	update_icon()

	glib.TimeoutAdd(TIMEOUT, update_icon)
	gtk.Main()
}

func update_icon() bool {

	var (
		hours int64
		minutes int64
		seconds int64
		pfull int64
		rate int64
		now int64
		status string
		text string
	)

	buf, err := ioutil.ReadFile("/sys/class/power_supply/BAT0/energy_now")
	if err != nil { panic(err) }
	str := string(bytes.Split(buf, []byte{NEWLINE})[0])
	now, err = strconv.ParseInt(str, 10, 64)
	if err != nil { panic(err) }

	buf, err = ioutil.ReadFile("/sys/class/power_supply/BAT0/power_now")
	if err != nil { panic(err) }
	str = string(bytes.Split(buf, []byte{NEWLINE})[0])
	rate, err = strconv.ParseInt(str, 10, 64)
	if err != nil { panic(err) }

	buf, err = ioutil.ReadFile("/sys/class/power_supply/BAT0/status")
	if err != nil { panic(err) }
	status = string(bytes.Split(buf, []byte{NEWLINE})[0])

	pfull = now * 100 / full

	if rate > 0 {
		switch status {
		case STATUS_CHARGING:
			seconds = 3600 * (full - now) / rate
		case STATUS_DISCHARGING:
			seconds = 3600 * now / rate
		default:
			seconds = 0
		}
	} else {
		seconds = 0
	}
	hours = seconds / 3600
	seconds -= hours * 3600
	minutes = seconds / 60
	seconds -= minutes * 60
	if seconds == 0 {
		text = fmt.Sprintf("%s, %d%%", status, pfull)
	} else {
		text = fmt.Sprintf("%s, %d%%, %d:%02d remaining",
		           status,
		           pfull,
		           hours,
		           minutes)
	}

	status_icon.SetTooltipText(text)
	status_icon.SetFromIconName(get_icon_name(status, pfull))
	return true
}

func get_icon_name(status string, pfull int64) string {
	if status == STATUS_DISCHARGING {
		switch {
		case pfull < 10:
			return "battery_empty"
		case pfull < 20:
			return "battery_caution"
		case pfull < 40:
			return "battery_low"
		case pfull < 60:
			return "battery_two_thirds"
		case pfull < 75:
			return "battery_third_fourth"
		default:
			return "battery_full"
		}
	} else if status == STATUS_CHARGING {
		return "battery_charged"
	}
	return "battery_plugged"
}<|endoftext|>


<commit_before>/*
 * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc.
 *
 * 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 cmd

import (
	"io"
	"mime/multipart"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/minio/minio/pkg/errors"
	httptracer "github.com/minio/minio/pkg/handlers"
)

// Parses location constraint from the incoming reader.
func parseLocationConstraint(r *http.Request) (location string, s3Error APIErrorCode) {
	// If the request has no body with content-length set to 0,
	// we do not have to validate location constraint. Bucket will
	// be created at default region.
	locationConstraint := createBucketLocationConfiguration{}
	err := xmlDecoder(r.Body, &locationConstraint, r.ContentLength)
	if err != nil && err != io.EOF {
		errorIf(err, "Unable to xml decode location constraint")
		// Treat all other failures as XML parsing errors.
		return "", ErrMalformedXML
	} // else for both err as nil or io.EOF
	location = locationConstraint.Location
	if location == "" {
		location = globalServerConfig.GetRegion()
	}
	return location, ErrNone
}

// Validates input location is same as configured region
// of Minio server.
func isValidLocation(location string) bool {
	return globalServerConfig.GetRegion() == "" || globalServerConfig.GetRegion() == location
}

// Supported headers that needs to be extracted.
var supportedHeaders = []string{
	"content-type",
	"cache-control",
	"content-encoding",
	"content-disposition",
	amzStorageClass,
	// Add more supported headers here.
}

// isMetadataDirectiveValid - check if metadata-directive is valid.
func isMetadataDirectiveValid(h http.Header) bool {
	_, ok := h[http.CanonicalHeaderKey("X-Amz-Metadata-Directive")]
	if ok {
		// Check atleast set metadata-directive is valid.
		return (isMetadataCopy(h) || isMetadataReplace(h))
	}
	// By default if x-amz-metadata-directive is not we
	// treat it as 'COPY' this function returns true.
	return true
}

// Check if the metadata COPY is requested.
func isMetadataCopy(h http.Header) bool {
	return h.Get("X-Amz-Metadata-Directive") == "COPY"
}

// Check if the metadata REPLACE is requested.
func isMetadataReplace(h http.Header) bool {
	return h.Get("X-Amz-Metadata-Directive") == "REPLACE"
}

// Splits an incoming path into bucket and object components.
func path2BucketAndObject(path string) (bucket, object string) {
	// Skip the first element if it is '/', split the rest.
	path = strings.TrimPrefix(path, "/")
	pathComponents := strings.SplitN(path, "/", 2)

	// Save the bucket and object extracted from path.
	switch len(pathComponents) {
	case 1:
		bucket = pathComponents[0]
	case 2:
		bucket = pathComponents[0]
		object = pathComponents[1]
	}
	return bucket, object
}

// userMetadataKeyPrefixes contains the prefixes of used-defined metadata keys.
// All values stored with a key starting with one of the following prefixes
// must be extracted from the header.
var userMetadataKeyPrefixes = []string{
	"X-Amz-Meta-",
	"X-Minio-Meta-",
}

// extractMetadataFromHeader extracts metadata from HTTP header.
func extractMetadataFromHeader(header http.Header) (map[string]string, error) {
	if header == nil {
		return nil, errors.Trace(errInvalidArgument)
	}
	metadata := make(map[string]string)

	// Save all supported headers.
	for _, supportedHeader := range supportedHeaders {
		canonicalHeader := http.CanonicalHeaderKey(supportedHeader)
		// HTTP headers are case insensitive, look for both canonical
		// and non canonical entries.
		if _, ok := header[canonicalHeader]; ok {
			metadata[supportedHeader] = header.Get(canonicalHeader)
		} else if _, ok := header[supportedHeader]; ok {
			metadata[supportedHeader] = header.Get(supportedHeader)
		}
	}

	// Go through all other headers for any additional headers that needs to be saved.
	for key := range header {
		if key != http.CanonicalHeaderKey(key) {
			return nil, errors.Trace(errInvalidArgument)
		}
		for _, prefix := range userMetadataKeyPrefixes {
			if strings.HasPrefix(key, prefix) {
				metadata[key] = header.Get(key)
				break
			}
		}
	}
	return metadata, nil
}

// The Query string for the redirect URL the client is
// redirected on successful upload.
func getRedirectPostRawQuery(objInfo ObjectInfo) string {
	redirectValues := make(url.Values)
	redirectValues.Set("bucket", objInfo.Bucket)
	redirectValues.Set("key", objInfo.Name)
	redirectValues.Set("etag", "\""+objInfo.ETag+"\"")
	return redirectValues.Encode()
}

// Extract request params to be sent with event notifiation.
func extractReqParams(r *http.Request) map[string]string {
	if r == nil {
		return nil
	}

	// Success.
	return map[string]string{
		"sourceIPAddress": r.RemoteAddr,
		// Add more fields here.
	}
}

// Trims away `aws-chunked` from the content-encoding header if present.
// Streaming signature clients can have custom content-encoding such as
// `aws-chunked,gzip` here we need to only save `gzip`.
// For more refer http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
func trimAwsChunkedContentEncoding(contentEnc string) (trimmedContentEnc string) {
	if contentEnc == "" {
		return contentEnc
	}
	var newEncs []string
	for _, enc := range strings.Split(contentEnc, ",") {
		if enc != streamingContentEncoding {
			newEncs = append(newEncs, enc)
		}
	}
	return strings.Join(newEncs, ",")
}

// Validate form field size for s3 specification requirement.
func validateFormFieldSize(formValues http.Header) error {
	// Iterate over form values
	for k := range formValues {
		// Check if value's field exceeds S3 limit
		if int64(len(formValues.Get(k))) > maxFormFieldSize {
			return errors.Trace(errSizeUnexpected)
		}
	}

	// Success.
	return nil
}

// Extract form fields and file data from a HTTP POST Policy
func extractPostPolicyFormValues(form *multipart.Form) (filePart io.ReadCloser, fileName string, fileSize int64, formValues http.Header, err error) {
	/// HTML Form values
	fileName = ""

	// Canonicalize the form values into http.Header.
	formValues = make(http.Header)
	for k, v := range form.Value {
		formValues[http.CanonicalHeaderKey(k)] = v
	}

	// Validate form values.
	if err = validateFormFieldSize(formValues); err != nil {
		return nil, "", 0, nil, err
	}

	// Iterator until we find a valid File field and break
	for k, v := range form.File {
		canonicalFormName := http.CanonicalHeaderKey(k)
		if canonicalFormName == "File" {
			if len(v) == 0 {
				return nil, "", 0, nil, errors.Trace(errInvalidArgument)
			}
			// Fetch fileHeader which has the uploaded file information
			fileHeader := v[0]
			// Set filename
			fileName = fileHeader.Filename
			// Open the uploaded part
			filePart, err = fileHeader.Open()
			if err != nil {
				return nil, "", 0, nil, errors.Trace(err)
			}
			// Compute file size
			fileSize, err = filePart.(io.Seeker).Seek(0, 2)
			if err != nil {
				return nil, "", 0, nil, errors.Trace(err)
			}
			// Reset Seek to the beginning
			_, err = filePart.(io.Seeker).Seek(0, 0)
			if err != nil {
				return nil, "", 0, nil, errors.Trace(err)
			}
			// File found and ready for reading
			break
		}
	}

	return filePart, fileName, fileSize, formValues, nil
}

// Log headers and body.
func httpTraceAll(f http.HandlerFunc) http.HandlerFunc {
	if globalHTTPTraceFile == nil {
		return f
	}
	return httptracer.TraceReqHandlerFunc(f, globalHTTPTraceFile, true)
}

// Log only the headers.
func httpTraceHdrs(f http.HandlerFunc) http.HandlerFunc {
	if globalHTTPTraceFile == nil {
		return f
	}
	return httptracer.TraceReqHandlerFunc(f, globalHTTPTraceFile, false)
}

// Returns "/bucketName/objectName" for path-style or virtual-host-style requests.
func getResource(path string, host string, domain string) (string, error) {
	if domain == "" {
		return path, nil
	}
	// If virtual-host-style is enabled construct the "resource" properly.
	if strings.Contains(host, ":") {
		// In bucket.mydomain.com:9000, strip out :9000
		var err error
		if host, _, err = net.SplitHostPort(host); err != nil {
			errorIf(err, "Unable to split %s", host)
			return "", err
		}
	}
	if !strings.HasSuffix(host, "."+domain) {
		return path, nil
	}
	bucket := strings.TrimSuffix(host, "."+domain)
	return slashSeparator + pathJoin(bucket, path), nil
}

// If none of the http routes match respond with MethodNotAllowed
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
	writeErrorResponse(w, ErrMethodNotAllowed, r.URL)
	return
}
<commit_msg>Support content-language header (#5648)<commit_after>/*
 * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc.
 *
 * 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 cmd

import (
	"io"
	"mime/multipart"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/minio/minio/pkg/errors"
	httptracer "github.com/minio/minio/pkg/handlers"
)

// Parses location constraint from the incoming reader.
func parseLocationConstraint(r *http.Request) (location string, s3Error APIErrorCode) {
	// If the request has no body with content-length set to 0,
	// we do not have to validate location constraint. Bucket will
	// be created at default region.
	locationConstraint := createBucketLocationConfiguration{}
	err := xmlDecoder(r.Body, &locationConstraint, r.ContentLength)
	if err != nil && err != io.EOF {
		errorIf(err, "Unable to xml decode location constraint")
		// Treat all other failures as XML parsing errors.
		return "", ErrMalformedXML
	} // else for both err as nil or io.EOF
	location = locationConstraint.Location
	if location == "" {
		location = globalServerConfig.GetRegion()
	}
	return location, ErrNone
}

// Validates input location is same as configured region
// of Minio server.
func isValidLocation(location string) bool {
	return globalServerConfig.GetRegion() == "" || globalServerConfig.GetRegion() == location
}

// Supported headers that needs to be extracted.
var supportedHeaders = []string{
	"content-type",
	"cache-control",
	"content-language",
	"content-encoding",
	"content-disposition",
	amzStorageClass,
	// Add more supported headers here.
}

// isMetadataDirectiveValid - check if metadata-directive is valid.
func isMetadataDirectiveValid(h http.Header) bool {
	_, ok := h[http.CanonicalHeaderKey("X-Amz-Metadata-Directive")]
	if ok {
		// Check atleast set metadata-directive is valid.
		return (isMetadataCopy(h) || isMetadataReplace(h))
	}
	// By default if x-amz-metadata-directive is not we
	// treat it as 'COPY' this function returns true.
	return true
}

// Check if the metadata COPY is requested.
func isMetadataCopy(h http.Header) bool {
	return h.Get("X-Amz-Metadata-Directive") == "COPY"
}

// Check if the metadata REPLACE is requested.
func isMetadataReplace(h http.Header) bool {
	return h.Get("X-Amz-Metadata-Directive") == "REPLACE"
}

// Splits an incoming path into bucket and object components.
func path2BucketAndObject(path string) (bucket, object string) {
	// Skip the first element if it is '/', split the rest.
	path = strings.TrimPrefix(path, "/")
	pathComponents := strings.SplitN(path, "/", 2)

	// Save the bucket and object extracted from path.
	switch len(pathComponents) {
	case 1:
		bucket = pathComponents[0]
	case 2:
		bucket = pathComponents[0]
		object = pathComponents[1]
	}
	return bucket, object
}

// userMetadataKeyPrefixes contains the prefixes of used-defined metadata keys.
// All values stored with a key starting with one of the following prefixes
// must be extracted from the header.
var userMetadataKeyPrefixes = []string{
	"X-Amz-Meta-",
	"X-Minio-Meta-",
}

// extractMetadataFromHeader extracts metadata from HTTP header.
func extractMetadataFromHeader(header http.Header) (map[string]string, error) {
	if header == nil {
		return nil, errors.Trace(errInvalidArgument)
	}
	metadata := make(map[string]string)

	// Save all supported headers.
	for _, supportedHeader := range supportedHeaders {
		canonicalHeader := http.CanonicalHeaderKey(supportedHeader)
		// HTTP headers are case insensitive, look for both canonical
		// and non canonical entries.
		if _, ok := header[canonicalHeader]; ok {
			metadata[supportedHeader] = header.Get(canonicalHeader)
		} else if _, ok := header[supportedHeader]; ok {
			metadata[supportedHeader] = header.Get(supportedHeader)
		}
	}

	// Go through all other headers for any additional headers that needs to be saved.
	for key := range header {
		if key != http.CanonicalHeaderKey(key) {
			return nil, errors.Trace(errInvalidArgument)
		}
		for _, prefix := range userMetadataKeyPrefixes {
			if strings.HasPrefix(key, prefix) {
				metadata[key] = header.Get(key)
				break
			}
		}
	}
	return metadata, nil
}

// The Query string for the redirect URL the client is
// redirected on successful upload.
func getRedirectPostRawQuery(objInfo ObjectInfo) string {
	redirectValues := make(url.Values)
	redirectValues.Set("bucket", objInfo.Bucket)
	redirectValues.Set("key", objInfo.Name)
	redirectValues.Set("etag", "\""+objInfo.ETag+"\"")
	return redirectValues.Encode()
}

// Extract request params to be sent with event notifiation.
func extractReqParams(r *http.Request) map[string]string {
	if r == nil {
		return nil
	}

	// Success.
	return map[string]string{
		"sourceIPAddress": r.RemoteAddr,
		// Add more fields here.
	}
}

// Trims away `aws-chunked` from the content-encoding header if present.
// Streaming signature clients can have custom content-encoding such as
// `aws-chunked,gzip` here we need to only save `gzip`.
// For more refer http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
func trimAwsChunkedContentEncoding(contentEnc string) (trimmedContentEnc string) {
	if contentEnc == "" {
		return contentEnc
	}
	var newEncs []string
	for _, enc := range strings.Split(contentEnc, ",") {
		if enc != streamingContentEncoding {
			newEncs = append(newEncs, enc)
		}
	}
	return strings.Join(newEncs, ",")
}

// Validate form field size for s3 specification requirement.
func validateFormFieldSize(formValues http.Header) error {
	// Iterate over form values
	for k := range formValues {
		// Check if value's field exceeds S3 limit
		if int64(len(formValues.Get(k))) > maxFormFieldSize {
			return errors.Trace(errSizeUnexpected)
		}
	}

	// Success.
	return nil
}

// Extract form fields and file data from a HTTP POST Policy
func extractPostPolicyFormValues(form *multipart.Form) (filePart io.ReadCloser, fileName string, fileSize int64, formValues http.Header, err error) {
	/// HTML Form values
	fileName = ""

	// Canonicalize the form values into http.Header.
	formValues = make(http.Header)
	for k, v := range form.Value {
		formValues[http.CanonicalHeaderKey(k)] = v
	}

	// Validate form values.
	if err = validateFormFieldSize(formValues); err != nil {
		return nil, "", 0, nil, err
	}

	// Iterator until we find a valid File field and break
	for k, v := range form.File {
		canonicalFormName := http.CanonicalHeaderKey(k)
		if canonicalFormName == "File" {
			if len(v) == 0 {
				return nil, "", 0, nil, errors.Trace(errInvalidArgument)
			}
			// Fetch fileHeader which has the uploaded file information
			fileHeader := v[0]
			// Set filename
			fileName = fileHeader.Filename
			// Open the uploaded part
			filePart, err = fileHeader.Open()
			if err != nil {
				return nil, "", 0, nil, errors.Trace(err)
			}
			// Compute file size
			fileSize, err = filePart.(io.Seeker).Seek(0, 2)
			if err != nil {
				return nil, "", 0, nil, errors.Trace(err)
			}
			// Reset Seek to the beginning
			_, err = filePart.(io.Seeker).Seek(0, 0)
			if err != nil {
				return nil, "", 0, nil, errors.Trace(err)
			}
			// File found and ready for reading
			break
		}
	}

	return filePart, fileName, fileSize, formValues, nil
}

// Log headers and body.
func httpTraceAll(f http.HandlerFunc) http.HandlerFunc {
	if globalHTTPTraceFile == nil {
		return f
	}
	return httptracer.TraceReqHandlerFunc(f, globalHTTPTraceFile, true)
}

// Log only the headers.
func httpTraceHdrs(f http.HandlerFunc) http.HandlerFunc {
	if globalHTTPTraceFile == nil {
		return f
	}
	return httptracer.TraceReqHandlerFunc(f, globalHTTPTraceFile, false)
}

// Returns "/bucketName/objectName" for path-style or virtual-host-style requests.
func getResource(path string, host string, domain string) (string, error) {
	if domain == "" {
		return path, nil
	}
	// If virtual-host-style is enabled construct the "resource" properly.
	if strings.Contains(host, ":") {
		// In bucket.mydomain.com:9000, strip out :9000
		var err error
		if host, _, err = net.SplitHostPort(host); err != nil {
			errorIf(err, "Unable to split %s", host)
			return "", err
		}
	}
	if !strings.HasSuffix(host, "."+domain) {
		return path, nil
	}
	bucket := strings.TrimSuffix(host, "."+domain)
	return slashSeparator + pathJoin(bucket, path), nil
}

// If none of the http routes match respond with MethodNotAllowed
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
	writeErrorResponse(w, ErrMethodNotAllowed, r.URL)
	return
}
<|endoftext|>


<commit_before>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strings"
	"unicode/utf8"
)

const STATUS_DEFAULT = "Type arrows to move, a number to input a number, 'm' to enter mark mode, or ESC to quit"
const STATUS_MARKING = "MARKING:"
const STATUS_MARKING_POSTFIX = "   ENTER to commit, ESC to cancel"

func main() {
	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	model := newModel()

	draw(model)

mainloop:
	for {
		evt := termbox.PollEvent()
		switch evt.Type {
		case termbox.EventKey:
			if model.state.handleInput(model, evt) {
				break mainloop
			}
		}
		draw(model)
	}
}

func clearScreen() {
	width, height := termbox.Size()
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
		}
	}
}

func draw(model *mainModel) {

	//TODO: have a mode line after the grid for if the grid is invalid, if it's solved.

	clearScreen()

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected().DiagramExtents()

	x := 0
	y := 0

	for _, line := range strings.Split(grid.Diagram(true), "\n") {
		x = 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = termbox.ColorBlue
			} else if ch == lockedRune {
				defaultColor = termbox.ColorRed
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = termbox.ColorWhite
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
		y++
	}

	x = 0
	for _, ch := range model.StatusLine() {
		termbox.SetCell(x, y, ch, termbox.ColorWhite, termbox.ColorDefault)
		x++
	}

	termbox.Flush()
}
<commit_msg>Have a mode line printing out whether the puzzle is solved, and whether it's invalid.<commit_after>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strings"
	"unicode/utf8"
)

const STATUS_DEFAULT = "Type arrows to move, a number to input a number, 'm' to enter mark mode, or ESC to quit"
const STATUS_MARKING = "MARKING:"
const STATUS_MARKING_POSTFIX = "   ENTER to commit, ESC to cancel"

const GRID_INVALID = " INVALID "
const GRID_VALID = "  VALID  "
const GRID_SOLVED = "  SOLVED  "
const GRID_NOT_SOLVED = " UNSOLVED "

func main() {
	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	model := newModel()

	draw(model)

mainloop:
	for {
		evt := termbox.PollEvent()
		switch evt.Type {
		case termbox.EventKey:
			if model.state.handleInput(model, evt) {
				break mainloop
			}
		}
		draw(model)
	}
}

func clearScreen() {
	width, height := termbox.Size()
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
		}
	}
}

func draw(model *mainModel) {

	clearScreen()

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected().DiagramExtents()

	x := 0
	y := 0

	for _, line := range strings.Split(grid.Diagram(true), "\n") {
		x = 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = termbox.ColorBlue
			} else if ch == lockedRune {
				defaultColor = termbox.ColorRed
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = termbox.ColorWhite
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
		y++
	}

	x = 0
	solvedMsg := GRID_NOT_SOLVED
	fg := termbox.ColorBlue
	bg := termbox.ColorBlack
	if grid.Solved() {
		solvedMsg = GRID_SOLVED
		fg, bg = bg, fg
	}

	for _, ch := range solvedMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	//don't reset x; this next message should go to the right.
	validMsg := GRID_VALID
	fg = termbox.ColorBlue
	bg = termbox.ColorBlack
	if grid.Invalid() {
		validMsg = GRID_INVALID
		fg, bg = bg, fg
	}
	for _, ch := range validMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	y++

	x = 0
	for _, ch := range model.StatusLine() {
		termbox.SetCell(x, y, ch, termbox.ColorWhite, termbox.ColorDefault)
		x++
	}

	termbox.Flush()
}
<|endoftext|>


<commit_before>// Copyright 2013, 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"io"

	"github.com/juju/loggo"
	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/cmd/envcmd"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/api"
)

type DebugLogCommand struct {
	envcmd.EnvCommandBase

	level  string
	params api.DebugLogParams
}

var DefaultLogLocation = "/var/log/juju/all-machines.log"

// defaultLineCount is the default number of lines to
// display, from the end of the consolidated log.
const defaultLineCount = 10

const debuglogDoc = `
Stream the consolidated debug log file. This file contains the log messages
from all nodes in the environment.
`

func (c *DebugLogCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "debug-log",
		Purpose: "display the consolidated log file",
		Doc:     debuglogDoc,
	}
}

func (c *DebugLogCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)

	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "i", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "include", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "x", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "exclude", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeModule), "include-module", "only show log messages for these logging modules")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeModule), "exclude-module", "do not show log messages for these logging modules")

	f.StringVar(&c.level, "l", "DEBUG", "log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]")
	f.StringVar(&c.level, "level", "DEBUG", "")

	f.UintVar(&c.params.Backlog, "n", defaultLineCount, "go back this many lines from the end before starting to filter")
	f.UintVar(&c.params.Backlog, "lines", defaultLineCount, "")
	f.UintVar(&c.params.Limit, "limit", 0, "show at most this many lines")
	f.BoolVar(&c.params.Replay, "replay", false, "start filtering from the start")
}

func (c *DebugLogCommand) Init(args []string) error {
	err := c.EnvCommandBase.Init()
	if err != nil {
		return err
	}

	level, ok := loggo.ParseLevel(c.level)
	if !ok || level < loggo.TRACE || level > loggo.ERROR {
		return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q",
			c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR)
	}
	c.params.Level = level

	return cmd.CheckEmpty(args)
}

// Run retrieves the debug log via the API.
func (c *DebugLogCommand) Run(ctx *cmd.Context) (err error) {
	client, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()
	debugLog, err := client.WatchDebugLog(c.params)
	if err != nil {
		if api.IsNotSupportedError(err) {
			return c.watchDebugLog1dot16(ctx)
		}
		return err
	}
	defer debugLog.Close()
	_, err = io.Copy(ctx.Stdout, debugLog)
	return err
}

// watchDebugLog1dot16 runs in case of an older API server and uses ssh
// but with server-side grep.
func (c *DebugLogCommand) watchDebugLog1dot16(ctx *cmd.Context) error {
	ctx.Infof("Server does not support new stream log, falling back to tail")
	ctx.Verbosef("filters are not supported with tail")
	sshCmd := &SSHCommand{}
	tailCmd := fmt.Sprintf("tail -n -%d -f %s", c.params.Backlog, DefaultLogLocation)
	// If the api doesn't support WatchDebugLog, then it won't be running in
	// HA either, so machine 0 is where it is all at.
	args := []string{"0", tailGrepCmd}
	err := sshCmd.Init(args)
	if err != nil {
		return err
	}
	sshCmd.EnvName = c.EnvName
	return sshCmd.Run(ctx)
}
<commit_msg>Check the not supported error.<commit_after>// Copyright 2013, 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"io"

	"github.com/juju/loggo"
	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/cmd/envcmd"
	"launchpad.net/juju-core/errors"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/api"
)

type DebugLogCommand struct {
	envcmd.EnvCommandBase

	level  string
	params api.DebugLogParams
}

var DefaultLogLocation = "/var/log/juju/all-machines.log"

// defaultLineCount is the default number of lines to
// display, from the end of the consolidated log.
const defaultLineCount = 10

const debuglogDoc = `
Stream the consolidated debug log file. This file contains the log messages
from all nodes in the environment.
`

func (c *DebugLogCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "debug-log",
		Purpose: "display the consolidated log file",
		Doc:     debuglogDoc,
	}
}

func (c *DebugLogCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)

	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "i", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeEntity), "include", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "x", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeEntity), "exclude", "only show log messages for these entities")
	f.Var(cmd.NewAppendStringsValue(&c.params.IncludeModule), "include-module", "only show log messages for these logging modules")
	f.Var(cmd.NewAppendStringsValue(&c.params.ExcludeModule), "exclude-module", "do not show log messages for these logging modules")

	f.StringVar(&c.level, "l", "DEBUG", "log level to show, one of [TRACE, DEBUG, INFO, WARNING, ERROR]")
	f.StringVar(&c.level, "level", "DEBUG", "")

	f.UintVar(&c.params.Backlog, "n", defaultLineCount, "go back this many lines from the end before starting to filter")
	f.UintVar(&c.params.Backlog, "lines", defaultLineCount, "")
	f.UintVar(&c.params.Limit, "limit", 0, "show at most this many lines")
	f.BoolVar(&c.params.Replay, "replay", false, "start filtering from the start")
}

func (c *DebugLogCommand) Init(args []string) error {
	err := c.EnvCommandBase.Init()
	if err != nil {
		return err
	}

	level, ok := loggo.ParseLevel(c.level)
	if !ok || level < loggo.TRACE || level > loggo.ERROR {
		return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q",
			c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR)
	}
	c.params.Level = level

	return cmd.CheckEmpty(args)
}

// Run retrieves the debug log via the API.
func (c *DebugLogCommand) Run(ctx *cmd.Context) (err error) {
	client, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()
	debugLog, err := client.WatchDebugLog(c.params)
	if err != nil {
		if errors.IsNotSupportedError(err) {
			return c.watchDebugLog1dot16(ctx)
		}
		return err
	}
	defer debugLog.Close()
	_, err = io.Copy(ctx.Stdout, debugLog)
	return err
}

// watchDebugLog1dot16 runs in case of an older API server and uses ssh
// but with server-side grep.
func (c *DebugLogCommand) watchDebugLog1dot16(ctx *cmd.Context) error {
	ctx.Infof("Server does not support new stream log, falling back to tail")
	ctx.Verbosef("filters are not supported with tail")
	sshCmd := &SSHCommand{}
	tailCmd := fmt.Sprintf("tail -n -%d -f %s", c.params.Backlog, DefaultLogLocation)
	// If the api doesn't support WatchDebugLog, then it won't be running in
	// HA either, so machine 0 is where it is all at.
	args := []string{"0", tailCmd}
	err := sshCmd.Init(args)
	if err != nil {
		return err
	}
	sshCmd.EnvName = c.EnvName
	return sshCmd.Run(ctx)
}
<|endoftext|>


<commit_before>package slack

import (
	"fmt"
	"log"

	slack_webhook "github.com/ashwanthkumar/slack-go-webhook"
	"github.com/checkr/codeflow/server/agent"
	"github.com/checkr/codeflow/server/plugins"
	"github.com/spf13/viper"
)

type Slack struct {
}

func init() {
	agent.RegisterPlugin("slack", func() agent.Plugin {
		return &Slack{}
	})
}

func (x *Slack) Description() string {
	return "Send slack events to subscribed plugins"
}

func (x *Slack) SampleConfig() string {
	return ` `
}

func (x *Slack) slack() error {
	return nil
}

func (x *Slack) Start(e chan agent.Event) error {
	go x.slack()
	log.Println("Started Slack")

	return nil
}

func (x *Slack) Stop() {
	log.Println("Stopping Slack")
}

func (x *Slack) Subscribe() []string {
	return []string{
		"plugins.DockerBuild",
		"plugins.DockerDeploy",
		"plugins.Project",
		"plugins.Release",
	}
}

func (x *Slack) Process(e agent.Event) error {
	switch e.Name {
	case "plugins.DockerDeploy:create":
		webhookUrl := viper.GetString("plugins.slack.webhook_url")
		payload := e.Payload.(plugins.DockerDeploy)

		for _, channel := range payload.Project.NotifyChannels {
			project := payload.Project.Slug
			release := payload.Release.HeadFeature.Hash
			message := payload.Release.HeadFeature.Message

			repository := payload.Project.Repository
			tail := payload.Release.TailFeature.Hash
			head := payload.Release.HeadFeature.Hash

			diffUrl := fmt.Sprintf("https://github.com/%s/compare/%s...%s", repository, tail, head)

			attachment1 := slack_webhook.Attachment {}
			attachment1.AddField(slack_webhook.Field { Title: "Commit", Value: message }).AddField(slack_webhook.Field { Title: "Link", Value: diffUrl })

			slackPayload := slack_webhook.Payload{
				Text: fmt.Sprintf("Deployed %s for %s", release, project),
				Username:  "codeflow-bot",
				Channel:   channel,
				IconEmoji: ":rocket:",
				Attachments: []slack_webhook.Attachment{attachment1},
			}
			err := slack_webhook.Send(webhookUrl, "", slackPayload)
			if len(err) > 0 {
				log.Println("error: %s\n", err)
			}
		}

	default:
	}

	return nil
}
<commit_msg>Handle status for slack<commit_after>package slack

import (
	"fmt"
	"log"

	slack_webhook "github.com/ashwanthkumar/slack-go-webhook"
	"github.com/checkr/codeflow/server/agent"
	"github.com/checkr/codeflow/server/plugins"
	"github.com/spf13/viper"
)

type Slack struct {
}

func init() {
	agent.RegisterPlugin("slack", func() agent.Plugin {
		return &Slack{}
	})
}

func (x *Slack) Description() string {
	return "Send slack events to subscribed plugins"
}

func (x *Slack) SampleConfig() string {
	return ` `
}

func (x *Slack) slack() error {
	return nil
}

func (x *Slack) Start(e chan agent.Event) error {
	go x.slack()
	log.Println("Started Slack")

	return nil
}

func (x *Slack) Stop() {
	log.Println("Stopping Slack")
}

func (x *Slack) Subscribe() []string {
	return []string{
		"plugins.DockerBuild",
		"plugins.DockerDeploy",
		"plugins.Project",
		"plugins.Release",
	}
}

func (x *Slack) Process(e agent.Event) error {
	webhookUrl := viper.GetString("plugins.slack.webhook_url")

	switch e.Name {
	case "plugins.DockerDeploy:create":
		payload := e.Payload.(plugins.DockerDeploy)

		for _, channel := range payload.Project.NotifyChannels {
			project := payload.Project.Slug
			release := payload.Release.HeadFeature.Hash
			message := payload.Release.HeadFeature.Message

			repository := payload.Project.Repository
			tail := payload.Release.TailFeature.Hash
			head := payload.Release.HeadFeature.Hash

			diffUrl := fmt.Sprintf("https://github.com/%s/compare/%s...%s", repository, tail, head)

			attachment1 := slack_webhook.Attachment{}
			attachment1.AddField(slack_webhook.Field{Title: "Commit", Value: message}).AddField(slack_webhook.Field{Title: "Link", Value: diffUrl})

			slackPayload := slack_webhook.Payload{
				Text:        fmt.Sprintf("Deploying %s for %s", release, project),
				Username:    "codeflow-bot",
				Channel:     channel,
				IconEmoji:   ":rocket:",
				Attachments: []slack_webhook.Attachment{attachment1},
			}
			err := slack_webhook.Send(webhookUrl, "", slackPayload)
			if len(err) > 0 {
				log.Println("error: %s\n", err)
			}
		}
	case "plugins.DockerDeploy:status":
		payload := e.Payload.(plugins.DockerDeploy)

		for _, channel := range payload.Project.NotifyChannels {
			project := payload.Project.Slug
			release := payload.Release.HeadFeature.Hash

			msg := fmt.Sprintf("Deploy %s for %s", release, project)
			color := "#00FF00"

			if payload.State == "failed" {
				color = "#FF0000"
				msg = fmt.Sprintf("Deploy %s for %s", release, project)
			}

			attachment1 := slack_webhook.Attachment{Color: &color}
			attachment1.AddField(slack_webhook.Field{Title: "Status", Value: string(payload.State)})

			slackPayload := slack_webhook.Payload{
				Text:        msg,
				Username:    "codeflow-bot",
				Channel:     channel,
				IconEmoji:   ":rocket:",
				Attachments: []slack_webhook.Attachment{attachment1},
			}
			err := slack_webhook.Send(webhookUrl, "", slackPayload)
			if len(err) > 0 {
				log.Println("error: %s\n", err)
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd-operator Authors
//
// 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 main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/coreos/etcd-operator/pkg/analytics"
	"github.com/coreos/etcd-operator/pkg/backup/s3/s3config"
	"github.com/coreos/etcd-operator/pkg/chaos"
	"github.com/coreos/etcd-operator/pkg/controller"
	"github.com/coreos/etcd-operator/pkg/garbagecollection"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil/election"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil/election/resourcelock"
	"github.com/coreos/etcd-operator/version"

	"github.com/Sirupsen/logrus"
	"golang.org/x/time/rate"
	"k8s.io/client-go/1.5/kubernetes"
	"k8s.io/client-go/1.5/pkg/api"
	"k8s.io/client-go/1.5/pkg/labels"
	"k8s.io/client-go/1.5/rest"
	"k8s.io/client-go/1.5/tools/record"
)

var (
	analyticsEnabled bool
	pvProvisioner    string
	masterHost       string
	tlsInsecure      bool
	certFile         string
	keyFile          string
	caFile           string
	namespace        string
	awsSecret        string
	awsConfig        string
	s3Bucket         string
	gcInterval       time.Duration

	chaosLevel int

	printVersion bool
)

var (
	leaseDuration = 15 * time.Second
	renewDuration = 5 * time.Second
	retryPeriod   = 3 * time.Second
)

func init() {
	flag.BoolVar(&analyticsEnabled, "analytics", true, "Send analytical event (Cluster Created/Deleted etc.) to Google Analytics")

	flag.StringVar(&pvProvisioner, "pv-provisioner", "kubernetes.io/gce-pd", "persistent volume provisioner type")
	flag.StringVar(&masterHost, "master", "", "API Server addr, e.g. ' - NOT RECOMMENDED FOR PRODUCTION - http://127.0.0.1:8080'. Omit parameter to run in on-cluster mode and utilize the service account token.")
	flag.StringVar(&certFile, "cert-file", "", " - NOT RECOMMENDED FOR PRODUCTION - Path to public TLS certificate file.")
	flag.StringVar(&keyFile, "key-file", "", "- NOT RECOMMENDED FOR PRODUCTION - Path to private TLS certificate file.")
	flag.StringVar(&caFile, "ca-file", "", "- NOT RECOMMENDED FOR PRODUCTION - Path to TLS CA file.")
	flag.BoolVar(&tlsInsecure, "tls-insecure", false, "- NOT RECOMMENDED FOR PRODUCTION - Don't verify API server's CA certificate.")
	flag.StringVar(&awsSecret, "backup-aws-secret", "", "The name of the kube secret object that stores the aws credential file.")
	flag.StringVar(&awsConfig, "backup-aws-config", "", "The name of the kube configmap object that presents the aws config file.")
	flag.StringVar(&s3Bucket, "backup-s3-bucket", "", "The name of the aws S3 bucket to store backups.")
	// chaos level will be removed once we have a formal tool to inject failures.
	flag.IntVar(&chaosLevel, "chaos-level", -1, "DO NOT USE IN PRODUCTION - level of chaos injected into the etcd clusters created by the operator.")
	flag.BoolVar(&printVersion, "version", false, "Show version and quit")
	flag.DurationVar(&gcInterval, "gc-interval", 10*time.Minute, "GC interval")
	flag.Parse()

	namespace = os.Getenv("MY_POD_NAMESPACE")
	if len(namespace) == 0 {
		namespace = "default"
	}
}

func main() {
	if printVersion {
		fmt.Println("etcd-operator Version:", version.Version)
		fmt.Println("Git SHA:", version.GitSHA)
		fmt.Println("Go Version:", runtime.Version())
		fmt.Printf("Go OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
		os.Exit(0)
	}

	logrus.Infof("etcd-operator Version: %v", version.Version)
	logrus.Infof("Git SHA: %s", version.GitSHA)
	logrus.Infof("Go Version: %s", runtime.Version())
	logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)

	if analyticsEnabled {
		analytics.Enable()
	}

	analytics.OperatorStarted()

	id, err := os.Hostname()
	if err != nil {
		logrus.Fatalf("failed to get hostname: %v", err)
	}

	// TODO: replace this to client-go once leader election pacakge is imported
	//       https://github.com/kubernetes/client-go/issues/28
	rl := &resourcelock.EndpointsLock{
		EndpointsMeta: api.ObjectMeta{
			Namespace: namespace,
			Name:      "etcd-operator",
		},
		Client: k8sutil.MustCreateClient(masterHost, tlsInsecure, &rest.TLSClientConfig{
			CertFile: certFile,
			KeyFile:  keyFile,
			CAFile:   caFile,
		}),
		LockConfig: resourcelock.ResourceLockConfig{
			Identity:      id,
			EventRecorder: &record.FakeRecorder{},
		},
	}

	election.RunOrDie(election.LeaderElectionConfig{
		Lock:          rl,
		LeaseDuration: leaseDuration,
		RenewDeadline: renewDuration,
		RetryPeriod:   retryPeriod,
		Callbacks: election.LeaderCallbacks{
			OnStartedLeading: run,
			OnStoppedLeading: func() {
				logrus.Fatalf("leader election lost")
			},
		},
	})
	panic("unreachable")
}

func run(stop <-chan struct{}) {
	cfg := newControllerConfig()
	if err := cfg.Validate(); err != nil {
		logrus.Fatalf("invalid operator config: %v", err)
	}

	go periodicFullGC(cfg.KubeCli, cfg.Namespace, gcInterval)

	startChaos(context.Background(), cfg.KubeCli, cfg.Namespace, chaosLevel)

	for {
		c := controller.New(cfg)
		err := c.Run()
		switch err {
		case controller.ErrVersionOutdated:
		default:
			logrus.Fatalf("controller Run() ended with failure: %v", err)
		}
	}
}

func newControllerConfig() controller.Config {
	tlsConfig := rest.TLSClientConfig{
		CertFile: certFile,
		KeyFile:  keyFile,
		CAFile:   caFile,
	}
	kubecli := k8sutil.MustCreateClient(masterHost, tlsInsecure, &tlsConfig)
	cfg := controller.Config{
		MasterHost:    masterHost,
		Namespace:     namespace,
		PVProvisioner: pvProvisioner,
		S3Context: s3config.S3Context{
			AWSSecret: awsSecret,
			AWSConfig: awsConfig,
			S3Bucket:  s3Bucket,
		},
		KubeCli: kubecli,
	}
	if len(cfg.MasterHost) == 0 {
		logrus.Info("use in cluster client from k8s library")
		cfg.MasterHost = k8sutil.MustGetInClusterMasterHost()
	}
	return cfg
}

func periodicFullGC(k8s kubernetes.Interface, ns string, d time.Duration) {
	gc := garbagecollection.New(k8s, ns)
	timer := time.NewTimer(d)
	defer timer.Stop()
	for {
		<-timer.C
		err := gc.FullyCollect()
		if err != nil {
			logrus.Warningf("failed to cleanup resources: %v", err)
		}
	}
}

func startChaos(ctx context.Context, k8s kubernetes.Interface, ns string, chaosLevel int) {
	m := chaos.NewMonkeys(k8s)
	ls := labels.SelectorFromSet(map[string]string{"app": "etcd"})

	switch chaosLevel {
	case 1:
		logrus.Info("chaos level = 1: randomly kill one etcd pod every 30 seconds at 50%")
		c := &chaos.CrashConfig{
			Namespace: ns,
			Selector:  ls,

			KillRate:        rate.Every(30 * time.Second),
			KillProbability: 0.5,
			KillMax:         1,
		}

		go m.CrushPods(ctx, c)

	case 2:
		logrus.Info("chaos level = 2: randomly kill at most five etcd pods every 30 seconds at 50%")
		c := &chaos.CrashConfig{
			Namespace: ns,
			Selector:  ls,

			KillRate:        rate.Every(30 * time.Second),
			KillProbability: 0.5,
			KillMax:         5,
		}

		go m.CrushPods(ctx, c)

	default:
	}
}
<commit_msg>operator: catch and print sigterm<commit_after>// Copyright 2016 The etcd-operator Authors
//
// 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 main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"time"

	"github.com/coreos/etcd-operator/pkg/analytics"
	"github.com/coreos/etcd-operator/pkg/backup/s3/s3config"
	"github.com/coreos/etcd-operator/pkg/chaos"
	"github.com/coreos/etcd-operator/pkg/controller"
	"github.com/coreos/etcd-operator/pkg/garbagecollection"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil/election"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil/election/resourcelock"
	"github.com/coreos/etcd-operator/version"

	"github.com/Sirupsen/logrus"
	"golang.org/x/time/rate"
	"k8s.io/client-go/1.5/kubernetes"
	"k8s.io/client-go/1.5/pkg/api"
	"k8s.io/client-go/1.5/pkg/labels"
	"k8s.io/client-go/1.5/rest"
	"k8s.io/client-go/1.5/tools/record"
)

var (
	analyticsEnabled bool
	pvProvisioner    string
	masterHost       string
	tlsInsecure      bool
	certFile         string
	keyFile          string
	caFile           string
	namespace        string
	awsSecret        string
	awsConfig        string
	s3Bucket         string
	gcInterval       time.Duration

	chaosLevel int

	printVersion bool
)

var (
	leaseDuration = 15 * time.Second
	renewDuration = 5 * time.Second
	retryPeriod   = 3 * time.Second
)

func init() {
	flag.BoolVar(&analyticsEnabled, "analytics", true, "Send analytical event (Cluster Created/Deleted etc.) to Google Analytics")

	flag.StringVar(&pvProvisioner, "pv-provisioner", "kubernetes.io/gce-pd", "persistent volume provisioner type")
	flag.StringVar(&masterHost, "master", "", "API Server addr, e.g. ' - NOT RECOMMENDED FOR PRODUCTION - http://127.0.0.1:8080'. Omit parameter to run in on-cluster mode and utilize the service account token.")
	flag.StringVar(&certFile, "cert-file", "", " - NOT RECOMMENDED FOR PRODUCTION - Path to public TLS certificate file.")
	flag.StringVar(&keyFile, "key-file", "", "- NOT RECOMMENDED FOR PRODUCTION - Path to private TLS certificate file.")
	flag.StringVar(&caFile, "ca-file", "", "- NOT RECOMMENDED FOR PRODUCTION - Path to TLS CA file.")
	flag.BoolVar(&tlsInsecure, "tls-insecure", false, "- NOT RECOMMENDED FOR PRODUCTION - Don't verify API server's CA certificate.")
	flag.StringVar(&awsSecret, "backup-aws-secret", "", "The name of the kube secret object that stores the aws credential file.")
	flag.StringVar(&awsConfig, "backup-aws-config", "", "The name of the kube configmap object that presents the aws config file.")
	flag.StringVar(&s3Bucket, "backup-s3-bucket", "", "The name of the aws S3 bucket to store backups.")
	// chaos level will be removed once we have a formal tool to inject failures.
	flag.IntVar(&chaosLevel, "chaos-level", -1, "DO NOT USE IN PRODUCTION - level of chaos injected into the etcd clusters created by the operator.")
	flag.BoolVar(&printVersion, "version", false, "Show version and quit")
	flag.DurationVar(&gcInterval, "gc-interval", 10*time.Minute, "GC interval")
	flag.Parse()

	namespace = os.Getenv("MY_POD_NAMESPACE")
	if len(namespace) == 0 {
		namespace = "default"
	}
}

func main() {
	c := make(chan os.Signal, 1)
	signal.Notify(c)
	go func() {
		logrus.Infof("received signal: %v", <-c)
		os.Exit(1)
	}()

	if printVersion {
		fmt.Println("etcd-operator Version:", version.Version)
		fmt.Println("Git SHA:", version.GitSHA)
		fmt.Println("Go Version:", runtime.Version())
		fmt.Printf("Go OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
		os.Exit(0)
	}

	logrus.Infof("etcd-operator Version: %v", version.Version)
	logrus.Infof("Git SHA: %s", version.GitSHA)
	logrus.Infof("Go Version: %s", runtime.Version())
	logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)

	if analyticsEnabled {
		analytics.Enable()
	}

	analytics.OperatorStarted()

	id, err := os.Hostname()
	if err != nil {
		logrus.Fatalf("failed to get hostname: %v", err)
	}

	// TODO: replace this to client-go once leader election pacakge is imported
	//       https://github.com/kubernetes/client-go/issues/28
	rl := &resourcelock.EndpointsLock{
		EndpointsMeta: api.ObjectMeta{
			Namespace: namespace,
			Name:      "etcd-operator",
		},
		Client: k8sutil.MustCreateClient(masterHost, tlsInsecure, &rest.TLSClientConfig{
			CertFile: certFile,
			KeyFile:  keyFile,
			CAFile:   caFile,
		}),
		LockConfig: resourcelock.ResourceLockConfig{
			Identity:      id,
			EventRecorder: &record.FakeRecorder{},
		},
	}

	election.RunOrDie(election.LeaderElectionConfig{
		Lock:          rl,
		LeaseDuration: leaseDuration,
		RenewDeadline: renewDuration,
		RetryPeriod:   retryPeriod,
		Callbacks: election.LeaderCallbacks{
			OnStartedLeading: run,
			OnStoppedLeading: func() {
				logrus.Fatalf("leader election lost")
			},
		},
	})
	panic("unreachable")
}

func run(stop <-chan struct{}) {
	cfg := newControllerConfig()
	if err := cfg.Validate(); err != nil {
		logrus.Fatalf("invalid operator config: %v", err)
	}

	go periodicFullGC(cfg.KubeCli, cfg.Namespace, gcInterval)

	startChaos(context.Background(), cfg.KubeCli, cfg.Namespace, chaosLevel)

	for {
		c := controller.New(cfg)
		err := c.Run()
		switch err {
		case controller.ErrVersionOutdated:
		default:
			logrus.Fatalf("controller Run() ended with failure: %v", err)
		}
	}
}

func newControllerConfig() controller.Config {
	tlsConfig := rest.TLSClientConfig{
		CertFile: certFile,
		KeyFile:  keyFile,
		CAFile:   caFile,
	}
	kubecli := k8sutil.MustCreateClient(masterHost, tlsInsecure, &tlsConfig)
	cfg := controller.Config{
		MasterHost:    masterHost,
		Namespace:     namespace,
		PVProvisioner: pvProvisioner,
		S3Context: s3config.S3Context{
			AWSSecret: awsSecret,
			AWSConfig: awsConfig,
			S3Bucket:  s3Bucket,
		},
		KubeCli: kubecli,
	}
	if len(cfg.MasterHost) == 0 {
		logrus.Info("use in cluster client from k8s library")
		cfg.MasterHost = k8sutil.MustGetInClusterMasterHost()
	}
	return cfg
}

func periodicFullGC(k8s kubernetes.Interface, ns string, d time.Duration) {
	gc := garbagecollection.New(k8s, ns)
	timer := time.NewTimer(d)
	defer timer.Stop()
	for {
		<-timer.C
		err := gc.FullyCollect()
		if err != nil {
			logrus.Warningf("failed to cleanup resources: %v", err)
		}
	}
}

func startChaos(ctx context.Context, k8s kubernetes.Interface, ns string, chaosLevel int) {
	m := chaos.NewMonkeys(k8s)
	ls := labels.SelectorFromSet(map[string]string{"app": "etcd"})

	switch chaosLevel {
	case 1:
		logrus.Info("chaos level = 1: randomly kill one etcd pod every 30 seconds at 50%")
		c := &chaos.CrashConfig{
			Namespace: ns,
			Selector:  ls,

			KillRate:        rate.Every(30 * time.Second),
			KillProbability: 0.5,
			KillMax:         1,
		}

		go m.CrushPods(ctx, c)

	case 2:
		logrus.Info("chaos level = 2: randomly kill at most five etcd pods every 30 seconds at 50%")
		c := &chaos.CrashConfig{
			Namespace: ns,
			Selector:  ls,

			KillRate:        rate.Every(30 * time.Second),
			KillProbability: 0.5,
			KillMax:         5,
		}

		go m.CrushPods(ctx, c)

	default:
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"gopkg.in/metakeule/config.v1"
	"gopkg.in/metakeule/scaffold.v1"
	"io/ioutil"
	"os"
	"path/filepath"
)

var (
	cfg = config.MustNew("scaffold", "1.0",
		`scaffold creates files and directories based on a template and json input.
		Complete documentation at http://godoc.org/gopkg.in/metakeule/scaffold.v1`)

	templateArg = cfg.NewString("template", "the file where the template resides", config.Required, config.Shortflag('t'))
	dirArg      = cfg.NewString("dir", "directory that is the target/root of the file creations", config.Default("."))
	exampleCmd  = cfg.MustCommand("example", "shows the example section of the given template")
)

func main() {

	var (
		err               error
		dir               string
		templateRaw       []byte
		example, template string
	)

steps:
	for jump := 1; err == nil; jump++ {
		switch jump - 1 {
		default:
			break steps
		case 0:
			err = cfg.Run()
		case 1:
			dir = dirArg.Get()
		case 2:
			dir, err = filepath.Abs(dir)
		case 3:
			templateRaw, err = ioutil.ReadFile(templateArg.Get())
		case 4:
			example, template = scaffold.SplitTemplate(string(templateRaw))
		case 5:
			switch cfg.ActiveCommand() {
			case nil:
				err = scaffold.Run(dir, template, os.Stdin, os.Stdout)
			case exampleCmd:
				fmt.Fprintln(os.Stdout, example)
			}
		}
	}

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<commit_msg>fixing help message<commit_after>package main

import (
	"fmt"
	"gopkg.in/metakeule/config.v1"
	"gopkg.in/metakeule/scaffold.v1"
	"io/ioutil"
	"os"
	"path/filepath"
)

var (
	cfg = config.MustNew("scaffold", "1.0",
		`scaffold creates files and directories based on a template and json input.
Complete documentation at http://godoc.org/gopkg.in/metakeule/scaffold.v1`)

	templateArg = cfg.NewString("template", "the file where the template resides", config.Required, config.Shortflag('t'))
	dirArg      = cfg.NewString("dir", "directory that is the target/root of the file creations", config.Default("."))
	exampleCmd  = cfg.MustCommand("example", "shows the example section of the given template")
)

func main() {

	var (
		err               error
		dir               string
		templateRaw       []byte
		example, template string
	)

steps:
	for jump := 1; err == nil; jump++ {
		switch jump - 1 {
		default:
			break steps
		case 0:
			err = cfg.Run()
		case 1:
			dir = dirArg.Get()
		case 2:
			dir, err = filepath.Abs(dir)
		case 3:
			templateRaw, err = ioutil.ReadFile(templateArg.Get())
		case 4:
			example, template = scaffold.SplitTemplate(string(templateRaw))
		case 5:
			switch cfg.ActiveCommand() {
			case nil:
				err = scaffold.Run(dir, template, os.Stdin, os.Stdout)
			case exampleCmd:
				fmt.Fprintln(os.Stdout, example)
			}
		}
	}

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package gokeepasslib

import (
	"encoding/binary"
	"fmt"
	"io"
)

// DBHashes stores the hashes of a Kdbx v4 database
type DBHashes struct {
	Sha256 [32]byte
	Hmac   [32]byte
}

// NewHashes creates a new DBHashes based on the given header
func NewHashes(header *DBHeader) *DBHashes {
	return &DBHashes{
		Sha256: header.GetSha256(),
	}
}

// readFrom reads the hashes from an io.Reader
func (h *DBHashes) readFrom(r io.Reader) error {
	if err := binary.Read(r, binary.LittleEndian, h); err != nil {
		return err
	}
	return nil
}

// writeTo writes the hashes to the given io.Writer
func (h DBHashes) writeTo(w io.Writer) error {
	return binary.Write(w, binary.LittleEndian, h)
}

func (h DBHashes) String() string {
	return fmt.Sprintf(
		"(1) Sha256: %x\n"+
			"(2) Hmac: %x\n",
		h.Sha256,
		h.Hmac,
	)
}
<commit_msg>Redundant return error<commit_after>package gokeepasslib

import (
	"encoding/binary"
	"fmt"
	"io"
)

// DBHashes stores the hashes of a Kdbx v4 database
type DBHashes struct {
	Sha256 [32]byte
	Hmac   [32]byte
}

// NewHashes creates a new DBHashes based on the given header
func NewHashes(header *DBHeader) *DBHashes {
	return &DBHashes{
		Sha256: header.GetSha256(),
	}
}

// readFrom reads the hashes from an io.Reader
func (h *DBHashes) readFrom(r io.Reader) error {
	return binary.Read(r, binary.LittleEndian, h)
}

// writeTo writes the hashes to the given io.Writer
func (h DBHashes) writeTo(w io.Writer) error {
	return binary.Write(w, binary.LittleEndian, h)
}

func (h DBHashes) String() string {
	return fmt.Sprintf(
		"(1) Sha256: %x\n"+
			"(2) Hmac: %x\n",
		h.Sha256,
		h.Hmac,
	)
}
<|endoftext|>