<commit_before>package gexec

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
)

var tmpDir string

/*
Build uses go build to compile the package at packagePath.  The resulting binary is saved off in a temporary directory.
A path pointing to this binary is returned.

Build uses the $GOPATH set in your environment.  It passes the variadic args on to `go build`.
*/
func Build(packagePath string, args ...string) (compiledPath string, err error) {
	return BuildIn(os.Getenv("GOPATH"), packagePath, args...)
}

/*
BuildIn is identical to Build but allows you to specify a custom $GOPATH (the first argument).
*/
func BuildIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) {
	tmpDir, err := temporaryDirectory()
	if err != nil {
		return "", err
	}

	if len(gopath) == 0 {
		return "", errors.New("$GOPATH not provided when building " + packagePath)
	}

	executable := filepath.Join(tmpDir, filepath.Base(packagePath))

	cmdArgs := append([]string{"build"}, args...)
	cmdArgs = append(cmdArgs, "-o", executable, packagePath)

	build := exec.Command("go", cmdArgs...)
	build.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)

	output, err := build.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output))
	}

	return executable, nil
}

/*
You should call CleanupBuildArtifacts before your test ends to clean up any temporary artifacts generated by
gexec. In Ginkgo this is typically done in an AfterSuite callback.
*/
func CleanupBuildArtifacts() {
	if tmpDir != "" {
		os.RemoveAll(tmpDir)
	}
}

func temporaryDirectory() (string, error) {
	var err error
	if tmpDir == "" {
		tmpDir, err = ioutil.TempDir("", "gexec_artifacts")
		if err != nil {
			return "", err
		}
	}

	return ioutil.TempDir(tmpDir, "g")
}
<commit_msg>Make gexec.Build work on windows<commit_after>package gexec

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
)

var tmpDir string

/*
Build uses go build to compile the package at packagePath.  The resulting binary is saved off in a temporary directory.
A path pointing to this binary is returned.

Build uses the $GOPATH set in your environment.  It passes the variadic args on to `go build`.
*/
func Build(packagePath string, args ...string) (compiledPath string, err error) {
	return BuildIn(os.Getenv("GOPATH"), packagePath, args...)
}

/*
BuildIn is identical to Build but allows you to specify a custom $GOPATH (the first argument).
*/
func BuildIn(gopath string, packagePath string, args ...string) (compiledPath string, err error) {
	tmpDir, err := temporaryDirectory()
	if err != nil {
		return "", err
	}

	if len(gopath) == 0 {
		return "", errors.New("$GOPATH not provided when building " + packagePath)
	}

	executable := filepath.Join(tmpDir, path.Base(packagePath))
	if runtime.GOOS == "windows" {
		executable = executable + ".exe"
	}

	cmdArgs := append([]string{"build"}, args...)
	cmdArgs = append(cmdArgs, "-o", executable, packagePath)

	build := exec.Command("go", cmdArgs...)
	build.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)

	output, err := build.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("Failed to build %s:\n\nError:\n%s\n\nOutput:\n%s", packagePath, err, string(output))
	}

	return executable, nil
}

/*
You should call CleanupBuildArtifacts before your test ends to clean up any temporary artifacts generated by
gexec. In Ginkgo this is typically done in an AfterSuite callback.
*/
func CleanupBuildArtifacts() {
	if tmpDir != "" {
		os.RemoveAll(tmpDir)
	}
}

func temporaryDirectory() (string, error) {
	var err error
	if tmpDir == "" {
		tmpDir, err = ioutil.TempDir("", "gexec_artifacts")
		if err != nil {
			return "", err
		}
	}

	return ioutil.TempDir(tmpDir, "g")
}
<|endoftext|>


<commit_before>package gf256

const (
	fieldSize = 256 // 2^8
)

var (
	// 0x11b prime polynomial and 0x03 as generator
	expTable = [fieldSize]Element{1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1}
	logTable = [fieldSize]Element{0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120, 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142, 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56, 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, 44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, 127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183, 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157, 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7}
)

// Element is an element in a GF(256) polynomial.
type Element byte

// Add returns the sum of the receiver and the argument.
func (e Element) Add(a Element) Element {
	return Element(e ^ a)
}

// Sub returns the difference between the receiver and the argument.
func (e Element) Sub(a Element) Element {
	// addition and subtraction are the same in GF(256)
	return Element(e ^ a)
}

// Mul returns the product of the receiver and the argument.
func (e Element) Mul(a Element) Element {
	if e == 0 || a == 0 {
		return 0
	}
	return expTable[(int(e.Log())+int(a.Log()))%255]
}

// Div returns the receiver divided by the argument.
func (e Element) Div(a Element) Element {
	if a == 0 {
		panic("div by zero")
	}

	if e == 0 {
		return 0
	}

	p := (int(e.Log()) - int(a.Log())) % 255
	if p < 0 {
		p += 255
	}

	return expTable[p]
}

// Log returns the power n such that x^n is equivalent to the receiver in GF(256).
func (e Element) Log() Element {
	return Element(logTable[e])
}
<commit_msg>Added docs for gf256.<commit_after>// Package gf256 implements polynomials over GF(256).
package gf256

const (
	fieldSize = 256 // 2^8
)

var (
	// 0x11b prime polynomial and 0x03 as generator
	expTable = [fieldSize]Element{1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205, 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154, 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163, 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202, 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14, 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23, 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1}
	logTable = [fieldSize]Element{0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120, 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142, 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56, 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16, 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, 44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, 127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183, 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157, 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209, 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171, 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165, 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7}
)

// Element is an element in a GF(256) polynomial.
type Element byte

// Add returns the sum of the receiver and the argument.
func (e Element) Add(a Element) Element {
	return Element(e ^ a)
}

// Sub returns the difference between the receiver and the argument.
func (e Element) Sub(a Element) Element {
	// addition and subtraction are the same in GF(256)
	return Element(e ^ a)
}

// Mul returns the product of the receiver and the argument.
func (e Element) Mul(a Element) Element {
	if e == 0 || a == 0 {
		return 0
	}
	return expTable[(int(e.Log())+int(a.Log()))%255]
}

// Div returns the receiver divided by the argument.
func (e Element) Div(a Element) Element {
	if a == 0 {
		panic("div by zero")
	}

	if e == 0 {
		return 0
	}

	p := (int(e.Log()) - int(a.Log())) % 255
	if p < 0 {
		p += 255
	}

	return expTable[p]
}

// Log returns the power n such that x^n is equivalent to the receiver in GF(256).
func (e Element) Log() Element {
	return Element(logTable[e])
}
<|endoftext|>


<commit_before>package checks

import (
	"database/sql"
	"encoding/json"
	"errors"
	"log"

	_ "github.com/lib/pq"
	"gopkg.in/gorp.v1"
)

func init() {
	Register("postgres", NewPostgres)
}

type Postgres struct {
	ConnectionURL string        `json:"connection_url"`
	MetricQueries []MetricQuery `json:"metric_queries"`
}

type MetricQuery struct {
	Metric string `json:"metric"`
	Query  string `json:"query"`
}

var NewPostgres = func(config Config, logger *log.Logger) (Checker, error) {
	postgres := new(Postgres)
	err := json.Unmarshal([]byte(config.Config), postgres)
	if err != nil {
		return nil, err
	}
	if postgres.ConnectionURL == "" {
		return nil, errors.New("postgres: connection url cannot be blank")
	}
	if len(postgres.MetricQueries) == 0 {
		return nil, errors.New("postgres: no metrics to query")
	}
	return Checker(postgres), nil
}

func (p *Postgres) Check() (Metrics, error) {

	output := Metrics(make(map[string]*float64))

	db, err := initDB(p.ConnectionURL)
	if err != nil {
		return output, err
	}

	for _, mq := range p.MetricQueries {
		count, err := query(db, mq.Query)
		if err != nil {
			return output, err
		}
		metricVal := float64(count)
		output[mq.Metric] = &metricVal
	}

	return output, nil
}

func initDB(url string) (*gorp.DbMap, error) {
	db, err := sql.Open("postgres", url)
	if err != nil {
		return nil, err
	}
	gorpDB := &gorp.DbMap{Db: db, Dialect: gorp.PostgresDialect{}}
	return gorpDB, nil
}

func query(db *gorp.DbMap, query string) (int64, error) {
	return db.SelectInt(query)
}

func (p *Postgres) MetricInfo(metric string) MetricInfo {
	return MetricInfo{Unit: ""}
}

func (p *Postgres) MessageContext() string {
	return ""
}
<commit_msg>Ensure db is closed after check<commit_after>package checks

import (
	"database/sql"
	"encoding/json"
	"errors"
	"log"

	_ "github.com/lib/pq"
	"gopkg.in/gorp.v1"
)

func init() {
	Register("postgres", NewPostgres)
}

type Postgres struct {
	ConnectionURL string        `json:"connection_url"`
	MetricQueries []MetricQuery `json:"metric_queries"`
}

type MetricQuery struct {
	Metric string `json:"metric"`
	Query  string `json:"query"`
}

var NewPostgres = func(config Config, logger *log.Logger) (Checker, error) {
	postgres := new(Postgres)
	err := json.Unmarshal([]byte(config.Config), postgres)
	if err != nil {
		return nil, err
	}
	if postgres.ConnectionURL == "" {
		return nil, errors.New("postgres: connection url cannot be blank")
	}
	if len(postgres.MetricQueries) == 0 {
		return nil, errors.New("postgres: no metrics to query")
	}
	return Checker(postgres), nil
}

func (p *Postgres) Check() (Metrics, error) {

	output := Metrics(make(map[string]*float64))

	db, err := initDB(p.ConnectionURL)
	if err != nil {
		return output, err
	}
	defer db.Db.Close()

	for _, mq := range p.MetricQueries {
		count, err := query(db, mq.Query)
		if err != nil {
			return output, err
		}
		metricVal := float64(count)
		output[mq.Metric] = &metricVal
	}

	return output, nil
}

func initDB(url string) (*gorp.DbMap, error) {
	db, err := sql.Open("postgres", url)
	if err != nil {
		return nil, err
	}
	gorpDB := &gorp.DbMap{Db: db, Dialect: gorp.PostgresDialect{}}
	return gorpDB, nil
}

func query(db *gorp.DbMap, query string) (int64, error) {
	return db.SelectInt(query)
}

func (p *Postgres) MetricInfo(metric string) MetricInfo {
	return MetricInfo{Unit: ""}
}

func (p *Postgres) MessageContext() string {
	return ""
}
<|endoftext|>


<commit_before>package build

import (
	"bytes"
	"text/template"

	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/buildtarget"
)

func nameFor(ctx *context.Context, target buildtarget.Target, name string) (string, error) {
	var out bytes.Buffer
	t, err := template.New(name).Parse(ctx.Config.Archive.NameTemplate)
	if err != nil {
		return "", err
	}
	data := struct {
		Os, Arch, Arm, Version, Tag, Binary, ProjectName string
	}{
		Os:          replace(ctx.Config.Archive.Replacements, target.OS),
		Arch:        replace(ctx.Config.Archive.Replacements, target.Arch),
		Arm:         replace(ctx.Config.Archive.Replacements, target.Arm),
		Version:     ctx.Version,
		Tag:         ctx.Git.CurrentTag,
		Binary:      name, // TODO: deprecated: remove this sometime
		ProjectName: name,
	}
	err = t.Execute(&out, data)
	return out.String(), err
}

func replace(replacements map[string]string, original string) string {
	result := replacements[original]
	if result == "" {
		return original
	}
	return result
}
<commit_msg>feat: support env vars for name_template<commit_after>package build

import (
	"bytes"
	"text/template"

	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/internal/buildtarget"
)

func nameFor(ctx *context.Context, target buildtarget.Target, name string) (string, error) {
	var out bytes.Buffer
	t, err := template.New(name).Parse(ctx.Config.Archive.NameTemplate)
	if err != nil {
		return "", err
	}
	data := struct {
		Os, Arch, Arm, Version, Tag, Binary, ProjectName string
		Env                                              map[string]string
	}{
		Os:          replace(ctx.Config.Archive.Replacements, target.OS),
		Arch:        replace(ctx.Config.Archive.Replacements, target.Arch),
		Arm:         replace(ctx.Config.Archive.Replacements, target.Arm),
		Version:     ctx.Version,
		Tag:         ctx.Git.CurrentTag,
		Binary:      name, // TODO: deprecated: remove this sometime
		ProjectName: name,
		Env:         ctx.Env,
	}
	err = t.Execute(&out, data)
	return out.String(), err
}

