<commit_before>package main

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

	"github.com/cenkalti/backoff"
	"github.com/docker/libkv/store"
	"github.com/docker/libkv/store/boltdb"
	"github.com/docker/libkv/store/consul"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/joho/godotenv"
	"github.com/oklog/run"
	"gopkg.in/alecthomas/kingpin.v2"
)

const (
	storeBolt   = "bolt"
	storeConsul = "consul"
)

var (
	// Version of alertmanager-bot.
	Version string
	// Revision or Commit this binary was built from.
	Revision string
	// BuildDate this binary was built.
	BuildDate string
	// GoVersion running this binary.
	GoVersion = runtime.Version()
	// StartTime has the time this was started.
	StartTime = time.Now()
)

func main() {
	godotenv.Load()

	config := struct {
		alertmanager  *url.URL
		boltPath      string
		consul        *url.URL
		listenAddr    string
		store         string
		telegramAdmin int
		telegramToken string
	}{}

	a := kingpin.New("alertmanager-bot", "Bot for Prometheus' Alertmanager")
	a.HelpFlag.Short('h')

	a.Flag("alertmanager.url", "The URL that's used to connect to the alertmanager").
		Required().
		Envar("ALERTMANAGER_URL").
		URLVar(&config.alertmanager)

	a.Flag("bolt.path", "The path to the file where bolt persists its data").
		Envar("BOLT_PATH").
		StringVar(&config.boltPath)

	a.Flag("consul.url", "The URL that's used to connect to the consul store").
		Envar("CONSUL_URL").
		URLVar(&config.consul)

	a.Flag("listen.addr", "The address the alertmanager-bot listens on for incoming webhooks").
		Required().
		Envar("LISTEN_ADDR").
		StringVar(&config.listenAddr)

	a.Flag("store", "The store to use").
		Required().
		Envar("STORE").
		EnumVar(&config.store, storeBolt, storeConsul)

	a.Flag("telegram.admin", "The ID of the initial Telegram Admin").
		Required().
		Envar("TELEGRAM_ADMIN").
		IntVar(&config.telegramAdmin)

	a.Flag("telegram.token", "The token used to connect with Telegram").
		Required().
		Envar("TELEGRAM_TOKEN").
		StringVar(&config.telegramToken)

	_, err := a.Parse(os.Args[1:])
	if err != nil {
		fmt.Printf("error parsing commandline arguments: %v\n", err)
		a.Usage(os.Args[1:])
		os.Exit(2)
	}

	logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
	logger = level.NewFilter(logger, level.AllowAll())
	logger = log.With(logger,
		"ts", log.DefaultTimestampUTC,
		"caller", log.DefaultCaller,
	)

	var kvStore store.Store
	{
		switch strings.ToLower(config.store) {
		case storeBolt:
			kvStore, err = boltdb.New([]string{config.boltPath}, &store.Config{Bucket: "alertmanager"})
			if err != nil {
				level.Error(logger).Log("msg", "failed to create bolt store backend", "err", err)
				os.Exit(1)
			}
		case storeConsul:
			kvStore, err = consul.New([]string{config.consul.String()}, nil)
			if err != nil {
				level.Error(logger).Log("msg", "failed to create consul store backend", "err", err)
				os.Exit(1)
			}
		default:
			level.Error(logger).Log("msg", "please provide one of the following supported store backends: bolt, consul")
			os.Exit(1)
		}
	}
	defer kvStore.Close()

	chats, err := NewChatStore(kvStore)
	if err != nil {
		level.Error(logger).Log("msg", "failed to create chat store", "err", err)
		os.Exit(1)
	}

	var g run.Group
	{
		bot, err := NewBot(
			chats, config.telegramToken, config.telegramAdmin,
			BotWithLogger(logger),
			BotWithAddr(config.listenAddr),
			BotWithAlertmanager(config.alertmanager),
		)
		if err != nil {
			level.Error(logger).Log("msg", "failed to create bot", "err", err)
			os.Exit(2)
		}

		g.Add(func() error {
			level.Info(logger).Log(
				"msg", "starting alertmanager-bot",
				"version", Version,
				"revision", Revision,
				"buildDate", BuildDate,
				"goVersion", GoVersion,
			)

			// Runs the webserver in a goroutine sending incoming webhooks to Telegram
			go bot.RunWebserver()

			// Runs the bot itself communicating with Telegram
			bot.Run()
			return nil
		}, func(err error) {
		})
	}

	if err := g.Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func httpBackoff() *backoff.ExponentialBackOff {
	b := backoff.NewExponentialBackOff()
	b.InitialInterval = 200 * time.Millisecond
	b.MaxInterval = 2 * time.Second
	b.MaxElapsedTime = 5 * time.Second // Telegram shows "typing" max 5 seconds
	return b
}

func httpRetry(logger log.Logger, method string, url string) (*http.Response, error) {
	var resp *http.Response
	var err error

	fn := func() error {
		req, err := http.NewRequest(method, url, nil)
		if err != nil {
			return err
		}

		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
		defer cancel()
		req = req.WithContext(ctx)

		resp, err = http.DefaultClient.Do(req)
		if err != nil {
			return err
		}

		switch method {
		case http.MethodGet:
			if resp.StatusCode != http.StatusOK {
				return fmt.Errorf("status code is %d not 200", resp.StatusCode)
			}
		case http.MethodPost:
			if resp.StatusCode == http.StatusBadRequest {
				return fmt.Errorf("status code is %d not 3xx", resp.StatusCode)
			}
		}

		return nil
	}

	notify := func(err error, dur time.Duration) {
		level.Info(logger).Log(
			"msg", "retrying",
			"duration", dur,
			"err", err,
			"url", url,
		)
	}

	if err := backoff.RetryNotify(fn, httpBackoff(), notify); err != nil {
		return nil, err
	}

	return resp, err
}
<commit_msg>Add log.level and log.json as cli flags<commit_after>package main

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

	"github.com/cenkalti/backoff"
	"github.com/docker/libkv/store"
	"github.com/docker/libkv/store/boltdb"
	"github.com/docker/libkv/store/consul"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/joho/godotenv"
	"github.com/oklog/run"
	"gopkg.in/alecthomas/kingpin.v2"
)

const (
	storeBolt   = "bolt"
	storeConsul = "consul"

	levelDebug = "debug"
	levelInfo  = "info"
	levelWarn  = "warn"
	levelError = "error"
)

var (
	// Version of alertmanager-bot.
	Version string
	// Revision or Commit this binary was built from.
	Revision string
	// BuildDate this binary was built.
	BuildDate string
	// GoVersion running this binary.
	GoVersion = runtime.Version()
	// StartTime has the time this was started.
	StartTime = time.Now()
)

