<commit_before>package main

import (
	"fmt"
	"github.com/keltia/ripe-atlas"
	"github.com/urfave/cli"
	"log"
	"os"
	"strings"
)

const (
	defQueryType  = "ANY"
	defQueryClass = "IN"
	defProtocol   = "UDP"
)

var (
	eDNS0 = false
)

// checkQueryParam checks against possible list of parameters
func checkQueryParam(arg string, list map[string]bool) bool {
	_, ok := list[strings.ToUpper(arg)]
	return ok
}

// init injects our "dns" related commands/options.
func init() {
	// Fill-in the various commands
	cliCommands = append(cliCommands, cli.Command{
		Name:        "dns",
		Usage:       "send dns queries",
		Description: "send DNS queries about an host/IP/domain\n   use: <Q> [<TYPE> [<CLASS>]]",
		Aliases: []string{
			"dig",
			"drill",
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:        "E, edns0",
				Usage:       "use EDNS0",
				Destination: &eDNS0,
			},
			cli.BoolFlag{
				Name:        "D, disable-dnssec",
				Usage:       "Do not try to validate DNSSEC RR",
				Destination: &fDisableDNSSEC,
			},
			cli.BoolFlag{
				Name:        "C, disable-dnssec-checks",
				Usage:       "Do not try to validate DNSSEC Check by probes",
				Destination: &fBitCD,
			},
			cli.StringFlag{
				Name:        "p, protocol",
				Usage:       "Select UDP or TCP",
				Destination: &fProtocol,
			},
		},
		Action: cmdDNS,
	})
}

func prepareDNS(proto, qa, qc, qt string, do, cd bool) (req *atlas.MeasurementRequest) {
	opts := map[string]string{
		"Type":          "dns",
		"Description":   fmt.Sprintf("DNS - %s", qa),
		"Protocol":      proto,
		"QueryArgument": qa,
		"QueryClass":    qc,
		"QueryType":     qt,
		"SetDOBit":      boolToString(do),
		"SetCDBit":      boolToString(cd),
	}

	if eDNS0 {
		opts["UDPPayloadSize"] = "4096"
		opts["Protocol"] = "UDP"
	} else {
		opts["UDPPayloadSize"] = "512"
	}

	// Check global parameters
	opts = checkGlobalFlags(opts)

	req = client.NewMeasurement()

	if mycnf.WantAF == WantBoth {

		opts["AF"] = "4"
		req.AddDefinition(opts)

		opts["AF"] = "6"
		req.AddDefinition(opts)
	} else {
		opts["AF"] = mycnf.WantAF
		req.AddDefinition(opts)
	}

	if fVerbose {
		displayOptions(opts)
	}

	return
}

func cmdDNS(c *cli.Context) error {
	var (
		bitDO  = true
		bitCD  = false
		qtype  = defQueryType
		qclass = defQueryClass
		proto  = defProtocol

		addr string
	)

	args := c.Args()
	if args == nil || len(args) == 0 {
		log.Fatal("Error: you must specify at least a name")
	}

	if len(args) == 1 {
		addr = args[0]
	} else if len(args) == 2 {
		addr = args[0]
		qtype = args[1]
	} else if len(args) == 3 {
		addr = args[0]
		qtype = args[1]
		qclass = args[2]
	}

	if fProtocol != "" {
		log.Printf("Use %s", fProtocol)
		proto = fProtocol
	}

	if fDisableDNSSEC {
		bitDO = false
	}

	if fBitCD {
		bitCD = true
	}

	req := prepareDNS(proto, addr, qclass, qtype, bitDO, bitCD)

	log.Printf("req=%#v", req)
	m, err := client.DNS(req)
	if err != nil {
		fmt.Printf("err: %v", err)
		os.Exit(1)
	}

	//str := res.Result.Display()
	fmt.Printf("m: %v\n", m)

	return nil
}
<commit_msg>These need to be uppercase.<commit_after>package main

import (
	"fmt"
	"github.com/keltia/ripe-atlas"
	"github.com/urfave/cli"
	"log"
	"os"
	"strings"
)

const (
	defQueryType  = "ANY"
	defQueryClass = "IN"
	defProtocol   = "UDP"
)

var (
	eDNS0 = false
)

// checkQueryParam checks against possible list of parameters
func checkQueryParam(arg string, list map[string]bool) bool {
	_, ok := list[strings.ToUpper(arg)]
	return ok
}

// init injects our "dns" related commands/options.
func init() {
	// Fill-in the various commands
	cliCommands = append(cliCommands, cli.Command{
		Name:        "dns",
		Usage:       "send dns queries",
		Description: "send DNS queries about an host/IP/domain\n   use: <Q> [<TYPE> [<CLASS>]]",
		Aliases: []string{
			"dig",
			"drill",
		},
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:        "E, edns0",
				Usage:       "use EDNS0",
				Destination: &eDNS0,
			},
			cli.BoolFlag{
				Name:        "D, disable-dnssec",
				Usage:       "Do not try to validate DNSSEC RR",
				Destination: &fDisableDNSSEC,
			},
			cli.BoolFlag{
				Name:        "C, disable-dnssec-checks",
				Usage:       "Do not try to validate DNSSEC Check by probes",
				Destination: &fBitCD,
			},
			cli.StringFlag{
				Name:        "p, protocol",
				Usage:       "Select UDP or TCP",
				Destination: &fProtocol,
			},
		},
		Action: cmdDNS,
	})
}

func prepareDNS(proto, qa, qc, qt string, do, cd bool) (req *atlas.MeasurementRequest) {
	opts := map[string]string{
		"Type":          "dns",
		"Description":   fmt.Sprintf("DNS - %s", qa),
		"Protocol":      proto,
		"QueryArgument": qa,
		"QueryClass":    qc,
		"QueryType":     qt,
		"SetDOBit":      boolToString(do),
		"SetCDBit":      boolToString(cd),
	}

	if eDNS0 {
		opts["UDPPayloadSize"] = "4096"
		opts["Protocol"] = "UDP"
	} else {
		opts["UDPPayloadSize"] = "512"
	}

	// Check global parameters
	opts = checkGlobalFlags(opts)

	req = client.NewMeasurement()

	if mycnf.WantAF == WantBoth {

		opts["AF"] = "4"
		req.AddDefinition(opts)

		opts["AF"] = "6"
		req.AddDefinition(opts)
	} else {
		opts["AF"] = mycnf.WantAF
		req.AddDefinition(opts)
	}

	if fVerbose {
		displayOptions(opts)
	}

	return
}

func cmdDNS(c *cli.Context) error {
	var (
		bitDO  = true
		bitCD  = false
		qtype  = defQueryType
		qclass = defQueryClass
		proto  = defProtocol

		addr string
	)

	args := c.Args()
	if args == nil || len(args) == 0 {
		log.Fatal("Error: you must specify at least a name")
	}

	if len(args) == 1 {
		addr = args[0]
	} else if len(args) == 2 {
		addr = args[0]
		qtype = strings.ToUpper(args[1])
	} else if len(args) == 3 {
		addr = args[0]
		qtype = strings.ToUpper(args[1])
		qclass = strings.ToUpper(args[2])
	}

	if fProtocol != "" {
		log.Printf("Use %s", fProtocol)
		proto = fProtocol
	}

	if fDisableDNSSEC {
		bitDO = false
	}

	if fBitCD {
		bitCD = true
	}

	req := prepareDNS(proto, addr, qclass, qtype, bitDO, bitCD)

	log.Printf("req=%#v", req)
	m, err := client.DNS(req)
	if err != nil {
		fmt.Printf("err: %v", err)
		os.Exit(1)
	}

	//str := res.Result.Display()
	fmt.Printf("m: %v\n", m)

	return nil
}
<|endoftext|>


<commit_before>// bootnode runs a bootstrap node for the Ethereum Discovery Protocol.
package main

import (
	"crypto/ecdsa"
	"encoding/hex"
	"flag"
	"net"
	"os"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/log"
	"github.com/ethereum/go-ethereum/p2p/discv5"
)

type bootnodes []*discv5.Node

func (f *bootnodes) String() string {
	return "discv5 nodes"
}

// Set unmarshals enode into discv5.Node.
func (f *bootnodes) Set(value string) error {
	n, err := discv5.ParseNode(value)
	if err != nil {
		return err
	}
	*f = append(*f, n)
	return nil
}

func main() {
	var (
		listenAddr  = flag.String("addr", ":30301", "listen address")
		nodeKeyFile = flag.String("nodekey", "", "private key filename")
		keydata     = flag.String("keydata", "", "hex encoded private key")
		verbosity   = flag.Int("verbosity", int(log.LvlInfo), "log verbosity (0-9)")
		vmodule     = flag.String("vmodule", "", "log verbosity pattern")
		nursery     = bootnodes{}
		nodeKey     *ecdsa.PrivateKey
		err         error
	)
	flag.Var(&nursery, "n", "These nodes are used to connect to the network if the table is empty and there are no known nodes in the database.")
	flag.Parse()

	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
	glogger.Verbosity(log.Lvl(*verbosity))
	if err = glogger.Vmodule(*vmodule); err != nil {
		log.Crit("Failed to set glog verbosity", "value", *vmodule, "err", err)
	}
	log.Root().SetHandler(glogger)

	if len(*nodeKeyFile) == 0 && len(*keydata) == 0 {
		log.Crit("either `nodekey` or `keydata` must be provided")
	}
	if len(*nodeKeyFile) != 0 {
		nodeKey, err = crypto.LoadECDSA(*nodeKeyFile)
		if err != nil {
			log.Crit("Failed to load ecdsa key from", "file", *nodeKeyFile, "error", err)
		}
	} else if len(*keydata) != 0 {
		log.Warn("key will be visible in process list. should be used only for tests")
		key, err := hex.DecodeString(*keydata)
		if err != nil {
			log.Crit("unable to decode hex", "data", keydata, "error", err)
		}
		nodeKey, err = crypto.ToECDSA(key)
		if err != nil {
			log.Crit("unable to convert decoded hex into ecdsa.PrivateKey", "data", key, "error", err)
		}
	}

	addr, err := net.ResolveUDPAddr("udp", *listenAddr)
	if err != nil {
		log.Crit("Unable to resolve UDP", "address", *listenAddr, "error", err)
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Crit("Unable to listen on udp", "address", addr, "error", err)
	}

	tab, err := discv5.ListenUDP(nodeKey, conn, "", nil)
	if err != nil {
		log.Crit("Failed to create discovery v5 table:", "error", err)
	}
	defer tab.Close()
	if err := tab.SetFallbackNodes(nursery); err != nil {
		log.Crit("Failed to set fallback", "nodes", nursery, "error", err)
	}
	select {}
}
<commit_msg>add -genkey flag to bootnode for making new keys<commit_after>// bootnode runs a bootstrap node for the Ethereum Discovery Protocol.
package main

import (
	"crypto/ecdsa"
	"encoding/hex"
	"flag"
	"fmt"
	"net"
	"os"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/log"
	"github.com/ethereum/go-ethereum/p2p/discv5"
)

type bootnodes []*discv5.Node

func (f *bootnodes) String() string {
	return "discv5 nodes"
}

// Set unmarshals enode into discv5.Node.
func (f *bootnodes) Set(value string) error {
	n, err := discv5.ParseNode(value)
	if err != nil {
		return err
	}
	*f = append(*f, n)
	return nil
}

func main() {
	var (
		writeAddr   = flag.Bool("writeaddress", false, "write out the node's public key and quit")
		listenAddr  = flag.String("addr", ":30301", "listen address")
		genKeyFile  = flag.String("genkey", "", "generate a node key")
		nodeKeyFile = flag.String("nodekey", "", "private key filename")
		keydata     = flag.String("keydata", "", "hex encoded private key")
		verbosity   = flag.Int("verbosity", int(log.LvlInfo), "log verbosity (0-9)")
		vmodule     = flag.String("vmodule", "", "log verbosity pattern")
		nursery     = bootnodes{}
		nodeKey     *ecdsa.PrivateKey
		err         error
	)
	flag.Var(&nursery, "n", "These nodes are used to connect to the network if the table is empty and there are no known nodes in the database.")
	flag.Parse()

	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
	glogger.Verbosity(log.Lvl(*verbosity))
	if err = glogger.Vmodule(*vmodule); err != nil {
		log.Crit("Failed to set glog verbosity", "value", *vmodule, "err", err)
	}
	log.Root().SetHandler(glogger)

	if len(*genKeyFile) != 0 {
		log.Info("Generating key file", "path", *genKeyFile)
		key, err := crypto.GenerateKey()
		if err != nil {
			log.Crit("unable to generate key", "error", err)
		}
		if err := crypto.SaveECDSA(*genKeyFile, key); err != nil {
			log.Crit("unable to save key", "error", err)
		}
		os.Exit(0)
	}
	if len(*nodeKeyFile) == 0 && len(*keydata) == 0 {
		log.Crit("either `nodekey` or `keydata` must be provided")
	}
	if len(*nodeKeyFile) != 0 {
		nodeKey, err = crypto.LoadECDSA(*nodeKeyFile)
		if err != nil {
			log.Crit("Failed to load ecdsa key from", "file", *nodeKeyFile, "error", err)
		}
	} else if len(*keydata) != 0 {
		log.Warn("key will be visible in process list. should be used only for tests")
		key, err := hex.DecodeString(*keydata)
		if err != nil {
			log.Crit("unable to decode hex", "data", keydata, "error", err)
		}
		nodeKey, err = crypto.ToECDSA(key)
		if err != nil {
			log.Crit("unable to convert decoded hex into ecdsa.PrivateKey", "data", key, "error", err)
		}
	}
	if *writeAddr {
		// we remove the first uncompressed byte since it's not used in an enode address
		fmt.Printf("%x\n", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
		os.Exit(0)
	}

	addr, err := net.ResolveUDPAddr("udp", *listenAddr)
	if err != nil {
		log.Crit("Unable to resolve UDP", "address", *listenAddr, "error", err)
	}
	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		log.Crit("Unable to listen on udp", "address", addr, "error", err)
	}

	tab, err := discv5.ListenUDP(nodeKey, conn, "", nil)
	if err != nil {
		log.Crit("Failed to create discovery v5 table:", "error", err)
	}
	defer tab.Close()
	if err := tab.SetFallbackNodes(nursery); err != nil {
		log.Crit("Failed to set fallback", "nodes", nursery, "error", err)
	}
	select {}
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"strconv"

	log "github.com/sirupsen/logrus"
	"github.com/urfave/cli"

	"github.com/gorilla/handlers"
	"github.com/usefathom/fathom/pkg/api"
	"golang.org/x/crypto/acme/autocert"
)