func replace(replacements map[string]string, original string) string {
	result := replacements[original]
	if result == "" {
		return original
	}
	return result
}
<|endoftext|>


<commit_before>package library

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
	"github.com/nytlabs/streamtools/st/blocks" // blocks
	"github.com/nytlabs/streamtools/st/util"
)

// specify those channels we're going to use to communicate with streamtools
type FromWebsocket struct {
	blocks.Block
	queryrule chan blocks.MsgChan
	inrule    blocks.MsgChan
	inpoll    blocks.MsgChan
	in        blocks.MsgChan
	out       blocks.MsgChan
	quit      blocks.MsgChan
}

// we need to build a simple factory so that streamtools can make new blocks of this kind
func NewFromWebsocket() blocks.BlockInterface {
	return &FromWebsocket{}
}

// Setup is called once before running the block. We build up the channels and specify what kind of block this is.
func (b *FromWebsocket) Setup() {
	b.Kind = "Network I/O"
	b.Desc = "connects to an existing websocket, emitting each message heard from the websocket"
	b.inrule = b.InRoute("rule")
	b.queryrule = b.QueryRoute("rule")
	b.quit = b.Quit()
	b.out = b.Broadcast()
}

type recvHandler struct {
	toOut   blocks.MsgChan
	toError chan error
}

func (self recvHandler) recv(ws *websocket.Conn, out blocks.MsgChan) {
	for {
		_, p, err := ws.ReadMessage()
		if err != nil {
			self.toError <- err
			return
		}

		var outMsg interface{}
		err = json.Unmarshal(p, &outMsg)
		// if the json parsing fails, store data unparsed as "data"
		if err != nil {
			outMsg = map[string]interface{}{
				"data": p,
			}
		}
		self.toOut <- outMsg
	}
}

// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *FromWebsocket) Run() {
	var ws *websocket.Conn
	var url string
	var handshakeDialer = &websocket.Dialer{
		Subprotocols: []string{"p1", "p2"},
	}
	listenWS := make(blocks.MsgChan)
	wsHeader := http.Header{"Origin": {"http://localhost/"}}

	toOut := make(blocks.MsgChan)
	toError := make(chan error)

	for {
		select {

		case msg := <-toOut:
			b.out <- msg

		case ruleI := <-b.inrule:
			var err error
			// set a parameter of the block
			url, err := util.ParseString(ruleI, "url")
			if err != nil {
				b.Error(err)
				continue
			}
			if ws != nil {
				ws.Close()
			}

			ws, _, err = handshakeDialer.Dial(url, wsHeader)
			if err != nil {
				b.Error("could not connect to url")
				break
			}
			ws.SetReadDeadline(time.Time{})
			h := recvHandler{toOut, toError}
			go h.recv(ws, listenWS)

		case err := <-toError:
			b.Error(err)

		case <-b.quit:
			// quit the block
			return
		case o := <-b.queryrule:
			o <- map[string]interface{}{
				"url": url,
			}
		case in := <-listenWS:
			b.out <- in
		}
	}
}
<commit_msg>fix for websocket forgetting rule<commit_after>package library

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
	"github.com/nytlabs/streamtools/st/blocks" // blocks
	"github.com/nytlabs/streamtools/st/util"
)

// specify those channels we're going to use to communicate with streamtools
type FromWebsocket struct {
	blocks.Block
	queryrule chan blocks.MsgChan
	inrule    blocks.MsgChan
	inpoll    blocks.MsgChan
	in        blocks.MsgChan
	out       blocks.MsgChan
	quit      blocks.MsgChan
}

// we need to build a simple factory so that streamtools can make new blocks of this kind
func NewFromWebsocket() blocks.BlockInterface {
	return &FromWebsocket{}
}

// Setup is called once before running the block. We build up the channels and specify what kind of block this is.
func (b *FromWebsocket) Setup() {
	b.Kind = "Network I/O"
	b.Desc = "connects to an existing websocket, emitting each message heard from the websocket"
	b.inrule = b.InRoute("rule")
	b.queryrule = b.QueryRoute("rule")
	b.quit = b.Quit()
	b.out = b.Broadcast()
}

type recvHandler struct {
	toOut   blocks.MsgChan
	toError chan error
}

func (self recvHandler) recv(ws *websocket.Conn, out blocks.MsgChan) {
	for {
		_, p, err := ws.ReadMessage()
		if err != nil {
			self.toError <- err
			return
		}

		var outMsg interface{}
		err = json.Unmarshal(p, &outMsg)
		// if the json parsing fails, store data unparsed as "data"
		if err != nil {
			outMsg = map[string]interface{}{
				"data": p,
			}
		}
		self.toOut <- outMsg
	}
}

// Run is the block's main loop. Here we listen on the different channels we set up.
func (b *FromWebsocket) Run() {
	var ws *websocket.Conn
	var url string
	var handshakeDialer = &websocket.Dialer{
		Subprotocols: []string{"p1", "p2"},
	}
	listenWS := make(blocks.MsgChan)
	wsHeader := http.Header{"Origin": {"http://localhost/"}}

	toOut := make(blocks.MsgChan)
	toError := make(chan error)

	for {
		select {

		case msg := <-toOut:
			b.out <- msg

		case ruleI := <-b.inrule:
			var err error
			// set a parameter of the block
			url, err = util.ParseString(ruleI, "url")
			if err != nil {
				b.Error(err)
				continue
			}
			if ws != nil {
				ws.Close()
			}

			ws, _, err = handshakeDialer.Dial(url, wsHeader)
			if err != nil {
				b.Error("could not connect to url")
				break
			}
			ws.SetReadDeadline(time.Time{})
			h := recvHandler{toOut, toError}
			go h.recv(ws, listenWS)

		case err := <-toError:
			b.Error(err)

		case <-b.quit:
			// quit the block
			return
		case o := <-b.queryrule:
			o <- map[string]interface{}{
				"url": url,
			}
		case in := <-listenWS:
			b.out <- in
		}
	}
}
<|endoftext|>


<commit_before>// problem56.go
//
// Considering natural numbers of the form, a**b, where a, b < 100,
// what is the maximum digital sum?

package main

import (
	"fmt"
	"math/big"
	"strconv"
)

func digitSum(n *big.Int) int64 {
	var sum int64
	for _, r := range n.String() {
		x, _ := strconv.Atoi(string(r))
		sum += int64(x)
	}
	return sum
}

func problem56() int64 {
	var max, i, j int64
	for i = 0; i < 100; i++ {
		for j = 0; j < 100; j++ {
			a, b := big.NewInt(i), big.NewInt(j)
			c := a.Exp(a, b, nil) // c = a**b
			sum := digitSum(c)
			if sum > max {
				max = sum
			}
		}
	}
	return max
}

func main() {
	ans := problem56()
	fmt.Println(ans)
}
<commit_msg>Better use of the big.Int API in problem56.go<commit_after>// problem56.go
//
// Considering natural numbers of the form, a**b, where a, b < 100,
// what is the maximum digital sum?

package main

import (
	"fmt"
	"math/big"
	"strconv"
)

func digitSum(n *big.Int) int64 {
	var sum int64
	for _, r := range n.String() {
		x, _ := strconv.Atoi(string(r))
		sum += int64(x)
	}
	return sum
}

func problem56() int64 {
	var max, i, j int64
	for i = 0; i < 100; i++ {
		for j = 0; j < 100; j++ {
			a, b, c := big.NewInt(i), big.NewInt(j), new(big.Int)
			c.Exp(a, b, nil) // c = a**b
			sum := digitSum(c)
			if sum > max {
				max = sum
			}
		}
	}
	return max
}