func main() {
	godotenv.Load()

	config := struct {
		alertmanager  *url.URL
		boltPath      string
		consul        *url.URL
		listenAddr    string
		logLevel      string
		logJSON       bool
		store         string
		telegramAdmin int
		telegramToken string
	}{}

	a := kingpin.New("alertmanager-bot", "Bot for Prometheus' Alertmanager")
	a.HelpFlag.Short('h')

	a.Flag("alertmanager.url", "The URL that's used to connect to the alertmanager").
		Required().
		Envar("ALERTMANAGER_URL").
		URLVar(&config.alertmanager)

	a.Flag("bolt.path", "The path to the file where bolt persists its data").
		Envar("BOLT_PATH").
		StringVar(&config.boltPath)

	a.Flag("consul.url", "The URL that's used to connect to the consul store").
		Envar("CONSUL_URL").
		URLVar(&config.consul)

	a.Flag("listen.addr", "The address the alertmanager-bot listens on for incoming webhooks").
		Required().
		Envar("LISTEN_ADDR").
		StringVar(&config.listenAddr)

	a.Flag("log.json", "Tell the application to log json and not key value pairs").
		Envar("LOG_JSON").
		BoolVar(&config.logJSON)

	a.Flag("log.level", "The log level to use for filtering logs").
		Envar("LOG_LEVEL").
		Default(levelInfo).
		EnumVar(&config.logLevel, levelError, levelWarn, levelInfo, levelDebug)

	a.Flag("store", "The store to use").
		Required().
		Envar("STORE").
		EnumVar(&config.store, storeBolt, storeConsul)

	a.Flag("telegram.admin", "The ID of the initial Telegram Admin").
		Required().
		Envar("TELEGRAM_ADMIN").
		IntVar(&config.telegramAdmin)

	a.Flag("telegram.token", "The token used to connect with Telegram").
		Required().
		Envar("TELEGRAM_TOKEN").
		StringVar(&config.telegramToken)

	_, err := a.Parse(os.Args[1:])
	if err != nil {
		fmt.Printf("error parsing commandline arguments: %v\n", err)
		a.Usage(os.Args[1:])
		os.Exit(2)
	}

	levelFilter := map[string]level.Option{
		levelError: level.AllowError(),
		levelWarn:  level.AllowWarn(),
		levelInfo:  level.AllowInfo(),
		levelDebug: level.AllowDebug(),
	}

	logger := log.NewLogfmtLogger(log.NewSyncWriter(os.Stderr))
	if config.logJSON {
		logger = log.NewJSONLogger(log.NewSyncWriter(os.Stderr))
	}

	logger = level.NewFilter(logger, levelFilter[config.logLevel])
	logger = log.With(logger,
		"ts", log.DefaultTimestampUTC,
		"caller", log.DefaultCaller,
	)

	var kvStore store.Store
	{
		switch strings.ToLower(config.store) {
		case storeBolt:
			kvStore, err = boltdb.New([]string{config.boltPath}, &store.Config{Bucket: "alertmanager"})
			if err != nil {
				level.Error(logger).Log("msg", "failed to create bolt store backend", "err", err)
				os.Exit(1)
			}
		case storeConsul:
			kvStore, err = consul.New([]string{config.consul.String()}, nil)
			if err != nil {
				level.Error(logger).Log("msg", "failed to create consul store backend", "err", err)
				os.Exit(1)
			}
		default:
			level.Error(logger).Log("msg", "please provide one of the following supported store backends: bolt, consul")
			os.Exit(1)
		}
	}
	defer kvStore.Close()

	chats, err := NewChatStore(kvStore)
	if err != nil {
		level.Error(logger).Log("msg", "failed to create chat store", "err", err)
		os.Exit(1)
	}

	var g run.Group
	{
		bot, err := NewBot(
			chats, config.telegramToken, config.telegramAdmin,
			BotWithLogger(logger),
			BotWithAddr(config.listenAddr),
			BotWithAlertmanager(config.alertmanager),
		)
		if err != nil {
			level.Error(logger).Log("msg", "failed to create bot", "err", err)
			os.Exit(2)
		}

		g.Add(func() error {
			level.Info(logger).Log(
				"msg", "starting alertmanager-bot",
				"version", Version,
				"revision", Revision,
				"buildDate", BuildDate,
				"goVersion", GoVersion,
			)

			// Runs the webserver in a goroutine sending incoming webhooks to Telegram
			go bot.RunWebserver()

			// Runs the bot itself communicating with Telegram
			bot.Run()
			return nil
		}, func(err error) {
		})
	}

	if err := g.Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func httpBackoff() *backoff.ExponentialBackOff {
	b := backoff.NewExponentialBackOff()
	b.InitialInterval = 200 * time.Millisecond
	b.MaxInterval = 2 * time.Second
	b.MaxElapsedTime = 5 * time.Second // Telegram shows "typing" max 5 seconds
	return b
}

func httpRetry(logger log.Logger, method string, url string) (*http.Response, error) {
	var resp *http.Response
	var err error

	fn := func() error {
		req, err := http.NewRequest(method, url, nil)
		if err != nil {
			return err
		}

		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
		defer cancel()
		req = req.WithContext(ctx)

		resp, err = http.DefaultClient.Do(req)
		if err != nil {
			return err
		}

		switch method {
		case http.MethodGet:
			if resp.StatusCode != http.StatusOK {
				return fmt.Errorf("status code is %d not 200", resp.StatusCode)
			}
		case http.MethodPost:
			if resp.StatusCode == http.StatusBadRequest {
				return fmt.Errorf("status code is %d not 3xx", resp.StatusCode)
			}
		}

		return nil
	}

	notify := func(err error, dur time.Duration) {
		level.Info(logger).Log(
			"msg", "retrying",
			"duration", dur,
			"err", err,
			"url", url,
		)
	}

	if err := backoff.RetryNotify(fn, httpBackoff(), notify); err != nil {
		return nil, err
	}

	return resp, err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"path/filepath"

	"github.com/mafraba/digger"
	"gopkg.in/yaml.v2"
)

func main() {
	// tempDir, _ := filepath.Abs("./tmp")
	// os.Mkdir(tempDir, 0666)

	metadata := parseMetadata()
	defaults, err := metadata.AttributeDefaults()
	if err != nil {
		panic(err)
	}

	roleList := `{"rc" : { "frontend" : { "number" : 3 }}}`
	roleListDigger, _ := digger.NewJSONDigger([]byte(roleList))
	attributes, _ := digger.NewMultiDigger(
		roleListDigger,
		defaults,
	)

	path := "rc/frontend/number"
	val, _ := attributes.GetNumber(path)
	fmt.Printf("%s -> %v", path, val)
}

func parseMetadata() Metadata {
	metadataFile, _ := filepath.Abs("./samples/metadata.yaml")
	metadataContent, err := ioutil.ReadFile(metadataFile)
	if err != nil {
		panic(err)
	}
	var metadata Metadata
	err = yaml.Unmarshal(metadataContent, &metadata)
	if err != nil {
		panic(err)
	}
	return metadata
}
<commit_msg>Example of templating<commit_after>package main

import (
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"text/template"

	"github.com/mafraba/digger"
	"gopkg.in/yaml.v2"
)

func main() {
	// tempDir, _ := filepath.Abs("./tmp")
	// os.Mkdir(tempDir, 0666)

	metadata := parseMetadata()
	defaults, err := metadata.AttributeDefaults()
	if err != nil {
		panic(err)
	}

	roleList := `
	{
		"rc" : {
			"frontend" : {
				"number" : 3,
				"container": {
					"name": "contname",
					"image": "somerepo/someimage",
					"version": "latest",
					"port": 8080
				}
			}
		}
	}
	`
	roleListDigger, err := digger.NewJSONDigger([]byte(roleList))
	if err != nil {
		panic(err)
	}
	attributes, _ := digger.NewMultiDigger(
		roleListDigger,
		defaults,
	)

	tmpl := parseTemplate("./samples/frontend-controller.yaml", attributes)

	// Run the template to verify the output.
	err = tmpl.Execute(os.Stdout, nil)
	if err != nil {
		log.Fatalf("error executing template: %s", err)
	}

}

func parseTemplate(templatePath string, attributes digger.Digger) *template.Template {
	templateFile, _ := filepath.Abs(templatePath)
	templateContent, err := ioutil.ReadFile(templateFile)
	if err != nil {
		panic(err)
	}
	// First we create a FuncMap with which to register the function.
	funcMap := template.FuncMap{
		// Associating functions with aliases
		"getString": attributes.GetString,
		"getNumber": attributes.GetNumber,
		"getBool":   attributes.GetBool,
	}
	// Create a template, add the function map, and parse the text.
	tmpl, err := template.New("templateTest").Funcs(funcMap).Parse(string(templateContent))
	if err != nil {
		log.Fatalf("error parsing: %s", err)
	}
	return tmpl
}

func parseMetadata() Metadata {
	metadataFile, _ := filepath.Abs("./samples/metadata.yaml")
	metadataContent, err := ioutil.ReadFile(metadataFile)
	if err != nil {
		panic(err)
	}
	var metadata Metadata
	err = yaml.Unmarshal(metadataContent, &metadata)
	if err != nil {
		panic(err)
	}
	return metadata
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative 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 test

import (
	pkgTest "knative.dev/pkg/test"

	// Mysteriously required to support GCP auth (required by k8s libs). Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/242
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)

// Constants for test images located in test/test_images.
const (
	// Test image names
	Autoscale           = "autoscale"
	Failing             = "failing"
	HelloVolume         = "hellovolume"
	HelloWorld          = "helloworld"
	HTTPProxy           = "httpproxy"
	InvalidHelloWorld   = "invalidhelloworld" // Not a real image
	PizzaPlanet1        = "pizzaplanetv1"
	PizzaPlanet2        = "pizzaplanetv2"
	Protocols           = "protocols"
	Runtime             = "runtime"
	SingleThreadedImage = "singlethreaded"
	Timeout             = "timeout"
	WorkingDir          = "workingdir"

	// Constants for test image output.
	PizzaPlanetText1 = "What a spaceport!"
	PizzaPlanetText2 = "Re-energize yourself with a slice of pepperoni!"
	HelloWorldText   = "Hello World! How about some tasty noodles?"

	ConcurrentRequests = 50
	// We expect to see 100% of requests succeed for traffic sent directly to revisions.
	// This might be a bad assumption.
	MinDirectPercentage = 1
	// We expect to see at least 25% of either response since we're routing 50/50.
	// This might be a bad assumption.
	MinSplitPercentage = 0.25
)

// Setup creates client to run Knative Service requests
func Setup(t pkgTest.TLegacy) *Clients {
	t.Helper()
	clients, err := NewClients(pkgTest.Flags.Kubeconfig, pkgTest.Flags.Cluster, ServingNamespace)
	if err != nil {
		t.Fatal("Couldn't initialize clients", "error", err.Error())
	}
	return clients
}
<commit_msg>Quadruple number of samples during traffic split. (#7564)<commit_after>/*
Copyright 2019 The Knative 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 test

import (
	pkgTest "knative.dev/pkg/test"

	// Mysteriously required to support GCP auth (required by k8s libs). Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/242
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)

// Constants for test images located in test/test_images.
const (
	// Test image names
	Autoscale           = "autoscale"
	Failing             = "failing"
	HelloVolume         = "hellovolume"
	HelloWorld          = "helloworld"
	HTTPProxy           = "httpproxy"
	InvalidHelloWorld   = "invalidhelloworld" // Not a real image
	PizzaPlanet1        = "pizzaplanetv1"
	PizzaPlanet2        = "pizzaplanetv2"
	Protocols           = "protocols"
	Runtime             = "runtime"
	SingleThreadedImage = "singlethreaded"
	Timeout             = "timeout"
	WorkingDir          = "workingdir"

	// Constants for test image output.
	PizzaPlanetText1 = "What a spaceport!"
	PizzaPlanetText2 = "Re-energize yourself with a slice of pepperoni!"
	HelloWorldText   = "Hello World! How about some tasty noodles?"

	ConcurrentRequests = 200
	// We expect to see 100% of requests succeed for traffic sent directly to revisions.
	// This might be a bad assumption.
	MinDirectPercentage = 1
	// We expect to see at least 25% of either response since we're routing 50/50.
	// The CDF of the binomial distribution tells us this will flake roughly
	// 1 time out of 10^12 (roughly the number of galaxies in the observable universe).
	MinSplitPercentage = 0.25
)

// Setup creates client to run Knative Service requests
func Setup(t pkgTest.TLegacy) *Clients {
	t.Helper()
	clients, err := NewClients(pkgTest.Flags.Kubeconfig, pkgTest.Flags.Cluster, ServingNamespace)
	if err != nil {
		t.Fatal("Couldn't initialize clients", "error", err.Error())
	}
	return clients
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/Guitarbum722/true-up/align"
)

func main() {
	delimiter := align.Comma // default
	var sw align.Alignable

	fi, _ := os.Stdin.Stat()
	if (fi.Mode() & os.ModeCharDevice) == 0 {
		switch len(os.Args) {
		case 2:
			f, err := os.Create(os.Args[1])
			if err != nil {
				log.Fatalln(err)
			}
			defer f.Close()
			sw = align.NewAligner(os.Stdin, f, delimiter)
		default:
			sw = align.NewAligner(os.Stdin, os.Stdout, delimiter)
		}
	} else {
		switch len(os.Args) {
		case 2:
			f, err := os.Open(os.Args[1])
			if err != nil {
				log.Fatalln(err)
			}
			defer f.Close()
			sw = align.NewAligner(f, os.Stdout, delimiter)
		case 3:
			f, err := os.Open(os.Args[1])
			if err != nil {
				log.Fatalln(err)
			}
			defer f.Close()
			out, err := os.Create(os.Args[2])
			if err != nil {
				log.Fatalln(err)
			}
			defer out.Close()
			sw = align.NewAligner(f, out, delimiter)
		default:
			sw = align.NewAligner(os.Stdin, os.Stdout, delimiter)
		}
	}

	lines := sw.ColumnCounts()
	sw.Export(lines)
}
<commit_msg>create CLI with options<commit_after>package main

import (
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/Guitarbum722/true-up/align"
	"github.com/fatih/flags"
)

func main() {
	if retval, err := run(); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(retval)
	}
}

func run() (int, error) {
	args := os.Args[1:]

	// defaults
	sep := ','
	var input io.Reader
	var output io.Writer

	if flags.Has("sep", args) {
		delimiter, err := flags.Value("sep", args)
		if err != nil {
			return 1, err
		}
		sep = []rune(delimiter)[0]
	}

	// check for piped input, but use specified input file if supplied
	fi, _ := os.Stdin.Stat()
	if (fi.Mode() & os.ModeCharDevice) == 0 {
		if flags.Has("file", args) {
			fn, err := flags.Value("file", args)
			if err != nil {
				return 1, err
			}
			f, err := os.Open(fn)
			if err != nil {
				return 1, err
			}
			defer f.Close()
			input = f
		} else {
			input = os.Stdin
		}
	} else {
		if flags.Has("file", args) {
			fn, err := flags.Value("file", args)
			if err != nil {
				return 1, err
			}
			f, err := os.Open(fn)
			if err != nil {
				return 1, err
			}
			defer f.Close()
			input = f
		} else {
			return 1, errors.New("no input provided")
		}
	}

	// if --output flag is not provided with a file name, then use Stdout
	if flags.Has("output", args) {
		fn, err := flags.Value("output", args)
		if err != nil {
			return 1, err
		}
		f, err := os.Create(fn)
		if err != nil {
			return 1, err
		}
		defer f.Close()
		output = f
	} else {
		output = os.Stdout
	}

	sw := align.NewAligner(input, output, sep)

	lines := sw.ColumnCounts()
	sw.Export(lines)

	return 0, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Stuart Glenn, OMRF. All rights reserved.
// Use of this code is governed by a 3 clause BSD style license
// Full license details in LICENSE file distributed with this software

package main

import (
	"encoding/csv"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/oklasoft/mmatcher/matcher"
	"gopkg.in/alecthomas/kingpin.v1"
)

func loadData(path string, skipHeader bool) matcher.Records {
	file, err := os.Open(path)
	if nil != err {
		log.Fatal(err)
	}
	defer file.Close()

	data, err := matcher.NewRecordsFromCSV(file, skipHeader)
	if nil != err {
		log.Fatal(err)
	}
	return data
}

func parseKeys(s string) ([]int, []matcher.Atter) {
	parts := strings.Split(s, ",")
	positions := make([]int, len(parts))
	ranges := make([]matcher.Atter, len(parts))
	for i, v := range parts {
		k := strings.Split(v, ":")
		p, err := strconv.ParseInt(k[0], 10, 32)
		if nil != err {
			log.Fatal(err)
		}
		positions[i] = int(p) - 1
		if len(k) > 1 {
			r, err := strconv.ParseFloat(k[1], 32)
			if nil != err {
				log.Fatal(err)
			}
			ranges[i] = matcher.NumericAtt{r}
		}
	}
	return positions, ranges
}

func version() string {
	return fmt.Sprintf("mmatcher - Multi Matcher 0.6.0 (20150403 %s)", build)
}

var (
	verbose      = kingpin.Flag("verbose", "Increase verbosity").Short('v').Bool()
	skipHeaders  = kingpin.Flag("skip-header", "Inputs have header line to be skipped, default is use everyline").Short('h').Bool()
	outFile      = kingpin.Flag("output", "Output file").Short('o').PlaceHolder("STDOUT").OpenFile(os.O_WRONLY|os.O_CREATE, 0660)
	outSep       = kingpin.Flag("out-separator", "Output field separator").Default(",").String()
	key          = kingpin.Arg("keys", "Keys to compare. A comma separated list of columns starting a 1, with optional :# +/- window").Required().String()
	case_file    = kingpin.Arg("case", "CSV file representing the cases").Required().ExistingFile()
	control_file = kingpin.Arg("controls", "CSV file representing the controls").Required().ExistingFile()
	build        string
)

func main() {
	kingpin.Version(version())
	kingpin.Parse()

	if nil == *outFile {
		outFile = &os.Stdout
	}

	positions, ranges := parseKeys(*key)
	cases := loadData(*case_file, *skipHeaders)
	controls := loadData(*control_file, *skipHeaders)

	all_matches := matcher.NewMatchSet()

	for _, r := range cases {
		spots := r.Matches(controls, positions, ranges...)
		for _, i := range spots {
			all_matches.AddPair(matcher.NewPair(r.ID, controls[i].ID))
		}
	}

	opti := all_matches.QuantityOptimized()

	out := csv.NewWriter(*outFile)
	sep, err := strconv.Unquote("'" + *outSep + "'")
	if nil != err {
		log.Fatal(err)
	}
	out.Comma = ([]rune(sep))[0]
	out.Write([]string{"case", "control"})

	for _, r := range cases {
		m := opti.MatchesFor(r.ID)
		if 0 == len(m) {
			out.Write([]string{r.ID})
			continue
		}
		line := []string{r.ID, m[0]}
		if *verbose {
			control := controls.Get(m[0])
			for _, p := range positions {
				line = append(line, r.Atts[p].String(), control.Atts[p].String())
			}
		}
		out.Write(line)
	}
	out.Flush()
	(*outFile).Close()

}
<commit_msg>Bump version<commit_after>// Copyright 2015 Stuart Glenn, OMRF. All rights reserved.
// Use of this code is governed by a 3 clause BSD style license
// Full license details in LICENSE file distributed with this software

package main

import (
	"encoding/csv"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/oklasoft/mmatcher/matcher"
	"gopkg.in/alecthomas/kingpin.v1"
)

func loadData(path string, skipHeader bool) matcher.Records {
	file, err := os.Open(path)
	if nil != err {
		log.Fatal(err)
	}
	defer file.Close()

	data, err := matcher.NewRecordsFromCSV(file, skipHeader)
	if nil != err {
		log.Fatal(err)
	}
	return data
}

func parseKeys(s string) ([]int, []matcher.Atter) {
	parts := strings.Split(s, ",")
	positions := make([]int, len(parts))
	ranges := make([]matcher.Atter, len(parts))
	for i, v := range parts {
		k := strings.Split(v, ":")
		p, err := strconv.ParseInt(k[0], 10, 32)
		if nil != err {
			log.Fatal(err)
		}
		positions[i] = int(p) - 1
		if len(k) > 1 {
			r, err := strconv.ParseFloat(k[1], 32)
			if nil != err {
				log.Fatal(err)
			}
			ranges[i] = matcher.NumericAtt{r}
		}
	}
	return positions, ranges
}

func version() string {
	return fmt.Sprintf("mmatcher - Multi Matcher 0.7.0 (20150404 %s)", build)
}

var (
	verbose      = kingpin.Flag("verbose", "Increase verbosity").Short('v').Bool()
	skipHeaders  = kingpin.Flag("skip-header", "Inputs have header line to be skipped, default is use everyline").Short('h').Bool()
	outFile      = kingpin.Flag("output", "Output file").Short('o').PlaceHolder("STDOUT").OpenFile(os.O_WRONLY|os.O_CREATE, 0660)
	outSep       = kingpin.Flag("out-separator", "Output field separator").Default(",").String()
	key          = kingpin.Arg("keys", "Keys to compare. A comma separated list of columns starting a 1, with optional :# +/- window").Required().String()
	case_file    = kingpin.Arg("case", "CSV file representing the cases").Required().ExistingFile()
	control_file = kingpin.Arg("controls", "CSV file representing the controls").Required().ExistingFile()
	build        string
)

func main() {
	kingpin.Version(version())
	kingpin.Parse()

	if nil == *outFile {
		outFile = &os.Stdout
	}

	positions, ranges := parseKeys(*key)
	cases := loadData(*case_file, *skipHeaders)
	controls := loadData(*control_file, *skipHeaders)

	all_matches := matcher.NewMatchSet()

	for _, r := range cases {
		spots := r.Matches(controls, positions, ranges...)
		for _, i := range spots {
			all_matches.AddPair(matcher.NewPair(r.ID, controls[i].ID))
		}
	}

	opti := all_matches.QuantityOptimized()

	out := csv.NewWriter(*outFile)
	sep, err := strconv.Unquote("'" + *outSep + "'")
	if nil != err {
		log.Fatal(err)
	}
	out.Comma = ([]rune(sep))[0]
	out.Write([]string{"case", "control"})

	for _, r := range cases {
		m := opti.MatchesFor(r.ID)
		if 0 == len(m) {
			out.Write([]string{r.ID})
			continue
		}
		line := []string{r.ID, m[0]}
		if *verbose {
			control := controls.Get(m[0])
			for _, p := range positions {
				line = append(line, r.Atts[p].String(), control.Atts[p].String())
			}
		}
		out.Write(line)
	}
	out.Flush()
	(*outFile).Close()

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"reflect"

	"code.cloudfoundry.org/cli/cf/cmd"
	"code.cloudfoundry.org/cli/commands"
	"code.cloudfoundry.org/cli/commands/ui"
	"code.cloudfoundry.org/cli/commands/v2"
	"code.cloudfoundry.org/cli/utils/config"
	"code.cloudfoundry.org/cli/utils/panichandler"
	"github.com/jessevdk/go-flags"
)

func main() {
	defer panichandler.HandlePanic()
	parse(os.Args[1:])
}

func parse(args []string) {
	parser := flags.NewParser(&v2.Commands, flags.HelpFlag)
	parser.CommandHandler = myCommandHandler
	extraArgs, err := parser.ParseArgs(args)
	if err == nil {
		return
	}

	if flagErr, ok := err.(*flags.Error); ok {
		switch flagErr.Type {
		case flags.ErrHelp, flags.ErrUnknownFlag, flags.ErrExpectedArgument:
			_, found := reflect.TypeOf(v2.Commands).FieldByNameFunc(
				func(fieldName string) bool {
					field, _ := reflect.TypeOf(v2.Commands).FieldByName(fieldName)
					return parser.Active != nil && parser.Active.Name == field.Tag.Get("command")
				},
			)

			if found {
				parse([]string{"help", parser.Active.Name})
			} else {
				switch len(extraArgs) {
				case 0:
					parse([]string{"help"})
				case 1:
					parse([]string{"help", extraArgs[0]})
				default:
					parse(extraArgs[1:])
				}
			}

			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
				os.Exit(1)
			}
		case flags.ErrRequired:
			fmt.Printf("%s\n\n", flagErr.Error())
			parse(append([]string{"help"}, args...))
			os.Exit(1)
		case flags.ErrUnknownCommand:
			cmd.Main(os.Getenv("CF_TRACE"), os.Args)
		case flags.ErrCommandRequired:
			if v2.Commands.VerboseOrVersion {
				parse([]string{"version"})
			} else {
				parse([]string{"help"})
			}
		default:
			fmt.Printf("unexpected flag error\ntype: %s\nmessage: %s\n", flagErr.Type, flagErr.Error())
		}
	} else {
		fmt.Println("unexpected error:", err.Error())
	}
}

func myCommandHandler(cmd flags.Commander, args []string) error {
	config, _ := config.LoadConfig()
	//defer write config
	var err error
	commandUI, err := ui.NewUI(config)
	if err != nil {
		return err
	}

	if extendedCmd, ok := cmd.(commands.ExtendedCommander); ok {
		err := extendedCmd.Setup(config, commandUI)
		if err != nil {
			return err
		}
		return extendedCmd.Execute(args)
	}

	return fmt.Errorf("unable to setup command")
}
<commit_msg>display flag/argument errors to the screen<commit_after>package main

import (
	"fmt"
	"os"
	"reflect"

	"code.cloudfoundry.org/cli/cf/cmd"
	"code.cloudfoundry.org/cli/commands"
	"code.cloudfoundry.org/cli/commands/ui"
	"code.cloudfoundry.org/cli/commands/v2"
	"code.cloudfoundry.org/cli/utils/config"
	"code.cloudfoundry.org/cli/utils/panichandler"
	"github.com/jessevdk/go-flags"
)

func main() {
	defer panichandler.HandlePanic()
	parse(os.Args[1:])
}

func parse(args []string) {
	parser := flags.NewParser(&v2.Commands, flags.HelpFlag)
	parser.CommandHandler = myCommandHandler
	extraArgs, err := parser.ParseArgs(args)
	if err == nil {
		return
	}

	if flagErr, ok := err.(*flags.Error); ok {
		switch flagErr.Type {
		case flags.ErrHelp, flags.ErrUnknownFlag, flags.ErrExpectedArgument:
			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
				fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
			}

			_, found := reflect.TypeOf(v2.Commands).FieldByNameFunc(
				func(fieldName string) bool {
					field, _ := reflect.TypeOf(v2.Commands).FieldByName(fieldName)
					return parser.Active != nil && parser.Active.Name == field.Tag.Get("command")
				},
			)

			if found {
				parse([]string{"help", parser.Active.Name})
			} else {
				switch len(extraArgs) {
				case 0:
					parse([]string{"help"})
				case 1:
					parse([]string{"help", extraArgs[0]})
				default:
					parse(extraArgs[1:])
				}
			}

			if flagErr.Type == flags.ErrUnknownFlag || flagErr.Type == flags.ErrExpectedArgument {
				os.Exit(1)
			}
		case flags.ErrRequired:
			fmt.Fprintf(os.Stderr, "Incorrect Usage: %s\n\n", flagErr.Error())
			parse(append([]string{"help"}, args...))
			os.Exit(1)
		case flags.ErrUnknownCommand:
			cmd.Main(os.Getenv("CF_TRACE"), os.Args)
		case flags.ErrCommandRequired:
			if v2.Commands.VerboseOrVersion {
				parse([]string{"version"})
			} else {
				parse([]string{"help"})
			}
		default:
			fmt.Fprintf(os.Stderr, "unexpected flag error\ntype: %s\nmessage: %s\n", flagErr.Type, flagErr.Error())
		}
	} else {
		fmt.Fprintf(os.Stderr, "unexpected error: %s\n", err.Error())
	}
}

func myCommandHandler(cmd flags.Commander, args []string) error {
	config, _ := config.LoadConfig()
	//defer write config
	var err error
	commandUI, err := ui.NewUI(config)
	if err != nil {
		return err
	}

	if extendedCmd, ok := cmd.(commands.ExtendedCommander); ok {
		err := extendedCmd.Setup(config, commandUI)
		if err != nil {
			return err
		}
		return extendedCmd.Execute(args)
	}

	return fmt.Errorf("unable to setup command")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"
	"runtime/pprof"
	"strings"
	"syscall"

	"github.com/atlassian/gostatsd/statsd"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	"golang.org/x/net/context"
)

var (
	// BuildDate is the date when the binary was built.
	BuildDate string
	// GitCommit is the commit hash when the binary was built.
	GitCommit string
	// Version is the version of the binary.
	Version string
)

const (
	// ParamVerbose enables verbose logging.
	ParamVerbose = "verbose"
	// ParamCPUProfile enables use of profiler and write results to this file.
	ParamCPUProfile = "cpu-profile"
	// ParamJSON makes logger log in JSON format.
	ParamJSON = "json"
	// ParamConfigPath provides file with configuration.
	ParamConfigPath = "config-path"
	// ParamVersion makes program output its version.
	ParamVersion = "version"
)

// EnvPrefix is the prefix of the inspected environment variables.
const EnvPrefix = "GSD" //Go Stats D

func main() {
	v, version, err := setupConfiguration()
	if err != nil {
		if err == pflag.ErrHelp {
			return
		}
		log.Fatalf("Error while parsing configuration: %v", err)
	}
	if version {
		fmt.Printf("Version: %s - Commit: %s - Date: %s\n", Version, GitCommit, BuildDate)
		return
	}
	var exitErr error
	defer func() {
		if exitErr != nil {
			log.Fatalf("%v", exitErr)
		}
	}()
	CPUProfile := v.GetString(ParamCPUProfile)
	if CPUProfile != "" {
		f, err := os.Create(CPUProfile)
		if err != nil {
			augmentErr(&exitErr, fmt.Errorf("Failed to open profile file: %v", err))
			return
		}
		defer func() {
			if closeErr := f.Close(); closeErr != nil {
				augmentErr(&exitErr, fmt.Errorf("Failed to close profile file: %v", closeErr))
			}
		}()
		err = pprof.StartCPUProfile(f)
		if err != nil {
			augmentErr(&exitErr, fmt.Errorf("Failed to start CPU profiler: %v", err))
			return
		}
		defer pprof.StopCPUProfile()
	}

	ctx, cancelFunc := context.WithCancel(context.Background())
	defer cancelFunc()
	cancelOnInterrupt(ctx, cancelFunc)

	log.Info("Starting server")
	s := statsd.Server{
		Backends:         toSlice(v.GetString(statsd.ParamBackends)),
		ConsoleAddr:      v.GetString(statsd.ParamConsoleAddr),
		CloudProvider:    v.GetString(statsd.ParamCloudProvider),
		DefaultTags:      toSlice(v.GetString(statsd.ParamDefaultTags)),
		ExpiryInterval:   v.GetDuration(statsd.ParamExpiryInterval),
		FlushInterval:    v.GetDuration(statsd.ParamFlushInterval),
		MaxReaders:       v.GetInt(statsd.ParamMaxReaders),
		MaxWorkers:       v.GetInt(statsd.ParamMaxWorkers),
		MetricsAddr:      v.GetString(statsd.ParamMetricsAddr),
		Namespace:        v.GetString(statsd.ParamNamespace),
		PercentThreshold: toSlice(v.GetString(statsd.ParamPercentThreshold)),
		WebConsoleAddr:   v.GetString(statsd.ParamWebAddr),
		Viper:            v,
	}
	if err := s.Run(ctx); err != nil && err != context.Canceled {
		augmentErr(&exitErr, fmt.Errorf("Server error: %v", err))
	}
}

// augmentErr updates exitErr to point to newErr if exitErr is nil, otherwise logs newErr.
// The idea is to log all errors and fail the program with the first one.
func augmentErr(exitErr *error, newErr error) {
	if *exitErr == nil {
		*exitErr = newErr
	} else {
		log.Errorf("%v", newErr)
	}
}

func toSlice(s string) []string {
	//TODO Remove workaround when https://github.com/spf13/viper/issues/112 is fixed
	if s == "" {
		return nil
	}
	return strings.Split(s, ",")
}

// cancelOnInterrupt calls f when os.Interrupt or SIGTERM is received.
func cancelOnInterrupt(ctx context.Context, f context.CancelFunc) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		select {
		case <-c:
			f()
		case <-ctx.Done():
		}
	}()
}