var serverCmd = cli.Command{
	Name:    "server",
	Aliases: []string{"s"},
	Usage:   "start the fathom web server",
	Action:  server,
	Flags: []cli.Flag{
		cli.StringFlag{
			EnvVar: "FATHOM_SERVER_ADDR,PORT",
			Name:   "addr,port",
			Usage:  "server address",
			Value:  ":8080",
		},

		cli.BoolFlag{
			EnvVar: "FATHOM_LETS_ENCRYPT",
			Name:   "lets-encrypt",
		},

		cli.StringFlag{
			EnvVar: "FATHOM_HOSTNAME",
			Name:   "hostname",
			Usage:  "domain when using --lets-encrypt",
		},

		cli.BoolFlag{
			EnvVar: "FATHOM_DEBUG",
			Name:   "debug, d",
		},
	},
}

func server(c *cli.Context) error {
	var h http.Handler
	a := api.New(app.database, app.config.Secret)
	h = a.Routes()

	// set debug log level if --debug was passed
	if c.Bool("debug") {
		log.SetLevel(log.DebugLevel)
		h = handlers.LoggingHandler(log.StandardLogger().Writer(), h)
	} else {
		log.SetLevel(log.WarnLevel)
	}

	// if addr looks like a number, prefix with :
	addr := c.String("addr")
	if _, err := strconv.Atoi(addr); err == nil {
		addr = ":" + addr
	}

	// start server without letsencrypt / tls enabled
	if !c.Bool("lets-encrypt") {
		// start listening
		log.Printf("Server is now listening on %s", addr)
		err := http.ListenAndServe(addr, h)
		if err != nil {
			log.Errorln(err)
		}
		return nil
	}

	// start server with autocert (letsencrypt)
	hostname := c.String("hostname")
	log.Printf("Server is now listening on %s:443", hostname)
	log.Fatal(http.Serve(autocert.NewListener(hostname), h))
	return nil
}
<commit_msg>set WriteTimeout and ReadTimeout on http.Server<commit_after>package main

import (
	"net/http"
	"strconv"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/urfave/cli"

	"github.com/gorilla/handlers"
	"github.com/usefathom/fathom/pkg/api"
	"golang.org/x/crypto/acme/autocert"
)

var serverCmd = cli.Command{
	Name:    "server",
	Aliases: []string{"s"},
	Usage:   "start the fathom web server",
	Action:  server,
	Flags: []cli.Flag{
		cli.StringFlag{
			EnvVar: "FATHOM_SERVER_ADDR,PORT",
			Name:   "addr,port",
			Usage:  "server address",
			Value:  ":8080",
		},

		cli.BoolFlag{
			EnvVar: "FATHOM_LETS_ENCRYPT",
			Name:   "lets-encrypt",
		},

		cli.StringFlag{
			EnvVar: "FATHOM_HOSTNAME",
			Name:   "hostname",
			Usage:  "domain when using --lets-encrypt",
		},

		cli.BoolFlag{
			EnvVar: "FATHOM_DEBUG",
			Name:   "debug, d",
		},
	},
}

func server(c *cli.Context) error {
	var h http.Handler
	a := api.New(app.database, app.config.Secret)
	h = a.Routes()

	// set debug log level if --debug was passed
	if c.Bool("debug") {
		log.SetLevel(log.DebugLevel)
		h = handlers.LoggingHandler(log.StandardLogger().Writer(), h)
	} else {
		log.SetLevel(log.WarnLevel)
	}

	// if addr looks like a number, prefix with :
	addr := c.String("addr")
	if _, err := strconv.Atoi(addr); err == nil {
		addr = ":" + addr
	}

	// start server without letsencrypt / tls enabled
	if !c.Bool("lets-encrypt") {
		// start listening
		log.Printf("Server is now listening on %s", addr)
		server := &http.Server{
			Addr:         addr,
			Handler:      h,
			ReadTimeout:  10 * time.Second,
			WriteTimeout: 10 * time.Second,
		}
		log.Fatal(server.ListenAndServe())
		return nil
	}

	// start server with autocert (letsencrypt)
	hostname := c.String("hostname")
	log.Printf("Server is now listening on %s:443", hostname)
	log.Fatal(http.Serve(autocert.NewListener(hostname), h))
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/codegangsta/cli"
	"github.com/mlafeldt/go-ghstatus"
)

func printStatus(t time.Time, status, body string) {
	ts := t.Format(time.Stamp)
	if body != "" {
		fmt.Printf("[%s] %s %s\n", ts, status, body)
	} else {
		fmt.Printf("[%s] %s\n", ts, status)
	}
}

func exitWithStatus(status string) {
	code := map[string]int{
		ghstatus.Good:  0,
		ghstatus.Minor: 1,
		ghstatus.Major: 2,
	}[status]
	os.Exit(code)
}

func cmdStatus(c *cli.Context) {
	s, err := ghstatus.GetStatus()
	if err != nil {
		log.Fatal("error: failed to get status: ", err)
	}
	printStatus(s.LastUpdated, s.Status, "")
	// exitWithStatus(s.Status)
}

func cmdMessages(c *cli.Context) {
	messages, err := ghstatus.GetMessages()
	if err != nil {
		log.Fatal("error: failed to get messages: ", err)
	}
	for _, m := range messages {
		printStatus(m.CreatedOn, m.Status, m.Body)
	}
}

func cmdLastMessage(c *cli.Context) {
	m, err := ghstatus.GetLastMessage()
	if err != nil {
		log.Fatal("error: failed to get last message: ", err)
	}
	printStatus(m.CreatedOn, m.Status, m.Body)
	// exitWithStatus(m.Status)
}

func main() {
	log.SetFlags(0)

	app := cli.NewApp()
	app.Name = "ghstatus"
	app.Usage = "Check the system status of GitHub from the command line"
	app.Version = "1.5"
	app.Commands = []cli.Command{
		{
			Name:      "status",
			ShortName: "s",
			Action:    cmdStatus,
		},
		{
			Name:      "messages",
			ShortName: "m",
			Action:    cmdMessages,
		},
		{
			Name:      "last",
			ShortName: "l",
			Action:    cmdLastMessage,
		},
	}

	args := os.Args
	if len(args) < 2 {
		args = append(args, "status")
	}

	if err := app.Run(args); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Add --exit-code<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/codegangsta/cli"
	"github.com/mlafeldt/go-ghstatus"
)

func printStatus(t time.Time, status, body string) {
	ts := t.Format(time.Stamp)
	if body != "" {
		fmt.Printf("[%s] %s %s\n", ts, status, body)
	} else {
		fmt.Printf("[%s] %s\n", ts, status)
	}
}

func exitWithStatus(status string) {
	code := map[string]int{
		ghstatus.Good:  0,
		ghstatus.Minor: 1,
		ghstatus.Major: 2,
	}[status]
	os.Exit(code)
}

func cmdStatus(c *cli.Context) {
	s, err := ghstatus.GetStatus()
	if err != nil {
		log.Fatal("error: failed to get status: ", err)
	}

	printStatus(s.LastUpdated, s.Status, "")

	if c != nil && c.Bool("exit-code") {
		exitWithStatus(s.Status)
	}
}

func cmdMessages(c *cli.Context) {
	messages, err := ghstatus.GetMessages()
	if err != nil {
		log.Fatal("error: failed to get messages: ", err)
	}

	for _, m := range messages {
		printStatus(m.CreatedOn, m.Status, m.Body)
	}
}

func cmdLastMessage(c *cli.Context) {
	m, err := ghstatus.GetLastMessage()
	if err != nil {
		log.Fatal("error: failed to get last message: ", err)
	}

	printStatus(m.CreatedOn, m.Status, m.Body)

	if c != nil && c.Bool("exit-code") {
		exitWithStatus(m.Status)
	}
}

func main() {
	log.SetFlags(0)

	app := cli.NewApp()
	app.Name = "ghstatus"
	app.Usage = "Check the system status of GitHub from the command line"
	app.Version = "1.5"
	app.Commands = []cli.Command{
		{
			Name:      "status",
			ShortName: "s",
			Action:    cmdStatus,
			Flags: []cli.Flag{
				cli.BoolFlag{
					"exit-code, e",
					"Make program exit with GitHub status as exit code",
				},
			},
		},
		{
			Name:      "messages",
			ShortName: "m",
			Action:    cmdMessages,
		},
		{
			Name:      "last",
			ShortName: "l",
			Action:    cmdLastMessage,
			Flags: []cli.Flag{
				cli.BoolFlag{
					"exit-code, e",
					"Make program exit with GitHub status as exit code",
				},
			},
		},
	}

	args := os.Args
	if len(args) < 2 {
		args = append(args, "status")
	}

	if err := app.Run(args); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"image"
	"image/png"
	"log"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/patdhlk/halftone"
)

var (
	rng           = rand.New(rand.NewSource(time.Now().UnixNano()))
	ditherModeVar int
)

func init() {
	flag.IntVar(&ditherModeVar, "mode", 0, "specifies the dither mode")
}

func main() {
	flag.Parse()
	files := []string{"img/Lenna.png", "img/Michelangelo.png", "img/radon.jpg", "img/sample.jpg", "img/timon.jpg"}
	worker := halftone.NewImageWorker()
	cv := halftone.NewImageConverter()
	for _, file := range files {
		var img, err = worker.LoadImage(file)

		if err != nil {
			log.Fatal(err)
		}

		var gray = cv.ConvertToGray(img)
		var dithered *image.Gray
		switch ditherModeVar {
		case 0:
			dithered = halftone.FloydSteinbergDitherer{}.Run(gray)
		case 1:
			dithered = halftone.NewGridDitherer(5, 3, 8, rng).Run(gray)
		case 2:
			dithered = halftone.NewThresholdDitherer(122).Run(gray)
		default:
			fmt.Println("wrong dither mode specified. Only 0, 1 and 2 supported")
			os.Exit(1)
		}

		// Save as out.png
		newFilename := strings.Replace(file, "img/", "out/", 1)
		f, _ := os.Create(newFilename)
		defer f.Close()
		png.Encode(f, dithered)
	}
}
<commit_msg>errorhandling<commit_after>package main

import (
	"flag"
	"fmt"
	"image"
	"image/png"
	"log"
	"math/rand"
	"os"
	"strings"
	"time"

	"github.com/patdhlk/halftone"
)

var (
	rng           = rand.New(rand.NewSource(time.Now().UnixNano()))
	ditherModeVar int
)

func init() {
	flag.IntVar(&ditherModeVar, "mode", 0, "specifies the dither mode")
}