func main() {
	ans := problem56()
	fmt.Println(ans)
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 adapter

import (
	"errors"
	"time"
)

// Metric kinds supported by mixer.
const (
	Gauge        MetricKind = iota // records instantaneous (non-cumulative) measurements
	Counter                        // records increasing cumulative values
	Distribution                   // aggregates values in buckets (values still reported un-aggregated)
)

type (
	// MetricsAspect handles metric reporting within Mixer.
	MetricsAspect interface {
		Aspect

		// Record directs a backend adapter to record the list of values
		// that have been generated from Report() calls.
		Record([]Value) error
	}

	// Value holds a single metric value that will be generated through
	// a Report() call to Mixer. It is synthesized by Mixer, based on
	// configuration and the attributes passed to Report().
	Value struct {
		// The definition describing this metric.
		Definition *MetricDefinition
		// Labels provide metadata about the metric value. They are
		// generated from the set of attributes provided by Report().
		Labels map[string]interface{}
		// StartTime marks the beginning of the period for which the
		// metric value is being reported. For instantaneous metrics,
		// StartTime records the relevant instant.
		StartTime time.Time
		// EndTime marks the end of the period for which the metric
		// value is being reported. For instantaneous metrics, EndTime
		// will be set to the same value as StartTime.
		EndTime time.Time

		// The value of this metric; this should be accessed type-safely via value.String(), value.Bool(), etc.
		MetricValue interface{}
	}

	// MetricKind defines the set of known metrics types that can be generated by Mixer.
	MetricKind int

	// MetricsBuilder builds instances of the Metrics aspect.
	MetricsBuilder interface {
		Builder

		// NewMetricsAspect returns a new instance of the Metrics aspect.
		NewMetricsAspect(env Env, config Config, metrics map[string]*MetricDefinition) (MetricsAspect, error)
	}

	// MetricDefinition provides the basic description of a metric schema
	// for which metrics adapters will be sent Values at runtime.
	MetricDefinition struct {
		// Name is the canonical name of the metric.
		Name string
		// Optional user-friendly name of the metric.
		DisplayName string
		// Optional user-friendly description of this metric.
		Description string
		// Kind provides type information about the metric.
		Kind MetricKind
		// Provides type information about the value (payload) of the metric.
		Value LabelType
		// Labels are the names of keys for dimensional data that will
		// be generated at runtime and passed along with metric values.
		Labels map[string]LabelType

		Buckets BucketDefinition
	}

	// BucketDefinition provides a common interface for the various types
	// of bucket definitions.
	BucketDefinition interface{}

	// LinearBuckets describes a linear sequence of buckets that all have
	// the same width (except for underflow and overflow).
	//
	// There are `Count + 2` (= N) buckets. The two additional
	// buckets are the underflow and overflow buckets.
	//
	// Bucket `i` has the following boundaries:
	//    Upper bound (0 <= i < N-1):     offset + (width * i).
	//    Lower bound (1 <= i < N):       offset + (width * (i - 1)).
	LinearBuckets struct {
		BucketDefinition

		// Count is the number of buckets in this bucket definition.
		// Must be greater than 0.
		Count int32

		// Width describes the size of each individual bucket. Must be
		// greater than 0.
		Width float64

		// Offset is the lower bound of the first specified bucket.
		Offset float64
	}

	// ExponentialBuckets describes an exponential sequence of buckets that
	// have a width that is proportional to the value of the lower bound.
	//
	// There are `Count + 2` (= N) buckets. The two additional
	// buckets are the underflow and overflow buckets.
	//
	// Bucket `i` has the following boundaries:
	//    Upper bound (0 <= i < N-1):     scale * (growth_factor ^ i).
	//    Lower bound (1 <= i < N):       scale * (growth_factor ^ (i - 1)).
	ExponentialBuckets struct {
		BucketDefinition

		// Count is the number of buckets in this bucket definition.
		// Must be greater than 0.
		Count int32

		// GrowthFactor controls the rate of increase in size of the
		// buckets. Must be greater than 1.
		GrowthFactor float64

		// Scale controls the relative size of the buckets. Must be
		// greater than 0.
		Scale float64
	}

	// ExplicitBuckets specifies a set of buckets with arbitrary widths.
	//
	// There are `size(bounds) + 1` (= N) buckets. Bucket `i` has the following
	// boundaries:
	//
	//    Upper bound (0 <= i < N-1):     bounds[i]
	//    Lower bound (1 <= i < N);       bounds[i - 1]
	//
	// If `Bounds` has only one element, then there are no finite buckets,
	// and that single element is the common boundary of the overflow and
	// underflow buckets.
	ExplicitBuckets struct {
		BucketDefinition

		// Bounds describes the explicit bounds of the buckets being
		// defined. Must be at least 1 element long and have
		// monotonically increasing values.
		Bounds []float64
	}
)

// String returns the string-valued metric value for a metrics.Value.
func (v Value) String() (string, error) {
	if v, ok := v.MetricValue.(string); ok {
		return v, nil
	}
	return "", errors.New("metric value is not a string")
}

// Bool returns the boolean metric value for a metrics.Value.
func (v Value) Bool() (bool, error) {
	if v, ok := v.MetricValue.(bool); ok {
		return v, nil
	}
	return false, errors.New("metric value is not a boolean")
}

// Int64 returns the int64-valued metric value for a metrics.Value.
func (v Value) Int64() (int64, error) {
	if v, ok := v.MetricValue.(int64); ok {
		return v, nil
	}
	return 0, errors.New("metric value is not an int64")
}

// Float64 returns the float64-valued metric value for a metrics.Value.
func (v Value) Float64() (float64, error) {
	if v, ok := v.MetricValue.(float64); ok {
		return v, nil
	}
	return 0, errors.New("metric value is not a float64")
}

// Duration returns the float64-valued metric value for a metrics.Value.
func (v Value) Duration() (time.Duration, error) {
	if v, ok := v.MetricValue.(time.Duration); ok {
		return v, nil
	}
	return 0, errors.New("metric value is not a time.Duration")
}
<commit_msg>merging<commit_after>// Copyright 2017 Istio 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 adapter

import (
	"errors"
	"time"
)

// Metric kinds supported by mixer.
const (
	Gauge        MetricKind = iota // records instantaneous (non-cumulative) measurements
	Counter                        // records increasing cumulative values
	Distribution                   // aggregates values in buckets (values still reported un-aggregated)
)

type (
	// MetricsAspect handles metric reporting within Mixer.
	MetricsAspect interface {
		Aspect

		// Record directs a backend adapter to record the list of values
		// that have been generated from Report() calls.
		Record([]Value) error
	}

	// Value holds a single metric value that will be generated through
	// a Report() call to Mixer. It is synthesized by Mixer, based on
	// configuration and the attributes passed to Report().
	Value struct {
		// The definition describing this metric.
		Definition *MetricDefinition
		// Labels provide metadata about the metric value. They are
		// generated from the set of attributes provided by Report().
		Labels map[string]interface{}
		// StartTime marks the beginning of the period for which the
		// metric value is being reported. For instantaneous metrics,
		// StartTime records the relevant instant.
		StartTime time.Time
		// EndTime marks the end of the period for which the metric
		// value is being reported. For instantaneous metrics, EndTime
		// will be set to the same value as StartTime.
		EndTime time.Time

		// The value of this metric; this should be accessed type-safely via value.String(), value.Bool(), etc.
		MetricValue interface{}
	}

	// MetricKind defines the set of known metrics types that can be generated by Mixer.
	MetricKind int

	// MetricsBuilder builds instances of the Metrics aspect.
	MetricsBuilder interface {
		Builder
		// NewMetricsAspect returns a new instance of the Metrics aspect.
		NewMetricsAspect(env Env, config Config, metrics map[string]*MetricDefinition) (MetricsAspect, error)
	}

	// MetricDefinition provides the basic description of a metric schema
	// for which metrics adapters will be sent Values at runtime.
	MetricDefinition struct {
		// Name is the canonical name of the metric.
		Name string
		// Optional user-friendly name of the metric.
		DisplayName string
		// Optional user-friendly description of this metric.
		Description string
		// Kind provides type information about the metric.
		Kind MetricKind
		// Provides type information about the value (payload) of the metric.
		Value LabelType
		// Labels are the names of keys for dimensional data that will
		// be generated at runtime and passed along with metric values.
		Labels map[string]LabelType

		Buckets BucketDefinition
	}

	// BucketDefinition provides a common interface for the various types
	// of bucket definitions.
	BucketDefinition interface{}

	// LinearBuckets describes a linear sequence of buckets that all have
	// the same width (except for underflow and overflow).
	//
	// There are `Count + 2` (= N) buckets. The two additional
	// buckets are the underflow and overflow buckets.
	//
	// Bucket `i` has the following boundaries:
	//    Upper bound (0 <= i < N-1):     offset + (width * i).
	//    Lower bound (1 <= i < N):       offset + (width * (i - 1)).
	LinearBuckets struct {
		BucketDefinition

		// Count is the number of buckets in this bucket definition.
		// Must be greater than 0.
		Count int32

		// Width describes the size of each individual bucket. Must be
		// greater than 0.
		Width float64

		// Offset is the lower bound of the first specified bucket.
		Offset float64
	}

	// ExponentialBuckets describes an exponential sequence of buckets that
	// have a width that is proportional to the value of the lower bound.
	//
	// There are `Count + 2` (= N) buckets. The two additional
	// buckets are the underflow and overflow buckets.
	//
	// Bucket `i` has the following boundaries:
	//    Upper bound (0 <= i < N-1):     scale * (growth_factor ^ i).
	//    Lower bound (1 <= i < N):       scale * (growth_factor ^ (i - 1)).
	ExponentialBuckets struct {
		BucketDefinition

		// Count is the number of buckets in this bucket definition.
		// Must be greater than 0.
		Count int32

		// GrowthFactor controls the rate of increase in size of the
		// buckets. Must be greater than 1.
		GrowthFactor float64

		// Scale controls the relative size of the buckets. Must be
		// greater than 0.
		Scale float64
	}

	// ExplicitBuckets specifies a set of buckets with arbitrary widths.
	//
	// There are `size(bounds) + 1` (= N) buckets. Bucket `i` has the following
	// boundaries:
	//
	//    Upper bound (0 <= i < N-1):     bounds[i]
	//    Lower bound (1 <= i < N);       bounds[i - 1]
	//
	// If `Bounds` has only one element, then there are no finite buckets,
	// and that single element is the common boundary of the overflow and
	// underflow buckets.
	ExplicitBuckets struct {
		BucketDefinition

		// Bounds describes the explicit bounds of the buckets being
		// defined. Must be at least 1 element long and have
		// monotonically increasing values.
		Bounds []float64
	}
)

// String returns the string-valued metric value for a metrics.Value.
func (v Value) String() (string, error) {
	if v, ok := v.MetricValue.(string); ok {
		return v, nil
	}
	return "", errors.New("metric value is not a string")
}

// Bool returns the boolean metric value for a metrics.Value.
func (v Value) Bool() (bool, error) {
	if v, ok := v.MetricValue.(bool); ok {
		return v, nil
	}
	return false, errors.New("metric value is not a boolean")
}

// Int64 returns the int64-valued metric value for a metrics.Value.
func (v Value) Int64() (int64, error) {
	if v, ok := v.MetricValue.(int64); ok {
		return v, nil
	}
	return 0, errors.New("metric value is not an int64")
}

// Float64 returns the float64-valued metric value for a metrics.Value.
func (v Value) Float64() (float64, error) {
	if v, ok := v.MetricValue.(float64); ok {
		return v, nil
	}
	return 0, errors.New("metric value is not a float64")
}

// Duration returns the float64-valued metric value for a metrics.Value.
func (v Value) Duration() (time.Duration, error) {
	if v, ok := v.MetricValue.(time.Duration); ok {
		return v, nil
	}
	return 0, errors.New("metric value is not a time.Duration")
}
<|endoftext|>


<commit_before>// Copyright 2017-2020 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package boot

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/u-root/u-root/pkg/boot/linux"
	"github.com/u-root/u-root/pkg/curl"
	"github.com/u-root/u-root/pkg/mount"
	"github.com/u-root/u-root/pkg/uio"
	"github.com/u-root/u-root/pkg/vfile"
	"golang.org/x/sys/unix"
)

func TestLinuxLabel(t *testing.T) {
	dir := t.TempDir()

	osKernel, err := os.Create(filepath.Join(dir, "kernel"))
	if err != nil {
		t.Fatal(err)
	}

	osInitrd, err := os.Create(filepath.Join(dir, "initrd"))
	if err != nil {
		t.Fatal(err)
	}

	k, _ := url.Parse("http://127.0.0.1/kernel")
	i1, _ := url.Parse("http://127.0.0.1/initrd1")
	i2, _ := url.Parse("http://127.0.0.1/initrd2")
	httpKernel, _ := curl.LazyFetch(k)
	httpInitrd1, _ := curl.LazyFetch(i1)
	httpInitrd2, _ := curl.LazyFetch(i2)

	for _, tt := range []struct {
		desc string
		img  *LinuxImage
		want string
	}{
		{
			desc: "os.File",
			img: &LinuxImage{
				Kernel: osKernel,
				Initrd: osInitrd,
			},
			want: fmt.Sprintf("Linux(kernel=%s/kernel initrd=%s/initrd)", dir, dir),
		},
		{
			desc: "lazy file",
			img: &LinuxImage{
				Kernel: uio.NewLazyFile(filepath.Join(dir, "kernel")),
				Initrd: uio.NewLazyFile(filepath.Join(dir, "initrd")),
			},
			want: fmt.Sprintf("Linux(kernel=%s/kernel initrd=%s/initrd)", dir, dir),
		},
		{
			desc: "concat lazy file",
			img: &LinuxImage{
				Kernel: uio.NewLazyFile(filepath.Join(dir, "kernel")),
				Initrd: CatInitrds(
					uio.NewLazyFile(filepath.Join(dir, "initrd")),
					uio.NewLazyFile(filepath.Join(dir, "initrd")),
				),
			},
			want: fmt.Sprintf("Linux(kernel=%s/kernel initrd=%s/initrd,%s/initrd)", dir, dir, dir),
		},
		{
			desc: "curl lazy file",
			img: &LinuxImage{
				Kernel: httpKernel,
				Initrd: CatInitrds(
					httpInitrd1,
					httpInitrd2,
				),
			},
			want: "Linux(kernel=http://127.0.0.1/kernel initrd=http://127.0.0.1/initrd1,http://127.0.0.1/initrd2)",
		},
		{
			desc: "verified file",
			img: &LinuxImage{
				Kernel: &vfile.File{Reader: nil, FileName: "/boot/foobar"},
				Initrd: CatInitrds(
					&vfile.File{Reader: nil, FileName: "/boot/initrd1"},
					&vfile.File{Reader: nil, FileName: "/boot/initrd2"},
				),
			},
			want: "Linux(kernel=/boot/foobar initrd=/boot/initrd1,/boot/initrd2)",
		},
		{
			desc: "no initrd",
			img: &LinuxImage{
				Kernel: &vfile.File{Reader: nil, FileName: "/boot/foobar"},
				Initrd: nil,
			},
			want: "Linux(kernel=/boot/foobar)",
		},
		{
			desc: "dtb file",
			img: &LinuxImage{
				Kernel: &vfile.File{Reader: nil, FileName: "/boot/foobar"},
				Initrd: &vfile.File{Reader: nil, FileName: "/boot/initrd"},
				KexecOpts: linux.KexecOptions{
					DTB: &vfile.File{Reader: nil, FileName: "/boot/board.dtb"},
				},
			},
			want: "Linux(kernel=/boot/foobar initrd=/boot/initrd dtb=/boot/board.dtb)",
		},
		{
			desc: "dtb file, no initrd",
			img: &LinuxImage{
				Kernel: &vfile.File{Reader: nil, FileName: "/boot/foobar"},
				KexecOpts: linux.KexecOptions{
					DTB: &vfile.File{Reader: nil, FileName: "/boot/board.dtb"},
				},
			},
			want: "Linux(kernel=/boot/foobar dtb=/boot/board.dtb)",
		},
	} {
		t.Run(tt.desc, func(t *testing.T) {
			got := tt.img.Label()
			if got != tt.want {
				t.Errorf("Label() = %s, want %s", got, tt.want)
			}
		})
	}
}