func setupConfiguration() (*viper.Viper, bool, error) {
	v := viper.New()
	v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
	v.SetEnvPrefix(EnvPrefix)
	v.SetTypeByDefaultValue(true)
	v.AutomaticEnv()

	var version bool

	cmd := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)

	cmd.BoolVar(&version, ParamVersion, false, "Print the version and exit")
	cmd.Bool(ParamVerbose, false, "Verbose")
	cmd.Bool(ParamJSON, false, "Log in JSON format")
	cmd.String(ParamCPUProfile, "", "Use profiler and write results to this file")
	cmd.String(ParamConfigPath, "", "Path to the configuration file")

	statsd.AddFlags(cmd)

	cmd.VisitAll(func(flag *pflag.Flag) {
		if err := v.BindPFlag(flag.Name, flag); err != nil {
			panic(err) // Should never happen
		}
	})

	setupLogger(v) // setup logger from environment vars and flag defaults

	if err := cmd.Parse(os.Args[1:]); err != nil {
		return nil, false, err
	}

	setupLogger(v) // update logger with config from command line flags

	configPath := v.GetString(ParamConfigPath)
	if configPath != "" {
		v.SetConfigFile(configPath)
		if err := v.ReadInConfig(); err != nil {
			return nil, false, err
		}
	}

	setupLogger(v) // finally update logger with vars from config

	return v, version, nil
}