func main() {
	flag.Parse()
	files := []string{"img/Lenna.png", "img/Michelangelo.png", "img/radon.jpg", "img/sample.jpg", "img/timon.jpg"}
	worker := halftone.NewImageWorker()
	cv := halftone.NewImageConverter()
	for _, file := range files {
		var img, err = worker.LoadImage(file)

		if err != nil {
			log.Fatal(err)
		}

		var gray = cv.ConvertToGray(img)
		var dithered *image.Gray
		switch ditherModeVar {
		case 0:
			dithered = halftone.FloydSteinbergDitherer{}.Run(gray)
		case 1:
			dithered = halftone.NewGridDitherer(5, 3, 8, rng).Run(gray)
		case 2:
			dithered = halftone.NewThresholdDitherer(122).Run(gray)
		default:
			fmt.Println("wrong dither mode specified. Only 0, 1 and 2 supported")
			os.Exit(1)
		}

		// Save as out.png
		newFilename := strings.Replace(file, "img/", "out/", 1)
		f, err := os.Create(newFilename)
		if err != nil {
			fmt.Printf("%s", err.Error())
			os.Exit(1)
		}
		defer f.Close()
		png.Encode(f, dithered)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/hashicorp/consul/api"
	"github.com/nu7hatch/gouuid"

	"code.cloudfoundry.org/auctioneer"
	"code.cloudfoundry.org/auctioneer/auctionmetricemitterdelegate"
	"code.cloudfoundry.org/auctioneer/auctionrunnerdelegate"
	"code.cloudfoundry.org/auctioneer/handlers"
	"code.cloudfoundry.org/bbs"
	"code.cloudfoundry.org/consuladapter"
	"code.cloudfoundry.org/debugserver"
	"code.cloudfoundry.org/locket"
	"code.cloudfoundry.org/rep"
	cf_lager "github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/cf_http"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/localip"

	"code.cloudfoundry.org/auction/auctionrunner"
	"code.cloudfoundry.org/auction/auctiontypes"
	"github.com/cloudfoundry/dropsonde"
	"github.com/cloudfoundry/gunk/workpool"
	"github.com/pivotal-golang/clock"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
)

var communicationTimeout = flag.Duration(
	"communicationTimeout",
	10*time.Second,
	"Timeout applied to all HTTP requests.",
)

var cellStateTimeout = flag.Duration(
	"cellStateTimeout",
	1*time.Second,
	"Timeout applied to HTTP requests to the Cell State endpoint.",
)

var consulCluster = flag.String(
	"consulCluster",
	"",
	"comma-separated list of consul server addresses (ip:port)",
)

var dropsondePort = flag.Int(
	"dropsondePort",
	3457,
	"port the local metron agent is listening on",
)

var lockTTL = flag.Duration(
	"lockTTL",
	locket.LockTTL,
	"TTL for service lock",
)

var lockRetryInterval = flag.Duration(
	"lockRetryInterval",
	locket.RetryInterval,
	"interval to wait before retrying a failed lock acquisition",
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:9016",
	"host:port to serve auction and LRP stop requests on",
)

var bbsAddress = flag.String(
	"bbsAddress",
	"",
	"Address to the BBS Server",
)

var bbsCACert = flag.String(
	"bbsCACert",
	"",
	"path to certificate authority cert used for mutually authenticated TLS BBS communication",
)

var bbsClientCert = flag.String(
	"bbsClientCert",
	"",
	"path to client cert used for mutually authenticated TLS BBS communication",
)

var bbsClientKey = flag.String(
	"bbsClientKey",
	"",
	"path to client key used for mutually authenticated TLS BBS communication",
)

var bbsClientSessionCacheSize = flag.Int(
	"bbsClientSessionCacheSize",
	0,
	"Capacity of the ClientSessionCache option on the TLS configuration. If zero, golang's default will be used",
)

var bbsMaxIdleConnsPerHost = flag.Int(
	"bbsMaxIdleConnsPerHost",
	0,
	"Controls the maximum number of idle (keep-alive) connctions per host. If zero, golang's default will be used",
)

var auctionRunnerWorkers = flag.Int(
	"auctionRunnerWorkers",
	1000,
	"Max concurrency for cell operations in the auction runner",
)

var startingContainerWeight = flag.Float64(
	"startingContainerWeight",
	0.25,
	"Factor to bias against cells with starting containers (0.0 - 1.0)",
)

const (
	auctionRunnerTimeout = 10 * time.Second
	dropsondeOrigin      = "auctioneer"
	serverProtocol       = "http"
)

func main() {
	debugserver.AddFlags(flag.CommandLine)
	cf_lager.AddFlags(flag.CommandLine)
	flag.Parse()

	cf_http.Initialize(*communicationTimeout)

	logger, reconfigurableSink := cf_lager.New("auctioneer")
	initializeDropsonde(logger)

	if err := validateBBSAddress(); err != nil {
		logger.Fatal("invalid-bbs-address", err)
	}

	consulClient, err := consuladapter.NewClientFromUrl(*consulCluster)
	if err != nil {
		logger.Fatal("new-client-failed", err)
	}

	port, err := strconv.Atoi(strings.Split(*listenAddr, ":")[1])
	if err != nil {
		logger.Fatal("invalid-port", err)
	}

	clock := clock.NewClock()
	auctioneerServiceClient := auctioneer.NewServiceClient(consulClient, clock)

	auctionRunner := initializeAuctionRunner(logger, *cellStateTimeout,
		initializeBBSClient(logger), *startingContainerWeight)
	auctionServer := initializeAuctionServer(logger, auctionRunner)
	lockMaintainer := initializeLockMaintainer(logger, auctioneerServiceClient, port)
	registrationRunner := initializeRegistrationRunner(logger, consulClient, clock, port)

	members := grouper.Members{
		{"lock-maintainer", lockMaintainer},
		{"auction-runner", auctionRunner},
		{"auction-server", auctionServer},
		{"registration-runner", registrationRunner},
	}

	if dbgAddr := debugserver.DebugAddress(flag.CommandLine); dbgAddr != "" {
		members = append(grouper.Members{
			{"debug-server", debugserver.Runner(dbgAddr, reconfigurableSink)},
		}, members...)
	}

	group := grouper.NewOrdered(os.Interrupt, members)

	monitor := ifrit.Invoke(sigmon.New(group))

	logger.Info("started")

	err = <-monitor.Wait()
	if err != nil {
		logger.Error("exited-with-failure", err)
		os.Exit(1)
	}

	logger.Info("exited")
}

func initializeAuctionRunner(logger lager.Logger, cellStateTimeout time.Duration, bbsClient bbs.InternalClient, startingContainerWeight float64) auctiontypes.AuctionRunner {
	httpClient := cf_http.NewClient()
	stateClient := cf_http.NewCustomTimeoutClient(cellStateTimeout)
	repClientFactory := rep.NewClientFactory(httpClient, stateClient)

	delegate := auctionrunnerdelegate.New(repClientFactory, bbsClient, logger)
	metricEmitter := auctionmetricemitterdelegate.New()
	workPool, err := workpool.NewWorkPool(*auctionRunnerWorkers)
	if err != nil {
		logger.Fatal("failed-to-construct-auction-runner-workpool", err, lager.Data{"num-workers": *auctionRunnerWorkers}) // should never happen
	}

	return auctionrunner.New(
		logger,
		delegate,
		metricEmitter,
		clock.NewClock(),
		workPool,
		startingContainerWeight,
	)
}

func initializeDropsonde(logger lager.Logger) {
	dropsondeDestination := fmt.Sprint("localhost:", *dropsondePort)
	err := dropsonde.Initialize(dropsondeDestination, dropsondeOrigin)
	if err != nil {
		logger.Error("failed to initialize dropsonde: %v", err)
	}
}

func initializeAuctionServer(logger lager.Logger, runner auctiontypes.AuctionRunner) ifrit.Runner {
	return http_server.New(*listenAddr, handlers.New(runner, logger))
}

func initializeRegistrationRunner(logger lager.Logger, consulClient consuladapter.Client, clock clock.Clock, port int) ifrit.Runner {
	registration := &api.AgentServiceRegistration{
		Name: "auctioneer",
		Port: port,
		Check: &api.AgentServiceCheck{
			TTL: "3s",
		},
	}
	return locket.NewRegistrationRunner(logger, registration, consulClient, locket.RetryInterval, clock)
}

func initializeLockMaintainer(logger lager.Logger, serviceClient auctioneer.ServiceClient, port int) ifrit.Runner {
	uuid, err := uuid.NewV4()
	if err != nil {
		logger.Fatal("Couldn't generate uuid", err)
	}

	localIP, err := localip.LocalIP()
	if err != nil {
		logger.Fatal("Couldn't determine local IP", err)
	}

	address := fmt.Sprintf("%s://%s:%d", serverProtocol, localIP, port)
	auctioneerPresence := auctioneer.NewPresence(uuid.String(), address)

	lockMaintainer, err := serviceClient.NewAuctioneerLockRunner(logger, auctioneerPresence, *lockRetryInterval, *lockTTL)
	if err != nil {
		logger.Fatal("Couldn't create lock maintainer", err)
	}

	return lockMaintainer
}

func validateBBSAddress() error {
	if *bbsAddress == "" {
		return errors.New("bbsAddress is required")
	}
	return nil
}

func initializeBBSClient(logger lager.Logger) bbs.InternalClient {
	bbsURL, err := url.Parse(*bbsAddress)
	if err != nil {
		logger.Fatal("Invalid BBS URL", err)
	}

	if bbsURL.Scheme != "https" {
		return bbs.NewClient(*bbsAddress)
	}

	bbsClient, err := bbs.NewSecureClient(*bbsAddress, *bbsCACert, *bbsClientCert, *bbsClientKey, *bbsClientSessionCacheSize, *bbsMaxIdleConnsPerHost)
	if err != nil {
		logger.Fatal("Failed to configure secure BBS client", err)
	}
	return bbsClient
}
<commit_msg>Update and renambe cf-lager -> cflager<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/hashicorp/consul/api"
	"github.com/nu7hatch/gouuid"

	"code.cloudfoundry.org/auctioneer"
	"code.cloudfoundry.org/auctioneer/auctionmetricemitterdelegate"
	"code.cloudfoundry.org/auctioneer/auctionrunnerdelegate"
	"code.cloudfoundry.org/auctioneer/handlers"
	"code.cloudfoundry.org/bbs"
	"code.cloudfoundry.org/cflager"
	"code.cloudfoundry.org/consuladapter"
	"code.cloudfoundry.org/debugserver"
	"code.cloudfoundry.org/locket"
	"code.cloudfoundry.org/rep"
	"github.com/cloudfoundry-incubator/cf_http"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/localip"

	"code.cloudfoundry.org/auction/auctionrunner"
	"code.cloudfoundry.org/auction/auctiontypes"
	"github.com/cloudfoundry/dropsonde"
	"github.com/cloudfoundry/gunk/workpool"
	"github.com/pivotal-golang/clock"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
)

var communicationTimeout = flag.Duration(
	"communicationTimeout",
	10*time.Second,
	"Timeout applied to all HTTP requests.",
)

var cellStateTimeout = flag.Duration(
	"cellStateTimeout",
	1*time.Second,
	"Timeout applied to HTTP requests to the Cell State endpoint.",
)

var consulCluster = flag.String(
	"consulCluster",
	"",
	"comma-separated list of consul server addresses (ip:port)",
)

var dropsondePort = flag.Int(
	"dropsondePort",
	3457,
	"port the local metron agent is listening on",
)

var lockTTL = flag.Duration(
	"lockTTL",
	locket.LockTTL,
	"TTL for service lock",
)

var lockRetryInterval = flag.Duration(
	"lockRetryInterval",
	locket.RetryInterval,
	"interval to wait before retrying a failed lock acquisition",
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:9016",
	"host:port to serve auction and LRP stop requests on",
)

var bbsAddress = flag.String(
	"bbsAddress",
	"",
	"Address to the BBS Server",
)

var bbsCACert = flag.String(
	"bbsCACert",
	"",
	"path to certificate authority cert used for mutually authenticated TLS BBS communication",
)

var bbsClientCert = flag.String(
	"bbsClientCert",
	"",
	"path to client cert used for mutually authenticated TLS BBS communication",
)

var bbsClientKey = flag.String(
	"bbsClientKey",
	"",
	"path to client key used for mutually authenticated TLS BBS communication",
)

var bbsClientSessionCacheSize = flag.Int(
	"bbsClientSessionCacheSize",
	0,
	"Capacity of the ClientSessionCache option on the TLS configuration. If zero, golang's default will be used",
)

var bbsMaxIdleConnsPerHost = flag.Int(
	"bbsMaxIdleConnsPerHost",
	0,
	"Controls the maximum number of idle (keep-alive) connctions per host. If zero, golang's default will be used",
)

var auctionRunnerWorkers = flag.Int(
	"auctionRunnerWorkers",
	1000,
	"Max concurrency for cell operations in the auction runner",
)

var startingContainerWeight = flag.Float64(
	"startingContainerWeight",
	0.25,
	"Factor to bias against cells with starting containers (0.0 - 1.0)",
)

const (
	auctionRunnerTimeout = 10 * time.Second
	dropsondeOrigin      = "auctioneer"
	serverProtocol       = "http"
)