func TestCopyToFile(t *testing.T) {
	want := "abcdefg hijklmnop"
	buf := bytes.NewReader([]byte(want))

	f, err := copyToFileIfNotRegular(buf, true)
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(f.Name())
	got, err := io.ReadAll(f)
	if err != nil {
		t.Fatal(err)
	}
	if string(got) != want {
		t.Errorf("got %s, expected %s", string(got), want)
	}
}

func TestLinuxRank(t *testing.T) {
	testRank := 2
	img := &LinuxImage{BootRank: testRank}
	l := img.Rank()
	if l != testRank {
		t.Fatalf("Expected Image rank %d, got %d", testRank, l)
	}
}

func checkReadOnly(t *testing.T, f *os.File) {
	t.Helper()
	wr := unix.O_RDWR | unix.O_WRONLY
	if am, err := unix.FcntlInt(f.Fd(), unix.F_GETFL, 0); err == nil && am&wr != 0 {
		t.Errorf("file %v opened for write, want read only", f)
	}
}

// checkFilePath checks if src and dst file are same file of fsrc were actually a os.File.
func checkFilePath(t *testing.T, fsrc io.ReaderAt, fdst *os.File) {
	t.Helper()
	if f, ok := fsrc.(*os.File); ok {
		if r, _ := mount.IsTmpRamfs(f.Name()); r {
			// Src is a file on tmpfs.
			if f.Name() != fdst.Name() {
				t.Errorf("Got a copied file %s, want skipping copy and use original file %s", fdst.Name(), f.Name())
			}
		}
	}
}

func setupTestFile(t *testing.T, path, content string) *os.File {
	t.Helper()
	f, err := os.Create(path)
	if err != nil {
		t.Fatal(err)
	}
	n, err := f.Write([]byte(content))
	if err != nil {
		t.Fatal(err)
	}
	if n != len([]byte(content)) {
		t.Fatalf("want %d bytes written, but got %d", len([]byte(content)), n)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("could not close test file: %v", err)
	}
	nf, err := os.Open(path)
	if err != nil {
		t.Fatalf("could not open test file: %v", err)
	}
	return nf
}

// GenerateCatDummyInitrd return padded string from the given list of strings following the same padding format of CatInitrds.
func GenerateCatDummyInitrd(t *testing.T, initrds ...string) string {
	var ins []io.ReaderAt
	for _, c := range initrds {
		ins = append(ins, strings.NewReader(c))
	}
	final := CatInitrds(ins...)
	d, err := io.ReadAll(uio.Reader(final))
	if err != nil {
		t.Fatalf("failed to generate concatenated initrd : %v", err)
	}
	return string(d)
}

type wantData struct {
	loadedImage *LoadedLinuxImage
	cleanup     func()
	err         error
}

func TestLoadLinuxImage(t *testing.T) {
	testDir := t.TempDir()

	for _, tt := range []struct {
		name string
		li   *LinuxImage
		want wantData
	}{
		{
			name: "kernel is nil",
			li:   &LinuxImage{Kernel: nil},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: nil,
				},
				err: errNilKernel,
			},
		},
		{
			name: "basic happy case w/o initrd",
			li: &LinuxImage{
				Kernel: strings.NewReader("testkernel"),
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "basic_happy_case_wo_initrd_bzimage"), "testkernel"),
				},
				err: nil,
			},
		},
		{
			name: "basic happy case w/ initrd",
			li: &LinuxImage{
				Kernel: strings.NewReader("testkernel"),
				Initrd: strings.NewReader("testinitrd"),
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "basic_happy_case_w_initrd_bzImage"), "testkernel"),
					Initrd: setupTestFile(t, filepath.Join(testDir, "basic_happy_case_w_initrd_initramfs"), "testinitrd"),
				},
				err: nil,
			},
		},
		{
			name: "empty initrd, with DTB present", // Expect DTB appended to loaded initrd.
			li: &LinuxImage{
				Kernel: strings.NewReader("testkernel"),
				Initrd: nil,
				KexecOpts: linux.KexecOptions{
					DTB: strings.NewReader("testdtb"),
				},
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "empty_inird_w_dtb_present_bzImage"), "testkernel"),
					Initrd: setupTestFile(t, filepath.Join(testDir, "empty_inird_w_dtb_present_initramfs"), "testdtb"),
				},
				err: nil,
			},
		},
		{
			name: "non-empty initrd, with DTB present", // Expect DTB appended to loaded initrd.
			li: &LinuxImage{
				Kernel: strings.NewReader("testkernel"),
				Initrd: strings.NewReader("testinitrd"),
				KexecOpts: linux.KexecOptions{
					DTB: strings.NewReader("testdtb"),
				},
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "non_empty_inird_w_dtb_present_bzImage"), "testkernel"),
					Initrd: setupTestFile(t, filepath.Join(testDir, "non_empty_inird_w_dtb_present_initramfs"), GenerateCatDummyInitrd(t, "testinitrd", "testdtb")),
				},
				err: nil,
			},
		},
		{
			name: "oringnal kernel and initrd are files, skip copying",
			li: &LinuxImage{
				Kernel: setupTestFile(t, filepath.Join(testDir, "original_kernel_and_initrd_are_files_skip_copying_bzImage"), "testkernel"),
				Initrd: setupTestFile(t, filepath.Join("original_kernel_and_initrd_are_files_skip_copying_initramfs"), "testinitrd"),
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "original_kernel_and_initrd_are_files_skip_copying_2_bzImage"), "testkernel"),
					Initrd: setupTestFile(t, filepath.Join("original_kernel_and_initrd_are_files_skip_copying_2_initramfs"), "testinitrd"),
				},
			},
		},
	} {
		t.Run(tt.name, func(t *testing.T) {
			gotImage, _, gotErr := loadLinuxImage(tt.li, true)
			if gotErr != nil {
				if gotErr != tt.want.err {
					t.Errorf("got error %v, want %v", gotErr, tt.want.err)
				}
				return
			}
			// Kernel is opened as read only, and contents match that from original LinuxImage.
			checkReadOnly(t, gotImage.Kernel)
			// If src is a read-only *os.File on tmpfs, shoukd skip copying.
			checkFilePath(t, tt.li.Kernel, gotImage.Kernel)
			kernelBytes, err := io.ReadAll(gotImage.Kernel)
			if err != nil {
				t.Fatalf("could not read kernel from loaded image: %v", err)
			}
			wantBytes, err := io.ReadAll(tt.want.loadedImage.Kernel)
			if err != nil {
				t.Fatalf("could not read expected kernel: %v", err)
			}
			if string(kernelBytes) != string(wantBytes) {
				t.Errorf("got kernel %s, want %s", string(kernelBytes), string(wantBytes))
			}
			// Initrd, if present, is opened as read only, and contents match that from original LinuxImage.
			// OR original initrd, with DTB appended.
			if tt.li.Initrd != nil {
				checkReadOnly(t, gotImage.Initrd)
				// If src is a read-only *os.File on tmpfs, should skip copying.
				checkFilePath(t, tt.li.Initrd, gotImage.Initrd)
				initrdBytes, err := io.ReadAll(gotImage.Initrd)
				if err != nil {
					t.Fatalf("could not read initrd from loaded image: %v", err)
				}
				wantInitrdBytes, err := io.ReadAll(tt.want.loadedImage.Initrd)
				if err != nil {
					t.Fatalf("could not read expected initrd: %v", err)
				}
				// Initrd involves appending, use cmp.Diff for catching the diff, easier to debug.
				if diff := cmp.Diff(string(initrdBytes), string(wantInitrdBytes)); diff != "" {
					t.Errorf("got initrd %s, want %s, diff (+got, -want): %s", string(initrdBytes), string(wantInitrdBytes), diff)
				}
			}
		})
	}
}
<commit_msg>Small fix for linux_test.go<commit_after>// Copyright 2017-2020 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package boot

import (
	"bytes"
	"fmt"
	"io"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/u-root/u-root/pkg/boot/linux"
	"github.com/u-root/u-root/pkg/curl"
	"github.com/u-root/u-root/pkg/mount"
	"github.com/u-root/u-root/pkg/uio"
	"github.com/u-root/u-root/pkg/vfile"
	"golang.org/x/sys/unix"
)

func TestLinuxLabel(t *testing.T) {
	dir := t.TempDir()

	osKernel, err := os.Create(filepath.Join(dir, "kernel"))
	if err != nil {
		t.Fatal(err)
	}

	osInitrd, err := os.Create(filepath.Join(dir, "initrd"))
	if err != nil {
		t.Fatal(err)
	}

	k, _ := url.Parse("http://127.0.0.1/kernel")
	i1, _ := url.Parse("http://127.0.0.1/initrd1")
	i2, _ := url.Parse("http://127.0.0.1/initrd2")
	httpKernel, _ := curl.LazyFetch(k)
	httpInitrd1, _ := curl.LazyFetch(i1)
	httpInitrd2, _ := curl.LazyFetch(i2)

	for _, tt := range []struct {
		desc string
		img  *LinuxImage
		want string
	}{
		{
			desc: "os.File",
			img: &LinuxImage{
				Kernel: osKernel,
				Initrd: osInitrd,
			},
			want: fmt.Sprintf("Linux(kernel=%s/kernel initrd=%s/initrd)", dir, dir),
		},
		{
			desc: "lazy file",
			img: &LinuxImage{
				Kernel: uio.NewLazyFile(filepath.Join(dir, "kernel")),
				Initrd: uio.NewLazyFile(filepath.Join(dir, "initrd")),
			},
			want: fmt.Sprintf("Linux(kernel=%s/kernel initrd=%s/initrd)", dir, dir),
		},
		{
			desc: "concat lazy file",
			img: &LinuxImage{
				Kernel: uio.NewLazyFile(filepath.Join(dir, "kernel")),
				Initrd: CatInitrds(
					uio.NewLazyFile(filepath.Join(dir, "initrd")),
					uio.NewLazyFile(filepath.Join(dir, "initrd")),
				),
			},
			want: fmt.Sprintf("Linux(kernel=%s/kernel initrd=%s/initrd,%s/initrd)", dir, dir, dir),
		},
		{
			desc: "curl lazy file",
			img: &LinuxImage{
				Kernel: httpKernel,
				Initrd: CatInitrds(
					httpInitrd1,
					httpInitrd2,
				),
			},
			want: "Linux(kernel=http://127.0.0.1/kernel initrd=http://127.0.0.1/initrd1,http://127.0.0.1/initrd2)",
		},
		{
			desc: "verified file",
			img: &LinuxImage{
				Kernel: &vfile.File{Reader: nil, FileName: "/boot/foobar"},
				Initrd: CatInitrds(
					&vfile.File{Reader: nil, FileName: "/boot/initrd1"},
					&vfile.File{Reader: nil, FileName: "/boot/initrd2"},
				),
			},
			want: "Linux(kernel=/boot/foobar initrd=/boot/initrd1,/boot/initrd2)",
		},
		{
			desc: "no initrd",
			img: &LinuxImage{
				Kernel: &vfile.File{Reader: nil, FileName: "/boot/foobar"},
				Initrd: nil,
			},
			want: "Linux(kernel=/boot/foobar)",
		},
		{
			desc: "dtb file",
			img: &LinuxImage{
				Kernel: &vfile.File{Reader: nil, FileName: "/boot/foobar"},
				Initrd: &vfile.File{Reader: nil, FileName: "/boot/initrd"},
				KexecOpts: linux.KexecOptions{
					DTB: &vfile.File{Reader: nil, FileName: "/boot/board.dtb"},
				},
			},
			want: "Linux(kernel=/boot/foobar initrd=/boot/initrd dtb=/boot/board.dtb)",
		},
		{
			desc: "dtb file, no initrd",
			img: &LinuxImage{
				Kernel: &vfile.File{Reader: nil, FileName: "/boot/foobar"},
				KexecOpts: linux.KexecOptions{
					DTB: &vfile.File{Reader: nil, FileName: "/boot/board.dtb"},
				},
			},
			want: "Linux(kernel=/boot/foobar dtb=/boot/board.dtb)",
		},
	} {
		t.Run(tt.desc, func(t *testing.T) {
			got := tt.img.Label()
			if got != tt.want {
				t.Errorf("Label() = %s, want %s", got, tt.want)
			}
		})
	}
}