func setupLogger(v *viper.Viper) {
	if v.GetBool(ParamVerbose) {
		log.SetLevel(log.DebugLevel)
	}
	if v.GetBool(ParamJSON) {
		log.SetFormatter(&log.JSONFormatter{})
	}
}
<commit_msg>Remove profiler<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/atlassian/gostatsd/statsd"

	log "github.com/Sirupsen/logrus"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	"golang.org/x/net/context"
)

var (
	// BuildDate is the date when the binary was built.
	BuildDate string
	// GitCommit is the commit hash when the binary was built.
	GitCommit string
	// Version is the version of the binary.
	Version string
)

const (
	// ParamVerbose enables verbose logging.
	ParamVerbose = "verbose"
	// ParamJSON makes logger log in JSON format.
	ParamJSON = "json"
	// ParamConfigPath provides file with configuration.
	ParamConfigPath = "config-path"
	// ParamVersion makes program output its version.
	ParamVersion = "version"
)

// EnvPrefix is the prefix of the inspected environment variables.
const EnvPrefix = "GSD" //Go Stats D

func main() {
	v, version, err := setupConfiguration()
	if err != nil {
		if err == pflag.ErrHelp {
			return
		}
		log.Fatalf("Error while parsing configuration: %v", err)
	}
	if version {
		fmt.Printf("Version: %s - Commit: %s - Date: %s\n", Version, GitCommit, BuildDate)
		return
	}
	var exitErr error
	defer func() {
		if exitErr != nil {
			log.Fatalf("%v", exitErr)
		}
	}()

	ctx, cancelFunc := context.WithCancel(context.Background())
	defer cancelFunc()
	cancelOnInterrupt(ctx, cancelFunc)

	log.Info("Starting server")
	s := statsd.Server{
		Backends:         toSlice(v.GetString(statsd.ParamBackends)),
		ConsoleAddr:      v.GetString(statsd.ParamConsoleAddr),
		CloudProvider:    v.GetString(statsd.ParamCloudProvider),
		DefaultTags:      toSlice(v.GetString(statsd.ParamDefaultTags)),
		ExpiryInterval:   v.GetDuration(statsd.ParamExpiryInterval),
		FlushInterval:    v.GetDuration(statsd.ParamFlushInterval),
		MaxReaders:       v.GetInt(statsd.ParamMaxReaders),
		MaxWorkers:       v.GetInt(statsd.ParamMaxWorkers),
		MetricsAddr:      v.GetString(statsd.ParamMetricsAddr),
		Namespace:        v.GetString(statsd.ParamNamespace),
		PercentThreshold: toSlice(v.GetString(statsd.ParamPercentThreshold)),
		WebConsoleAddr:   v.GetString(statsd.ParamWebAddr),
		Viper:            v,
	}
	if err := s.Run(ctx); err != nil && err != context.Canceled {
		augmentErr(&exitErr, fmt.Errorf("Server error: %v", err))
	}
}

// augmentErr updates exitErr to point to newErr if exitErr is nil, otherwise logs newErr.
// The idea is to log all errors and fail the program with the first one.
func augmentErr(exitErr *error, newErr error) {
	if *exitErr == nil {
		*exitErr = newErr
	} else {
		log.Errorf("%v", newErr)
	}
}

func toSlice(s string) []string {
	//TODO Remove workaround when https://github.com/spf13/viper/issues/112 is fixed
	if s == "" {
		return nil
	}
	return strings.Split(s, ",")
}

// cancelOnInterrupt calls f when os.Interrupt or SIGTERM is received.
func cancelOnInterrupt(ctx context.Context, f context.CancelFunc) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		select {
		case <-c:
			f()
		case <-ctx.Done():
		}
	}()
}

func setupConfiguration() (*viper.Viper, bool, error) {
	v := viper.New()
	v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
	v.SetEnvPrefix(EnvPrefix)
	v.SetTypeByDefaultValue(true)
	v.AutomaticEnv()

	var version bool

	cmd := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)

	cmd.BoolVar(&version, ParamVersion, false, "Print the version and exit")
	cmd.Bool(ParamVerbose, false, "Verbose")
	cmd.Bool(ParamJSON, false, "Log in JSON format")
	cmd.String(ParamConfigPath, "", "Path to the configuration file")

	statsd.AddFlags(cmd)

	cmd.VisitAll(func(flag *pflag.Flag) {
		if err := v.BindPFlag(flag.Name, flag); err != nil {
			panic(err) // Should never happen
		}
	})

	setupLogger(v) // setup logger from environment vars and flag defaults

	if err := cmd.Parse(os.Args[1:]); err != nil {
		return nil, false, err
	}

	setupLogger(v) // update logger with config from command line flags

	configPath := v.GetString(ParamConfigPath)
	if configPath != "" {
		v.SetConfigFile(configPath)
		if err := v.ReadInConfig(); err != nil {
			return nil, false, err
		}
	}

	setupLogger(v) // finally update logger with vars from config

	return v, version, nil
}

func setupLogger(v *viper.Viper) {
	if v.GetBool(ParamVerbose) {
		log.SetLevel(log.DebugLevel)
	}
	if v.GetBool(ParamJSON) {
		log.SetFormatter(&log.JSONFormatter{})
	}
}
<|endoftext|>


<commit_before>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package test

import (
	"context"
	"reflect"
	"testing"
	"time"

	driver "github.com/arangodb/go-driver"
)

type queryTest struct {
	Query             string
	BindVars          map[string]interface{}
	ExpectSuccess     bool
	ExpectedDocuments []interface{}
	DocumentType      reflect.Type
}

type queryTestContext struct {
	Context     context.Context
	ExpectCount bool
}