func main() {
	debugserver.AddFlags(flag.CommandLine)
	cflager.AddFlags(flag.CommandLine)
	flag.Parse()

	cf_http.Initialize(*communicationTimeout)

	logger, reconfigurableSink := cflager.New("auctioneer")
	initializeDropsonde(logger)

	if err := validateBBSAddress(); err != nil {
		logger.Fatal("invalid-bbs-address", err)
	}

	consulClient, err := consuladapter.NewClientFromUrl(*consulCluster)
	if err != nil {
		logger.Fatal("new-client-failed", err)
	}

	port, err := strconv.Atoi(strings.Split(*listenAddr, ":")[1])
	if err != nil {
		logger.Fatal("invalid-port", err)
	}

	clock := clock.NewClock()
	auctioneerServiceClient := auctioneer.NewServiceClient(consulClient, clock)

	auctionRunner := initializeAuctionRunner(logger, *cellStateTimeout,
		initializeBBSClient(logger), *startingContainerWeight)
	auctionServer := initializeAuctionServer(logger, auctionRunner)
	lockMaintainer := initializeLockMaintainer(logger, auctioneerServiceClient, port)
	registrationRunner := initializeRegistrationRunner(logger, consulClient, clock, port)

	members := grouper.Members{
		{"lock-maintainer", lockMaintainer},
		{"auction-runner", auctionRunner},
		{"auction-server", auctionServer},
		{"registration-runner", registrationRunner},
	}

	if dbgAddr := debugserver.DebugAddress(flag.CommandLine); dbgAddr != "" {
		members = append(grouper.Members{
			{"debug-server", debugserver.Runner(dbgAddr, reconfigurableSink)},
		}, members...)
	}

	group := grouper.NewOrdered(os.Interrupt, members)

	monitor := ifrit.Invoke(sigmon.New(group))

	logger.Info("started")

	err = <-monitor.Wait()
	if err != nil {
		logger.Error("exited-with-failure", err)
		os.Exit(1)
	}

	logger.Info("exited")
}

func initializeAuctionRunner(logger lager.Logger, cellStateTimeout time.Duration, bbsClient bbs.InternalClient, startingContainerWeight float64) auctiontypes.AuctionRunner {
	httpClient := cf_http.NewClient()
	stateClient := cf_http.NewCustomTimeoutClient(cellStateTimeout)
	repClientFactory := rep.NewClientFactory(httpClient, stateClient)

	delegate := auctionrunnerdelegate.New(repClientFactory, bbsClient, logger)
	metricEmitter := auctionmetricemitterdelegate.New()
	workPool, err := workpool.NewWorkPool(*auctionRunnerWorkers)
	if err != nil {
		logger.Fatal("failed-to-construct-auction-runner-workpool", err, lager.Data{"num-workers": *auctionRunnerWorkers}) // should never happen
	}

	return auctionrunner.New(
		logger,
		delegate,
		metricEmitter,
		clock.NewClock(),
		workPool,
		startingContainerWeight,
	)
}

func initializeDropsonde(logger lager.Logger) {
	dropsondeDestination := fmt.Sprint("localhost:", *dropsondePort)
	err := dropsonde.Initialize(dropsondeDestination, dropsondeOrigin)
	if err != nil {
		logger.Error("failed to initialize dropsonde: %v", err)
	}
}

func initializeAuctionServer(logger lager.Logger, runner auctiontypes.AuctionRunner) ifrit.Runner {
	return http_server.New(*listenAddr, handlers.New(runner, logger))
}

func initializeRegistrationRunner(logger lager.Logger, consulClient consuladapter.Client, clock clock.Clock, port int) ifrit.Runner {
	registration := &api.AgentServiceRegistration{
		Name: "auctioneer",
		Port: port,
		Check: &api.AgentServiceCheck{
			TTL: "3s",
		},
	}
	return locket.NewRegistrationRunner(logger, registration, consulClient, locket.RetryInterval, clock)
}

func initializeLockMaintainer(logger lager.Logger, serviceClient auctioneer.ServiceClient, port int) ifrit.Runner {
	uuid, err := uuid.NewV4()
	if err != nil {
		logger.Fatal("Couldn't generate uuid", err)
	}

	localIP, err := localip.LocalIP()
	if err != nil {
		logger.Fatal("Couldn't determine local IP", err)
	}

	address := fmt.Sprintf("%s://%s:%d", serverProtocol, localIP, port)
	auctioneerPresence := auctioneer.NewPresence(uuid.String(), address)

	lockMaintainer, err := serviceClient.NewAuctioneerLockRunner(logger, auctioneerPresence, *lockRetryInterval, *lockTTL)
	if err != nil {
		logger.Fatal("Couldn't create lock maintainer", err)
	}

	return lockMaintainer
}

func validateBBSAddress() error {
	if *bbsAddress == "" {
		return errors.New("bbsAddress is required")
	}
	return nil
}