func TestCopyToFile(t *testing.T) {
	want := "abcdefg hijklmnop"
	buf := bytes.NewReader([]byte(want))

	f, err := copyToFileIfNotRegular(buf, true)
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(f.Name())
	got, err := io.ReadAll(f)
	if err != nil {
		t.Fatal(err)
	}
	if string(got) != want {
		t.Errorf("got %s, expected %s", string(got), want)
	}
}

func TestLinuxRank(t *testing.T) {
	testRank := 2
	img := &LinuxImage{BootRank: testRank}
	l := img.Rank()
	if l != testRank {
		t.Fatalf("Expected Image rank %d, got %d", testRank, l)
	}
}

func checkReadOnly(t *testing.T, f *os.File) {
	t.Helper()
	wr := unix.O_RDWR | unix.O_WRONLY
	if am, err := unix.FcntlInt(f.Fd(), unix.F_GETFL, 0); err == nil && am&wr != 0 {
		t.Errorf("file %v opened for write, want read only", f)
	}
}

// checkFilePath checks if src and dst file are same file of fsrc were actually a os.File.
func checkFilePath(t *testing.T, fsrc io.ReaderAt, fdst *os.File) {
	t.Helper()
	if f, ok := fsrc.(*os.File); ok {
		if r, _ := mount.IsTmpRamfs(f.Name()); r {
			// Src is a file on tmpfs.
			if f.Name() != fdst.Name() {
				t.Errorf("Got a copied file %s, want skipping copy and use original file %s", fdst.Name(), f.Name())
			}
		}
	}
}

func setupTestFile(t *testing.T, path, content string) *os.File {
	t.Helper()
	f, err := os.Create(path)
	if err != nil {
		t.Fatal(err)
	}
	n, err := f.Write([]byte(content))
	if err != nil {
		t.Fatal(err)
	}
	if n != len([]byte(content)) {
		t.Fatalf("want %d bytes written, but got %d", len([]byte(content)), n)
	}
	if err := f.Close(); err != nil {
		t.Fatalf("could not close test file: %v", err)
	}
	nf, err := os.Open(path)
	if err != nil {
		t.Fatalf("could not open test file: %v", err)
	}
	return nf
}

// GenerateCatDummyInitrd return padded string from the given list of strings following the same padding format of CatInitrds.
func GenerateCatDummyInitrd(t *testing.T, initrds ...string) string {
	var ins []io.ReaderAt
	for _, c := range initrds {
		ins = append(ins, strings.NewReader(c))
	}
	final := CatInitrds(ins...)
	d, err := io.ReadAll(uio.Reader(final))
	if err != nil {
		t.Fatalf("failed to generate concatenated initrd : %v", err)
	}
	return string(d)
}

type wantData struct {
	loadedImage *LoadedLinuxImage
	cleanup     func()
	err         error
}