// TestCreateCursor creates several cursors.
func TestCreateCursor(t *testing.T) {
	ctx := context.Background()
	c := createClientFromEnv(t, true)
	db := ensureDatabase(ctx, c, "cursor_test", nil, t)

	// Create data set
	collectionData := map[string][]interface{}{
		"books": []interface{}{
			Book{Title: "Book 01"},
			Book{Title: "Book 02"},
			Book{Title: "Book 03"},
			Book{Title: "Book 04"},
			Book{Title: "Book 05"},
			Book{Title: "Book 06"},
			Book{Title: "Book 07"},
			Book{Title: "Book 08"},
			Book{Title: "Book 09"},
			Book{Title: "Book 10"},
			Book{Title: "Book 11"},
			Book{Title: "Book 12"},
			Book{Title: "Book 13"},
			Book{Title: "Book 14"},
			Book{Title: "Book 15"},
			Book{Title: "Book 16"},
			Book{Title: "Book 17"},
			Book{Title: "Book 18"},
			Book{Title: "Book 19"},
			Book{Title: "Book 20"},
		},
		"users": []interface{}{
			UserDoc{Name: "John", Age: 13},
			UserDoc{Name: "Jake", Age: 25},
			UserDoc{Name: "Clair", Age: 12},
			UserDoc{Name: "Johnny", Age: 42},
			UserDoc{Name: "Blair", Age: 67},
		},
	}
	for colName, colDocs := range collectionData {
		col := ensureCollection(ctx, db, colName, nil, t)
		if _, _, err := col.CreateDocuments(ctx, colDocs); err != nil {
			t.Fatalf("Expected success, got %s", describe(err))
		}
	}

	// Setup tests
	tests := []queryTest{
		queryTest{
			Query:             "FOR d IN books SORT d.Title RETURN d",
			ExpectSuccess:     true,
			ExpectedDocuments: collectionData["books"],
			DocumentType:      reflect.TypeOf(Book{}),
		},
		queryTest{
			Query:             "FOR d IN books FILTER d.Title==@title SORT d.Title RETURN d",
			BindVars:          map[string]interface{}{"title": "Book 02"},
			ExpectSuccess:     true,
			ExpectedDocuments: []interface{}{collectionData["books"][1]},
			DocumentType:      reflect.TypeOf(Book{}),
		},
		queryTest{
			Query:         "FOR d IN books FILTER d.Title==@title SORT d.Title RETURN d",
			BindVars:      map[string]interface{}{"somethingelse": "Book 02"},
			ExpectSuccess: false, // Unknown `@title`
		},
		queryTest{
			Query:             "FOR u IN users FILTER u.age>100 SORT u.name RETURN u",
			ExpectSuccess:     true,
			ExpectedDocuments: []interface{}{},
			DocumentType:      reflect.TypeOf(UserDoc{}),
		},
		queryTest{
			Query:             "FOR u IN users FILTER u.age<@maxAge SORT u.name RETURN u",
			BindVars:          map[string]interface{}{"maxAge": 20},
			ExpectSuccess:     true,
			ExpectedDocuments: []interface{}{collectionData["users"][2], collectionData["users"][0]},
			DocumentType:      reflect.TypeOf(UserDoc{}),
		},
		queryTest{
			Query:         "FOR u IN users FILTER u.age<@maxAge SORT u.name RETURN u",
			BindVars:      map[string]interface{}{"maxage": 20},
			ExpectSuccess: false, // `@maxage` versus `@maxAge`
		},
		queryTest{
			Query:             "FOR u IN users SORT u.age RETURN u.age",
			ExpectedDocuments: []interface{}{12, 13, 25, 42, 67},
			DocumentType:      reflect.TypeOf(12),
			ExpectSuccess:     true,
		},
	}

	// Setup context alternatives
	contexts := []queryTestContext{
		queryTestContext{nil, false},
		queryTestContext{context.Background(), false},
		queryTestContext{driver.WithQueryCount(nil), true},
		queryTestContext{driver.WithQueryCount(nil, true), true},
		queryTestContext{driver.WithQueryCount(nil, false), false},
		queryTestContext{driver.WithQueryBatchSize(nil, 1), false},
		queryTestContext{driver.WithQueryCache(nil), false},
		queryTestContext{driver.WithQueryCache(nil, true), false},
		queryTestContext{driver.WithQueryCache(nil, false), false},
		queryTestContext{driver.WithQueryMemoryLimit(nil, 60000), false},
		queryTestContext{driver.WithQueryTTL(nil, time.Minute), false},
		queryTestContext{driver.WithQueryBatchSize(driver.WithQueryCount(nil), 1), true},
		queryTestContext{driver.WithQueryCache(driver.WithQueryCount(driver.WithQueryBatchSize(nil, 2))), true},
	}

	// Run tests for every context alternative
	for _, qctx := range contexts {
		ctx := qctx.Context
		for i, test := range tests {
			cursor, err := db.Query(ctx, test.Query, test.BindVars)
			if err == nil {
				// Close upon exit of the function
				defer cursor.Close()
			}
			if test.ExpectSuccess {
				if err != nil {
					t.Errorf("Expected success in query %d (%s), got '%s'", i, test.Query, describe(err))
					continue
				}
				count := cursor.Count()
				if qctx.ExpectCount {
					if count != int64(len(test.ExpectedDocuments)) {
						t.Errorf("Expected count of %d, got %d in query %d (%s)", len(test.ExpectedDocuments), count, i, test.Query)
					}
				} else {
					if count != 0 {
						t.Errorf("Expected count of 0, got %d in query %d (%s)", count, i, test.Query)
					}
				}
				var result []interface{}
				for {
					hasMore := cursor.HasMore()
					doc := reflect.New(test.DocumentType)
					if _, err := cursor.ReadDocument(ctx, doc.Interface()); driver.IsNoMoreDocuments(err) {
						if hasMore {
							t.Error("HasMore returned true, but ReadDocument returns a IsNoMoreDocuments error")
						}
						break
					} else if err != nil {
						t.Errorf("Failed to result document %d: %s", len(result), describe(err))
					}
					if !hasMore {
						t.Error("HasMore returned false, but ReadDocument returns a document")
					}
					result = append(result, doc.Elem().Interface())
				}
				if len(result) != len(test.ExpectedDocuments) {
					t.Errorf("Expected %d documents, got %d in query %d (%s)", len(test.ExpectedDocuments), len(result), i, test.Query)
				} else {
					for resultIdx, resultDoc := range result {
						if !reflect.DeepEqual(resultDoc, test.ExpectedDocuments[resultIdx]) {
							t.Errorf("Unexpected document in query %d (%s) at index %d: got %+v, expected %+v", i, test.Query, resultIdx, resultDoc, test.ExpectedDocuments[resultIdx])
						}
					}
				}
				// Close anyway (this tests calling Close more than once)
				if err := cursor.Close(); err != nil {
					t.Errorf("Expected success in Close of cursor from query %d (%s), got '%s'", i, test.Query, describe(err))
				}
			} else {
				if err == nil {
					t.Errorf("Expected error in query %d (%s), got '%s'", i, test.Query, describe(err))
					continue
				}
			}
		}
	}
}
<commit_msg>Added more cursor tests<commit_after>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package test

import (
	"context"
	"reflect"
	"testing"
	"time"

	driver "github.com/arangodb/go-driver"
)

type queryTest struct {
	Query             string
	BindVars          map[string]interface{}
	ExpectSuccess     bool
	ExpectedDocuments []interface{}
	DocumentType      reflect.Type
}

type queryTestContext struct {
	Context     context.Context
	ExpectCount bool
}