func initializeBBSClient(logger lager.Logger) bbs.InternalClient {
	bbsURL, err := url.Parse(*bbsAddress)
	if err != nil {
		logger.Fatal("Invalid BBS URL", err)
	}

	if bbsURL.Scheme != "https" {
		return bbs.NewClient(*bbsAddress)
	}

	bbsClient, err := bbs.NewSecureClient(*bbsAddress, *bbsCACert, *bbsClientCert, *bbsClientKey, *bbsClientSessionCacheSize, *bbsMaxIdleConnsPerHost)
	if err != nil {
		logger.Fatal("Failed to configure secure BBS client", err)
	}
	return bbsClient
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes 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 cmd

import (
	"os"
	"path/filepath"

	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"k8s.io/release/pkg/log"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:     "krel",
	Short:   "krel",
	PreRunE: initLogging,
}

type rootOptions struct {
	nomock   bool
	cleanup  bool
	repoPath string
	logLevel string
}

var rootOpts = &rootOptions{}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := rootCmd.Execute(); err != nil {
		logrus.Fatal(err)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	rootCmd.PersistentFlags().BoolVar(&rootOpts.nomock, "nomock", false, "nomock flag")
	rootCmd.PersistentFlags().BoolVar(&rootOpts.cleanup, "cleanup", false, "cleanup flag")
	rootCmd.PersistentFlags().StringVar(&rootOpts.repoPath, "repo", filepath.Join(os.TempDir(), "k8s"), "the local path to the repository to be used")
	rootCmd.PersistentFlags().StringVar(&rootOpts.logLevel, "log-level", "info", "the logging verbosity, either 'panic', 'fatal', 'error', 'warn', 'warning', 'info', 'debug' or 'trace'")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
}

func initLogging(*cobra.Command, []string) error {
	logrus.SetFormatter(&logrus.TextFormatter{DisableTimestamp: true})
	lvl, err := logrus.ParseLevel(rootOpts.logLevel)
	if err != nil {
		return err
	}
	logrus.SetLevel(lvl)
	logrus.AddHook(log.NewFilenameHook())
	logrus.Debugf("Using log level %q", lvl)
	return nil
}
<commit_msg>Make log setup available to sub commands<commit_after>/*
Copyright 2019 The Kubernetes 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 cmd

import (
	"os"
	"path/filepath"

	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"k8s.io/release/pkg/log"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:               "krel",
	Short:             "krel",
	PersistentPreRunE: initLogging,
}

type rootOptions struct {
	nomock   bool
	cleanup  bool
	repoPath string
	logLevel string
}

var rootOpts = &rootOptions{}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := rootCmd.Execute(); err != nil {
		logrus.Fatal(err)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	rootCmd.PersistentFlags().BoolVar(&rootOpts.nomock, "nomock", false, "nomock flag")
	rootCmd.PersistentFlags().BoolVar(&rootOpts.cleanup, "cleanup", false, "cleanup flag")
	rootCmd.PersistentFlags().StringVar(&rootOpts.repoPath, "repo", filepath.Join(os.TempDir(), "k8s"), "the local path to the repository to be used")
	rootCmd.PersistentFlags().StringVar(&rootOpts.logLevel, "log-level", "info", "the logging verbosity, either 'panic', 'fatal', 'error', 'warn', 'warning', 'info', 'debug' or 'trace'")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
}

func initLogging(*cobra.Command, []string) error {
	logrus.SetFormatter(&logrus.TextFormatter{DisableTimestamp: true})
	lvl, err := logrus.ParseLevel(rootOpts.logLevel)
	if err != nil {
		return err
	}
	logrus.SetLevel(lvl)
	logrus.AddHook(log.NewFilenameHook())
	logrus.Debugf("Using log level %q", lvl)
	return nil
}
<|endoftext|>


<commit_before>package entrypoint

import (
	"context"
	"encoding/json"
	"fmt"
	"os/exec"
	"reflect"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/datawire/ambassador/cmd/ambex"
	amb "github.com/datawire/ambassador/pkg/api/getambassador.io/v2"
	"github.com/datawire/ambassador/pkg/consulwatch"
	"github.com/datawire/ambassador/pkg/kates"
	"github.com/datawire/ambassador/pkg/snapshot/v1"
	"github.com/datawire/dlib/dgroup"

	bootstrap "github.com/datawire/ambassador/pkg/api/envoy/config/bootstrap/v2"
)

// The Fake struct is a test harness for edgestack. Its goals are to help us fill out our test
// pyramid by making it super easy to create unit-like tests directly from the snapshots, bug
// reports, and other inputs provided by users who find regressions and/or encounter other problems
// in the field. Since we have no shortage of these reports, if we make it easy to create tests from
// them, we will fill out our test pyramid quickly and hopefully reduce our rate of
// regressions. This also means the tests produced this way need to scale well both in terms of
// execution time/parallelism as well as flakiness since we will quickly have a large number of
// these tests.
//
// The way this works is by isolating via dependency injection the key portions of the control plane
// where the bulk of our business logic is implemented. The Fake utilities directly feed this
// lightweight control plane its input as specified by the test code without passing the resources
// all the way through a real kubernetes API server and/or a real consul deployment. This is not
// only significantly more efficient than spinning up real kubernetes and/or consul deployments, but
// it also lets us precisely control the order of events thereby a) removing the nondeterminism that
// leads to flaky tests, and b) also allowing us to deliberately create/recreate the sort of low
// probability sequence of events that are often at the root of heisenbugs.
//
// The key to being able to build tests this way is expressing our business logic as "hermetically
// sealed" libraries, i.e. libraries with no/few hardcoded dependencies. This doesn't have to be
// done in a fancy/elegant way, it is well worth practicing "stupidly mechanical dependency
// injection" in order to quickly excise some business logic of its hardcoded dependencies and
// enable this sort of testing.
//
// See TestFakeHello, TestFakeHelloWithEnvoyConfig, and TestFakeHelloConsul for examples of how to
// get started using this struct to write tests.
type Fake struct {
	// These are all read only fields. They implement the dependencies that get injected into
	// the watcher loop.
	config FakeConfig
	T      *testing.T
	group  *dgroup.Group
	cancel context.CancelFunc

	k8sSource       *fakeK8sSource
	watcher         *fakeWatcher
	istioCertSource *fakeIstioCertSource
	// This group of fields are used to store kubernetes resources and consul endpoint data and
	// provide explicit control over when changes to that data are sent to the control plane.
	k8sStore       *K8sStore
	consulStore    *ConsulStore
	k8sNotifier    *Notifier
	consulNotifier *Notifier

	// This holds the current snapshot.
	currentSnapshot *atomic.Value

	snapshots    *Queue // All snapshots that have been produced.
	envoyConfigs *Queue // All envoyConfigs that have been produced.

	// This is used to make Teardown idempotent.
	teardownOnce sync.Once
}

// FakeConfig provides option when constructing a new Fake.
type FakeConfig struct {
	EnvoyConfig bool          // If true then the Fake will produce envoy configs in addition to Snapshots.
	DiagdDebug  bool          // If true then diagd will have debugging enabled
	Timeout     time.Duration // How long to wait for snapshots and/or envoy configs to become available.
}

func (fc *FakeConfig) fillDefaults() {
	if fc.Timeout == 0 {
		fc.Timeout = 10 * time.Second
	}
}

// NewFake will construct a new Fake object. See RunFake for a convenient way to handle construct,
// Setup, and Teardown of a Fake with one line of code.
func NewFake(t *testing.T, config FakeConfig) *Fake {
	config.fillDefaults()
	ctx, cancel := context.WithCancel(context.Background())
	k8sStore := NewK8sStore()
	consulStore := NewConsulStore()

	fake := &Fake{
		config: config,
		T:      t,
		cancel: cancel,
		group:  dgroup.NewGroup(ctx, dgroup.GroupConfig{EnableWithSoftness: true}),

		k8sStore:       k8sStore,
		consulStore:    consulStore,
		k8sNotifier:    NewNotifier(),
		consulNotifier: NewNotifier(),

		currentSnapshot: &atomic.Value{},

		snapshots:    NewQueue(t, config.Timeout),
		envoyConfigs: NewQueue(t, config.Timeout),
	}

	fake.k8sSource = &fakeK8sSource{fake: fake, store: k8sStore}
	fake.watcher = &fakeWatcher{fake: fake, store: consulStore}
	fake.istioCertSource = &fakeIstioCertSource{}

	return fake
}

// RunFake will create a new fake, invoke its Setup method and register its Teardown method as a
// Cleanup function with the test object.
func RunFake(t *testing.T, config FakeConfig) *Fake {
	fake := NewFake(t, config)
	fake.Setup()
	fake.T.Cleanup(fake.Teardown)
	return fake
}

// Setup will start up all the goroutines needed for this fake edgestack instance. Depending on the
// FakeConfig supplied wen constructing the Fake, this may also involve launching external
// processes, you should therefore ensure that you call Teardown whenever you call Setup.
func (f *Fake) Setup() {
	if f.config.EnvoyConfig {
		_, err := exec.LookPath("diagd")
		if err != nil {
			f.T.Skip("unable to find diagd, cannot run")
		}

		f.group.Go("snapshot_server", func(ctx context.Context) error {
			return snapshotServer(ctx, f.currentSnapshot)
		})

		f.group.Go("diagd", func(ctx context.Context) error {
			cmdArgs := []string{
				"/tmp", "/tmp/bootstrap-ads.json", "/tmp/envoy.json",
				"--no-envoy", "--host", "127.0.0.1", "--port", GetDiagdBindPort(),
			}

			if f.config.DiagdDebug {
				cmdArgs = append(cmdArgs, "--debug")
			}

			cmd := subcommand(ctx, "diagd", cmdArgs...)
			if envbool("DEV_SHUTUP_DIAGD") {
				cmd.Stdout = nil
				cmd.Stderr = nil
			}
			return cmd.Run()
		})
	}
	f.group.Go("fake-watcher", f.runWatcher)

}

// Teardown will clean up anything that Setup has started. It is idempotent. Note that if you use
// RunFake Setup will be called and Teardown will be automatically registered as a Cleanup function
// with the supplied testing.T
func (f *Fake) Teardown() {
	f.teardownOnce.Do(func() {
		f.cancel()
		err := f.group.Wait()
		if err != nil && err != context.Canceled {
			f.T.Fatalf("fake edgestack errored out: %+v", err)
		}
	})
}

func (f *Fake) runWatcher(ctx context.Context) error {
	interestingTypes := GetInterestingTypes(ctx, nil)
	queries := GetQueries(ctx, interestingTypes)

	var err error
	defer func() {
		r := recover()
		if r != nil {
			err = r.(error)
		}
	}()
	watcherLoop(ctx, f.currentSnapshot, f.k8sSource, queries, f.watcher, f.istioCertSource, f.notifySnapshot)
	return err
}

// We pass this into the watcher loop to get notified when a snapshot is produced.
func (f *Fake) notifySnapshot(ctx context.Context) {
	if f.config.EnvoyConfig {
		notifyReconfigWebhooksFunc(ctx, &noopNotable{}, false)
		f.appendEnvoyConfig()
	}

	f.appendSnapshot()
}

func (f *Fake) appendSnapshot() {
	snapshotBytes := f.currentSnapshot.Load().([]byte)
	var snap *snapshot.Snapshot
	err := json.Unmarshal(snapshotBytes, &snap)
	if err != nil {
		f.T.Fatalf("error unmarshalling snapshot: %+v", err)
	}

	f.snapshots.Add(snap)
}

// GetSnapshot will return the next snapshot that satisfies the supplied predicate.
func (f *Fake) GetSnapshot(predicate func(*snapshot.Snapshot) bool) *snapshot.Snapshot {
	return f.snapshots.Get(func(obj interface{}) bool {
		return predicate(obj.(*snapshot.Snapshot))
	}).(*snapshot.Snapshot)
}

func (f *Fake) appendEnvoyConfig() {
	msg, err := ambex.Decode("/tmp/envoy.json")
	if err != nil {
		f.T.Fatalf("error decoding envoy.json after sending snapshot to python: %+v", err)
	}
	bs := msg.(*bootstrap.Bootstrap)
	f.envoyConfigs.Add(bs)
}

// GetEnvoyConfig will return the next envoy config that satisfies the supplied predicate.
func (f *Fake) GetEnvoyConfig(predicate func(*bootstrap.Bootstrap) bool) *bootstrap.Bootstrap {
	return f.envoyConfigs.Get(func(obj interface{}) bool {
		return predicate(obj.(*bootstrap.Bootstrap))
	}).(*bootstrap.Bootstrap)
}

// AutoFlush will cause a flush whenever any inputs are modified.
func (f *Fake) AutoFlush(enabled bool) {
	f.k8sNotifier.AutoNotify(enabled)
	f.consulNotifier.AutoNotify(enabled)
}

// Feed will cause inputs from all datasources to be delivered to the control plane.
func (f *Fake) Flush() {
	f.k8sNotifier.Notify()
	f.consulNotifier.Notify()
}

// UpsertFile will parse the contents of the file as yaml and feed them into the control plane
// created or updating any overlapping resources that exist.
func (f *Fake) UpsertFile(filename string) {
	f.k8sStore.UpsertFile(filename)
	f.k8sNotifier.Changed()
}

// UpsertYAML will parse the provided YAML and feed the resources in it into the control plane,
// creating or updating any overlapping resources that exist.
func (f *Fake) UpsertYAML(yaml string) {
	f.k8sStore.UpsertYAML(yaml)
	f.k8sNotifier.Changed()
}

// Upsert will update (or if necessary create) the supplied resource in the fake k8s datastore.
func (f *Fake) Upsert(resource kates.Object) {
	f.k8sStore.Upsert(resource)
	f.k8sNotifier.Changed()
}

// Delete will removes the specified resource from the fake k8s datastore.
func (f *Fake) Delete(kind, namespace, name string) {
	f.k8sStore.Delete(kind, namespace, name)
	f.k8sNotifier.Changed()
}

// ConsulEndpoint stores the supplied consul endpoint data.
func (f *Fake) ConsulEndpoint(datacenter, service, address string, port int, tags ...string) {
	f.consulStore.ConsulEndpoint(datacenter, service, address, port, tags...)
	f.consulNotifier.Changed()
}

// SendIstioCertUpdate sends the supplied Istio certificate update.
func (f *Fake) SendIstioCertUpdate(update IstioCertUpdate) {
	f.istioCertSource.updateChannel <- update
}

type fakeK8sSource struct {
	fake  *Fake
	store *K8sStore
}

func (fs *fakeK8sSource) Watch(ctx context.Context, queries ...kates.Query) K8sWatcher {
	fw := &fakeK8sWatcher{fs.store.Cursor(), make(chan struct{}), queries}
	fs.fake.k8sNotifier.Listen(func() {
		go func() {
			fw.notifyCh <- struct{}{}
		}()
	})
	return fw
}

type fakeK8sWatcher struct {
	cursor   *K8sStoreCursor
	notifyCh chan struct{}
	queries  []kates.Query
}

func (f *fakeK8sWatcher) Changed() chan struct{} {
	return f.notifyCh
}

func (f *fakeK8sWatcher) FilteredUpdate(target interface{}, deltas *[]*kates.Delta, predicate func(*kates.Unstructured) bool) bool {
	byname := map[string][]kates.Object{}
	resources, newDeltas := f.cursor.Get()
	for _, obj := range resources {
		for _, q := range f.queries {
			var un *kates.Unstructured
			err := convert(obj, &un)
			if err != nil {
				panic(err)
			}
			if matches(q, obj) && predicate(un) {
				byname[q.Name] = append(byname[q.Name], obj)
			}
		}
	}

	// XXX: this stuff is copied from kates/accumulator.go
	targetVal := reflect.ValueOf(target)
	targetType := targetVal.Type().Elem()
	for name, v := range byname {
		fieldEntry, ok := targetType.FieldByName(name)
		if !ok {
			panic(fmt.Sprintf("no such field: %q", name))
		}
		val := reflect.New(fieldEntry.Type)
		err := convert(v, val.Interface())
		if err != nil {
			panic(err)
		}
		targetVal.Elem().FieldByName(name).Set(reflect.Indirect(val))
	}

	*deltas = newDeltas

	return len(newDeltas) > 0
}

func matches(query kates.Query, obj kates.Object) bool {
	kind := canon(query.Kind)
	gvk := obj.GetObjectKind().GroupVersionKind()
	return kind == canon(gvk.Kind)
}

type fakeWatcher struct {
	fake  *Fake
	store *ConsulStore
}

func (f *fakeWatcher) Watch(resolver *amb.ConsulResolver, mapping *amb.Mapping, endpoints chan consulwatch.Endpoints) Stopper {
	var sent consulwatch.Endpoints
	stop := f.fake.consulNotifier.Listen(func() {
		ep, ok := f.store.Get(resolver.Spec.Datacenter, mapping.Spec.Service)
		if ok && !reflect.DeepEqual(ep, sent) {
			endpoints <- ep
			sent = ep
		}
	})
	return &fakeStopper{stop}
}

type fakeStopper struct {
	stop StopFunc
}

func (f *fakeStopper) Stop() {
	f.stop()
}

type fakeIstioCertSource struct {
	updateChannel chan IstioCertUpdate
}

func (src *fakeIstioCertSource) Watch(ctx context.Context) IstioCertWatcher {
	src.updateChannel = make(chan IstioCertUpdate)

	return &istioCertWatcher{
		updateChannel: src.updateChannel,
	}
}
<commit_msg>(from AES) don't fail if diagd exits with an error code<commit_after>package entrypoint

import (
	"context"
	"encoding/json"
	"fmt"
	"os/exec"
	"reflect"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/datawire/ambassador/cmd/ambex"
	amb "github.com/datawire/ambassador/pkg/api/getambassador.io/v2"
	"github.com/datawire/ambassador/pkg/consulwatch"
	"github.com/datawire/ambassador/pkg/kates"
	"github.com/datawire/ambassador/pkg/snapshot/v1"
	"github.com/datawire/dlib/dgroup"

	bootstrap "github.com/datawire/ambassador/pkg/api/envoy/config/bootstrap/v2"
)

// The Fake struct is a test harness for edgestack. Its goals are to help us fill out our test
// pyramid by making it super easy to create unit-like tests directly from the snapshots, bug
// reports, and other inputs provided by users who find regressions and/or encounter other problems
// in the field. Since we have no shortage of these reports, if we make it easy to create tests from
// them, we will fill out our test pyramid quickly and hopefully reduce our rate of
// regressions. This also means the tests produced this way need to scale well both in terms of
// execution time/parallelism as well as flakiness since we will quickly have a large number of
// these tests.
//
// The way this works is by isolating via dependency injection the key portions of the control plane
// where the bulk of our business logic is implemented. The Fake utilities directly feed this
// lightweight control plane its input as specified by the test code without passing the resources
// all the way through a real kubernetes API server and/or a real consul deployment. This is not
// only significantly more efficient than spinning up real kubernetes and/or consul deployments, but
// it also lets us precisely control the order of events thereby a) removing the nondeterminism that
// leads to flaky tests, and b) also allowing us to deliberately create/recreate the sort of low
// probability sequence of events that are often at the root of heisenbugs.
//
// The key to being able to build tests this way is expressing our business logic as "hermetically
// sealed" libraries, i.e. libraries with no/few hardcoded dependencies. This doesn't have to be
// done in a fancy/elegant way, it is well worth practicing "stupidly mechanical dependency
// injection" in order to quickly excise some business logic of its hardcoded dependencies and
// enable this sort of testing.
//
// See TestFakeHello, TestFakeHelloWithEnvoyConfig, and TestFakeHelloConsul for examples of how to
// get started using this struct to write tests.
type Fake struct {
	// These are all read only fields. They implement the dependencies that get injected into
	// the watcher loop.
	config FakeConfig
	T      *testing.T
	group  *dgroup.Group
	cancel context.CancelFunc

	k8sSource       *fakeK8sSource
	watcher         *fakeWatcher
	istioCertSource *fakeIstioCertSource
	// This group of fields are used to store kubernetes resources and consul endpoint data and
	// provide explicit control over when changes to that data are sent to the control plane.
	k8sStore       *K8sStore
	consulStore    *ConsulStore
	k8sNotifier    *Notifier
	consulNotifier *Notifier

	// This holds the current snapshot.
	currentSnapshot *atomic.Value

	snapshots    *Queue // All snapshots that have been produced.
	envoyConfigs *Queue // All envoyConfigs that have been produced.

	// This is used to make Teardown idempotent.
	teardownOnce sync.Once
}

// FakeConfig provides option when constructing a new Fake.
type FakeConfig struct {
	EnvoyConfig bool          // If true then the Fake will produce envoy configs in addition to Snapshots.
	DiagdDebug  bool          // If true then diagd will have debugging enabled
	Timeout     time.Duration // How long to wait for snapshots and/or envoy configs to become available.
}

func (fc *FakeConfig) fillDefaults() {
	if fc.Timeout == 0 {
		fc.Timeout = 10 * time.Second
	}
}

// NewFake will construct a new Fake object. See RunFake for a convenient way to handle construct,
// Setup, and Teardown of a Fake with one line of code.
func NewFake(t *testing.T, config FakeConfig) *Fake {
	config.fillDefaults()
	ctx, cancel := context.WithCancel(context.Background())
	k8sStore := NewK8sStore()
	consulStore := NewConsulStore()

	fake := &Fake{
		config: config,
		T:      t,
		cancel: cancel,
		group:  dgroup.NewGroup(ctx, dgroup.GroupConfig{EnableWithSoftness: true}),

		k8sStore:       k8sStore,
		consulStore:    consulStore,
		k8sNotifier:    NewNotifier(),
		consulNotifier: NewNotifier(),

		currentSnapshot: &atomic.Value{},

		snapshots:    NewQueue(t, config.Timeout),
		envoyConfigs: NewQueue(t, config.Timeout),
	}

	fake.k8sSource = &fakeK8sSource{fake: fake, store: k8sStore}
	fake.watcher = &fakeWatcher{fake: fake, store: consulStore}
	fake.istioCertSource = &fakeIstioCertSource{}

	return fake
}

// RunFake will create a new fake, invoke its Setup method and register its Teardown method as a
// Cleanup function with the test object.
func RunFake(t *testing.T, config FakeConfig) *Fake {
	fake := NewFake(t, config)
	fake.Setup()
	fake.T.Cleanup(fake.Teardown)
	return fake
}

// Setup will start up all the goroutines needed for this fake edgestack instance. Depending on the
// FakeConfig supplied wen constructing the Fake, this may also involve launching external
// processes, you should therefore ensure that you call Teardown whenever you call Setup.
func (f *Fake) Setup() {
	if f.config.EnvoyConfig {
		_, err := exec.LookPath("diagd")
		if err != nil {
			f.T.Skip("unable to find diagd, cannot run")
		}

		f.group.Go("snapshot_server", func(ctx context.Context) error {
			return snapshotServer(ctx, f.currentSnapshot)
		})

		f.group.Go("diagd", func(ctx context.Context) error {
			cmdArgs := []string{
				"/tmp", "/tmp/bootstrap-ads.json", "/tmp/envoy.json",
				"--no-envoy", "--host", "127.0.0.1", "--port", GetDiagdBindPort(),
			}

			if f.config.DiagdDebug {
				cmdArgs = append(cmdArgs, "--debug")
			}

			cmd := subcommand(ctx, "diagd", cmdArgs...)
			if envbool("DEV_SHUTUP_DIAGD") {
				cmd.Stdout = nil
				cmd.Stderr = nil
			}
			err := cmd.Run()
			if err != nil {
				exErr, ok := err.(*exec.ExitError)
				if ok {
					f.T.Logf("diagd exited with error: %+v", exErr)
					return nil
				}
			}
			return err
		})
	}
	f.group.Go("fake-watcher", f.runWatcher)

}

// Teardown will clean up anything that Setup has started. It is idempotent. Note that if you use
// RunFake Setup will be called and Teardown will be automatically registered as a Cleanup function
// with the supplied testing.T
func (f *Fake) Teardown() {
	f.teardownOnce.Do(func() {
		f.cancel()
		err := f.group.Wait()
		if err != nil && err != context.Canceled {
			f.T.Fatalf("fake edgestack errored out: %+v", err)
		}
	})
}

func (f *Fake) runWatcher(ctx context.Context) error {
	interestingTypes := GetInterestingTypes(ctx, nil)
	queries := GetQueries(ctx, interestingTypes)

	var err error
	defer func() {
		r := recover()
		if r != nil {
			err = r.(error)
		}
	}()
	watcherLoop(ctx, f.currentSnapshot, f.k8sSource, queries, f.watcher, f.istioCertSource, f.notifySnapshot)
	return err
}

// We pass this into the watcher loop to get notified when a snapshot is produced.
func (f *Fake) notifySnapshot(ctx context.Context) {
	if f.config.EnvoyConfig {
		notifyReconfigWebhooksFunc(ctx, &noopNotable{}, false)
		f.appendEnvoyConfig()
	}

	f.appendSnapshot()
}

func (f *Fake) appendSnapshot() {
	snapshotBytes := f.currentSnapshot.Load().([]byte)
	var snap *snapshot.Snapshot
	err := json.Unmarshal(snapshotBytes, &snap)
	if err != nil {
		f.T.Fatalf("error unmarshalling snapshot: %+v", err)
	}

	f.snapshots.Add(snap)
}

// GetSnapshot will return the next snapshot that satisfies the supplied predicate.
func (f *Fake) GetSnapshot(predicate func(*snapshot.Snapshot) bool) *snapshot.Snapshot {
	return f.snapshots.Get(func(obj interface{}) bool {
		return predicate(obj.(*snapshot.Snapshot))
	}).(*snapshot.Snapshot)
}

func (f *Fake) appendEnvoyConfig() {
	msg, err := ambex.Decode("/tmp/envoy.json")
	if err != nil {
		f.T.Fatalf("error decoding envoy.json after sending snapshot to python: %+v", err)
	}
	bs := msg.(*bootstrap.Bootstrap)
	f.envoyConfigs.Add(bs)
}

// GetEnvoyConfig will return the next envoy config that satisfies the supplied predicate.
func (f *Fake) GetEnvoyConfig(predicate func(*bootstrap.Bootstrap) bool) *bootstrap.Bootstrap {
	return f.envoyConfigs.Get(func(obj interface{}) bool {
		return predicate(obj.(*bootstrap.Bootstrap))
	}).(*bootstrap.Bootstrap)
}

// AutoFlush will cause a flush whenever any inputs are modified.
func (f *Fake) AutoFlush(enabled bool) {
	f.k8sNotifier.AutoNotify(enabled)
	f.consulNotifier.AutoNotify(enabled)
}

// Feed will cause inputs from all datasources to be delivered to the control plane.
func (f *Fake) Flush() {
	f.k8sNotifier.Notify()
	f.consulNotifier.Notify()
}

// UpsertFile will parse the contents of the file as yaml and feed them into the control plane
// created or updating any overlapping resources that exist.
func (f *Fake) UpsertFile(filename string) {
	f.k8sStore.UpsertFile(filename)
	f.k8sNotifier.Changed()
}

// UpsertYAML will parse the provided YAML and feed the resources in it into the control plane,
// creating or updating any overlapping resources that exist.
func (f *Fake) UpsertYAML(yaml string) {
	f.k8sStore.UpsertYAML(yaml)
	f.k8sNotifier.Changed()
}

// Upsert will update (or if necessary create) the supplied resource in the fake k8s datastore.
func (f *Fake) Upsert(resource kates.Object) {
	f.k8sStore.Upsert(resource)
	f.k8sNotifier.Changed()
}

// Delete will removes the specified resource from the fake k8s datastore.
func (f *Fake) Delete(kind, namespace, name string) {
	f.k8sStore.Delete(kind, namespace, name)
	f.k8sNotifier.Changed()
}

// ConsulEndpoint stores the supplied consul endpoint data.
func (f *Fake) ConsulEndpoint(datacenter, service, address string, port int, tags ...string) {
	f.consulStore.ConsulEndpoint(datacenter, service, address, port, tags...)
	f.consulNotifier.Changed()
}

// SendIstioCertUpdate sends the supplied Istio certificate update.
func (f *Fake) SendIstioCertUpdate(update IstioCertUpdate) {
	f.istioCertSource.updateChannel <- update
}

type fakeK8sSource struct {
	fake  *Fake
	store *K8sStore
}

func (fs *fakeK8sSource) Watch(ctx context.Context, queries ...kates.Query) K8sWatcher {
	fw := &fakeK8sWatcher{fs.store.Cursor(), make(chan struct{}), queries}
	fs.fake.k8sNotifier.Listen(func() {
		go func() {
			fw.notifyCh <- struct{}{}
		}()
	})
	return fw
}

type fakeK8sWatcher struct {
	cursor   *K8sStoreCursor
	notifyCh chan struct{}
	queries  []kates.Query
}

func (f *fakeK8sWatcher) Changed() chan struct{} {
	return f.notifyCh
}

func (f *fakeK8sWatcher) FilteredUpdate(target interface{}, deltas *[]*kates.Delta, predicate func(*kates.Unstructured) bool) bool {
	byname := map[string][]kates.Object{}
	resources, newDeltas := f.cursor.Get()
	for _, obj := range resources {
		for _, q := range f.queries {
			var un *kates.Unstructured
			err := convert(obj, &un)
			if err != nil {
				panic(err)
			}
			if matches(q, obj) && predicate(un) {
				byname[q.Name] = append(byname[q.Name], obj)
			}
		}
	}

	// XXX: this stuff is copied from kates/accumulator.go
	targetVal := reflect.ValueOf(target)
	targetType := targetVal.Type().Elem()
	for name, v := range byname {
		fieldEntry, ok := targetType.FieldByName(name)
		if !ok {
			panic(fmt.Sprintf("no such field: %q", name))
		}
		val := reflect.New(fieldEntry.Type)
		err := convert(v, val.Interface())
		if err != nil {
			panic(err)
		}
		targetVal.Elem().FieldByName(name).Set(reflect.Indirect(val))
	}

	*deltas = newDeltas

	return len(newDeltas) > 0
}

func matches(query kates.Query, obj kates.Object) bool {
	kind := canon(query.Kind)
	gvk := obj.GetObjectKind().GroupVersionKind()
	return kind == canon(gvk.Kind)
}

type fakeWatcher struct {
	fake  *Fake
	store *ConsulStore
}

func (f *fakeWatcher) Watch(resolver *amb.ConsulResolver, mapping *amb.Mapping, endpoints chan consulwatch.Endpoints) Stopper {
	var sent consulwatch.Endpoints
	stop := f.fake.consulNotifier.Listen(func() {
		ep, ok := f.store.Get(resolver.Spec.Datacenter, mapping.Spec.Service)
		if ok && !reflect.DeepEqual(ep, sent) {
			endpoints <- ep
			sent = ep
		}
	})
	return &fakeStopper{stop}
}

type fakeStopper struct {
	stop StopFunc
}

func (f *fakeStopper) Stop() {
	f.stop()
}

type fakeIstioCertSource struct {
	updateChannel chan IstioCertUpdate
}

func (src *fakeIstioCertSource) Watch(ctx context.Context) IstioCertWatcher {
	src.updateChannel = make(chan IstioCertUpdate)

	return &istioCertWatcher{
		updateChannel: src.updateChannel,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.internal.digitalocean.com/bknox/logtalez"
)

func main() {

	endpointsPtr := flag.String("endpoints", "", "comma delimited list of zeromq endpoints")
	hostsPtr := flag.String("hosts", "", "comma delimited list of hostnames to get logs from")
	programsPtr := flag.String("programs", "", "comma delimited list of programs to get logs from")
	serverCertPathPtr := flag.String("servercertpath", "", "path to server public cert")
	clientCertPathPtr := flag.String("clientcertpath", "", "path to client public cert")

	flag.Parse()

	if *endpointsPtr == "" {
		log.Fatal("--endpoints is mandatory")
	}

	if *serverCertPathPtr == "" {
		log.Fatal("--servercertpath is mandatory")
	}

	if *clientCertPathPtr == "" {
		log.Fatal("--clientcertpath is mandatory")
	}

	topicList := logtalez.MakeTopicList(*hostsPtr, *programsPtr)
	endpointList := logtalez.MakeEndpointList(*endpointsPtr)

	lt, err := logtalez.New(endpointList, topicList, *serverCertPathPtr, *clientCertPathPtr)
	if err != nil {
		log.Fatal(err)
	}

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, os.Kill)

	for {
		select {
		case msg := <-lt.TailChan:
			logline := strings.Split(string(msg[0]), "@cee:")[1]
			fmt.Println(logline)
		case <-sigChan:
			lt.Destroy()
			time.Sleep(100 * time.Millisecond)
			os.Exit(0)
		}
	}
}
<commit_msg>replacing older import path<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/digitalocean/logtalez"
)

func main() {

	endpointsPtr := flag.String("endpoints", "", "comma delimited list of zeromq endpoints")
	hostsPtr := flag.String("hosts", "", "comma delimited list of hostnames to get logs from")
	programsPtr := flag.String("programs", "", "comma delimited list of programs to get logs from")
	serverCertPathPtr := flag.String("servercertpath", "", "path to server public cert")
	clientCertPathPtr := flag.String("clientcertpath", "", "path to client public cert")

	flag.Parse()

	if *endpointsPtr == "" {
		log.Fatal("--endpoints is mandatory")
	}

	if *serverCertPathPtr == "" {
		log.Fatal("--servercertpath is mandatory")
	}

	if *clientCertPathPtr == "" {
		log.Fatal("--clientcertpath is mandatory")
	}

	topicList := logtalez.MakeTopicList(*hostsPtr, *programsPtr)
	endpointList := logtalez.MakeEndpointList(*endpointsPtr)

	lt, err := logtalez.New(endpointList, topicList, *serverCertPathPtr, *clientCertPathPtr)
	if err != nil {
		log.Fatal(err)
	}

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, os.Kill)

	for {
		select {
		case msg := <-lt.TailChan:
			logline := strings.Split(string(msg[0]), "@cee:")[1]
			fmt.Println(logline)
		case <-sigChan:
			lt.Destroy()
			time.Sleep(100 * time.Millisecond)
			os.Exit(0)
		}
	}
}
<|endoftext|>


<commit_before>// Command line interface to ping ports
package main

import (
	"flag"
	"fmt"
	"os"
	"github.com/janosgyerik/portping"
	"net"
	"time"
)

// TODO
// flags: --tcp, --udp; default is tcp
// flag: -W timeout
// flag: -v verbose; default=false
// drop default count, print forever, until cancel with Control-C, and print stats

const (
	defaultCount = 5
	defaultTimeout = 10 * time.Second
	defaultNetwork = "tcp"
)

func exit() {
	flag.Usage()
	os.Exit(1)
}

type Params struct {
	host  string
	port  string
	count int
}

func parseArgs() Params {
	flag.Usage = func() {
		fmt.Printf("Usage: %s [options] host port\n\n", os.Args[0])
		flag.PrintDefaults()
	}

	countPtr := flag.Int("c", defaultCount, "stop after count connections")
	flag.Parse()

	if len(flag.Args()) < 2 {
		exit()
	}

	host := flag.Args()[0]
	port := flag.Args()[1]

	return Params{
		host: host,
		port: port,
		count: *countPtr,
	}
}

// FormatResult converts the result returned by Ping to string.
func formatResult(err error) string {
	if err == nil {
		return "success"
	}
	switch err := err.(type) {
	case *net.OpError:
		return err.Err.Error()
	default:
		return err.Error()
	}
}

func main() {
	params := parseArgs()

	host := params.host
	port := params.port
	count := params.count

	addr := net.JoinHostPort(host, port)
	fmt.Printf("Starting to ping %s ...\n", addr)

	c := make(chan error)
	go portping.PingN(defaultNetwork, addr, defaultTimeout, count, c)

	allSuccessful := true

	for i := 0; i < count; i++ {
		// TODO add time
		err := <-c
		if err != nil {
			allSuccessful = false
		}
		fmt.Printf("%s [%d] -> %s\n", addr, i + 1, formatResult(err))
	}

	// TODO print summary
	// --- host:port ping statistics ---
	// n connections attempted, m successful, x% failed
	// round-trip min/avg/max/stddev = a/b/c/d ms

	if !allSuccessful {
		os.Exit(1)
	}
}
<commit_msg>added -W flag for cli<commit_after>// Command line interface to ping ports
package main

import (
	"flag"
	"fmt"
	"os"
	"github.com/janosgyerik/portping"
	"net"
	"time"
)

// TODO
// flags: --tcp, --udp; default is tcp
// flag: -v verbose; default=false
// drop default count, print forever, until cancel with Control-C, and print stats

const (
	defaultCount = 5
	defaultTimeout = 10
	defaultNetwork = "tcp"
)

func exit() {
	flag.Usage()
	os.Exit(1)
}

type Params struct {
	host    string
	port    string
	count   int
	timeout time.Duration
}

func parseArgs() Params {
	flag.Usage = func() {
		fmt.Printf("Usage: %s [options] host port\n\n", os.Args[0])
		flag.PrintDefaults()
	}

	countPtr := flag.Int("c", defaultCount, "stop after count connections")
	timeoutPtr := flag.Int("W", defaultTimeout, "time in seconds to wait for connections")
	flag.Parse()

	if len(flag.Args()) < 2 {
		exit()
	}

	host := flag.Args()[0]
	port := flag.Args()[1]

	return Params{
		host: host,
		port: port,
		count: *countPtr,
		timeout: time.Duration(*timeoutPtr) * time.Second,
	}
}

// FormatResult converts the result returned by Ping to string.
func formatResult(err error) string {
	if err == nil {
		return "success"
	}
	switch err := err.(type) {
	case *net.OpError:
		return err.Err.Error()
	default:
		return err.Error()
	}
}

func main() {
	params := parseArgs()

	host := params.host
	port := params.port
	count := params.count

	addr := net.JoinHostPort(host, port)
	fmt.Printf("Starting to ping %s ...\n", addr)

	c := make(chan error)
	go portping.PingN(defaultNetwork, addr, params.timeout, count, c)

	allSuccessful := true

	for i := 0; i < count; i++ {
		// TODO add time
		err := <-c
		if err != nil {
			allSuccessful = false
		}
		fmt.Printf("%s [%d] -> %s\n", addr, i + 1, formatResult(err))
	}

	// TODO print summary
	// --- host:port ping statistics ---
	// n connections attempted, m successful, x% failed
	// round-trip min/avg/max/stddev = a/b/c/d ms

	if !allSuccessful {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"bytes"
	"context"
	"debug/dwarf"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"time"

	"github.com/tsavola/confi"
	"github.com/tsavola/gate/entry"
	"github.com/tsavola/gate/image"
	"github.com/tsavola/gate/runtime"
	"github.com/tsavola/gate/service"
	"github.com/tsavola/gate/service/origin"
	"github.com/tsavola/gate/service/plugin"
	"github.com/tsavola/wag/binding"
	"github.com/tsavola/wag/compile"
	"github.com/tsavola/wag/object/debug"
	"github.com/tsavola/wag/object/stack"
	"github.com/tsavola/wag/object/stack/stacktrace"
	"github.com/tsavola/wag/section"
	"github.com/tsavola/wag/wa"
)

const (
	DefaultMaxProcesses = 100
	DefaultStackSize    = wa.PageSize
)

type ProgramConfig struct {
	StackSize int
}

type timing struct {
	loading time.Duration
	running time.Duration
	overall time.Duration
}

var processPolicy = runtime.ProcessPolicy{
	TimeResolution: 1, // Best resolution.
	Debug:          os.Stderr,
}

func init() {
	log.SetFlags(0)
}

type Config struct {
	Runtime runtime.Config

	Plugin struct {
		LibDir string
	}

	Service map[string]interface{}

	Program ProgramConfig

	Function string

	Benchmark struct {
		Repeat int
		Timing bool
	}
}

var c = new(Config)

func parseConfig(flags *flag.FlagSet) {
	flags.Var(confi.FileReader(c), "f", "read TOML configuration file")
	flags.Var(confi.Assigner(c), "c", "set a configuration key (path.to.key=value)")
	flags.Parse(os.Args[1:])
}

func main() {
	c.Runtime.MaxProcesses = DefaultMaxProcesses
	c.Runtime.Cgroup.Title = runtime.DefaultCgroupTitle
	c.Plugin.LibDir = "lib/gate/plugin"
	c.Program.StackSize = DefaultStackSize
	c.Benchmark.Repeat = 1

	flags := flag.NewFlagSet("", flag.ContinueOnError)
	flags.SetOutput(ioutil.Discard)
	parseConfig(flags)

	plugins, err := plugin.OpenAll(c.Plugin.LibDir)
	if err != nil {
		log.Fatal(err)
	}

	c.Service = plugins.ServiceConfig

	originConfig := origin.Config{MaxConns: 1}
	c.Service["origin"] = &originConfig

	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] wasmfile...\n\nOptions:\n", flag.CommandLine.Name())
		flag.PrintDefaults()
	}
	flag.Usage = confi.FlagUsage(nil, c)
	parseConfig(flag.CommandLine)

	filenames := flag.Args()
	if len(filenames) == 0 {
		flag.Usage()
		os.Exit(2)
	}

	ctx := context.Background()

	serviceConfig := service.Config{
		Registry: new(service.Registry),
	}

	if err := plugins.InitServices(serviceConfig); err != nil {
		log.Fatal(err)
	}

	if c.Runtime.LibDir == "" {
		filename, err := os.Executable()
		if err != nil {
			log.Fatalf("%s: %v", os.Args[0], err)
		}

		c.Runtime.LibDir = path.Join(path.Dir(filename), "../lib/gate/runtime")
	}

	var execClosed bool

	executor, err := runtime.NewExecutor(ctx, &c.Runtime)
	if err != nil {
		log.Fatalf("runtime: %v", err)
	}
	defer func() {
		execClosed = true
		executor.Close()
	}()

	go func() {
		<-executor.Dead()
		if !execClosed {
			log.Fatal("executor died")
		}
	}()

	timings := make([]timing, len(filenames))
	exitCode := 0

	for round := 0; round < c.Benchmark.Repeat; round++ {
		var (
			execDone = make(chan int, len(filenames))
			ioDone   = make(chan struct{}, len(filenames))
		)

		for i, filename := range filenames {
			i := i
			filename := filename

			connector := origin.New(&originConfig)
			conn := connector.Connect(ctx)

			var input io.Reader = os.Stdin
			if i > 0 {
				input = bytes.NewReader(nil)
			}

			go func() {
				defer func() { ioDone <- struct{}{} }()
				if err := conn(ctx, input, os.Stdout); err != nil {
					log.Print(err)
				}
			}()

			r := serviceConfig.Registry.Clone()
			r.Register(connector)

			go func() {
				defer connector.Close()
				execute(ctx, executor, filename, r, &timings[i], execDone)
			}()
		}

		for range filenames {
			if n := <-execDone; n > exitCode {
				exitCode = n
			}
			<-ioDone
		}
	}

	if c.Benchmark.Timing {
		for i, filename := range filenames {
			output := func(title string, sum time.Duration) {
				avg := sum / time.Duration(c.Benchmark.Repeat)
				log.Printf("%s "+title+": %6d.%03dµs", filename, avg/time.Microsecond, avg%time.Microsecond)
			}

			output("loading time", timings[i].loading)
			output("running time", timings[i].running)
			output("overall time", timings[i].overall)
		}
	}

	if exitCode != 0 {
		os.Exit(exitCode)
	}
}

func execute(ctx context.Context, executor *runtime.Executor, filename string, services runtime.ServiceRegistry, timing *timing, done chan<- int) {
	var exit int

	defer func() {
		done <- exit
	}()

	tBegin := time.Now()

	proc, err := executor.NewProcess(ctx)
	if err != nil {
		log.Fatalf("process: %v", err)
	}
	defer proc.Kill()

	tLoadBegin := tBegin

	var im debug.InsnMap
	var ns = new(section.NameSection)
	var cs = new(section.CustomSections)

	funcSigs, prog, inst, err := load(filename, &im, ns, cs)
	if err != nil {
		log.Fatalf("load: %v", err)
	}
	defer prog.Close()
	defer inst.Close()

	tLoadEnd := time.Now()
	tRunBegin := tLoadEnd

	err = proc.Start(prog, inst, processPolicy)
	if err != nil {
		log.Fatalf("execute: %v", err)
	}

	exit, trapID, err := proc.Serve(ctx, services, nil)

	tRunEnd := time.Now()
	tEnd := tRunEnd

	if err != nil {
		defer os.Exit(1)
		log.Printf("serve: %v", err)
	} else {
		if trapID != 0 {
			log.Printf("%v", trapID)
			exit = 3
		} else if exit != 0 {
			log.Printf("exit: %d", exit)
		}
	}

	timing.loading += tLoadEnd.Sub(tLoadBegin)
	timing.running += tRunEnd.Sub(tRunBegin)
	timing.overall += tEnd.Sub(tBegin)

	var trace []stack.Frame

	if trapID != 0 || err != nil {
		trace, err = inst.Stacktrace(im, funcSigs)
		if err != nil {
			log.Fatalf("stacktrace: %v", err)
		}
	}

	debugInfo, err := newDWARF(cs.Sections)
	if err != nil {
		log.Printf("dwarf: %v", err) // Not fatal
	}

	if len(trace) > 0 {
		stacktrace.Fprint(os.Stderr, trace, funcSigs, ns, debugInfo)
	}
}

func load(filename string, codeMap *debug.InsnMap, ns *section.NameSection, cs *section.CustomSections,
) (funcSigs []wa.FuncType, prog *image.Program, inst *image.Instance, err error) {
	f, err := os.Open(filename)
	if err != nil {
		return
	}
	defer f.Close()

	build, err := image.NewBuild(image.Memory, 0, compile.DefaultMaxTextSize, &codeMap.CallMap, true)
	if err != nil {
		return
	}
	defer build.Close()

	r := codeMap.Reader(bufio.NewReader(f))

	var loadConfig = compile.Config{
		CustomSectionLoader: section.CustomLoaders{
			".debug_abbrev":   cs.Load,
			".debug_info":     cs.Load,
			".debug_line":     cs.Load,
			".debug_pubnames": cs.Load,
			".debug_ranges":   cs.Load,
			".debug_str":      cs.Load,
			"name":            ns.Load,
		}.Load,
	}

	mod, err := compile.LoadInitialSections(&compile.ModuleConfig{Config: loadConfig}, r)
	if err != nil {
		return
	}

	err = binding.BindImports(&mod, build.ImportResolver())
	if err != nil {
		return
	}

	text := build.TextBuffer()

	var codeConfig = &compile.CodeConfig{
		Text:   text,
		Mapper: codeMap,
		Config: loadConfig,
	}

	err = compile.LoadCodeSection(codeConfig, r, mod)
	if err != nil {
		return
	}

	// textCopy := make([]byte, len(text.Bytes()))
	// copy(textCopy, text.Bytes())

	var entryIndex uint32
	var entryAddr uint32

	if c.Function != "" {
		entryIndex, err = entry.ModuleFuncIndex(mod, c.Function)
		if err != nil {
			return
		}

		entryAddr = codeMap.FuncAddrs[entryIndex]
	}

	err = build.FinishText(c.Program.StackSize, 0, mod.GlobalsSize(), mod.InitialMemorySize(), mod.MemorySizeLimit())
	if err != nil {
		return
	}

	var dataConfig = &compile.DataConfig{
		GlobalsMemory:   build.GlobalsMemoryBuffer(),
		MemoryAlignment: build.MemoryAlignment(),
		Config:          loadConfig,
	}

	err = compile.LoadDataSection(dataConfig, r, mod)
	if err != nil {
		return
	}

	// if f, err := os.Create("/tmp/datadump.txt"); err != nil {
	// 	log.Fatal(err)
	// } else {
	// 	defer f.Close()
	// 	if _, err := f.Write(dataConfig.GlobalsMemory.Bytes()); err != nil {
	// 		log.Fatal(err)
	// 	}
	// }

	err = compile.LoadCustomSections(&loadConfig, r)
	if err != nil {
		return
	}

	// if f, err := os.Create("/tmp/textdump.txt"); err != nil {
	// 	log.Fatal(err)
	// } else {
	// 	defer f.Close()
	// 	if err := dump.Text(f, textCopy, 0, codeMap.FuncAddrs, ns); err != nil {
	// 		log.Fatal(err)
	// 	}
	// }

	prog, err = build.FinishProgram(image.SectionMap{}, nil, nil, nil)
	if err != nil {
		return
	}

	inst, err = build.FinishInstance(entryIndex, entryAddr)
	if err != nil {
		return
	}

	funcSigs = mod.FuncTypes()
	return
}

func newDWARF(sections map[string][]byte) (data *dwarf.Data, err error) {
	var (
		abbrev   = sections[".debug_abbrev"]
		info     = sections[".debug_info"]
		line     = sections[".debug_line"]
		pubnames = sections[".debug_pubnames"]
		ranges   = sections[".debug_ranges"]
		str      = sections[".debug_str"]
	)

	if info != nil {
		data, err = dwarf.New(abbrev, nil, nil, info, line, pubnames, ranges, str)
	}
	return
}
<commit_msg>gate-run: find plugin dir based on binary location<commit_after>// Copyright (c) 2016 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"bytes"
	"context"
	"debug/dwarf"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path"
	"time"

	"github.com/tsavola/confi"
	"github.com/tsavola/gate/entry"
	"github.com/tsavola/gate/image"
	"github.com/tsavola/gate/runtime"
	"github.com/tsavola/gate/service"
	"github.com/tsavola/gate/service/origin"
	"github.com/tsavola/gate/service/plugin"
	"github.com/tsavola/wag/binding"
	"github.com/tsavola/wag/compile"
	"github.com/tsavola/wag/object/debug"
	"github.com/tsavola/wag/object/stack"
	"github.com/tsavola/wag/object/stack/stacktrace"
	"github.com/tsavola/wag/section"
	"github.com/tsavola/wag/wa"
)

const (
	DefaultMaxProcesses = 100
	DefaultStackSize    = wa.PageSize
)

type ProgramConfig struct {
	StackSize int
}

type timing struct {
	loading time.Duration
	running time.Duration
	overall time.Duration
}

var processPolicy = runtime.ProcessPolicy{
	TimeResolution: 1, // Best resolution.
	Debug:          os.Stderr,
}

func init() {
	log.SetFlags(0)
}

type Config struct {
	Runtime runtime.Config

	Plugin struct {
		LibDir string
	}

	Service map[string]interface{}

	Program ProgramConfig

	Function string

	Benchmark struct {
		Repeat int
		Timing bool
	}
}

var c = new(Config)

func parseConfig(flags *flag.FlagSet) {
	flags.Var(confi.FileReader(c), "f", "read TOML configuration file")
	flags.Var(confi.Assigner(c), "c", "set a configuration key (path.to.key=value)")
	flags.Parse(os.Args[1:])
}

func main() {
	c.Runtime.MaxProcesses = DefaultMaxProcesses
	c.Runtime.Cgroup.Title = runtime.DefaultCgroupTitle
	c.Program.StackSize = DefaultStackSize
	c.Benchmark.Repeat = 1

	flags := flag.NewFlagSet("", flag.ContinueOnError)
	flags.SetOutput(ioutil.Discard)
	parseConfig(flags)

	if c.Runtime.LibDir == "" || c.Plugin.LibDir == "" {
		filename, err := os.Executable()
		if err != nil {
			log.Fatalf("%s: %v", os.Args[0], err)
		}
		bindir := path.Dir(filename)
		libdir := path.Join(bindir, "..", "lib", "gate")
		if c.Runtime.LibDir == "" {
			c.Runtime.LibDir = path.Join(libdir, "runtime")
		}
		if c.Plugin.LibDir == "" {
			c.Plugin.LibDir = path.Join(libdir, "plugin")
		}
	}

	plugins, err := plugin.OpenAll(c.Plugin.LibDir)
	if err != nil {
		log.Fatal(err)
	}

	c.Service = plugins.ServiceConfig

	originConfig := origin.Config{MaxConns: 1}
	c.Service["origin"] = &originConfig

	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] wasmfile...\n\nOptions:\n", flag.CommandLine.Name())
		flag.PrintDefaults()
	}
	flag.Usage = confi.FlagUsage(nil, c)
	parseConfig(flag.CommandLine)

	filenames := flag.Args()
	if len(filenames) == 0 {
		flag.Usage()
		os.Exit(2)
	}

	ctx := context.Background()

	serviceConfig := service.Config{
		Registry: new(service.Registry),
	}

	if err := plugins.InitServices(serviceConfig); err != nil {
		log.Fatal(err)
	}

	var execClosed bool

	executor, err := runtime.NewExecutor(ctx, &c.Runtime)
	if err != nil {
		log.Fatalf("runtime: %v", err)
	}
	defer func() {
		execClosed = true
		executor.Close()
	}()

	go func() {
		<-executor.Dead()
		if !execClosed {
			log.Fatal("executor died")
		}
	}()

	timings := make([]timing, len(filenames))
	exitCode := 0

	for round := 0; round < c.Benchmark.Repeat; round++ {
		var (
			execDone = make(chan int, len(filenames))
			ioDone   = make(chan struct{}, len(filenames))
		)

		for i, filename := range filenames {
			i := i
			filename := filename

			connector := origin.New(&originConfig)
			conn := connector.Connect(ctx)

			var input io.Reader = os.Stdin
			if i > 0 {
				input = bytes.NewReader(nil)
			}

			go func() {
				defer func() { ioDone <- struct{}{} }()
				if err := conn(ctx, input, os.Stdout); err != nil {
					log.Print(err)
				}
			}()

			r := serviceConfig.Registry.Clone()
			r.Register(connector)

			go func() {
				defer connector.Close()
				execute(ctx, executor, filename, r, &timings[i], execDone)
			}()
		}

		for range filenames {
			if n := <-execDone; n > exitCode {
				exitCode = n
			}
			<-ioDone
		}
	}

	if c.Benchmark.Timing {
		for i, filename := range filenames {
			output := func(title string, sum time.Duration) {
				avg := sum / time.Duration(c.Benchmark.Repeat)
				log.Printf("%s "+title+": %6d.%03dµs", filename, avg/time.Microsecond, avg%time.Microsecond)
			}

			output("loading time", timings[i].loading)
			output("running time", timings[i].running)
			output("overall time", timings[i].overall)
		}
	}

	if exitCode != 0 {
		os.Exit(exitCode)
	}
}

func execute(ctx context.Context, executor *runtime.Executor, filename string, services runtime.ServiceRegistry, timing *timing, done chan<- int) {
	var exit int

	defer func() {
		done <- exit
	}()

	tBegin := time.Now()

	proc, err := executor.NewProcess(ctx)
	if err != nil {
		log.Fatalf("process: %v", err)
	}
	defer proc.Kill()

	tLoadBegin := tBegin

	var im debug.InsnMap
	var ns = new(section.NameSection)
	var cs = new(section.CustomSections)

	funcSigs, prog, inst, err := load(filename, &im, ns, cs)
	if err != nil {
		log.Fatalf("load: %v", err)
	}
	defer prog.Close()
	defer inst.Close()

	tLoadEnd := time.Now()
	tRunBegin := tLoadEnd

	err = proc.Start(prog, inst, processPolicy)
	if err != nil {
		log.Fatalf("execute: %v", err)
	}

	exit, trapID, err := proc.Serve(ctx, services, nil)

	tRunEnd := time.Now()
	tEnd := tRunEnd

	if err != nil {
		defer os.Exit(1)
		log.Printf("serve: %v", err)
	} else {
		if trapID != 0 {
			log.Printf("%v", trapID)
			exit = 3
		} else if exit != 0 {
			log.Printf("exit: %d", exit)
		}
	}

	timing.loading += tLoadEnd.Sub(tLoadBegin)
	timing.running += tRunEnd.Sub(tRunBegin)
	timing.overall += tEnd.Sub(tBegin)

	var trace []stack.Frame

	if trapID != 0 || err != nil {
		trace, err = inst.Stacktrace(im, funcSigs)
		if err != nil {
			log.Fatalf("stacktrace: %v", err)
		}
	}

	debugInfo, err := newDWARF(cs.Sections)
	if err != nil {
		log.Printf("dwarf: %v", err) // Not fatal
	}

	if len(trace) > 0 {
		stacktrace.Fprint(os.Stderr, trace, funcSigs, ns, debugInfo)
	}
}

func load(filename string, codeMap *debug.InsnMap, ns *section.NameSection, cs *section.CustomSections,
) (funcSigs []wa.FuncType, prog *image.Program, inst *image.Instance, err error) {
	f, err := os.Open(filename)
	if err != nil {
		return
	}
	defer f.Close()

	build, err := image.NewBuild(image.Memory, 0, compile.DefaultMaxTextSize, &codeMap.CallMap, true)
	if err != nil {
		return
	}
	defer build.Close()

	r := codeMap.Reader(bufio.NewReader(f))

	var loadConfig = compile.Config{
		CustomSectionLoader: section.CustomLoaders{
			".debug_abbrev":   cs.Load,
			".debug_info":     cs.Load,
			".debug_line":     cs.Load,
			".debug_pubnames": cs.Load,
			".debug_ranges":   cs.Load,
			".debug_str":      cs.Load,
			"name":            ns.Load,
		}.Load,
	}

	mod, err := compile.LoadInitialSections(&compile.ModuleConfig{Config: loadConfig}, r)
	if err != nil {
		return
	}

	err = binding.BindImports(&mod, build.ImportResolver())
	if err != nil {
		return
	}

	text := build.TextBuffer()

	var codeConfig = &compile.CodeConfig{
		Text:   text,
		Mapper: codeMap,
		Config: loadConfig,
	}

	err = compile.LoadCodeSection(codeConfig, r, mod)
	if err != nil {
		return
	}

	// textCopy := make([]byte, len(text.Bytes()))
	// copy(textCopy, text.Bytes())

	var entryIndex uint32
	var entryAddr uint32

	if c.Function != "" {
		entryIndex, err = entry.ModuleFuncIndex(mod, c.Function)
		if err != nil {
			return
		}

		entryAddr = codeMap.FuncAddrs[entryIndex]
	}

	err = build.FinishText(c.Program.StackSize, 0, mod.GlobalsSize(), mod.InitialMemorySize(), mod.MemorySizeLimit())
	if err != nil {
		return
	}

	var dataConfig = &compile.DataConfig{
		GlobalsMemory:   build.GlobalsMemoryBuffer(),
		MemoryAlignment: build.MemoryAlignment(),
		Config:          loadConfig,
	}

	err = compile.LoadDataSection(dataConfig, r, mod)
	if err != nil {
		return
	}

	// if f, err := os.Create("/tmp/datadump.txt"); err != nil {
	// 	log.Fatal(err)
	// } else {
	// 	defer f.Close()
	// 	if _, err := f.Write(dataConfig.GlobalsMemory.Bytes()); err != nil {
	// 		log.Fatal(err)
	// 	}
	// }

	err = compile.LoadCustomSections(&loadConfig, r)
	if err != nil {
		return
	}

	// if f, err := os.Create("/tmp/textdump.txt"); err != nil {
	// 	log.Fatal(err)
	// } else {
	// 	defer f.Close()
	// 	if err := dump.Text(f, textCopy, 0, codeMap.FuncAddrs, ns); err != nil {
	// 		log.Fatal(err)
	// 	}
	// }

	prog, err = build.FinishProgram(image.SectionMap{}, nil, nil, nil)
	if err != nil {
		return
	}

	inst, err = build.FinishInstance(entryIndex, entryAddr)
	if err != nil {
		return
	}

	funcSigs = mod.FuncTypes()
	return
}

func newDWARF(sections map[string][]byte) (data *dwarf.Data, err error) {
	var (
		abbrev   = sections[".debug_abbrev"]
		info     = sections[".debug_info"]
		line     = sections[".debug_line"]
		pubnames = sections[".debug_pubnames"]
		ranges   = sections[".debug_ranges"]
		str      = sections[".debug_str"]
	)

	if info != nil {
		data, err = dwarf.New(abbrev, nil, nil, info, line, pubnames, ranges, str)
	}
	return
}
<|endoftext|>