func TestLoadLinuxImage(t *testing.T) {
	testDir := t.TempDir()

	for _, tt := range []struct {
		name string
		li   *LinuxImage
		want wantData
	}{
		{
			name: "kernel is nil",
			li:   &LinuxImage{Kernel: nil},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: nil,
				},
				err: errNilKernel,
			},
		},
		{
			name: "basic happy case w/o initrd",
			li: &LinuxImage{
				Kernel: strings.NewReader("testkernel"),
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "basic_happy_case_wo_initrd_bzimage"), "testkernel"),
				},
				err: nil,
			},
		},
		{
			name: "basic happy case w/ initrd",
			li: &LinuxImage{
				Kernel: strings.NewReader("testkernel"),
				Initrd: strings.NewReader("testinitrd"),
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "basic_happy_case_w_initrd_bzImage"), "testkernel"),
					Initrd: setupTestFile(t, filepath.Join(testDir, "basic_happy_case_w_initrd_initramfs"), "testinitrd"),
				},
				err: nil,
			},
		},
		{
			name: "empty initrd, with DTB present", // Expect DTB appended to loaded initrd.
			li: &LinuxImage{
				Kernel: strings.NewReader("testkernel"),
				Initrd: nil,
				KexecOpts: linux.KexecOptions{
					DTB: strings.NewReader("testdtb"),
				},
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "empty_inird_w_dtb_present_bzImage"), "testkernel"),
					Initrd: setupTestFile(t, filepath.Join(testDir, "empty_inird_w_dtb_present_initramfs"), "testdtb"),
				},
				err: nil,
			},
		},
		{
			name: "non-empty initrd, with DTB present", // Expect DTB appended to loaded initrd.
			li: &LinuxImage{
				Kernel: strings.NewReader("testkernel"),
				Initrd: strings.NewReader("testinitrd"),
				KexecOpts: linux.KexecOptions{
					DTB: strings.NewReader("testdtb"),
				},
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "non_empty_inird_w_dtb_present_bzImage"), "testkernel"),
					Initrd: setupTestFile(t, filepath.Join(testDir, "non_empty_inird_w_dtb_present_initramfs"), GenerateCatDummyInitrd(t, "testinitrd", "testdtb")),
				},
				err: nil,
			},
		},
		{
			name: "oringnal kernel and initrd are files, skip copying",
			li: &LinuxImage{
				Kernel: setupTestFile(t, filepath.Join(testDir, "original_kernel_and_initrd_are_files_skip_copying_bzImage"), "testkernel"),
				Initrd: setupTestFile(t, filepath.Join(testDir, "original_kernel_and_initrd_are_files_skip_copying_initramfs"), "testinitrd"),
			},
			want: wantData{
				loadedImage: &LoadedLinuxImage{
					Kernel: setupTestFile(t, filepath.Join(testDir, "original_kernel_and_initrd_are_files_skip_copying_2_bzImage"), "testkernel"),
					Initrd: setupTestFile(t, filepath.Join(testDir, "original_kernel_and_initrd_are_files_skip_copying_2_initramfs"), "testinitrd"),
				},
			},
		},
	} {
		t.Run(tt.name, func(t *testing.T) {
			gotImage, _, gotErr := loadLinuxImage(tt.li, true)
			if gotErr != nil {
				if gotErr != tt.want.err {
					t.Errorf("got error %v, want %v", gotErr, tt.want.err)
				}
				return
			}
			// Kernel is opened as read only, and contents match that from original LinuxImage.
			checkReadOnly(t, gotImage.Kernel)
			// If src is a read-only *os.File on tmpfs, shoukd skip copying.
			checkFilePath(t, tt.li.Kernel, gotImage.Kernel)
			kernelBytes, err := io.ReadAll(gotImage.Kernel)
			if err != nil {
				t.Fatalf("could not read kernel from loaded image: %v", err)
			}
			wantBytes, err := io.ReadAll(tt.want.loadedImage.Kernel)
			if err != nil {
				t.Fatalf("could not read expected kernel: %v", err)
			}
			if string(kernelBytes) != string(wantBytes) {
				t.Errorf("got kernel %s, want %s", string(kernelBytes), string(wantBytes))
			}
			// Initrd, if present, is opened as read only, and contents match that from original LinuxImage.
			// OR original initrd, with DTB appended.
			if tt.li.Initrd != nil {
				checkReadOnly(t, gotImage.Initrd)
				// If src is a read-only *os.File on tmpfs, should skip copying.
				checkFilePath(t, tt.li.Initrd, gotImage.Initrd)
				initrdBytes, err := io.ReadAll(gotImage.Initrd)
				if err != nil {
					t.Fatalf("could not read initrd from loaded image: %v", err)
				}
				wantInitrdBytes, err := io.ReadAll(tt.want.loadedImage.Initrd)
				if err != nil {
					t.Fatalf("could not read expected initrd: %v", err)
				}
				// Initrd involves appending, use cmp.Diff for catching the diff, easier to debug.
				if diff := cmp.Diff(string(initrdBytes), string(wantInitrdBytes)); diff != "" {
					t.Errorf("got initrd %s, want %s, diff (+got, -want): %s", string(initrdBytes), string(wantInitrdBytes), diff)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package auth

import (
	"context"
	"fmt"
	"io"
	"sort"

	"github.com/spf13/cobra"
	authenticationv1alpha1 "k8s.io/api/authentication/v1alpha1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/printers"
	authenticationv1alpha1client "k8s.io/client-go/kubernetes/typed/authentication/v1alpha1"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/scheme"
	"k8s.io/kubectl/pkg/util/templates"
)

// WhoAmIFlags directly reflect the information that CLI is gathering via flags.  They will be converted to Options, which
// reflect the runtime requirements for the command.  This structure reduces the transformation to wiring and makes
// the logic itself easy to unit test.
type WhoAmIFlags struct {
	RESTClientGetter genericclioptions.RESTClientGetter
	PrintFlags       *genericclioptions.PrintFlags

	genericclioptions.IOStreams
}

// NewWhoAmIFlags returns a default WhoAmIFlags.
func NewWhoAmIFlags(restClientGetter genericclioptions.RESTClientGetter, streams genericclioptions.IOStreams) *WhoAmIFlags {
	return &WhoAmIFlags{
		RESTClientGetter: restClientGetter,
		PrintFlags:       genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme),
		IOStreams:        streams,
	}
}

// AddFlags registers flags for a cli.
func (flags *WhoAmIFlags) AddFlags(cmd *cobra.Command) {
	flags.PrintFlags.AddFlags(cmd)
}

// ToOptions converts from CLI inputs to runtime inputs.
func (flags *WhoAmIFlags) ToOptions(ctx context.Context, args []string) (*WhoAmIOptions, error) {
	w := &WhoAmIOptions{
		ctx:       ctx,
		IOStreams: flags.IOStreams,
	}

	clientConfig, err := flags.RESTClientGetter.ToRESTConfig()
	if err != nil {
		return nil, err
	}

	w.authClient, err = authenticationv1alpha1client.NewForConfig(clientConfig)
	if err != nil {
		return nil, err
	}

	if !flags.PrintFlags.OutputFlagSpecified() {
		w.resourcePrinterFunc = printTableSelfSubjectAccessReview
	} else {
		printer, err := flags.PrintFlags.ToPrinter()
		if err != nil {
			return nil, err
		}
		w.resourcePrinterFunc = printer.PrintObj
	}

	return w, nil
}

// WhoAmIOptions is the start of the data required to perform the operation. As new fields are added,
// add them here instead of referencing the cmd.Flags()
type WhoAmIOptions struct {
	authClient authenticationv1alpha1client.AuthenticationV1alpha1Interface
	ctx        context.Context

	resourcePrinterFunc printers.ResourcePrinterFunc

	genericclioptions.IOStreams
}

var (
	whoAmILong = templates.LongDesc(`
		Experimental: Check who you are and your attributes (groups, extra).

        This command is helpful to get yourself aware of the current user attributes,
        especially when dynamic authentication, e.g., token webhook, auth proxy, or OIDC provider,
        is enabled in the Kubernetes cluster.
	`)

	whoAmIExample = templates.Examples(`
		# Get your subject attributes.
		kubectl alpha auth whoami

		# Get your subject attributes in JSON format.
		kubectl alpha auth whoami -o json
	`)
)

// NewCmdWhoAmI returns an initialized Command for 'auth whoami' sub command. Experimental.
func NewCmdWhoAmI(restClientGetter genericclioptions.RESTClientGetter, streams genericclioptions.IOStreams) *cobra.Command {
	flags := NewWhoAmIFlags(restClientGetter, streams)

	cmd := &cobra.Command{
		Use:                   "whoami",
		DisableFlagsInUseLine: true,
		Short:                 "Experimental: Check self subject attributes",
		Long:                  whoAmILong,
		Example:               whoAmIExample,
		Run: func(cmd *cobra.Command, args []string) {
			o, err := flags.ToOptions(cmd.Context(), args)
			cmdutil.CheckErr(err)
			cmdutil.CheckErr(o.Run())
		},
	}

	flags.AddFlags(cmd)
	return cmd
}

// Run prints all user attributes.
func (o WhoAmIOptions) Run() error {
	sar := &authenticationv1alpha1.SelfSubjectReview{}
	response, err := o.authClient.SelfSubjectReviews().Create(context.TODO(), sar, metav1.CreateOptions{})
	if err != nil {
		if errors.IsNotFound(err) {
			return fmt.Errorf("the selfsubjectreviews API is not enabled in the cluster.\n" +
				"enable APISelfSubjectReview feature gate and authentication.k8s.io/v1alpha1 API.")
		}
		return err
	}

	return o.resourcePrinterFunc(response, o.Out)
}

func printTableSelfSubjectAccessReview(obj runtime.Object, out io.Writer) error {
	ssr, ok := obj.(*authenticationv1alpha1.SelfSubjectReview)
	if !ok {
		return fmt.Errorf("object is not SelfSubjectReview")
	}

	w := printers.GetNewTabWriter(out)
	defer w.Flush()

	_, err := fmt.Fprintf(w, "ATTRIBUTE\tVALUE\n")
	if err != nil {
		return fmt.Errorf("cannot write a header: %w", err)
	}

	ui := ssr.Status.UserInfo

	if ui.Username != "" {
		_, err := fmt.Fprintf(w, "Username\t%s\n", ui.Username)
		if err != nil {
			return fmt.Errorf("cannot write a username: %w", err)
		}
	}

	if ui.UID != "" {
		_, err := fmt.Fprintf(w, "UID\t%s\n", ui.UID)
		if err != nil {
			return fmt.Errorf("cannot write a uid: %w", err)
		}
	}

	if len(ui.Groups) > 0 {
		_, err := fmt.Fprintf(w, "Groups\t%v\n", ui.Groups)
		if err != nil {
			return fmt.Errorf("cannot write groups: %w", err)
		}
	}

	if len(ui.Extra) > 0 {
		sortedKeys := make([]string, 0, len(ui.Extra))
		for k := range ui.Extra {
			sortedKeys = append(sortedKeys, k)
		}
		sort.Strings(sortedKeys)

		for _, k := range sortedKeys {
			v := ui.Extra[k]
			_, err := fmt.Fprintf(w, "Extra: %s\t%v\n", k, v)
			if err != nil {
				return fmt.Errorf("cannot write an extra: %w", err)
			}
		}

	}
	return nil
}
<commit_msg>Cleanup WhoAmI sorting code<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package auth

import (
	"context"
	"fmt"
	"io"

	"github.com/spf13/cobra"
	authenticationv1alpha1 "k8s.io/api/authentication/v1alpha1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/printers"
	authenticationv1alpha1client "k8s.io/client-go/kubernetes/typed/authentication/v1alpha1"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/scheme"
	"k8s.io/kubectl/pkg/util/templates"
)

// WhoAmIFlags directly reflect the information that CLI is gathering via flags.  They will be converted to Options, which
// reflect the runtime requirements for the command.  This structure reduces the transformation to wiring and makes
// the logic itself easy to unit test.
type WhoAmIFlags struct {
	RESTClientGetter genericclioptions.RESTClientGetter
	PrintFlags       *genericclioptions.PrintFlags

	genericclioptions.IOStreams
}

// NewWhoAmIFlags returns a default WhoAmIFlags.
func NewWhoAmIFlags(restClientGetter genericclioptions.RESTClientGetter, streams genericclioptions.IOStreams) *WhoAmIFlags {
	return &WhoAmIFlags{
		RESTClientGetter: restClientGetter,
		PrintFlags:       genericclioptions.NewPrintFlags("").WithTypeSetter(scheme.Scheme),
		IOStreams:        streams,
	}
}

// AddFlags registers flags for a cli.
func (flags *WhoAmIFlags) AddFlags(cmd *cobra.Command) {
	flags.PrintFlags.AddFlags(cmd)
}

// ToOptions converts from CLI inputs to runtime inputs.
func (flags *WhoAmIFlags) ToOptions(ctx context.Context, args []string) (*WhoAmIOptions, error) {
	w := &WhoAmIOptions{
		ctx:       ctx,
		IOStreams: flags.IOStreams,
	}

	clientConfig, err := flags.RESTClientGetter.ToRESTConfig()
	if err != nil {
		return nil, err
	}

	w.authClient, err = authenticationv1alpha1client.NewForConfig(clientConfig)
	if err != nil {
		return nil, err
	}

	if !flags.PrintFlags.OutputFlagSpecified() {
		w.resourcePrinterFunc = printTableSelfSubjectAccessReview
	} else {
		printer, err := flags.PrintFlags.ToPrinter()
		if err != nil {
			return nil, err
		}
		w.resourcePrinterFunc = printer.PrintObj
	}

	return w, nil
}

// WhoAmIOptions is the start of the data required to perform the operation. As new fields are added,
// add them here instead of referencing the cmd.Flags()
type WhoAmIOptions struct {
	authClient authenticationv1alpha1client.AuthenticationV1alpha1Interface
	ctx        context.Context

	resourcePrinterFunc printers.ResourcePrinterFunc

	genericclioptions.IOStreams
}

var (
	whoAmILong = templates.LongDesc(`
		Experimental: Check who you are and your attributes (groups, extra).

        This command is helpful to get yourself aware of the current user attributes,
        especially when dynamic authentication, e.g., token webhook, auth proxy, or OIDC provider,
        is enabled in the Kubernetes cluster.
	`)

	whoAmIExample = templates.Examples(`
		# Get your subject attributes.
		kubectl alpha auth whoami

		# Get your subject attributes in JSON format.
		kubectl alpha auth whoami -o json
	`)
)

// NewCmdWhoAmI returns an initialized Command for 'auth whoami' sub command. Experimental.
func NewCmdWhoAmI(restClientGetter genericclioptions.RESTClientGetter, streams genericclioptions.IOStreams) *cobra.Command {
	flags := NewWhoAmIFlags(restClientGetter, streams)

	cmd := &cobra.Command{
		Use:                   "whoami",
		DisableFlagsInUseLine: true,
		Short:                 "Experimental: Check self subject attributes",
		Long:                  whoAmILong,
		Example:               whoAmIExample,
		Run: func(cmd *cobra.Command, args []string) {
			o, err := flags.ToOptions(cmd.Context(), args)
			cmdutil.CheckErr(err)
			cmdutil.CheckErr(o.Run())
		},
	}

	flags.AddFlags(cmd)
	return cmd
}

// Run prints all user attributes.
func (o WhoAmIOptions) Run() error {
	sar := &authenticationv1alpha1.SelfSubjectReview{}
	response, err := o.authClient.SelfSubjectReviews().Create(context.TODO(), sar, metav1.CreateOptions{})
	if err != nil {
		if errors.IsNotFound(err) {
			return fmt.Errorf("the selfsubjectreviews API is not enabled in the cluster.\n" +
				"enable APISelfSubjectReview feature gate and authentication.k8s.io/v1alpha1 API.")
		}
		return err
	}

	return o.resourcePrinterFunc(response, o.Out)
}

func printTableSelfSubjectAccessReview(obj runtime.Object, out io.Writer) error {
	ssr, ok := obj.(*authenticationv1alpha1.SelfSubjectReview)
	if !ok {
		return fmt.Errorf("object is not SelfSubjectReview")
	}

	w := printers.GetNewTabWriter(out)
	defer w.Flush()

	_, err := fmt.Fprintf(w, "ATTRIBUTE\tVALUE\n")
	if err != nil {
		return fmt.Errorf("cannot write a header: %w", err)
	}

	ui := ssr.Status.UserInfo

	if ui.Username != "" {
		_, err := fmt.Fprintf(w, "Username\t%s\n", ui.Username)
		if err != nil {
			return fmt.Errorf("cannot write a username: %w", err)
		}
	}

	if ui.UID != "" {
		_, err := fmt.Fprintf(w, "UID\t%s\n", ui.UID)
		if err != nil {
			return fmt.Errorf("cannot write a uid: %w", err)
		}
	}

	if len(ui.Groups) > 0 {
		_, err := fmt.Fprintf(w, "Groups\t%v\n", ui.Groups)
		if err != nil {
			return fmt.Errorf("cannot write groups: %w", err)
		}
	}

	if len(ui.Extra) > 0 {
		for _, k := range sets.StringKeySet(ui.Extra).List() {
			v := ui.Extra[k]
			_, err := fmt.Fprintf(w, "Extra: %s\t%v\n", k, v)
			if err != nil {
				return fmt.Errorf("cannot write an extra: %w", err)
			}
		}

	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package gnmi

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"math"
	"net"
	"time"

	"io/ioutil"
	"strings"

	"github.com/aristanetworks/goarista/netns"
	pb "github.com/openconfig/gnmi/proto/gnmi"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/encoding/gzip"
	"google.golang.org/grpc/metadata"
)

const (
	defaultPort = "6030"
)

// Config is the gnmi.Client config
type Config struct {
	Addr        string
	CAFile      string
	CertFile    string
	KeyFile     string
	Password    string
	Username    string
	TLS         bool
	Compression string
}

// SubscribeOptions is the gNMI subscription request options
type SubscribeOptions struct {
	UpdatesOnly       bool
	Prefix            string
	Mode              string
	StreamMode        string
	SampleInterval    uint64
	HeartbeatInterval uint64
	Paths             [][]string
	Origin            string
}

// Dial connects to a gnmi service and returns a client
func Dial(cfg *Config) (pb.GNMIClient, error) {
	var opts []grpc.DialOption

	switch cfg.Compression {
	case "":
	case "gzip":
		opts = append(opts, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
	default:
		return nil, fmt.Errorf("unsupported compression option: %q", cfg.Compression)
	}

	if cfg.TLS || cfg.CAFile != "" || cfg.CertFile != "" {
		tlsConfig := &tls.Config{}
		if cfg.CAFile != "" {
			b, err := ioutil.ReadFile(cfg.CAFile)
			if err != nil {
				return nil, err
			}
			cp := x509.NewCertPool()
			if !cp.AppendCertsFromPEM(b) {
				return nil, fmt.Errorf("credentials: failed to append certificates")
			}
			tlsConfig.RootCAs = cp
		} else {
			tlsConfig.InsecureSkipVerify = true
		}
		if cfg.CertFile != "" {
			if cfg.KeyFile == "" {
				return nil, fmt.Errorf("please provide both -certfile and -keyfile")
			}
			cert, err := tls.LoadX509KeyPair(cfg.CertFile, cfg.KeyFile)
			if err != nil {
				return nil, err
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		}
		opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
	} else {
		opts = append(opts, grpc.WithInsecure())
	}

	if !strings.ContainsRune(cfg.Addr, ':') {
		cfg.Addr += ":" + defaultPort
	}

	dial := func(addrIn string, time time.Duration) (net.Conn, error) {
		var conn net.Conn
		nsName, addr, err := netns.ParseAddress(addrIn)
		if err != nil {
			return nil, err
		}

		err = netns.Do(nsName, func() error {
			var err error
			conn, err = net.Dial("tcp", addr)
			return err
		})
		return conn, err
	}

	opts = append(opts,
		grpc.WithDialer(dial),

		// Allows received protobuf messages to be larger than 4MB
		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt32)),
	)
	grpcconn, err := grpc.Dial(cfg.Addr, opts...)
	if err != nil {
		return nil, fmt.Errorf("failed to dial: %s", err)
	}
	return pb.NewGNMIClient(grpcconn), nil
}

// NewContext returns a new context with username and password
// metadata if they are set in cfg.
func NewContext(ctx context.Context, cfg *Config) context.Context {
	if cfg.Username != "" {
		ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(
			"username", cfg.Username,
			"password", cfg.Password))
	}
	return ctx
}

// NewGetRequest returns a GetRequest for the given paths
func NewGetRequest(paths [][]string, origin string) (*pb.GetRequest, error) {
	req := &pb.GetRequest{
		Path: make([]*pb.Path, len(paths)),
	}
	for i, p := range paths {
		gnmiPath, err := ParseGNMIElements(p)
		if err != nil {
			return nil, err
		}
		req.Path[i] = gnmiPath
		req.Path[i].Origin = origin
	}
	return req, nil
}

// NewSubscribeRequest returns a SubscribeRequest for the given paths
func NewSubscribeRequest(subscribeOptions *SubscribeOptions) (*pb.SubscribeRequest, error) {
	var mode pb.SubscriptionList_Mode
	switch subscribeOptions.Mode {
	case "once":
		mode = pb.SubscriptionList_ONCE
	case "poll":
		mode = pb.SubscriptionList_POLL
	case "":
		fallthrough
	case "stream":
		mode = pb.SubscriptionList_STREAM
	default:
		return nil, fmt.Errorf("subscribe mode (%s) invalid", subscribeOptions.Mode)
	}

	var streamMode pb.SubscriptionMode
	switch subscribeOptions.StreamMode {
	case "on_change":
		streamMode = pb.SubscriptionMode_ON_CHANGE
	case "sample":
		streamMode = pb.SubscriptionMode_SAMPLE
	case "":
		fallthrough
	case "target_defined":
		streamMode = pb.SubscriptionMode_TARGET_DEFINED
	default:
		return nil, fmt.Errorf("subscribe stream mode (%s) invalid", subscribeOptions.StreamMode)
	}

	prefixPath, err := ParseGNMIElements(SplitPath(subscribeOptions.Prefix))
	if err != nil {
		return nil, err
	}
	subList := &pb.SubscriptionList{
		Subscription: make([]*pb.Subscription, len(subscribeOptions.Paths)),
		Mode:         mode,
		UpdatesOnly:  subscribeOptions.UpdatesOnly,
		Prefix:       prefixPath,
	}
	for i, p := range subscribeOptions.Paths {
		gnmiPath, err := ParseGNMIElements(p)
		if err != nil {
			return nil, err
		}
		gnmiPath.Origin = subscribeOptions.Origin
		subList.Subscription[i] = &pb.Subscription{
			Path:              gnmiPath,
			Mode:              streamMode,
			SampleInterval:    subscribeOptions.SampleInterval,
			HeartbeatInterval: subscribeOptions.HeartbeatInterval,
		}
	}
	return &pb.SubscribeRequest{Request: &pb.SubscribeRequest_Subscribe{
		Subscribe: subList}}, nil
}
<commit_msg>gnmi: Add DialOptions to gNMI client config<commit_after>// Copyright (c) 2017 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package gnmi

import (
	"context"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"math"
	"net"
	"time"

	"io/ioutil"
	"strings"

	"github.com/aristanetworks/goarista/netns"
	pb "github.com/openconfig/gnmi/proto/gnmi"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/encoding/gzip"
	"google.golang.org/grpc/metadata"
)

const (
	defaultPort = "6030"
)

// Config is the gnmi.Client config
type Config struct {
	Addr        string
	CAFile      string
	CertFile    string
	KeyFile     string
	Password    string
	Username    string
	TLS         bool
	Compression string
	DialOptions []grpc.DialOption
}

// SubscribeOptions is the gNMI subscription request options
type SubscribeOptions struct {
	UpdatesOnly       bool
	Prefix            string
	Mode              string
	StreamMode        string
	SampleInterval    uint64
	HeartbeatInterval uint64
	Paths             [][]string
	Origin            string
}

// Dial connects to a gnmi service and returns a client
func Dial(cfg *Config) (pb.GNMIClient, error) {
	opts := append([]grpc.DialOption(nil), cfg.DialOptions...)

	switch cfg.Compression {
	case "":
	case "gzip":
		opts = append(opts, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
	default:
		return nil, fmt.Errorf("unsupported compression option: %q", cfg.Compression)
	}

	if cfg.TLS || cfg.CAFile != "" || cfg.CertFile != "" {
		tlsConfig := &tls.Config{}
		if cfg.CAFile != "" {
			b, err := ioutil.ReadFile(cfg.CAFile)
			if err != nil {
				return nil, err
			}
			cp := x509.NewCertPool()
			if !cp.AppendCertsFromPEM(b) {
				return nil, fmt.Errorf("credentials: failed to append certificates")
			}
			tlsConfig.RootCAs = cp
		} else {
			tlsConfig.InsecureSkipVerify = true
		}
		if cfg.CertFile != "" {
			if cfg.KeyFile == "" {
				return nil, fmt.Errorf("please provide both -certfile and -keyfile")
			}
			cert, err := tls.LoadX509KeyPair(cfg.CertFile, cfg.KeyFile)
			if err != nil {
				return nil, err
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		}
		opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
	} else {
		opts = append(opts, grpc.WithInsecure())
	}

	if !strings.ContainsRune(cfg.Addr, ':') {
		cfg.Addr += ":" + defaultPort
	}

	dial := func(addrIn string, time time.Duration) (net.Conn, error) {
		var conn net.Conn
		nsName, addr, err := netns.ParseAddress(addrIn)
		if err != nil {
			return nil, err
		}

		err = netns.Do(nsName, func() error {
			var err error
			conn, err = net.Dial("tcp", addr)
			return err
		})
		return conn, err
	}

	opts = append(opts,
		grpc.WithDialer(dial),

		// Allows received protobuf messages to be larger than 4MB
		grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt32)),
	)
	grpcconn, err := grpc.Dial(cfg.Addr, opts...)
	if err != nil {
		return nil, fmt.Errorf("failed to dial: %s", err)
	}
	return pb.NewGNMIClient(grpcconn), nil
}

// NewContext returns a new context with username and password
// metadata if they are set in cfg.
func NewContext(ctx context.Context, cfg *Config) context.Context {
	if cfg.Username != "" {
		ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(
			"username", cfg.Username,
			"password", cfg.Password))
	}
	return ctx
}

// NewGetRequest returns a GetRequest for the given paths
func NewGetRequest(paths [][]string, origin string) (*pb.GetRequest, error) {
	req := &pb.GetRequest{
		Path: make([]*pb.Path, len(paths)),
	}
	for i, p := range paths {
		gnmiPath, err := ParseGNMIElements(p)
		if err != nil {
			return nil, err
		}
		req.Path[i] = gnmiPath
		req.Path[i].Origin = origin
	}
	return req, nil
}

// NewSubscribeRequest returns a SubscribeRequest for the given paths
func NewSubscribeRequest(subscribeOptions *SubscribeOptions) (*pb.SubscribeRequest, error) {
	var mode pb.SubscriptionList_Mode
	switch subscribeOptions.Mode {
	case "once":
		mode = pb.SubscriptionList_ONCE
	case "poll":
		mode = pb.SubscriptionList_POLL
	case "":
		fallthrough
	case "stream":
		mode = pb.SubscriptionList_STREAM
	default:
		return nil, fmt.Errorf("subscribe mode (%s) invalid", subscribeOptions.Mode)
	}

	var streamMode pb.SubscriptionMode
	switch subscribeOptions.StreamMode {
	case "on_change":
		streamMode = pb.SubscriptionMode_ON_CHANGE
	case "sample":
		streamMode = pb.SubscriptionMode_SAMPLE
	case "":
		fallthrough
	case "target_defined":
		streamMode = pb.SubscriptionMode_TARGET_DEFINED
	default:
		return nil, fmt.Errorf("subscribe stream mode (%s) invalid", subscribeOptions.StreamMode)
	}

	prefixPath, err := ParseGNMIElements(SplitPath(subscribeOptions.Prefix))
	if err != nil {
		return nil, err
	}
	subList := &pb.SubscriptionList{
		Subscription: make([]*pb.Subscription, len(subscribeOptions.Paths)),
		Mode:         mode,
		UpdatesOnly:  subscribeOptions.UpdatesOnly,
		Prefix:       prefixPath,
	}
	for i, p := range subscribeOptions.Paths {
		gnmiPath, err := ParseGNMIElements(p)
		if err != nil {
			return nil, err
		}
		gnmiPath.Origin = subscribeOptions.Origin
		subList.Subscription[i] = &pb.Subscription{
			Path:              gnmiPath,
			Mode:              streamMode,
			SampleInterval:    subscribeOptions.SampleInterval,
			HeartbeatInterval: subscribeOptions.HeartbeatInterval,
		}
	}
	return &pb.SubscribeRequest{Request: &pb.SubscribeRequest_Subscribe{
		Subscribe: subList}}, nil
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build dragonfly freebsd linux nacl netbsd openbsd solaris

package x509

import "io/ioutil"

// Possible certificate files; stop after finding one.
var certFiles = []string{
	"/etc/ssl/certs/ca-certificates.crt",     // Debian/Ubuntu/Gentoo etc.
	"/etc/pki/tls/certs/ca-bundle.crt",       // Fedora/RHEL
	"/etc/ssl/ca-bundle.pem",                 // OpenSUSE
	"/etc/ssl/cert.pem",                      // OpenBSD
	"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
	"/etc/pki/tls/cacert.pem",                // OpenELEC
}

// Possible directories with certificate files; stop after successfully
// reading at least one file from a directory.
var certDirectories = []string{
	"/system/etc/security/cacerts", // Android

}

func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
	return nil, nil
}

func initSystemRoots() {
	roots := NewCertPool()
	for _, file := range certFiles {
		data, err := ioutil.ReadFile(file)
		if err == nil {
			roots.AppendCertsFromPEM(data)
			systemRoots = roots
			return
		}
	}

	for _, directory := range certDirectories {
		fis, err := ioutil.ReadDir(directory)
		if err != nil {
			continue
		}
		rootsAdded := false
		for _, fi := range fis {
			data, err := ioutil.ReadFile(directory + "/" + fi.Name())
			if err == nil && roots.AppendCertsFromPEM(data) {
				rootsAdded = true
			}
		}
		if rootsAdded {
			systemRoots = roots
			return
		}
	}

	// All of the files failed to load. systemRoots will be nil which will
	// trigger a specific error at verification time.
}
<commit_msg>crypto/x509: add Solaris certificate file location<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build dragonfly freebsd linux nacl netbsd openbsd solaris

package x509

import "io/ioutil"

// Possible certificate files; stop after finding one.
var certFiles = []string{
	"/etc/ssl/certs/ca-certificates.crt",     // Debian/Ubuntu/Gentoo etc.
	"/etc/pki/tls/certs/ca-bundle.crt",       // Fedora/RHEL
	"/etc/ssl/ca-bundle.pem",                 // OpenSUSE
	"/etc/ssl/cert.pem",                      // OpenBSD
	"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
	"/etc/pki/tls/cacert.pem",                // OpenELEC
	"/etc/certs/ca-certificates.crt",         // Solaris 11.2+
}

// Possible directories with certificate files; stop after successfully
// reading at least one file from a directory.
var certDirectories = []string{
	"/system/etc/security/cacerts", // Android

}

func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
	return nil, nil
}

func initSystemRoots() {
	roots := NewCertPool()
	for _, file := range certFiles {
		data, err := ioutil.ReadFile(file)
		if err == nil {
			roots.AppendCertsFromPEM(data)
			systemRoots = roots
			return
		}
	}

	for _, directory := range certDirectories {
		fis, err := ioutil.ReadDir(directory)
		if err != nil {
			continue
		}
		rootsAdded := false
		for _, fi := range fis {
			data, err := ioutil.ReadFile(directory + "/" + fi.Name())
			if err == nil && roots.AppendCertsFromPEM(data) {
				rootsAdded = true
			}
		}
		if rootsAdded {
			systemRoots = roots
			return
		}
	}

	// All of the files failed to load. systemRoots will be nil which will
	// trigger a specific error at verification time.
}
<|endoftext|>


<commit_before>package web

import (
	"net/http"
	"net/url"
	"time"

	"github.com/pkg/errors"
	"github.com/yuuki/diamondb/lib/log"
	"github.com/yuuki/diamondb/lib/model"
	"github.com/yuuki/diamondb/lib/query"
	"github.com/yuuki/diamondb/lib/timeparser"
)

const (
	DAYTIME = time.Duration(24*60*60) * time.Second
)

func Render(w http.ResponseWriter, r *http.Request) {
	until := time.Now().Round(time.Second)
	from := until.Add(-DAYTIME)

	if v := r.FormValue("from"); v != "" {
		t, err := timeparser.ParseAtTime(url.QueryEscape(v))
		if err != nil {
			log.Println("%+v", err) // Print stack trace by pkg/errors
			BadRequest(w, errors.Cause(err).Error())
			return
		}
		from = t
	}
	if v := r.FormValue("until"); v != "" {
		t, err := timeparser.ParseAtTime(url.QueryEscape(v))
		if err != nil {
			log.Println("%+v", err) // Print stack trace by pkg/errors
			BadRequest(w, errors.Cause(err).Error())
			return
		}
		until = t
	}
	log.Debugf("from:%d until:%d", from.Unix(), until.Unix())

	targets := r.Form["target"]
	if len(targets) < 1 {
		BadRequest(w, "no targets requested")
		return
	}

	vmList := make([]*model.ViewMetric, 0, len(targets))
	for _, target := range targets {
		mList, err := query.EvalTarget(target, from, until)
		if err != nil {
			log.Println("%+v", err) // Print stack trace by pkg/errors
			switch err.(type) {
			case *query.ParserError, *query.UnsupportedFunctionError:
				BadRequest(w, errors.Cause(err).Error())
			default:
				ServerError(w, errors.Cause(err).Error())
			}
			return
		}
		for _, metric := range mList {
			vmList = append(vmList, metric.AsResponse())
		}
	}
	JSON(w, http.StatusOK, vmList)

	return
}
<commit_msg>Fix log format<commit_after>package web

import (
	"net/http"
	"net/url"
	"time"

	"github.com/pkg/errors"
	"github.com/yuuki/diamondb/lib/log"
	"github.com/yuuki/diamondb/lib/model"
	"github.com/yuuki/diamondb/lib/query"
	"github.com/yuuki/diamondb/lib/timeparser"
)

const (
	DAYTIME = time.Duration(24*60*60) * time.Second
)

func Render(w http.ResponseWriter, r *http.Request) {
	until := time.Now().Round(time.Second)
	from := until.Add(-DAYTIME)

	if v := r.FormValue("from"); v != "" {
		t, err := timeparser.ParseAtTime(url.QueryEscape(v))
		if err != nil {
			log.Printf("%+v", err) // Print stack trace by pkg/errors
			BadRequest(w, errors.Cause(err).Error())
			return
		}
		from = t
	}
	if v := r.FormValue("until"); v != "" {
		t, err := timeparser.ParseAtTime(url.QueryEscape(v))
		if err != nil {
			log.Printf("%+v", err) // Print stack trace by pkg/errors
			BadRequest(w, errors.Cause(err).Error())
			return
		}
		until = t
	}
	log.Debugf("from:%d until:%d", from.Unix(), until.Unix())

	targets := r.Form["target"]
	if len(targets) < 1 {
		BadRequest(w, "no targets requested")
		return
	}

	vmList := make([]*model.ViewMetric, 0, len(targets))
	for _, target := range targets {
		mList, err := query.EvalTarget(target, from, until)
		if err != nil {
			log.Printf("%+v", err) // Print stack trace by pkg/errors
			switch err.(type) {
			case *query.ParserError, *query.UnsupportedFunctionError:
				BadRequest(w, errors.Cause(err).Error())
			default:
				ServerError(w, errors.Cause(err).Error())
			}
			return
		}
		for _, metric := range mList {
			vmList = append(vmList, metric.AsResponse())
		}
	}
	JSON(w, http.StatusOK, vmList)

	return
}
<|endoftext|>


<commit_before>// runner to start up the proxy
package statsdproxy

import (
	"log"
	"net"
	"strconv"
	"strings"
)

const (
	CHANNEL_SIZE = 100
	WORKER_COUNT = 8
)

// variable to indicate whether or not we run in DebugMode
var DebugMode bool

// channel to gather internal metrics
var internalMetrics chan StatsDMetric
var metricsOutput chan metricsRequest

type StatsDMetric struct {
	name  string
	value float64
	raw   string
}

// exported functions
func StartProxy(cfgFilePath string, quit chan bool) error {
	var err error
	config, err := NewConfig(cfgFilePath)
	if err != nil {
		log.Printf("Error parsing config file: %s (exiting...)", err)
		return nil
	}
	internalMetrics = make(chan StatsDMetric, CHANNEL_SIZE)
	metricsOutput = make(chan metricsRequest, CHANNEL_SIZE)

	go metricsCollector(internalMetrics)
	go StartMainListener(*config)
	go StartManagementConsole(*config)

	// wait until you're told to quit
	<-quit

	return nil

}

// function to set up the main UDP listener. Everything that is needed to
// receive and relay metrics
func StartMainListener(config ProxyConfig) error {

	log.Printf("Starting StatsD listener on %s and port %d", config.Host, config.Port)
	listener, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP(config.Host), Port: config.Port})
	if err != nil {
		log.Printf("Error setting up listener: %s (exiting...)", err)
		return nil
	}

	relay_channel := make(chan StatsDMetric, CHANNEL_SIZE)
	hash_ring := *NewHashRing()
	for _, node := range config.Nodes {
		backend := NewStatsDBackend(node.Host, node.Port, node.Adminport,
			config.CheckInterval)
		if DebugMode {
			log.Printf("Adding backend %s:%d", backend.Host, backend.Port)
		}
		hash_ring, err = hash_ring.Add(*backend)
		if err != nil {
			log.Println("Error adding backend to Hashring")
			log.Println(err)
		}
	}
	go relay_metric(hash_ring, relay_channel)

  worker_channel := make(chan []byte)

  for x := 0; x < WORKER_COUNT; x++ {
			go handleConnection(worker_channel, relay_channel)
  }

	for {
		buf := make([]byte, 512)
		num, _, err := listener.ReadFromUDP(buf)
		if err != nil {
			log.Printf("Error reading from UDP buffer: %s (skipping...)", err)
			return nil
		} else {
      worker_channel <- buf[0:num]
		}
	}

	return nil
}