// TestCreateCursor creates several cursors.
func TestCreateCursor(t *testing.T) {
	ctx := context.Background()
	c := createClientFromEnv(t, true)
	db := ensureDatabase(ctx, c, "cursor_test", nil, t)

	// Create data set
	collectionData := map[string][]interface{}{
		"books": []interface{}{
			Book{Title: "Book 01"},
			Book{Title: "Book 02"},
			Book{Title: "Book 03"},
			Book{Title: "Book 04"},
			Book{Title: "Book 05"},
			Book{Title: "Book 06"},
			Book{Title: "Book 07"},
			Book{Title: "Book 08"},
			Book{Title: "Book 09"},
			Book{Title: "Book 10"},
			Book{Title: "Book 11"},
			Book{Title: "Book 12"},
			Book{Title: "Book 13"},
			Book{Title: "Book 14"},
			Book{Title: "Book 15"},
			Book{Title: "Book 16"},
			Book{Title: "Book 17"},
			Book{Title: "Book 18"},
			Book{Title: "Book 19"},
			Book{Title: "Book 20"},
		},
		"users": []interface{}{
			UserDoc{Name: "John", Age: 13},
			UserDoc{Name: "Jake", Age: 25},
			UserDoc{Name: "Clair", Age: 12},
			UserDoc{Name: "Johnny", Age: 42},
			UserDoc{Name: "Blair", Age: 67},
			UserDoc{Name: "Zz", Age: 12},
		},
	}
	for colName, colDocs := range collectionData {
		col := ensureCollection(ctx, db, colName, nil, t)
		if _, _, err := col.CreateDocuments(ctx, colDocs); err != nil {
			t.Fatalf("Expected success, got %s", describe(err))
		}
	}

	// Setup tests
	tests := []queryTest{
		queryTest{
			Query:             "FOR d IN books SORT d.Title RETURN d",
			ExpectSuccess:     true,
			ExpectedDocuments: collectionData["books"],
			DocumentType:      reflect.TypeOf(Book{}),
		},
		queryTest{
			Query:             "FOR d IN books FILTER d.Title==@title SORT d.Title RETURN d",
			BindVars:          map[string]interface{}{"title": "Book 02"},
			ExpectSuccess:     true,
			ExpectedDocuments: []interface{}{collectionData["books"][1]},
			DocumentType:      reflect.TypeOf(Book{}),
		},
		queryTest{
			Query:         "FOR d IN books FILTER d.Title==@title SORT d.Title RETURN d",
			BindVars:      map[string]interface{}{"somethingelse": "Book 02"},
			ExpectSuccess: false, // Unknown `@title`
		},
		queryTest{
			Query:             "FOR u IN users FILTER u.age>100 SORT u.name RETURN u",
			ExpectSuccess:     true,
			ExpectedDocuments: []interface{}{},
			DocumentType:      reflect.TypeOf(UserDoc{}),
		},
		queryTest{
			Query:             "FOR u IN users FILTER u.age<@maxAge SORT u.name RETURN u",
			BindVars:          map[string]interface{}{"maxAge": 20},
			ExpectSuccess:     true,
			ExpectedDocuments: []interface{}{collectionData["users"][2], collectionData["users"][0], collectionData["users"][5]},
			DocumentType:      reflect.TypeOf(UserDoc{}),
		},
		queryTest{
			Query:         "FOR u IN users FILTER u.age<@maxAge SORT u.name RETURN u",
			BindVars:      map[string]interface{}{"maxage": 20},
			ExpectSuccess: false, // `@maxage` versus `@maxAge`
		},
		queryTest{
			Query:             "FOR u IN users SORT u.age RETURN u.age",
			ExpectedDocuments: []interface{}{12, 12, 13, 25, 42, 67},
			DocumentType:      reflect.TypeOf(12),
			ExpectSuccess:     true,
		},
		queryTest{
			Query:             "FOR p IN users COLLECT a = p.age WITH COUNT INTO c SORT a RETURN [a, c]",
			ExpectedDocuments: []interface{}{[]int{12, 2}, []int{13, 1}, []int{25, 1}, []int{42, 1}, []int{67, 1}},
			DocumentType:      reflect.TypeOf([]int{}),
			ExpectSuccess:     true,
		},
		queryTest{
			Query:             "FOR u IN users SORT u.name RETURN u.name",
			ExpectedDocuments: []interface{}{"Blair", "Clair", "Jake", "John", "Johnny", "Zz"},
			DocumentType:      reflect.TypeOf("foo"),
			ExpectSuccess:     true,
		},
	}

	// Setup context alternatives
	contexts := []queryTestContext{
		queryTestContext{nil, false},
		queryTestContext{context.Background(), false},
		queryTestContext{driver.WithQueryCount(nil), true},
		queryTestContext{driver.WithQueryCount(nil, true), true},
		queryTestContext{driver.WithQueryCount(nil, false), false},
		queryTestContext{driver.WithQueryBatchSize(nil, 1), false},
		queryTestContext{driver.WithQueryCache(nil), false},
		queryTestContext{driver.WithQueryCache(nil, true), false},
		queryTestContext{driver.WithQueryCache(nil, false), false},
		queryTestContext{driver.WithQueryMemoryLimit(nil, 60000), false},
		queryTestContext{driver.WithQueryTTL(nil, time.Minute), false},
		queryTestContext{driver.WithQueryBatchSize(driver.WithQueryCount(nil), 1), true},
		queryTestContext{driver.WithQueryCache(driver.WithQueryCount(driver.WithQueryBatchSize(nil, 2))), true},
	}

	// Run tests for every context alternative
	for _, qctx := range contexts {
		ctx := qctx.Context
		for i, test := range tests {
			cursor, err := db.Query(ctx, test.Query, test.BindVars)
			if err == nil {
				// Close upon exit of the function
				defer cursor.Close()
			}
			if test.ExpectSuccess {
				if err != nil {
					t.Errorf("Expected success in query %d (%s), got '%s'", i, test.Query, describe(err))
					continue
				}
				count := cursor.Count()
				if qctx.ExpectCount {
					if count != int64(len(test.ExpectedDocuments)) {
						t.Errorf("Expected count of %d, got %d in query %d (%s)", len(test.ExpectedDocuments), count, i, test.Query)
					}
				} else {
					if count != 0 {
						t.Errorf("Expected count of 0, got %d in query %d (%s)", count, i, test.Query)
					}
				}
				var result []interface{}
				for {
					hasMore := cursor.HasMore()
					doc := reflect.New(test.DocumentType)
					if _, err := cursor.ReadDocument(ctx, doc.Interface()); driver.IsNoMoreDocuments(err) {
						if hasMore {
							t.Error("HasMore returned true, but ReadDocument returns a IsNoMoreDocuments error")
						}
						break
					} else if err != nil {
						t.Errorf("Failed to result document %d: %s", len(result), describe(err))
					}
					if !hasMore {
						t.Error("HasMore returned false, but ReadDocument returns a document")
					}
					result = append(result, doc.Elem().Interface())
				}
				if len(result) != len(test.ExpectedDocuments) {
					t.Errorf("Expected %d documents, got %d in query %d (%s)", len(test.ExpectedDocuments), len(result), i, test.Query)
				} else {
					for resultIdx, resultDoc := range result {
						if !reflect.DeepEqual(resultDoc, test.ExpectedDocuments[resultIdx]) {
							t.Errorf("Unexpected document in query %d (%s) at index %d: got %+v, expected %+v", i, test.Query, resultIdx, resultDoc, test.ExpectedDocuments[resultIdx])
						}
					}
				}
				// Close anyway (this tests calling Close more than once)
				if err := cursor.Close(); err != nil {
					t.Errorf("Expected success in Close of cursor from query %d (%s), got '%s'", i, test.Query, describe(err))
				}
			} else {
				if err == nil {
					t.Errorf("Expected error in query %d (%s), got '%s'", i, test.Query, describe(err))
					continue
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"google.golang.org/grpc"
	"github.com/envoyproxy/go-control-plane/pkg/resource/v3"
	endpointservice "github.com/envoyproxy/go-control-plane/envoy/service/endpoint/v3"
	envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
	envoy_service_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
)

func main() {
	// Take a resource flag to practice sending different resources.
	// For simplicity, we will only request a single resource
	resourceFlag := flag.String("resource", "foo", "a string")
	flag.Parse()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// The go-control-plane example server by default listens at :18000
	conn, err := grpc.Dial(":18000", grpc.WithInsecure())
	if err != nil {
		fmt.Printf("Error connecting to management server: %v\n", err)
	}
	log.Printf("Connected to xDS Server. State: %v", conn.GetState())

	client := endpointservice.NewEndpointDiscoveryServiceClient(conn)

	// Discovery Request following format of go-control-plane integration test.
	// we do not provide version_info to match the initial ACK diagram in
	// xDS protocol docs
	discoveryRequest := &envoy_service_discovery_v3.DiscoveryRequest{
		Node: &envoy_config_core_v3.Node{
			Id: "test-id",
		},
		TypeUrl:       resource.EndpointType,
		ResourceNames: []string{*resourceFlag},
	}

	// Stream, send, and receive following integration test.
	sclient, err := client.StreamEndpoints(ctx)
	if err != nil {
		log.Fatalf("err setting up stream: %v", err.Error())
	}

	err = sclient.Send(discoveryRequest)
	if err != nil {
		log.Fatalf("err sending discoveryRequest: %v", err.Error())
	}

	awaitResponse := func() *envoy_service_discovery_v3.DiscoveryResponse {
		doneCh := make(chan *envoy_service_discovery_v3.DiscoveryResponse)
		go func() {

			r, err := sclient.Recv()
			if err != nil {
				fmt.Printf("errrrr: %v", err.Error())
			}
			doneCh <- r
		}()
		return <-doneCh
	}

	discoveryResponse := awaitResponse()
	respJSON, err := json.MarshalIndent(discoveryResponse, "", "   ")
	if err != nil {
		log.Fatalf("Error marshalling discoveryResponse: %v", err.Error())
	}
	log.Printf("response: %v\n", string(respJSON))
}
<commit_msg>Changing from EDS to CDS<commit_after>package main

import (
	"context"
	"encoding/json"
	//"flag"
	"fmt"
	"log"
	"google.golang.org/grpc"
	"github.com/envoyproxy/go-control-plane/pkg/resource/v3"
	cluster_service "github.com/envoyproxy/go-control-plane/envoy/service/cluster/v3"
	envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
	envoy_service_discovery_v3 "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
)

func main() {
	// Take a resource flag to practice sending different resources.
	// For simplicity, we will only request a single resource
	//resourceFlag := flag.String("resource", "foo", "a string")
	//flag.Parse()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// The go-control-plane example server by default listens at :18000
	conn, err := grpc.Dial(":18000", grpc.WithInsecure())
	if err != nil {
		fmt.Printf("Error connecting to management server: %v\n", err)
	}
	log.Printf("Connected to xDS Server. State: %v", conn.GetState())

	client := cluster_service.NewClusterDiscoveryServiceClient(conn)

	// Discovery Request following format of go-control-plane integration test.
	// we do not provide version_info to match the initial ACK diagram in
	// xDS protocol docs
	discoveryRequest := &envoy_service_discovery_v3.DiscoveryRequest{
		Node: &envoy_config_core_v3.Node{
			Id: "test-id",
		},
		TypeUrl:       resource.ClusterType,
		// Note that for CDS it is also possible to send a request w/o ResourceNames,
		// and it will return all clusters (wildcard request)
		ResourceNames: []string{"example_proxy_cluster"},
	}

	// Stream, send, and receive following integration test.
	sclient, err := client.StreamClusters(ctx)
	if err != nil {
		log.Fatalf("err setting up stream: %v", err.Error())
	}

	err = sclient.Send(discoveryRequest)
	if err != nil {
		log.Fatalf("err sending discoveryRequest: %v", err.Error())
	}

	awaitResponse := func() *envoy_service_discovery_v3.DiscoveryResponse {
		doneCh := make(chan *envoy_service_discovery_v3.DiscoveryResponse)
		go func() {

			r, err := sclient.Recv()
			if err != nil {
				fmt.Printf("errrrr: %v", err.Error())
			}
			doneCh <- r
		}()
		return <-doneCh
	}

	discoveryResponse := awaitResponse()
	respJSON, err := json.MarshalIndent(discoveryResponse, "", "   ")
	if err != nil {
		log.Fatalf("Error marshalling discoveryResponse: %v", err.Error())
	}
	log.Printf("response: %v\n", string(respJSON))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
)

// Print errors to os.Stderr
func printFatal(format string, a ...interface{}) {
	msg := fmt.Sprintf(format, a...)
	fmt.Fprintf(os.Stderr, "\x1b[31;1m%s\x1b[0m\n", msg)
	os.Exit(1)
}

// Print outputs to os.Stderr
func printOutput(format string, a ...interface{}) {
	msg := fmt.Sprintf(format, a...)
	fmt.Fprintf(os.Stderr, "\x1b[32;1m%s\x1b[0m\n", msg)
}

// Send infos to bitrise througth os.Stdout as JSON string
func sendBitriseInfo() {
	msg := map[string]string{
		"bitrise-info": "Bitrise CLI plugin sample",
	}

	msgJSON, err := json.Marshal(msg)
	if err != nil {
		printFatal("%s", err)
	}

	fmt.Fprintf(os.Stdout, "%s\n", msgJSON)
}

// Bitrise send informations to Plugin on os.Stdin as JSON string
func parseBitriseInfo() (string, error) {
	args := os.Args
	if len(args) < 2 {
		return "", errors.New("Invalid plugin usage, no bitrise infos passed to the plugin")
	}

	infos := args[1]
	return infos, nil
}

func main() {
	// Parse cli
	infos, err := parseBitriseInfo()
	if err != nil {
		printFatal("Failed to parse cli, err: %s", err)
	}

	printOutput("Hello World!")
	printOutput("Bitrise infos: %s", infos)
	sendBitriseInfo()
}
<commit_msg>requirements<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
)

//-----------------------------------
// Communication
//-----------------------------------

// Plugin output (logs, errors, ...) should send to os.Stderr
// Messages to bitrise (plugin requirements, plugin version, ...) should send to os.Stdout as JSON string

// Print errors to os.Stderr
func sendFatal(format string, a ...interface{}) {
	msg := fmt.Sprintf(format, a...)
	fmt.Fprintf(os.Stderr, "\x1b[31;1m%s\x1b[0m\n", msg)
	os.Exit(1)
}

// Print outputs to os.Stderr
func sendMessageToOutput(format string, a ...interface{}) {
	msg := fmt.Sprintf(format, a...)
	fmt.Fprintf(os.Stderr, "\x1b[32;1m%s\x1b[0m\n", msg)
}

// Send message to bitrise througth os.Stdout as JSON string
func sendMessageToBitrise(format string, a ...interface{}) {
	msgStr := fmt.Sprintf(format, a...)
	msg := map[string]string{
		"bitrise-info": msgStr,
	}

	msgJSON, err := json.Marshal(msg)
	if err != nil {
		sendFatal("%s", err)
	}

	fmt.Fprintf(os.Stdout, "%s\n", msgJSON)
}

//-----------------------------------
// CLI
//-----------------------------------

// Command model
type Command struct {
	Name string
	Func func() error
}

// Available commands
var commands = []Command{
	Command{
		Name: "requirements",
		Func: requirements,
	},
}

// Requirements command, all plugin should implement this.
// After installing a plugin, bitrise ask a plugin for plugin requirements.
func requirements() error {
	type Requirement struct {
		ToolName   string
		MinVersion string
		MaxVersion string
	}

	var requirements = []Requirement{
		Requirement{
			ToolName:   "bitrise",
			MinVersion: "1.3.0",
			MaxVersion: "",
		},
		Requirement{
			ToolName:   "stepman",
			MinVersion: "1.3.0",
			MaxVersion: "",
		},
		Requirement{
			ToolName:   "envman",
			MinVersion: "1.3.0",
			MaxVersion: "",
		},
	}

	bytes, err := json.Marshal(requirements)
	if err != nil {
		return err
	}

	sendMessageToBitrise(string(bytes))

	return nil
}

// Bitrise send messages to Plugin on os.Stdin as JSON string.
// Message can be request for command (ex: requirements, doSomething, ...),
// or informations from bitrise (ex: bitrise version, bitrise workflow path, ...)
func parseCli() (string, error) {
	args := os.Args
	if len(args) < 2 {
		return "", errors.New("Invalid plugin usage, no bitrise infos, even command passed to the plugin")
	}

	msg := os.Args[1]
	return msg, nil
}

//-----------------------------------
// Main
//-----------------------------------

func main() {
	message, err := parseCli()
	if err != nil {
		sendFatal("Failed to parse cli, err: %s", err)
	}

	messageIsCommand := false
	for _, command := range commands {
		if command.Name == message {
			if err := command.Func(); err != nil {
				sendFatal("Failed to perform command (%s), err: %s", command.Name, err)
			}
			messageIsCommand = true
		}
	}

	if !messageIsCommand {
		sendMessageToOutput("Bitrise message: %s", message)
		sendMessageToOutput("Hello World!")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/spiegel-im-spiegel/gocli"
	"github.com/spiegel-im-spiegel/gpgpdump/facade"
)

const (
	// Name of application
	Name string = "gpgpdump"
	// Version of application
	Version string = "version 0.0.0\nCopyright (C) 2016 Spiegel\nLicensed under Apache License Version 2.0 <http://www.apache.org/licenses/>"
)

func setupFacade(ui *gocli.UI) *facade.Facade {
	return facade.NewFacade(Name, Version, ui)
}

func main() {
	ui := gocli.NewUI()
	fcd := setupFacade(ui)
	if rtn, err := fcd.Run(os.Args[1:]); rtn != facade.ExitSuccess {
		if err != nil {
			ui.OutputErrln(err)
		}
		os.Exit(rtn)
	}
	os.Exit(facade.ExitSuccess)
}
<commit_msg>fix license.<commit_after>package main

import (
	"os"

	"github.com/spiegel-im-spiegel/gocli"
	"github.com/spiegel-im-spiegel/gpgpdump/facade"
)

const (
	// Name of application
	Name string = "gpgpdump"
	// Version of application
	Version string = "version 0.0.0\nCopyright 2016 Spiegel\nLicensed under Apache License Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0>"
)

func setupFacade(ui *gocli.UI) *facade.Facade {
	return facade.NewFacade(Name, Version, ui)
}

func main() {
	ui := gocli.NewUI()
	fcd := setupFacade(ui)
	if rtn, err := fcd.Run(os.Args[1:]); rtn != facade.ExitSuccess {
		if err != nil {
			ui.OutputErrln(err)
		}
		os.Exit(rtn)
	}
	os.Exit(facade.ExitSuccess)
}
<|endoftext|>


<commit_before>package docker_helpers

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"sync"

	"github.com/Sirupsen/logrus"
)

type logWriter struct {
	log     *logrus.Entry
	isError bool
}

func (l *logWriter) Write(data []byte) (int, error) {
	row := strings.TrimRight(string(data), "\n")

	if l.isError {
		l.log.Error(row)
	} else {
		l.log.Info(row)
	}

	return len(data), nil
}

func newLogWriter(isError bool, fields logrus.Fields) *logWriter {
	return &logWriter{
		log: logrus.WithFields(fields),
		isError: isError,
	}
}

type machineCommand struct {
	lsCmd   *exec.Cmd
	lsLock  sync.Mutex
	lsCond  *sync.Cond
	lsData  []byte
	lsError error
}

func (m *machineCommand) ls() (data []byte, err error) {
	m.lsLock.Lock()
	defer m.lsLock.Unlock()

	if m.lsCond == nil {
		m.lsCond = sync.NewCond(&m.lsLock)
	}

	if m.lsCmd == nil {
		m.lsCmd = exec.Command("docker-machine", "ls", "-q")
		m.lsCmd.Env = os.Environ()
		go func() {
			m.lsData, m.lsError = m.lsCmd.Output()
			m.lsCmd = nil
			m.lsCond.Broadcast()
		}()
	}

	m.lsCond.Wait()

	return m.lsData, m.lsError
}

func (m *machineCommand) Create(driver, name string, opts ...string) error {
	args := []string{
		"create",
		"--driver", driver,
	}
	for _, opt := range opts {
		args = append(args, "--"+opt)
	}
	args = append(args, name)

	cmd := exec.Command("docker-machine", args...)
	cmd.Env = os.Environ()

	fields := logrus.Fields{
		"operation": "create",
		"driver": driver,
		"name": name,
	}
	cmd.Stdout = newLogWriter(false, fields)
	cmd.Stderr = newLogWriter(true, fields)

	logrus.Debugln("Executing", cmd.Path, cmd.Args)
	return cmd.Run()
}

func (m *machineCommand) Provision(name string) error {
	cmd := exec.Command("docker-machine", "provision", name)
	cmd.Env = os.Environ()

	fields := logrus.Fields{
		"operation": "provision",
		"name": name,
	}
	cmd.Stdout = newLogWriter(false, fields)
	cmd.Stderr = newLogWriter(true, fields)

	return cmd.Run()
}

func (m *machineCommand) Remove(name string) error {
	cmd := exec.Command("docker-machine", "rm", "-y", name)
	cmd.Env = os.Environ()

	fields := logrus.Fields{
		"operation": "remove",
		"name": name,
	}
	cmd.Stdout = newLogWriter(false, fields)
	cmd.Stderr = newLogWriter(true, fields)

	return cmd.Run()
}

func (m *machineCommand) List(nodeFilter string) (machines []string, err error) {
	data, err := m.ls()
	if err != nil {
		return
	}

	reader := bufio.NewReader(bytes.NewReader(data))
	for {
		var line string

		line, err = reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			return
		}

		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		var query string
		if n, _ := fmt.Sscanf(line, nodeFilter, &query); n != 1 {
			continue
		}

		machines = append(machines, line)
	}
}

func (m *machineCommand) get(args ...string) (out string, err error) {
	// Execute docker-machine to fetch IP
	cmd := exec.Command("docker-machine", args...)
	cmd.Env = os.Environ()
	data, err := cmd.Output()
	if err != nil {
		return
	}

	// Save the IP
	out = strings.TrimSpace(string(data))
	if out == "" {
		err = fmt.Errorf("failed to get %v", args)
	}
	return
}

func (m *machineCommand) IP(name string) (string, error) {
	return m.get("ip", name)
}

func (m *machineCommand) URL(name string) (string, error) {
	return m.get("url", name)
}

func (m *machineCommand) CertPath(name string) (string, error) {
	return m.get("inspect", name, "-f", "{{.HostOptions.AuthOptions.StorePath}}")
}

func (m *machineCommand) Status(name string) (string, error) {
	return m.get("status", name)
}

func (m *machineCommand) Exist(name string) bool {
	cmd := exec.Command("docker-machine", "inspect", name)
	cmd.Env = os.Environ()

	fields := logrus.Fields{
		"operation": "exists",
		"name": name,
	}
	cmd.Stderr = newLogWriter(true, fields)

	return cmd.Run() == nil
}

func (m *machineCommand) CanConnect(name string) bool {
	// Execute docker-machine config which actively ask the machine if it is up and online
	cmd := exec.Command("docker-machine", "config", name)
	cmd.Env = os.Environ()
	err := cmd.Run()
	if err == nil {
		return true
	}
	return false
}

func (m *machineCommand) Credentials(name string) (dc DockerCredentials, err error) {
	if !m.CanConnect(name) {
		err = errors.New("Can't connect")
		return
	}

	dc.TLSVerify = true
	dc.Host, err = m.URL(name)
	if err == nil {
		dc.CertPath, err = m.CertPath(name)
	}
	return
}

func NewMachineCommand() Machine {
	return &machineCommand{}
}
<commit_msg>Change docker machine operations logger to pipereader<commit_after>package docker_helpers

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"sync"

	"github.com/Sirupsen/logrus"
)

type logWriter struct {
	log    func(args ...interface{})
	reader *bufio.Reader
}

func (l *logWriter) write(line string) {
	line = strings.TrimRight(line, "\n")

	if len(line) <= 0 {
		return
	}

	l.log(line)
}

func (l *logWriter) watch() {
	for {
		line, err := l.reader.ReadString('\n')
		if err == nil || err == io.EOF {
			l.write(line)
			if err == io.EOF {
				return
			}
		} else {
			logrus.WithError(err).Errorln("Problem while reading command output")
		}
	}
}

func newLogWriter(logFunction func(args ...interface{}), reader io.Reader) {
	writer := &logWriter{
		log:    logFunction,
		reader: bufio.NewReader(reader),
	}

	go writer.watch()
}

func stdoutLogWriter(cmd *exec.Cmd, fields logrus.Fields) {
	log := logrus.WithFields(fields)
	reader, _ := cmd.StdoutPipe()

	newLogWriter(log.Infoln, reader)
}

func stderrLogWriter(cmd *exec.Cmd, fields logrus.Fields) {
	log := logrus.WithFields(fields)
	reader, _ := cmd.StderrPipe()

	newLogWriter(log.Errorln, reader)
}

type machineCommand struct {
	lsCmd   *exec.Cmd
	lsLock  sync.Mutex
	lsCond  *sync.Cond
	lsData  []byte
	lsError error
}

func (m *machineCommand) ls() (data []byte, err error) {
	m.lsLock.Lock()
	defer m.lsLock.Unlock()

	if m.lsCond == nil {
		m.lsCond = sync.NewCond(&m.lsLock)
	}

	if m.lsCmd == nil {
		m.lsCmd = exec.Command("docker-machine", "ls", "-q")
		m.lsCmd.Env = os.Environ()
		go func() {
			m.lsData, m.lsError = m.lsCmd.Output()
			m.lsCmd = nil
			m.lsCond.Broadcast()
		}()
	}

	m.lsCond.Wait()

	return m.lsData, m.lsError
}

func (m *machineCommand) Create(driver, name string, opts ...string) error {
	args := []string{
		"create",
		"--driver", driver,
	}
	for _, opt := range opts {
		args = append(args, "--"+opt)
	}
	args = append(args, name)

	cmd := exec.Command("docker-machine", args...)
	cmd.Env = os.Environ()

	fields := logrus.Fields{
		"operation": "create",
		"driver":    driver,
		"name":      name,
	}
	stdoutLogWriter(cmd, fields)
	stderrLogWriter(cmd, fields)

	logrus.Debugln("Executing", cmd.Path, cmd.Args)
	return cmd.Run()
}

func (m *machineCommand) Provision(name string) error {
	cmd := exec.Command("docker-machine", "provision", name)
	cmd.Env = os.Environ()

	fields := logrus.Fields{
		"operation": "provision",
		"name":      name,
	}
	stdoutLogWriter(cmd, fields)
	stderrLogWriter(cmd, fields)

	return cmd.Run()
}

func (m *machineCommand) Remove(name string) error {
	cmd := exec.Command("docker-machine", "rm", "-y", name)
	cmd.Env = os.Environ()

	fields := logrus.Fields{
		"operation": "remove",
		"name":      name,
	}
	stdoutLogWriter(cmd, fields)
	stderrLogWriter(cmd, fields)

	return cmd.Run()
}

func (m *machineCommand) List(nodeFilter string) (machines []string, err error) {
	data, err := m.ls()
	if err != nil {
		return
	}

	reader := bufio.NewReader(bytes.NewReader(data))
	for {
		var line string

		line, err = reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			return
		}

		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		var query string
		if n, _ := fmt.Sscanf(line, nodeFilter, &query); n != 1 {
			continue
		}

		machines = append(machines, line)
	}
}