// handle the actual incoming connection and figure out which packet types we
// got sent.
// accepts a byte array of data
func handleConnection(data_channel chan []byte, relay_channel chan StatsDMetric) {
	for {
		select {
		case data := <- data_channel:
      if DebugMode {
        log.Printf("Got packet: %s", string(data))
      }
      metrics := strings.Split(string(data), "\n")
      for _, str := range metrics {
        metric := parsePacketString(str)
        internalMetrics <- StatsDMetric{name: "packets_received", value: 1}
        relay_channel <- *metric
      }

        }
	}
}

// parse a string into a statsd packet
// accepts a string of data
// returns a StatsDMetric
func parsePacketString(data string) *StatsDMetric {
	ret := new(StatsDMetric)
	first := strings.Split(data, ":")
	if len(first) < 2 {
		log.Printf("Malformatted metric: %s", data)
		return ret
	}
	name := first[0]
	second := strings.Split(first[1], "|")
	value64, _ := strconv.ParseInt(second[0], 10, 0)
	value := float64(value64)
	// check for a samplerate
	third := strings.Split(second[1], "@")
	metric_type := third[0]

	switch metric_type {
	case "c", "ms", "g":
		ret.name = name
		ret.value = value
		ret.raw = data
	default:
		log.Printf("Unknown metrics type: %s", metric_type)
	}

	return ret
}