func (m *machineCommand) get(args ...string) (out string, err error) {
	// Execute docker-machine to fetch IP
	cmd := exec.Command("docker-machine", args...)
	cmd.Env = os.Environ()
	data, err := cmd.Output()
	if err != nil {
		return
	}

	// Save the IP
	out = strings.TrimSpace(string(data))
	if out == "" {
		err = fmt.Errorf("failed to get %v", args)
	}
	return
}

func (m *machineCommand) IP(name string) (string, error) {
	return m.get("ip", name)
}

func (m *machineCommand) URL(name string) (string, error) {
	return m.get("url", name)
}

func (m *machineCommand) CertPath(name string) (string, error) {
	return m.get("inspect", name, "-f", "{{.HostOptions.AuthOptions.StorePath}}")
}

func (m *machineCommand) Status(name string) (string, error) {
	return m.get("status", name)
}

func (m *machineCommand) Exist(name string) bool {
	cmd := exec.Command("docker-machine", "inspect", name)
	cmd.Env = os.Environ()

	fields := logrus.Fields{
		"operation": "exists",
		"name":      name,
	}
	stderrLogWriter(cmd, fields)

	return cmd.Run() == nil
}

func (m *machineCommand) CanConnect(name string) bool {
	// Execute docker-machine config which actively ask the machine if it is up and online
	cmd := exec.Command("docker-machine", "config", name)
	cmd.Env = os.Environ()
	err := cmd.Run()
	if err == nil {
		return true
	}
	return false
}

func (m *machineCommand) Credentials(name string) (dc DockerCredentials, err error) {
	if !m.CanConnect(name) {
		err = errors.New("Can't connect")
		return
	}

	dc.TLSVerify = true
	dc.Host, err = m.URL(name)
	if err == nil {
		dc.CertPath, err = m.CertPath(name)
	}
	return
}

func NewMachineCommand() Machine {
	return &machineCommand{}
}
<|endoftext|>


<commit_before>// Copyright 2016 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"

	"github.com/docker/go-plugins-helpers/authorization"
	"github.com/fsnotify/fsnotify"
)

// DockerAuthZPlugin implements the authorization.Plugin interface.
// Every request received by the Docker daemon will be forwarded to the
// AuthZReq function. The AuthZReq function returns a response that indicates
// whether the request should be allowed or denied.
type DockerAuthZPlugin struct {
	opaURL string
}

// AuthZReq is called when the Docker daemon receives an API request.
// AuthZReq returns an authorization.Response that indicates whether the request should be
// allowed or denied.
func (p DockerAuthZPlugin) AuthZReq(r authorization.Request) authorization.Response {

	fmt.Println("Received request from Docker:", r)

	b, err := IsAllowed(p.opaURL, r)

	if b {
		return authorization.Response{Allow: true}
	} else if err != nil {
		return authorization.Response{Err: err.Error()}
	}

	return authorization.Response{Msg: "request rejected by administrative policy"}
}

// AuthZRes is called before the Docker daemon returns an API response. All responses
// are allowed.
func (p DockerAuthZPlugin) AuthZRes(r authorization.Request) authorization.Response {
	return authorization.Response{Allow: true}
}

// IsAllowed queries the policy that was loaded into OPA and returns (true, nil) if the
// request should be allowed. If the request is not allowed, b will be false and e will
// be set to indicate if an error occurred. This function "fails closed" meaning if an error
// occurs, the request will be rejected.
func IsAllowed(opaURL string, r authorization.Request) (b bool, e error) {

	// Query OPA to see if the request should be allowed.
	resp, err := QueryDataAPI(opaURL, "/opa/example/allow_request", r)
	if err != nil {
		return false, err
	}

	// If the request succeeded, the request should be allowed.
	if resp.StatusCode == 200 {
		return true, nil
	}

	// If the response is undefined, the request should be rejected.
	if IsUndefined(resp) {
		return false, nil
	}

	// Othewrise, an error occured so reject the request and include an error message.
	if resp.StatusCode == 404 {
		return false, fmt.Errorf("policy does not exist")
	}

	return false, fmt.Errorf("unexpected error: %v", resp)
}

// IsUndefined returns true if the http.Response resp from OPA indicates
// an undefined query result
func IsUndefined(resp *http.Response) bool {
	return resp.StatusCode == 404
}

// LoadPolicy reads the policy definition from the path f and upserts it into OPA.
func LoadPolicy(opaURL, f string) error {
	r, err := os.Open(f)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", opaURL+"/policies/example_policy", r)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		d := json.NewDecoder(resp.Body)
		var e map[string]interface{}
		if err := d.Decode(&e); err != nil {
			return err
		}
		return fmt.Errorf("upsert failed (code: %v): %v", e["Code"], e["Message"])
	}

	return nil
}

// WatchPolicy creates a filesystem watch on the path f and waits for changes. When the
// file changes, LoadPolicy is called with the path f.
func WatchPolicy(opaURL, f string) error {

	w, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {
		for {
			select {
			case evt := <-w.Events:
				if evt.Op&fsnotify.Write != 0 {
					if err := LoadPolicy(opaURL, f); err != nil {
						fmt.Println("Error reloading policy definition:", err)
					} else {
						fmt.Println("Reloaded policy definition.")
					}
				}
			}
		}
	}()

	if err := w.Add(f); err != nil {
		return err
	}

	return nil
}

// QueryDataAPI executes a GET request against OPA's Data API. If successful, an http.Response is
// returned. The doc parameter identifies the document defined by the authorization policy. The
// query includes the authorization.Request r as input.
func QueryDataAPI(opaURL string, doc string, r authorization.Request) (*http.Response, error) {

	m := map[string]interface{}{
		"Headers":    r.RequestHeaders,
		"Path":       r.RequestURI,
		"Method":     r.RequestMethod,
		"Body":       r.RequestBody,
		"User":       r.User,
		"AuthMethod": r.UserAuthNMethod,
	}

	if r.RequestHeaders["Content-Type"] == "application/json" {
		var body interface{}
		if err := json.Unmarshal(r.RequestBody, &body); err != nil {
			return nil, err
		}
		m["Body"] = body
	}

	bs, err := json.Marshal(m)
	if err != nil {
		return nil, err
	}

	global := url.QueryEscape(string(bs))

	// The policy declares an input named "request" that is intended to contain
	// the Docker API request.
	url := fmt.Sprintf("%s/data%s?global=request:%s", opaURL, doc, global)

	return http.Get(url)
}

const (
	version = "0.1.2"
)

func main() {

	bindAddr := flag.String("bind-addr", ":8080", "sets the address the plugin will bind to")
	pluginName := flag.String("plugin-name", "opa-docker-authz", "sets the plugin name that will be registered with Docker")
	opaURL := flag.String("opa-url", "http://localhost:8181/v1", "sets the base URL of OPA's HTTP API")
	policyFile := flag.String("policy-file", "", "sets the path of the policy file to load")
	vers := flag.Bool("version", false, "print the version of the plugin")

	flag.Parse()

	if *vers {
		fmt.Println(version)
		os.Exit(0)
	}

	p := DockerAuthZPlugin{*opaURL}
	h := authorization.NewHandler(p)

	if *policyFile != "" {
		if err := LoadPolicy(*opaURL, *policyFile); err != nil {
			fmt.Println("Error while loading policy:", err)
			os.Exit(1)
		}

		if err := WatchPolicy(*opaURL, *policyFile); err != nil {
			fmt.Println("Error while starting watch:", err)
			os.Exit(1)
		}
	}

	fmt.Println("Starting server.")

	// No TLS configuration given for now.
	if err := h.ServeTCP(*pluginName, *bindAddr, nil); err != nil {
		fmt.Println("Error while serving HTTP:", err)
		os.Exit(1)
	}
}
<commit_msg>Update to OPA v0.3.0<commit_after>// Copyright 2016 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"

	"github.com/docker/go-plugins-helpers/authorization"
	"github.com/fsnotify/fsnotify"
)

// DockerAuthZPlugin implements the authorization.Plugin interface.
// Every request received by the Docker daemon will be forwarded to the
// AuthZReq function. The AuthZReq function returns a response that indicates
// whether the request should be allowed or denied.
type DockerAuthZPlugin struct {
	opaURL string
}

// AuthZReq is called when the Docker daemon receives an API request.
// AuthZReq returns an authorization.Response that indicates whether the request should be
// allowed or denied.
func (p DockerAuthZPlugin) AuthZReq(r authorization.Request) authorization.Response {

	fmt.Println("Received request from Docker:", r)

	b, err := IsAllowed(p.opaURL, r)

	if b {
		return authorization.Response{Allow: true}
	} else if err != nil {
		return authorization.Response{Err: err.Error()}
	}

	return authorization.Response{Msg: "request rejected by administrative policy"}
}

// AuthZRes is called before the Docker daemon returns an API response. All responses
// are allowed.
func (p DockerAuthZPlugin) AuthZRes(r authorization.Request) authorization.Response {
	return authorization.Response{Allow: true}
}

// IsAllowed queries the policy that was loaded into OPA and returns (true, nil) if the
// request should be allowed. If the request is not allowed, b will be false and e will
// be set to indicate if an error occurred. This function "fails closed" meaning if an error
// occurs, the request will be rejected.
func IsAllowed(opaURL string, r authorization.Request) (b bool, e error) {

	// Query OPA to see if the request should be allowed.
	resp, err := QueryDataAPI(opaURL, "/opa/example/allow_request", r)
	if err != nil {
		return false, err
	}

	// If the request succeeded, the request should be allowed.
	if resp.StatusCode == 200 {
		return true, nil
	}

	// If the response is undefined, the request should be rejected.
	if IsUndefined(resp) {
		return false, nil
	}

	// Othewrise, an error occured so reject the request and include an error message.
	if resp.StatusCode == 404 {
		return false, fmt.Errorf("policy does not exist")
	}

	return false, fmt.Errorf("unexpected error: %v", resp)
}

// IsUndefined returns true if the http.Response resp from OPA indicates
// an undefined query result
func IsUndefined(resp *http.Response) bool {
	return resp.StatusCode == 404
}

// LoadPolicy reads the policy definition from the path f and upserts it into OPA.
func LoadPolicy(opaURL, f string) error {
	r, err := os.Open(f)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", opaURL+"/policies/example_policy", r)
	if err != nil {
		return err
	}

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		d := json.NewDecoder(resp.Body)
		var e map[string]interface{}
		if err := d.Decode(&e); err != nil {
			return err
		}
		return fmt.Errorf("upsert failed (code: %v): %v", e["Code"], e["Message"])
	}

	return nil
}

// WatchPolicy creates a filesystem watch on the path f and waits for changes. When the
// file changes, LoadPolicy is called with the path f.
func WatchPolicy(opaURL, f string) error {

	w, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	go func() {
		for {
			select {
			case evt := <-w.Events:
				if evt.Op&fsnotify.Write != 0 {
					if err := LoadPolicy(opaURL, f); err != nil {
						fmt.Println("Error reloading policy definition:", err)
					} else {
						fmt.Println("Reloaded policy definition.")
					}
				}
			}
		}
	}()

	if err := w.Add(f); err != nil {
		return err
	}

	return nil
}

// QueryDataAPI executes a GET request against OPA's Data API. If successful, an http.Response is
// returned. The doc parameter identifies the document defined by the authorization policy. The
// query includes the authorization.Request r as input.
func QueryDataAPI(opaURL string, doc string, r authorization.Request) (*http.Response, error) {

	m := map[string]interface{}{
		"Headers":    r.RequestHeaders,
		"Path":       r.RequestURI,
		"Method":     r.RequestMethod,
		"Body":       r.RequestBody,
		"User":       r.User,
		"AuthMethod": r.UserAuthNMethod,
	}

	if r.RequestHeaders["Content-Type"] == "application/json" {
		var body interface{}
		if err := json.Unmarshal(r.RequestBody, &body); err != nil {
			return nil, err
		}
		m["Body"] = body
	}

	bs, err := json.Marshal(m)
	if err != nil {
		return nil, err
	}

	// Set the request document to the Docker request content.
	url := fmt.Sprintf("%s/data%s?request=:%s", opaURL, doc, url.QueryEscape(string(bs)))

	return http.Get(url)
}

const (
	version = "0.1.3"
)

func main() {

	bindAddr := flag.String("bind-addr", ":8080", "sets the address the plugin will bind to")
	pluginName := flag.String("plugin-name", "opa-docker-authz", "sets the plugin name that will be registered with Docker")
	opaURL := flag.String("opa-url", "http://localhost:8181/v1", "sets the base URL of OPA's HTTP API")
	policyFile := flag.String("policy-file", "", "sets the path of the policy file to load")
	vers := flag.Bool("version", false, "print the version of the plugin")

	flag.Parse()

	if *vers {
		fmt.Println(version)
		os.Exit(0)
	}

	p := DockerAuthZPlugin{*opaURL}
	h := authorization.NewHandler(p)

	if *policyFile != "" {
		if err := LoadPolicy(*opaURL, *policyFile); err != nil {
			fmt.Println("Error while loading policy:", err)
			os.Exit(1)
		}

		if err := WatchPolicy(*opaURL, *policyFile); err != nil {
			fmt.Println("Error while starting watch:", err)
			os.Exit(1)
		}
	}

	fmt.Println("Starting server.")

	// No TLS configuration given for now.
	if err := h.ServeTCP(*pluginName, *bindAddr, nil); err != nil {
		fmt.Println("Error while serving HTTP:", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
       "os"

       "github.com/ninjasphere/go-ninja"
       "github.com/ninjasphere/go-ninja/logger"
       "github.com/ninjasphere/go-openzwave"
       "github.com/ninjasphere/go-openzwave/LOG_LEVEL"
)

const driverName = "driver-zwave"

var log = logger.GetLogger(driverName)

func main() {

	log.Infof("Starting " + driverName)

	conn, err := ninja.Connect("com.ninjablocks.zwave")
	if err != nil {
		log.FatalError(err, "Could not connect to MQTT")
	}

	pwd, _ := os.Getwd()

	bus, err := conn.AnnounceDriver("com.ninjablocks.zwave", driverName, pwd)
	if err != nil {
		log.FatalError(err, "Could not get driver bus")
	}

	statusJob, err := ninja.CreateStatusJob(conn, driverName)

	if err != nil {
		log.FatalError(err, "Could not setup status job")
	}

	statusJob.Start()

	ipAddr, err := ninja.GetNetAddress()
	if err != nil {
		log.FatalError(err, "Could not get net address")
	}

	_ = bus
	_ = ipAddr

	loop := func(api openzwave.API) {
		for {
		    select {
		    	case notification := <- api.Notifications():
			     log.Infof("notification received <- %v\n", notification);
			     api.FreeNotification(notification);
			case quitReceived := <- api.QuitSignal():
			     _ = quitReceived
			     return;
		    }
		}
	}

	os.Exit(openzwave.
		BuildAPI("/usr/local/etc/openzwave", "", "").
		AddIntOption("SaveLogLevel", LOG_LEVEL.DETAIL).
		AddIntOption("QueueLogLevel", LOG_LEVEL.DEBUG).
		AddIntOption("DumpTrigger", LOG_LEVEL.ERROR).
		AddIntOption("PollInterval", 500).
		AddBoolOption("IntervalBetweenPolls", true).
		AddBoolOption("ValidateValueChanges", true).
		Run(loop));

}
<commit_msg>Turn off verbose logging, change poll interval to 60 seconds.<commit_after>package main

import (
       "os"

       "github.com/ninjasphere/go-ninja"
       "github.com/ninjasphere/go-ninja/logger"
       "github.com/ninjasphere/go-openzwave"
       "github.com/ninjasphere/go-openzwave/LOG_LEVEL"
)

const driverName = "driver-zwave"

var log = logger.GetLogger(driverName)

func main() {

	log.Infof("Starting " + driverName)

	conn, err := ninja.Connect("com.ninjablocks.zwave")
	if err != nil {
		log.FatalError(err, "Could not connect to MQTT")
	}

	pwd, _ := os.Getwd()

	bus, err := conn.AnnounceDriver("com.ninjablocks.zwave", driverName, pwd)
	if err != nil {
		log.FatalError(err, "Could not get driver bus")
	}

	statusJob, err := ninja.CreateStatusJob(conn, driverName)

	if err != nil {
		log.FatalError(err, "Could not setup status job")
	}

	statusJob.Start()

	ipAddr, err := ninja.GetNetAddress()
	if err != nil {
		log.FatalError(err, "Could not get net address")
	}

	_ = bus
	_ = ipAddr

	loop := func(api openzwave.API) {
		for {
		    select {
		    	case notification := <- api.Notifications():
			     log.Infof("notification received <- %v\n", notification);
			     api.FreeNotification(notification);
			case quitReceived := <- api.QuitSignal():
			     _ = quitReceived
			     return;
		    }
		}
	}

	os.Exit(openzwave.
		BuildAPI("/usr/local/etc/openzwave", "", "").
		AddIntOption("SaveLogLevel", LOG_LEVEL.NONE).
		AddIntOption("QueueLogLevel", LOG_LEVEL.NONE).
		AddIntOption("DumpTrigger", LOG_LEVEL.NONE).
		AddIntOption("PollInterval", 60).
		AddBoolOption("IntervalBetweenPolls", true).
		AddBoolOption("ValidateValueChanges", true).
		Run(loop));

}
<|endoftext|>