// relay a metric to one of the active statsd backends
func relay_metric(ring HashRing, relay_channel chan StatsDMetric) {
	for {
		select {
		case metric := <-relay_channel:
			// find out which backend to relay to and do it
			backend_host, err := ring.GetBackendForMetric(metric.name)
			if err != nil {
				log.Printf("Unable to get backend for metric: %s", metric.name)
			} else {
				if DebugMode {
					log.Printf("relaying metric: %s to %s:%d", metric.raw,
						backend_host.Host, backend_host.Port)
				}
				backend_host.Send(metric.raw)
			}
		}
	}
}
<commit_msg>go fmt<commit_after>// runner to start up the proxy
package statsdproxy

import (
	"log"
	"net"
	"strconv"
	"strings"
)

const (
	CHANNEL_SIZE = 100
	WORKER_COUNT = 8
)

// variable to indicate whether or not we run in DebugMode
var DebugMode bool

// channel to gather internal metrics
var internalMetrics chan StatsDMetric
var metricsOutput chan metricsRequest

type StatsDMetric struct {
	name  string
	value float64
	raw   string
}

// exported functions
func StartProxy(cfgFilePath string, quit chan bool) error {
	var err error
	config, err := NewConfig(cfgFilePath)
	if err != nil {
		log.Printf("Error parsing config file: %s (exiting...)", err)
		return nil
	}
	internalMetrics = make(chan StatsDMetric, CHANNEL_SIZE)
	metricsOutput = make(chan metricsRequest, CHANNEL_SIZE)

	go metricsCollector(internalMetrics)
	go StartMainListener(*config)
	go StartManagementConsole(*config)

	// wait until you're told to quit
	<-quit

	return nil

}

// function to set up the main UDP listener. Everything that is needed to
// receive and relay metrics
func StartMainListener(config ProxyConfig) error {

	log.Printf("Starting StatsD listener on %s and port %d", config.Host, config.Port)
	listener, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP(config.Host), Port: config.Port})
	if err != nil {
		log.Printf("Error setting up listener: %s (exiting...)", err)
		return nil
	}

	relay_channel := make(chan StatsDMetric, CHANNEL_SIZE)
	hash_ring := *NewHashRing()
	for _, node := range config.Nodes {
		backend := NewStatsDBackend(node.Host, node.Port, node.Adminport,
			config.CheckInterval)
		if DebugMode {
			log.Printf("Adding backend %s:%d", backend.Host, backend.Port)
		}
		hash_ring, err = hash_ring.Add(*backend)
		if err != nil {
			log.Println("Error adding backend to Hashring")
			log.Println(err)
		}
	}
	go relay_metric(hash_ring, relay_channel)

	worker_channel := make(chan []byte)

	for x := 0; x < WORKER_COUNT; x++ {
		go handleConnection(worker_channel, relay_channel)
	}

	for {
		buf := make([]byte, 512)
		num, _, err := listener.ReadFromUDP(buf)
		if err != nil {
			log.Printf("Error reading from UDP buffer: %s (skipping...)", err)
			return nil
		} else {
			worker_channel <- buf[0:num]
		}
	}

	return nil
}

// handle the actual incoming connection and figure out which packet types we
// got sent.
// accepts a byte array of data
func handleConnection(data_channel chan []byte, relay_channel chan StatsDMetric) {
	for {
		select {
		case data := <-data_channel:
			if DebugMode {
				log.Printf("Got packet: %s", string(data))
			}
			metrics := strings.Split(string(data), "\n")
			for _, str := range metrics {
				metric := parsePacketString(str)
				internalMetrics <- StatsDMetric{name: "packets_received", value: 1}
				relay_channel <- *metric
			}

		}
	}
}

// parse a string into a statsd packet
// accepts a string of data
// returns a StatsDMetric
func parsePacketString(data string) *StatsDMetric {
	ret := new(StatsDMetric)
	first := strings.Split(data, ":")
	if len(first) < 2 {
		log.Printf("Malformatted metric: %s", data)
		return ret
	}
	name := first[0]
	second := strings.Split(first[1], "|")
	value64, _ := strconv.ParseInt(second[0], 10, 0)
	value := float64(value64)
	// check for a samplerate
	third := strings.Split(second[1], "@")
	metric_type := third[0]

	switch metric_type {
	case "c", "ms", "g":
		ret.name = name
		ret.value = value
		ret.raw = data
	default:
		log.Printf("Unknown metrics type: %s", metric_type)
	}

	return ret
}

// relay a metric to one of the active statsd backends
func relay_metric(ring HashRing, relay_channel chan StatsDMetric) {
	for {
		select {
		case metric := <-relay_channel:
			// find out which backend to relay to and do it
			backend_host, err := ring.GetBackendForMetric(metric.name)
			if err != nil {
				log.Printf("Unable to get backend for metric: %s", metric.name)
			} else {
				if DebugMode {
					log.Printf("relaying metric: %s to %s:%d", metric.raw,
						backend_host.Host, backend_host.Port)
				}
				backend_host.Send(metric.raw)
			}
		}
	}
}
<|endoftext|>