<commit_before>package main

import (
	"fmt"
	"strconv"

	"github.com/codegangsta/cli"
)

func cmdNodeAdd(c *cli.Context) {
	keySlice := []string{"assetid", "name", "team", "server", "online"}
	reqSlice := []string{"assetid", "name", "team", "server"}

	switch utl.GetCliArgumentCount(c) {
	case 8, 10:
		break
	default:
		utl.Abort("Syntax error, unexpected argument count")
	}
	argSlice := utl.GetFullArgumentSlice(c)

	options, optional := utl.ParseVariableArguments(keySlice, reqSlice, argSlice)
	var req somaproto.ProtoRequestNode

	utl.ValidateStringAsNodeAssetId(options["assetid"])
	if utl.SliceContainsString("online", optional) {
		utl.ValidateStringAsBool(options["online"])
		req.Node.IsOnline, _ = strconv.ParseBool(options["online"])
	} else {
		req.Node.IsOnline = true
	}
	req.Node.AssetId, _ = strconv.ParseUint(options["assetid"], 10, 64)
	req.Node.Name = options["name"]
	req.Node.Team = options["team"]
	req.Node.Server = options["server"]

	_ = utl.PostRequestWithBody(req, "/nodes/")
}

func cmdNodeDel(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	_ = utl.DeleteRequest(path)
}

func cmdNodePurge(c *cli.Context) {
	var (
		path string
		req  somaproto.ProtoRequestNode
	)
	if c.Bool("all") {
		utl.ValidateCliArgumentCount(c, 0)
		path = "/nodes/"
	} else {
		utl.ValidateCliArgumentCount(c, 1)
		id := utl.TryGetNodeByUUIDOrName(c.Args().First())
		path = fmt.Sprintf("/nodes/%s", id.String())
	}

	req.Purge = true

	_ = utl.DeleteRequestWithBody(req, path)
}

func cmdNodeRestore(c *cli.Context) {
	var (
		path string
		req  somaproto.ProtoRequestNode
	)
	if c.Bool("all") {
		utl.ValidateCliArgumentCount(c, 0)
		path = "/nodes/"
	} else {
		utl.ValidateCliArgumentCount(c, 1)
		id := utl.TryGetNodeByUUIDOrName(c.Args().First())
		path = fmt.Sprintf("/nodes/%s", id.String())
	}

	req.Restore = true

	_ = utl.DeleteRequestWithBody(req, path)
}

func cmdNodeRename(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 3)
	utl.ValidateCliArgument(c, 2, "to")
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.Name = c.Args().Get(2)

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeRepo(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 3)
	utl.ValidateCliArgument(c, 2, "to")
	id := utl.TryGetNodeByUUIDOrName(c.Args().Get(0))
	team := c.Args().Get(2)
	// try resolving team name to uuid as name validation
	_ = utl.GetTeamIdByName(team)
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.Team = team

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeMove(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 3)
	utl.ValidateCliArgument(c, 2, "to")
	id := utl.TryGetNodeByUUIDOrName(c.Args().Get(0))
	server := c.Args().Get(2)
	// try resolving server name to uuid as name validation
	_ = utl.GetServerAssetIdByName(server)
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.Server = server

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeOnline(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.IsOnline = true

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeOffline(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.IsOnline = false

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeAssign(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 6)
	utl.ValidateCliArgument(c, 2, "to")
	keySlice := []string{"repository", "bucket"}
	argSlice := utl.GetFullArgumentSlice(c)[2:]

	options, _ := utl.ParseVariableArguments(keySlice, keySlice, argSlice)
	var req somaproto.ProtoRequestJob
	req.JobType = "node"
	req.Node.Action = "assign"
	req.Node.Node.Config.RepositoryName = options["repository"]
	req.Node.Node.Config.BucketName = options["bucket"]

	_ = utl.PostRequestWithBody(req, "/jobs/")
	// TODO save jobid locally as outstanding
}

func cmdNodeList(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 0)

	_ = utl.GetRequest("/nodes/")
}

func cmdNodeShow(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	_ = utl.GetRequest(path)
}

func cmdNodePropertyAdd(c *cli.Context) {
	// preliminary argv validation
	switch utl.GetCliArgumentCount(c) {
	case 4, 6, 8, 10, 12:
		break
	default:
		utl.Abort("Syntax error, unexpected argument count")
	}
	utl.ValidateCliArgument(c, 3, "to")
	argSlice := utl.GetFullArgumentSlice(c)

	// get property types
	typSlice := utl.PropertyTypes

	// first argument must be a valid property type
	utl.ValidateStringInSlice(argSlice[0], typSlice)

	// TODO: validate property of that type and name exists
	propertyType := argSlice[0]
	property := argSlice[1]

	// get which node is being modified
	id := utl.TryGetNodeByUUIDOrName(argSlice[3])
	path := fmt.Sprintf("/nodes/%s/property/", id.String())

	// variable key/value part of argv
	argSlice = argSlice[4:]

	// define accepted and required keys
	keySlice := []string{"inheritance", "childrenonly", "view", "value"}
	reqSlice := []string{"view"}
	if propertyType != "service" {
		// non service properties require values, services are
		// predefined and do not
		reqSlice = append(reqSlice, "value")
	}
	options, optional := utl.ParseVariableArguments(keySlice, reqSlice, argSlice)

	// build node property JSON
	var prop somaproto.ProtoNodeProperty
	prop.Type = propertyType
	prop.View = options["view"] //required
	prop.Property = property
	// add value if it was required
	if utl.SliceContainsString("value", reqSlice) {
		prop.Value = options["value"]
	}

	// optional inheritance, default true
	if utl.SliceContainsString("inheritance", optional) {
		utl.ValidateStringAsBool(options["inheritance"])
		prop.Inheritance, _ = strconv.ParseBool(options["inheritance"])
	} else {
		prop.Inheritance = true
	}

	// optional childrenonly, default false
	if utl.SliceContainsString("childrenonly", optional) {
		utl.ValidateStringAsBool(options["childrenonly"])
		prop.ChildrenOnly, _ = strconv.ParseBool(options["childrenonly"])
	} else {
		prop.ChildrenOnly = false
	}

	// build request JSON
	var req somaproto.ProtoRequestNode
	req.Node.Properties = append(req.Node.Properties, prop)

	_ = utl.PostRequestWithBody(req, path)
	// TODO save jobid locally as outstanding
}

func cmdNodePropertyGet(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 6)
	utl.ValidateCliArgument(c, 3, "from")
	utl.ValidateCliArgument(c, 5, "view")
	argSlice := utl.GetFullArgumentSlice(c)

	// first argument must be a valid property type, sixth a view
	utl.ValidateStringInSlice(argSlice[0], utl.PropertyTypes)
	utl.ValidateStringInSlice(argSlice[5], utl.Views)

	// get which node is being modified
	id := utl.TryGetNodeByUUIDOrName(argSlice[3])

	// TODO: validate property of that type and name exists
	path := fmt.Sprintf("/nodes/%s/property/%s/%s/%s",
		id.String(),
		argSlice[0], // type
		argSlice[5], // view
		argSlice[1], // property
	)

	_ = utl.GetRequest(path)
}

func cmdNodePropertyDel(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 6)
	utl.ValidateCliArgument(c, 3, "from")
	utl.ValidateCliArgument(c, 5, "view")
	argSlice := utl.GetFullArgumentSlice(c)

	// first argument must be a valid property type, sixth a view
	utl.ValidateStringInSlice(argSlice[0], utl.PropertyTypes)
	utl.ValidateStringInSlice(argSlice[5], utl.Views)

	propertyType := argSlice[0]
	property := argSlice[1]

	// get which node is being modified
	id := utl.TryGetNodeByUUIDOrName(argSlice[3])

	// TODO: validate property of that type and name exists
	path := fmt.Sprintf("/nodes/%s/property/%s/%s/%s",
		id.String(),
		argSlice[0], //type
		argSlice[5], //view
		argSlice[1], //property
	)

	_ = DeleteRequest(path)
}

func cmdNodePropertyList(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s/property/", id.String())

	var req somaproto.ProtoRequestNode

	if c.Bool("all") {
		req.Filter.LocalProperty = false
		_ = GetRequest(path)
	} else {
		req.Filter.LocalProperty = true
		_ = GetRequestWithBody(req, path)
	}
}

func cmdNodePropertyShow(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s/property/", id.String())

	_ = GetRequest(path)
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Unbreak build from last commit<commit_after>package main

import (
	"fmt"
	"strconv"

	"github.com/codegangsta/cli"
)

func cmdNodeAdd(c *cli.Context) {
	keySlice := []string{"assetid", "name", "team", "server", "online"}
	reqSlice := []string{"assetid", "name", "team", "server"}

	switch utl.GetCliArgumentCount(c) {
	case 8, 10:
		break
	default:
		utl.Abort("Syntax error, unexpected argument count")
	}
	argSlice := utl.GetFullArgumentSlice(c)

	options, optional := utl.ParseVariableArguments(keySlice, reqSlice, argSlice)
	var req somaproto.ProtoRequestNode

	utl.ValidateStringAsNodeAssetId(options["assetid"])
	if utl.SliceContainsString("online", optional) {
		utl.ValidateStringAsBool(options["online"])
		req.Node.IsOnline, _ = strconv.ParseBool(options["online"])
	} else {
		req.Node.IsOnline = true
	}
	req.Node.AssetId, _ = strconv.ParseUint(options["assetid"], 10, 64)
	req.Node.Name = options["name"]
	req.Node.Team = options["team"]
	req.Node.Server = options["server"]

	_ = utl.PostRequestWithBody(req, "/nodes/")
}

func cmdNodeDel(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	_ = utl.DeleteRequest(path)
}

func cmdNodePurge(c *cli.Context) {
	var (
		path string
		req  somaproto.ProtoRequestNode
	)
	if c.Bool("all") {
		utl.ValidateCliArgumentCount(c, 0)
		path = "/nodes/"
	} else {
		utl.ValidateCliArgumentCount(c, 1)
		id := utl.TryGetNodeByUUIDOrName(c.Args().First())
		path = fmt.Sprintf("/nodes/%s", id.String())
	}

	req.Purge = true

	_ = utl.DeleteRequestWithBody(req, path)
}

func cmdNodeRestore(c *cli.Context) {
	var (
		path string
		req  somaproto.ProtoRequestNode
	)
	if c.Bool("all") {
		utl.ValidateCliArgumentCount(c, 0)
		path = "/nodes/"
	} else {
		utl.ValidateCliArgumentCount(c, 1)
		id := utl.TryGetNodeByUUIDOrName(c.Args().First())
		path = fmt.Sprintf("/nodes/%s", id.String())
	}

	req.Restore = true

	_ = utl.DeleteRequestWithBody(req, path)
}

func cmdNodeRename(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 3)
	utl.ValidateCliArgument(c, 2, "to")
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.Name = c.Args().Get(2)

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeRepo(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 3)
	utl.ValidateCliArgument(c, 2, "to")
	id := utl.TryGetNodeByUUIDOrName(c.Args().Get(0))
	team := c.Args().Get(2)
	// try resolving team name to uuid as name validation
	_ = utl.GetTeamIdByName(team)
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.Team = team

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeMove(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 3)
	utl.ValidateCliArgument(c, 2, "to")
	id := utl.TryGetNodeByUUIDOrName(c.Args().Get(0))
	server := c.Args().Get(2)
	// try resolving server name to uuid as name validation
	_ = utl.GetServerAssetIdByName(server)
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.Server = server

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeOnline(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.IsOnline = true

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeOffline(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	var req somaproto.ProtoRequestNode
	req.Node.IsOnline = false

	_ = utl.PatchRequestWithBody(req, path)
}

func cmdNodeAssign(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 6)
	utl.ValidateCliArgument(c, 2, "to")
	keySlice := []string{"repository", "bucket"}
	argSlice := utl.GetFullArgumentSlice(c)[2:]

	options, _ := utl.ParseVariableArguments(keySlice, keySlice, argSlice)
	var req somaproto.ProtoRequestJob
	req.JobType = "node"
	req.Node.Action = "assign"
	req.Node.Node.Config.RepositoryName = options["repository"]
	req.Node.Node.Config.BucketName = options["bucket"]

	_ = utl.PostRequestWithBody(req, "/jobs/")
	// TODO save jobid locally as outstanding
}

func cmdNodeList(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 0)

	_ = utl.GetRequest("/nodes/")
}

func cmdNodeShow(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s", id.String())

	_ = utl.GetRequest(path)
}

func cmdNodePropertyAdd(c *cli.Context) {
	// preliminary argv validation
	switch utl.GetCliArgumentCount(c) {
	case 4, 6, 8, 10, 12:
		break
	default:
		utl.Abort("Syntax error, unexpected argument count")
	}
	utl.ValidateCliArgument(c, 3, "to")
	argSlice := utl.GetFullArgumentSlice(c)

	// get property types
	typSlice := utl.PropertyTypes

	// first argument must be a valid property type
	utl.ValidateStringInSlice(argSlice[0], typSlice)

	// TODO: validate property of that type and name exists
	propertyType := argSlice[0]
	property := argSlice[1]

	// get which node is being modified
	id := utl.TryGetNodeByUUIDOrName(argSlice[3])
	path := fmt.Sprintf("/nodes/%s/property/", id.String())

	// variable key/value part of argv
	argSlice = argSlice[4:]

	// define accepted and required keys
	keySlice := []string{"inheritance", "childrenonly", "view", "value"}
	reqSlice := []string{"view"}
	if propertyType != "service" {
		// non service properties require values, services are
		// predefined and do not
		reqSlice = append(reqSlice, "value")
	}
	options, optional := utl.ParseVariableArguments(keySlice, reqSlice, argSlice)

	// build node property JSON
	var prop somaproto.ProtoNodeProperty
	prop.Type = propertyType
	prop.View = options["view"] //required
	prop.Property = property
	// add value if it was required
	if utl.SliceContainsString("value", reqSlice) {
		prop.Value = options["value"]
	}

	// optional inheritance, default true
	if utl.SliceContainsString("inheritance", optional) {
		utl.ValidateStringAsBool(options["inheritance"])
		prop.Inheritance, _ = strconv.ParseBool(options["inheritance"])
	} else {
		prop.Inheritance = true
	}

	// optional childrenonly, default false
	if utl.SliceContainsString("childrenonly", optional) {
		utl.ValidateStringAsBool(options["childrenonly"])
		prop.ChildrenOnly, _ = strconv.ParseBool(options["childrenonly"])
	} else {
		prop.ChildrenOnly = false
	}

	// build request JSON
	var req somaproto.ProtoRequestNode
	req.Node.Properties = append(req.Node.Properties, prop)

	_ = utl.PostRequestWithBody(req, path)
	// TODO save jobid locally as outstanding
}

func cmdNodePropertyGet(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 6)
	utl.ValidateCliArgument(c, 3, "from")
	utl.ValidateCliArgument(c, 5, "view")
	argSlice := utl.GetFullArgumentSlice(c)

	// first argument must be a valid property type, sixth a view
	utl.ValidateStringInSlice(argSlice[0], utl.PropertyTypes)
	utl.ValidateStringInSlice(argSlice[5], utl.Views)

	// get which node is being modified
	id := utl.TryGetNodeByUUIDOrName(argSlice[3])

	// TODO: validate property of that type and name exists
	path := fmt.Sprintf("/nodes/%s/property/%s/%s/%s",
		id.String(),
		argSlice[0], // type
		argSlice[5], // view
		argSlice[1], // property
	)

	_ = utl.GetRequest(path)
}

func cmdNodePropertyDel(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 6)
	utl.ValidateCliArgument(c, 3, "from")
	utl.ValidateCliArgument(c, 5, "view")
	argSlice := utl.GetFullArgumentSlice(c)

	// first argument must be a valid property type, sixth a view
	utl.ValidateStringInSlice(argSlice[0], utl.PropertyTypes)
	utl.ValidateStringInSlice(argSlice[5], utl.Views)

	// get which node is being modified
	id := utl.TryGetNodeByUUIDOrName(argSlice[3])

	// TODO: validate property of that type and name exists
	path := fmt.Sprintf("/nodes/%s/property/%s/%s/%s",
		id.String(),
		argSlice[0], //type
		argSlice[5], //view
		argSlice[1], //property
	)

	_ = utl.DeleteRequest(path)
}

func cmdNodePropertyList(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s/property/", id.String())

	var req somaproto.ProtoRequestNode

	if c.Bool("all") {
		req.Filter.LocalProperty = false
		_ = utl.GetRequest(path)
	} else {
		req.Filter.LocalProperty = true
		_ = utl.GetRequestWithBody(req, path)
	}
}

func cmdNodePropertyShow(c *cli.Context) {
	utl.ValidateCliArgumentCount(c, 1)
	id := utl.TryGetNodeByUUIDOrName(c.Args().First())
	path := fmt.Sprintf("/nodes/%s/property/", id.String())

	_ = utl.GetRequest(path)
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package fire

import (
	"time"

	"github.com/gin-gonic/gin"
	"github.com/kr/pretty"
	"github.com/ory-am/fosite"
	"github.com/ory-am/fosite/handler/core"
	"github.com/ory-am/fosite/handler/core/client"
	"github.com/ory-am/fosite/handler/core/implicit"
	"github.com/ory-am/fosite/handler/core/owner"
	"github.com/ory-am/fosite/handler/core/strategy"
	"github.com/ory-am/fosite/token/hmac"
	"gopkg.in/mgo.v2"
)

type AccessToken struct {
	Base         `bson:",inline" fire:"access-token:access-tokens:access_tokens"`
	Signature    string                `json:"-" valid:"-"`
	PlainRequest *fosite.Request       `json:"-" valid:"-" bson:"plain_request"`
	PlainClient  *fosite.DefaultClient `json:"-" valid:"-" bson:"plain_client"`
}

type Authenticator struct {
	storage *authenticatorStorage

	strategy     *strategy.HMACSHAStrategy
	handleHelper *core.HandleHelper
	fosite       *fosite.Fosite
}

var accessTokenModel *AccessToken

func init() {
	accessTokenModel = &AccessToken{}
	Init(accessTokenModel)
}

func NewAuthenticator(db *mgo.Database, ownerModel, clientModel Model, secret string) *Authenticator {
	// initialize models
	Init(ownerModel)
	Init(clientModel)

	// extract attributes from owner
	ownerIdentifiable := ownerModel.getBase().attributesByTag("identifiable")
	if len(ownerIdentifiable) != 1 {
		panic("expected to find exactly one 'identifiable' tag on model")
	}
	ownerVerifiable := ownerModel.getBase().attributesByTag("verifiable")
	if len(ownerVerifiable) != 1 {
		panic("expected to find exactly one 'verifiable' tag on model")
	}

	// extract attributes from client
	clientIdentifiable := clientModel.getBase().attributesByTag("identifiable")
	if len(clientIdentifiable) != 1 {
		panic("expected to find exactly one 'identifiable' tag on model")
	}
	clientVerifiable := clientModel.getBase().attributesByTag("verifiable")
	if len(clientVerifiable) != 1 {
		panic("expected to find exactly one 'verifiable' tag on model")
	}

	// create storage
	s := &authenticatorStorage{
		db:               db,
		ownerModel:       ownerModel,
		ownerIDAttr:      ownerIdentifiable[0],
		ownerSecretAttr:  ownerVerifiable[0],
		clientModel:      clientModel,
		clientIDAttr:     clientIdentifiable[0],
		clientSecretAttr: clientVerifiable[0],
	}

	// set the default token lifespan to one hour
	tokenLifespan := time.Hour

	// create a new token generation strategy
	strategy := &strategy.HMACSHAStrategy{
		Enigma: &hmac.HMACStrategy{
			GlobalSecret: []byte(secret),
		},
		AccessTokenLifespan:   tokenLifespan,
		AuthorizeCodeLifespan: tokenLifespan,
	}

	// instantiate a new fosite instance
	f := fosite.NewFosite(s)

	// set mandatory scope
	f.MandatoryScope = "fire"

	// this little helper is used by some of the handlers later
	handleHelper := &core.HandleHelper{
		AccessTokenStrategy: strategy,
		AccessTokenStorage:  s,
		AccessTokenLifespan: tokenLifespan,
	}

	// add a request validator for access tokens to fosite
	f.AuthorizedRequestValidators.Append(&core.CoreValidator{
		AccessTokenStrategy: strategy,
		AccessTokenStorage:  s,
	})

	return &Authenticator{
		storage:      s,
		fosite:       f,
		handleHelper: handleHelper,
		strategy:     strategy,
	}
}

// EnablePasswordGrant enables the usage of the OAuth 2.0 Resource Owner Password
// Credentials Grant.
func (a *Authenticator) EnablePasswordGrant() {
	// create handler
	passwordHandler := &owner.ResourceOwnerPasswordCredentialsGrantHandler{
		HandleHelper:                                 a.handleHelper,
		ResourceOwnerPasswordCredentialsGrantStorage: a.storage,
	}

	// add handler to fosite
	a.fosite.TokenEndpointHandlers.Append(passwordHandler)

	// TODO: Enable refresh token.
	// this handler is responsible for the refresh token grant
	//refreshHandler := &refresh.RefreshTokenGrantHandler{
	//	AccessTokenStrategy:      strategy,
	//	RefreshTokenStrategy:     strategy,
	//	RefreshTokenGrantStorage: s,
	//	AccessTokenLifespan:      accessTokenLifespan,
	//}

	// add handler to fosite
	//f.TokenEndpointHandlers.Append(refreshHandler)
}

// EnableCredentialsGrant enables the usage of the OAuth 2.0 Client Credentials Grant.
func (a *Authenticator) EnableCredentialsGrant() {
	// create handler
	credentialsHandler := &client.ClientCredentialsGrantHandler{
		HandleHelper: a.handleHelper,
	}

	// add handler to fosite
	a.fosite.TokenEndpointHandlers.Append(credentialsHandler)
}

// EnableImplicitGrant enables the usage of the OAuth 2.0 Implicit Grant.
func (a *Authenticator) EnableImplicitGrant() {
	// This handler is responsible for the implicit flow. The implicit flow does not return an authorize code
	// but instead returns the access token directly via an url fragment.
	implicitHandler := &implicit.AuthorizeImplicitGrantTypeHandler{
		AccessTokenStrategy: a.handleHelper.AccessTokenStrategy,
		AccessTokenStorage:  a.handleHelper.AccessTokenStorage,
		AccessTokenLifespan: a.handleHelper.AccessTokenLifespan,
	}
	a.fosite.AuthorizeEndpointHandlers.Append(implicitHandler)
}

// HashPassword returns an Authenticator compatible hash of the password.
func (a *Authenticator) HashPassword(password string) ([]byte, error) {
	return a.fosite.Hasher.Hash([]byte(password))
}

// MustHashPassword is the same as HashPassword except that it raises and error
// when the hashing failed.
func (a *Authenticator) MustHashPassword(password string) []byte {
	bytes, err := a.HashPassword(password)
	if err != nil {
		panic(err)
	}

	return bytes
}

func (a *Authenticator) Register(prefix string, router gin.IRouter) {
	router.POST(prefix+"/token", a.tokenEndpoint)
	router.GET(prefix+"/authorize", a.authEndpoint)
	router.POST(prefix+"/authorize", a.authEndpoint)
}

func (a *Authenticator) Authorizer() Callback {
	return func(ctx *Context) (error, error) {
		// prepare fosite
		f := fosite.NewContext()
		session := &strategy.HMACSession{}

		// validate request
		_, err := a.fosite.ValidateRequestAuthorization(f, ctx.GinContext.Request, session, "fire")
		if err != nil {
			return err, nil
		}

		return nil, nil
	}
}

func (a *Authenticator) tokenEndpoint(ctx *gin.Context) {
	// create new context
	f := fosite.NewContext()

	// create new session
	s := &strategy.HMACSession{}

	// obtain access request
	req, err := a.fosite.NewAccessRequest(f, ctx.Request, s)
	if err != nil {
		pretty.Println(err)
		a.fosite.WriteAccessError(ctx.Writer, req, err)
		return
	}

	// grant the mandatory scope
	if req.GetScopes().Has("fire") {
		req.GrantScope("fire")
	}

	// obtain access response
	res, err := a.fosite.NewAccessResponse(f, ctx.Request, req)
	if err != nil {
		pretty.Println(err)
		a.fosite.WriteAccessError(ctx.Writer, req, err)
		return
	}

	// write response
	a.fosite.WriteAccessResponse(ctx.Writer, req, res)
}

func (a *Authenticator) authEndpoint(ctx *gin.Context) {
	// create new context
	f := fosite.NewContext()

	// obtain authorize request
	req, err := a.fosite.NewAuthorizeRequest(f, ctx.Request)
	if err != nil {
		pretty.Println(err)
		a.fosite.WriteAuthorizeError(ctx.Writer, req, err)
		return
	}
	// You have now access to authorizeRequest, Code ResponseTypes, Scopes ...

	// Normally, this would be the place where you would check if the user is logged in and gives his consent.
	// We're simplifying things and just checking if the request includes a valid username and password
	if ctx.Request.Form.Get("username") != "peter" {
		ctx.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
		ctx.Writer.Write([]byte(`<h1>Login page</h1>`))
		ctx.Writer.Write([]byte(`

Howdy! This is the log in page. For this example, it is enough to supply the username.

			<form method="post">
				<input type="text" name="username" /> try peter

				<input type="submit">
			</form>
		`))
		return
	}

	// we allow issuing of refresh tokens per default
	if req.GetScopes().Has("offline") {
		req.GrantScope("offline")
	}

	// create new session
	s := &strategy.HMACSession{}

	// obtain authorize response
	res, err := a.fosite.NewAuthorizeResponse(ctx, ctx.Request, req, s)
	if err != nil {
		pretty.Println(err)
		a.fosite.WriteAuthorizeError(ctx.Writer, req, err)
		return
	}

	// write response
	a.fosite.WriteAuthorizeResponse(ctx.Writer, req, res)
}
<commit_msg>cleanup<commit_after>package fire

import (
	"time"

	"github.com/gin-gonic/gin"
	"github.com/kr/pretty"
	"github.com/ory-am/fosite"
	"github.com/ory-am/fosite/handler/core"
	"github.com/ory-am/fosite/handler/core/client"
	"github.com/ory-am/fosite/handler/core/implicit"
	"github.com/ory-am/fosite/handler/core/owner"
	"github.com/ory-am/fosite/handler/core/strategy"
	"github.com/ory-am/fosite/token/hmac"
	"gopkg.in/mgo.v2"
)

type AccessToken struct {
	Base         `bson:",inline" fire:"access-token:access-tokens:access_tokens"`
	Signature    string                `json:"-" valid:"-"`
	PlainRequest *fosite.Request       `json:"-" valid:"-" bson:"plain_request"`
	PlainClient  *fosite.DefaultClient `json:"-" valid:"-" bson:"plain_client"`
}

type Authenticator struct {
	storage *authenticatorStorage

	strategy     *strategy.HMACSHAStrategy
	handleHelper *core.HandleHelper
	fosite       *fosite.Fosite
}

var accessTokenModel *AccessToken

func init() {
	accessTokenModel = &AccessToken{}
	Init(accessTokenModel)
}

func NewAuthenticator(db *mgo.Database, ownerModel, clientModel Model, secret string) *Authenticator {
	// initialize models
	Init(ownerModel)
	Init(clientModel)

	// extract attributes from owner
	ownerIdentifiable := ownerModel.getBase().attributesByTag("identifiable")
	if len(ownerIdentifiable) != 1 {
		panic("expected to find exactly one 'identifiable' tag on model")
	}
	ownerVerifiable := ownerModel.getBase().attributesByTag("verifiable")
	if len(ownerVerifiable) != 1 {
		panic("expected to find exactly one 'verifiable' tag on model")
	}

	// extract attributes from client
	clientIdentifiable := clientModel.getBase().attributesByTag("identifiable")
	if len(clientIdentifiable) != 1 {
		panic("expected to find exactly one 'identifiable' tag on model")
	}
	clientVerifiable := clientModel.getBase().attributesByTag("verifiable")
	if len(clientVerifiable) != 1 {
		panic("expected to find exactly one 'verifiable' tag on model")
	}

	// create storage
	s := &authenticatorStorage{
		db:               db,
		ownerModel:       ownerModel,
		ownerIDAttr:      ownerIdentifiable[0],
		ownerSecretAttr:  ownerVerifiable[0],
		clientModel:      clientModel,
		clientIDAttr:     clientIdentifiable[0],
		clientSecretAttr: clientVerifiable[0],
	}

	// set the default token lifespan to one hour
	tokenLifespan := time.Hour

	// create a new token generation strategy
	strategy := &strategy.HMACSHAStrategy{
		Enigma: &hmac.HMACStrategy{
			GlobalSecret: []byte(secret),
		},
		AccessTokenLifespan:   tokenLifespan,
		AuthorizeCodeLifespan: tokenLifespan,
	}

	// instantiate a new fosite instance
	f := fosite.NewFosite(s)

	// set mandatory scope
	f.MandatoryScope = "fire"

	// this little helper is used by some of the handlers later
	handleHelper := &core.HandleHelper{
		AccessTokenStrategy: strategy,
		AccessTokenStorage:  s,
		AccessTokenLifespan: tokenLifespan,
	}

	// TODO: Enable refresh token.
	// this handler is responsible for the refresh token grant
	//refreshHandler := &refresh.RefreshTokenGrantHandler{
	//	AccessTokenStrategy:      strategy,
	//	RefreshTokenStrategy:     strategy,
	//	RefreshTokenGrantStorage: s,
	//	AccessTokenLifespan:      accessTokenLifespan,
	//}

	// add handler to fosite
	//f.TokenEndpointHandlers.Append(refreshHandler)

	// add a request validator for access tokens to fosite
	f.AuthorizedRequestValidators.Append(&core.CoreValidator{
		AccessTokenStrategy: strategy,
		AccessTokenStorage:  s,
	})

	return &Authenticator{
		storage:      s,
		fosite:       f,
		handleHelper: handleHelper,
		strategy:     strategy,
	}
}

// EnablePasswordGrant enables the usage of the OAuth 2.0 Resource Owner Password
// Credentials Grant.
func (a *Authenticator) EnablePasswordGrant() {
	// create handler
	passwordHandler := &owner.ResourceOwnerPasswordCredentialsGrantHandler{
		HandleHelper:                                 a.handleHelper,
		ResourceOwnerPasswordCredentialsGrantStorage: a.storage,
	}

	// add handler to fosite
	a.fosite.TokenEndpointHandlers.Append(passwordHandler)
}

// EnableCredentialsGrant enables the usage of the OAuth 2.0 Client Credentials Grant.
func (a *Authenticator) EnableCredentialsGrant() {
	// create handler
	credentialsHandler := &client.ClientCredentialsGrantHandler{
		HandleHelper: a.handleHelper,
	}

	// add handler to fosite
	a.fosite.TokenEndpointHandlers.Append(credentialsHandler)
}

// EnableImplicitGrant enables the usage of the OAuth 2.0 Implicit Grant.
func (a *Authenticator) EnableImplicitGrant() {
	// create handler
	implicitHandler := &implicit.AuthorizeImplicitGrantTypeHandler{
		AccessTokenStrategy: a.handleHelper.AccessTokenStrategy,
		AccessTokenStorage:  a.handleHelper.AccessTokenStorage,
		AccessTokenLifespan: a.handleHelper.AccessTokenLifespan,
	}

	// add handler to fosite
	a.fosite.AuthorizeEndpointHandlers.Append(implicitHandler)
}

// HashPassword returns an Authenticator compatible hash of the password.
func (a *Authenticator) HashPassword(password string) ([]byte, error) {
	return a.fosite.Hasher.Hash([]byte(password))
}

// MustHashPassword is the same as HashPassword except that it raises and error
// when the hashing failed.
func (a *Authenticator) MustHashPassword(password string) []byte {
	bytes, err := a.HashPassword(password)
	if err != nil {
		panic(err)
	}

	return bytes
}

func (a *Authenticator) Register(prefix string, router gin.IRouter) {
	router.POST(prefix+"/token", a.tokenEndpoint)
	router.GET(prefix+"/authorize", a.authorizeEndpoint)
	router.POST(prefix+"/authorize", a.authorizeEndpoint)
}

func (a *Authenticator) Authorizer() Callback {
	return func(ctx *Context) (error, error) {
		// prepare fosite
		f := fosite.NewContext()
		session := &strategy.HMACSession{}

		// validate request
		_, err := a.fosite.ValidateRequestAuthorization(f, ctx.GinContext.Request, session, "fire")
		if err != nil {
			return err, nil
		}

		return nil, nil
	}
}

func (a *Authenticator) tokenEndpoint(ctx *gin.Context) {
	// create new context
	f := fosite.NewContext()

	// create new session
	s := &strategy.HMACSession{}

	// obtain access request
	req, err := a.fosite.NewAccessRequest(f, ctx.Request, s)
	if err != nil {
		pretty.Println(err)
		a.fosite.WriteAccessError(ctx.Writer, req, err)
		return
	}

	// grant the mandatory scope
	if req.GetScopes().Has("fire") {
		req.GrantScope("fire")
	}

	// obtain access response
	res, err := a.fosite.NewAccessResponse(f, ctx.Request, req)
	if err != nil {
		pretty.Println(err)
		a.fosite.WriteAccessError(ctx.Writer, req, err)
		return
	}

	// write response
	a.fosite.WriteAccessResponse(ctx.Writer, req, res)
}

func (a *Authenticator) authorizeEndpoint(ctx *gin.Context) {
	// create new context
	f := fosite.NewContext()

	// obtain authorize request
	req, err := a.fosite.NewAuthorizeRequest(f, ctx.Request)
	if err != nil {
		pretty.Println(err)
		a.fosite.WriteAuthorizeError(ctx.Writer, req, err)
		return
	}
	// You have now access to authorizeRequest, Code ResponseTypes, Scopes ...

	// Normally, this would be the place where you would check if the user is logged in and gives his consent.
	// We're simplifying things and just checking if the request includes a valid username and password
	if ctx.Request.Form.Get("username") != "peter" {
		ctx.Writer.Header().Set("Content-Type", "text/html; charset=utf-8")
		ctx.Writer.Write([]byte(`<h1>Login page</h1>`))
		ctx.Writer.Write([]byte(`

Howdy! This is the log in page. For this example, it is enough to supply the username.

			<form method="post">
				<input type="text" name="username" /> try peter

				<input type="submit">
			</form>
		`))
		return
	}

	// we allow issuing of refresh tokens per default
	if req.GetScopes().Has("offline") {
		req.GrantScope("offline")
	}

	// create new session
	s := &strategy.HMACSession{}

	// obtain authorize response
	res, err := a.fosite.NewAuthorizeResponse(ctx, ctx.Request, req, s)
	if err != nil {
		pretty.Println(err)
		a.fosite.WriteAuthorizeError(ctx.Writer, req, err)
		return
	}

	// write response
	a.fosite.WriteAuthorizeResponse(ctx.Writer, req, res)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/bmatsuo/lmdb-go/exp/lmdbsync"
	"github.com/bmatsuo/lmdb-go/lmdb"
)

func main() {
	flag.Parse()

	failed := false
	defer func() {
		if failed {
			os.Exit(1)
		}
	}()
	fail := func(err error) {
		failed = true
		log.Print(err)
	}

	err := WriteRandomItems("db", 1<<20, 10<<10)
	if err != nil {
		fail(err)
	} else {
		log.Printf("success")
	}
}

// WriteRandomItems writes numitem items with checksize sized values full of
// random data.
func WriteRandomItems(path string, numitem, chunksize int64) error {
	env, err := OpenEnv(path)
	if err != nil {
		return err
	}
	defer env.Close()

	numResize := 0
	defer func() {
		log.Printf("%d resizes", numResize)
	}()
	mapFullLogger := func(b lmdbsync.Bag, err error) (lmdbsync.Bag, error) {
		if lmdb.IsMapFull(err) {
			log.Printf("resize required: %v", err)
			numResize++
		}
		return b, err
	}
	env.Handlers = env.Handlers.Append(
		lmdbsync.MapResizedHandler(2, func(int) time.Duration { return 100 * time.Microsecond }),
		handlerFunc(mapFullLogger),
		lmdbsync.MapFullHandler(func(size int64) (int64, bool) {
			newsize := size * 2
			log.Printf("oldsize=%d newsize=%d", size, newsize)
			return newsize, true
		}),
	)

	pid := os.Getpid()

	for i := int64(0); i < numitem; {
		start := i
		chunkmax := i + chunksize
		if chunkmax > numitem {
			chunkmax = numitem
		}
		v := make([]byte, 512)
		_, err := io.ReadFull(rand.Reader, v)
		if err != nil {
			return err
		}
		log.Printf("i=%d", i)
		err = env.Update(func(txn *lmdb.Txn) (err error) {
			dbi, err := txn.OpenRoot(0)
			if err != nil {
				return err
			}

			for i = start; i < chunkmax; i++ {
				k := fmt.Sprintf("%d-%016x", pid, i)
				err = txn.Put(dbi, []byte(k), v, 0)
				if err != nil {
					return err
				}
			}

			return nil
		})
		if err != nil {
			return err
		}
	}

	return nil
}

// OpenEnv is a helper for opening an lmdbsync.Env.
func OpenEnv(path string) (*lmdbsync.Env, error) {
	env, err := lmdbsync.NewEnv(nil)
	if err != nil {
		return nil, err
	}
	err = env.Open(path, 0, 0644)
	if err != nil {
		env.Close()
		return nil, err
	}
	return env, nil
}

type handlerFunc func(b lmdbsync.Bag, err error) (lmdbsync.Bag, error)

func (fn handlerFunc) HandleTxnErr(b lmdbsync.Bag, err error) (lmdbsync.Bag, error) {
	return fn(b, err)
}
<commit_msg>typo fix<commit_after>package main

import (
	"crypto/rand"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/bmatsuo/lmdb-go/exp/lmdbsync"
	"github.com/bmatsuo/lmdb-go/lmdb"
)

func main() {
	flag.Parse()

	failed := false
	defer func() {
		if failed {
			os.Exit(1)
		}
	}()
	fail := func(err error) {
		failed = true
		log.Print(err)
	}

	err := WriteRandomItems("db", 1<<20, 10<<10)
	if err != nil {
		fail(err)
	} else {
		log.Printf("success")
	}
}

// WriteRandomItems writes numitem items with chunksize sized values full of
// random data.
func WriteRandomItems(path string, numitem, chunksize int64) error {
	env, err := OpenEnv(path)
	if err != nil {
		return err
	}
	defer env.Close()

	numResize := 0
	defer func() {
		log.Printf("%d resizes", numResize)
	}()
	mapFullLogger := func(b lmdbsync.Bag, err error) (lmdbsync.Bag, error) {
		if lmdb.IsMapFull(err) {
			log.Printf("resize required: %v", err)
			numResize++
		}
		return b, err
	}
	env.Handlers = env.Handlers.Append(
		lmdbsync.MapResizedHandler(2, func(int) time.Duration { return 100 * time.Microsecond }),
		handlerFunc(mapFullLogger),
		lmdbsync.MapFullHandler(func(size int64) (int64, bool) {
			newsize := size * 2
			log.Printf("oldsize=%d newsize=%d", size, newsize)
			return newsize, true
		}),
	)

	pid := os.Getpid()

	for i := int64(0); i < numitem; {
		start := i
		chunkmax := i + chunksize
		if chunkmax > numitem {
			chunkmax = numitem
		}
		v := make([]byte, 512)
		_, err := io.ReadFull(rand.Reader, v)
		if err != nil {
			return err
		}
		log.Printf("i=%d", i)
		err = env.Update(func(txn *lmdb.Txn) (err error) {
			dbi, err := txn.OpenRoot(0)
			if err != nil {
				return err
			}

			for i = start; i < chunkmax; i++ {
				k := fmt.Sprintf("%d-%016x", pid, i)
				err = txn.Put(dbi, []byte(k), v, 0)
				if err != nil {
					return err
				}
			}

			return nil
		})
		if err != nil {
			return err
		}
	}

	return nil
}

// OpenEnv is a helper for opening an lmdbsync.Env.
func OpenEnv(path string) (*lmdbsync.Env, error) {
	env, err := lmdbsync.NewEnv(nil)
	if err != nil {
		return nil, err
	}
	err = env.Open(path, 0, 0644)
	if err != nil {
		env.Close()
		return nil, err
	}
	return env, nil
}

type handlerFunc func(b lmdbsync.Bag, err error) (lmdbsync.Bag, error)

func (fn handlerFunc) HandleTxnErr(b lmdbsync.Bag, err error) (lmdbsync.Bag, error) {
	return fn(b, err)
}
<|endoftext|>


<commit_before>package rds

import (
	"fmt"
	"net/url"
	"reflect"
)

func loadValues(v url.Values, i interface{}) error {
	value := reflect.ValueOf(i)
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	t := value.Type()
	for i := 0; i < value.NumField(); i++ {
		value := value.Field(i)
		name := t.Field(i).Name
		switch casted := value.Interface().(type) {
		case string:
			if casted != "" {
				v.Set(name, casted)
			}
		case bool:
			if casted {
				v.Set(name, "true")
			}
		case int64:
			if casted != 0 {
				v.Set(name, fmt.Sprintf("%d", casted))
			}
		case int:
			if casted != 0 {
				v.Set(name, fmt.Sprintf("%d", casted))
			}
		}
	}
	return nil
}
<commit_msg>added support for string list<commit_after>package rds

import (
	"fmt"
	"net/url"
	"reflect"
)

func loadValues(v url.Values, i interface{}) error {
	value := reflect.ValueOf(i)
	if value.Kind() == reflect.Ptr {
		value = value.Elem()
	}
	t := value.Type()
	for i := 0; i < value.NumField(); i++ {
		value := value.Field(i)
		name := t.Field(i).Name
		switch casted := value.Interface().(type) {
		case string:
			if casted != "" {
				v.Set(name, casted)
			}
		case bool:
			if casted {
				v.Set(name, "true")
			}
		case int64:
			if casted != 0 {
				v.Set(name, fmt.Sprintf("%d", casted))
			}
		case int:
			if casted != 0 {
				v.Set(name, fmt.Sprintf("%d", casted))
			}
		case []string:
			if len(casted) != 0 {
				for i, val := range casted {
					v.Set(fmt.Sprintf("%s.member.%d", name, i+1), val)
				}
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

package agent_test

import (
	"log"
	"net"
	"os"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

func ExampleClientAgent() {
	// ssh-agent has a UNIX socket under $SSH_AUTH_SOCK
	socket := os.Getenv("SSH_AUTH_SOCK")
	conn, err := net.Dial("unix", socket)
	if err != nil {
		log.Fatalf("net.Dial: %v", err)
	}
	agentClient := agent.NewClient(conn)
	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			// Use a callback rather than PublicKeys
			// so we only consult the agent once the remote server
			// wants it.
			ssh.PublicKeysCallback(agentClient.Signers),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	sshc, err := ssh.Dial("tcp", "localhost:22", config)
	if err != nil {
		log.Fatalf("Dial: %v", err)
	}
	// .. use sshc
	sshc.Close()
}
<commit_msg>ssh/agent: fix example<commit_after>// Copyright 2016 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.

package agent_test

import (
	"log"
	"net"
	"os"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

func ExampleNewClient() {
	// ssh-agent(1) provides a UNIX socket at $SSH_AUTH_SOCK.
	socket := os.Getenv("SSH_AUTH_SOCK")
	conn, err := net.Dial("unix", socket)
	if err != nil {
		log.Fatalf("Failed to open SSH_AUTH_SOCK: %v", err)
	}

	agentClient := agent.NewClient(conn)
	config := &ssh.ClientConfig{
		User: "gopher",
		Auth: []ssh.AuthMethod{
			// Use a callback rather than PublicKeys so we only consult the
			// agent once the remote server wants it.
			ssh.PublicKeysCallback(agentClient.Signers),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	sshc, err := ssh.Dial("tcp", "localhost:22", config)
	if err != nil {
		log.Fatal(err)
	}
	// Use sshc...
	sshc.Close()
}
<|endoftext|>


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

package apiserver

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/juju/juju/state/api/params"
	"github.com/juju/juju/state/backup/backup"
)

var Backup = backup.Backup

// backupHandler handles backup requests
type backupHandler struct {
	httpHandler
}

func (h *backupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := h.authenticate(r); err != nil {
		h.authError(w, h)
		return
	}

	switch r.Method {
	case "POST":
		tempDir, err := ioutil.TempDir("", "jujuBackup")
		if err != nil {
			h.sendError(w, http.StatusInternalServerError, fmt.Sprintf("backup failed: %v", err))
			return
		}

		defer os.RemoveAll(tempDir)
		filename, sha, err := Backup(tempDir)
		if err != nil {
			h.sendError(w, http.StatusInternalServerError, fmt.Sprintf("backup failed: %v", err))
			return
		}

		file, err := os.Open(filename)
		if err != nil {
			h.sendError(w, http.StatusInternalServerError, fmt.Sprintf("backup failed: missing backup file"))
			return
		}

		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("X-Content-SHA", sha)

		w.WriteHeader(http.StatusOK)
		io.Copy(w, file)
	default:
		h.sendError(w, http.StatusMethodNotAllowed, fmt.Sprintf("unsupported method: %q", r.Method))
	}
}

// sendError sends a JSON-encoded error response.
func (h *backupHandler) sendError(w http.ResponseWriter, statusCode int, message string) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	body, err := json.Marshal(&params.BackupResponse{Error: message})
	if err != nil {
		return err
	}
	w.Write(body)
	return nil
}
<commit_msg>Correct package reference<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package apiserver

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/juju/juju/state/api/params"
	"github.com/juju/juju/state/backup"
)

var Backup = backup.Backup

// backupHandler handles backup requests
type backupHandler struct {
	httpHandler
}

func (h *backupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := h.authenticate(r); err != nil {
		h.authError(w, h)
		return
	}

	switch r.Method {
	case "POST":
		tempDir, err := ioutil.TempDir("", "jujuBackup")
		if err != nil {
			h.sendError(w, http.StatusInternalServerError, fmt.Sprintf("backup failed: %v", err))
			return
		}

		defer os.RemoveAll(tempDir)
		filename, sha, err := Backup(tempDir)
		if err != nil {
			h.sendError(w, http.StatusInternalServerError, fmt.Sprintf("backup failed: %v", err))
			return
		}

		file, err := os.Open(filename)
		if err != nil {
			h.sendError(w, http.StatusInternalServerError, fmt.Sprintf("backup failed: missing backup file"))
			return
		}

		w.Header().Set("Content-Type", "application/octet-stream")
		w.Header().Set("X-Content-SHA", sha)

		w.WriteHeader(http.StatusOK)
		io.Copy(w, file)
	default:
		h.sendError(w, http.StatusMethodNotAllowed, fmt.Sprintf("unsupported method: %q", r.Method))
	}
}

// sendError sends a JSON-encoded error response.
func (h *backupHandler) sendError(w http.ResponseWriter, statusCode int, message string) error {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	body, err := json.Marshal(&params.BackupResponse{Error: message})
	if err != nil {
		return err
	}
	w.Write(body)
	return nil
}
<|endoftext|>


<commit_before>package backup

import (
	"strings"

	"github.com/codeskyblue/go-sh"
	"github.com/pkg/errors"
)

func CheckMongodump() (string, error) {
	output, err := sh.Command("/bin/sh", "-c", "mongodump --version").CombinedOutput()
	if err != nil {
		ex := ""
		if len(output) > 0 {
			ex = strings.Replace(string(output), "\n", " ", -1)
		}
		return "", errors.Wrapf(err, "mongodump failed %v", ex)
	}

	return strings.Replace(string(output), "\n", " ", -1), nil
}

func CheckMinioClient() (string, error) {
	output, err := sh.Command("/bin/sh", "-c", "mc version").CombinedOutput()
	if err != nil {
		ex := ""
		if len(output) > 0 {
			ex = strings.Replace(string(output), "\n", " ", -1)
		}
		return "", errors.Wrapf(err, "mc failed %v", ex)
	}

	return strings.Replace(string(output), "\n", " ", -1), nil
}
<commit_msg>Adds CheckGCloudClient<commit_after>package backup

import (
	"strings"

	"github.com/codeskyblue/go-sh"
	"github.com/pkg/errors"
)

func CheckMongodump() (string, error) {
	output, err := sh.Command("/bin/sh", "-c", "mongodump --version").CombinedOutput()
	if err != nil {
		ex := ""
		if len(output) > 0 {
			ex = strings.Replace(string(output), "\n", " ", -1)
		}
		return "", errors.Wrapf(err, "mongodump failed %v", ex)
	}

	return strings.Replace(string(output), "\n", " ", -1), nil
}

func CheckMinioClient() (string, error) {
	output, err := sh.Command("/bin/sh", "-c", "mc version").CombinedOutput()
	if err != nil {
		ex := ""
		if len(output) > 0 {
			ex = strings.Replace(string(output), "\n", " ", -1)
		}
		return "", errors.Wrapf(err, "mc failed %v", ex)
	}

	return strings.Replace(string(output), "\n", " ", -1), nil
}

func CheckGCloudClient() (string, error) {
	output, err := sh.Command("/bin/sh", "-c", "gcloud --version").CombinedOutput()
	if err != nil {
		ex := ""
		if len(output) > 0 {
			ex = strings.Replace(string(output), "\n", " ", -1)
		}
		return "", errors.Wrapf(err, "gcloud failed %v", ex)
	}

	return strings.Replace(string(output), "\n", " ", -1), nil
}<|endoftext|>


<commit_before>// Copyright 2016 ePoxy 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 storage

import (
	"context"
	"fmt"
	"reflect"
	"testing"

	"cloud.google.com/go/datastore"
)

// fakeDatastoreClient implements the datastoreClient interface for testing.
// Every operation should be successful.
type fakeDatastoreClient struct {
	host *Host
}

// Get reads the Host value from f.host and copies it to dst.
func (f *fakeDatastoreClient) Get(ctx context.Context, key *datastore.Key, dst interface{}) error {
	// Copy the host from f.host into dst.
	h, ok := dst.(*Host)
	if !ok {
		return fmt.Errorf("type assertion failed: got %T; want *Host", dst)
	}
	*h = *f.host
	return nil
}

// Put reads the Host value from src and copies it to f.host.
func (f *fakeDatastoreClient) Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
	// Copy the host from src into f.host.
	h, ok := src.(*Host)
	if !ok {
		return nil, fmt.Errorf("type assertion failed: got %T; want *Host", src)
	}
	*f.host = *h
	return nil, nil
}

func (f *fakeDatastoreClient) GetAll(ctx context.Context, q *datastore.Query, dst interface{}) ([]*datastore.Key, error) {
	// Extract the pointer to a list of *Host, and append f.host to the list.
	hosts, ok := dst.(*[]*Host)
	if !ok {
		return nil, fmt.Errorf("type assertion failed: got %T; want *[]*Host", dst)
	}
	*hosts = append(*hosts, f.host)
	return nil, nil
}

// errDatastoreClient implements a datastoreClient interface where every call fails with an error.
// The error returned is defined in errDatastoreClient.err.
type errDatastoreClient struct {
	err error
}

func (f *errDatastoreClient) Get(ctx context.Context, key *datastore.Key, dst interface{}) error {
	return f.err
}

func (f *errDatastoreClient) Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
	return nil, f.err
}

func (f *errDatastoreClient) GetAll(ctx context.Context, q *datastore.Query, dst interface{}) ([]*datastore.Key, error) {
	return nil, f.err
}

func TestNewDatastoreClient(t *testing.T) {
	h := Host{
		Name: "mlab1.iad1t.measurement-lab.org",
	}
	f := &fakeDatastoreClient{&h}
	c := NewDatastoreConfig(f)

	h2, err := c.Load("malb1.iad1t.measurement-lab.org")
	if err != nil {
		t.Fatal(err)
	}
	if h.Name != h2.Name {
		t.Errorf("Load for NewDatastoreConfig failed; want %q, got %q", h.Name, h2.Name)
	}
}

func TestDatastore(t *testing.T) {
	// NB: we store a partial Host record for brevity.
	h := Host{
		Name:     "mlab1.iad1t.measurement-lab.org",
		IPv4Addr: "165.117.240.9",
		Boot: Sequence{
			Stage1ChainURL: "https://example.com/path/stage1to2/stage1to2.ipxe",
		},
		CurrentSessionIDs: SessionIDs{
			Stage2ID: "01234",
		},
	}
	// Declare the fake datastore client outside the function below so we can access member elements.
	f := &fakeDatastoreClient{&h}
	c := &DatastoreConfig{f}

	// Store host record.
	err := c.Save(&h)
	if err != nil {
		t.Fatalf("Failed to save host: %s", err)
	}
	if !reflect.DeepEqual(&h, f.host) {
		t.Fatalf("Host records does not match: got %#v; want %#v\n", f.host, &h)
	}

	// Retrieve host record.
	h2, err := c.Load("mlab1.iad1t.measurement-lab.org")
	if err != nil {
		t.Fatalf("Failed to load host: %s", err)
	}
	if !reflect.DeepEqual(&h, h2) {
		t.Fatalf("Host records does not match: got %#v; want %#v\n", h2, &h)
	}

	// GetAll all hosts.
	hosts, err := c.List()
	if err != nil {
		t.Fatalf("Failed to list hosts: %s", err)
	}
	if len(hosts) != 1 {
		t.Fatalf("Failed to list hosts: got %d; want 1\n", len(hosts))
	}
}

func TestDatastoreFailures(t *testing.T) {
	// NB: we store a partial Host record for brevity.
	h := Host{
		Name:     "mlab1.iad1t.measurement-lab.org",
		IPv4Addr: "165.117.240.9",
		Boot: Sequence{
			Stage1ChainURL: "https://example.com/path/stage1to2/stage1to2.ipxe",
		},
		CurrentSessionIDs: SessionIDs{
			Stage2ID: "01234",
		},
	}
	// Declare the fake datastore client outside the function below so we can access member elements.
	f := &errDatastoreClient{fmt.Errorf("Fake failure")}
	c := &DatastoreConfig{f}

	// Store host record.
	err := c.Save(&h)
	if err != f.err {
		t.Fatalf("Saved without error: got %q; want %q\n", err, f.err)
	}

	// Retrieve host record.
	_, err = c.Load("mlab1.iad1t.measurement-lab.org")
	if err != f.err {
		t.Fatalf("Load without error: got %q; want %q\n", err, f.err)
	}

	// GetAll all hosts.
	_, err = c.List()
	if err != f.err {
		t.Fatalf("List without error: got %q; want %q\n", err, f.err)
	}
}
<commit_msg>Fix typo<commit_after>// Copyright 2016 ePoxy 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 storage

import (
	"context"
	"fmt"
	"reflect"
	"testing"

	"cloud.google.com/go/datastore"
)

// fakeDatastoreClient implements the datastoreClient interface for testing.
// Every operation should be successful.
type fakeDatastoreClient struct {
	host *Host
}

// Get reads the Host value from f.host and copies it to dst.
func (f *fakeDatastoreClient) Get(ctx context.Context, key *datastore.Key, dst interface{}) error {
	// Copy the host from f.host into dst.
	h, ok := dst.(*Host)
	if !ok {
		return fmt.Errorf("type assertion failed: got %T; want *Host", dst)
	}
	*h = *f.host
	return nil
}

// Put reads the Host value from src and copies it to f.host.
func (f *fakeDatastoreClient) Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
	// Copy the host from src into f.host.
	h, ok := src.(*Host)
	if !ok {
		return nil, fmt.Errorf("type assertion failed: got %T; want *Host", src)
	}
	*f.host = *h
	return nil, nil
}

func (f *fakeDatastoreClient) GetAll(ctx context.Context, q *datastore.Query, dst interface{}) ([]*datastore.Key, error) {
	// Extract the pointer to a list of *Host, and append f.host to the list.
	hosts, ok := dst.(*[]*Host)
	if !ok {
		return nil, fmt.Errorf("type assertion failed: got %T; want *[]*Host", dst)
	}
	*hosts = append(*hosts, f.host)
	return nil, nil
}

// errDatastoreClient implements a datastoreClient interface where every call fails with an error.
// The error returned is defined in errDatastoreClient.err.
type errDatastoreClient struct {
	err error
}

func (f *errDatastoreClient) Get(ctx context.Context, key *datastore.Key, dst interface{}) error {
	return f.err
}

func (f *errDatastoreClient) Put(ctx context.Context, key *datastore.Key, src interface{}) (*datastore.Key, error) {
	return nil, f.err
}

func (f *errDatastoreClient) GetAll(ctx context.Context, q *datastore.Query, dst interface{}) ([]*datastore.Key, error) {
	return nil, f.err
}

func TestNewDatastoreClient(t *testing.T) {
	h := Host{
		Name: "mlab1.iad1t.measurement-lab.org",
	}
	f := &fakeDatastoreClient{&h}
	c := NewDatastoreConfig(f)

	h2, err := c.Load("mlab1.iad1t.measurement-lab.org")
	if err != nil {
		t.Fatal(err)
	}
	if h.Name != h2.Name {
		t.Errorf("Load for NewDatastoreConfig failed; want %q, got %q", h.Name, h2.Name)
	}
}

func TestDatastore(t *testing.T) {
	// NB: we store a partial Host record for brevity.
	h := Host{
		Name:     "mlab1.iad1t.measurement-lab.org",
		IPv4Addr: "165.117.240.9",
		Boot: Sequence{
			Stage1ChainURL: "https://example.com/path/stage1to2/stage1to2.ipxe",
		},
		CurrentSessionIDs: SessionIDs{
			Stage2ID: "01234",
		},
	}
	// Declare the fake datastore client outside the function below so we can access member elements.
	f := &fakeDatastoreClient{&h}
	c := &DatastoreConfig{f}

	// Store host record.
	err := c.Save(&h)
	if err != nil {
		t.Fatalf("Failed to save host: %s", err)
	}
	if !reflect.DeepEqual(&h, f.host) {
		t.Fatalf("Host records does not match: got %#v; want %#v\n", f.host, &h)
	}

	// Retrieve host record.
	h2, err := c.Load("mlab1.iad1t.measurement-lab.org")
	if err != nil {
		t.Fatalf("Failed to load host: %s", err)
	}
	if !reflect.DeepEqual(&h, h2) {
		t.Fatalf("Host records does not match: got %#v; want %#v\n", h2, &h)
	}

	// GetAll all hosts.
	hosts, err := c.List()
	if err != nil {
		t.Fatalf("Failed to list hosts: %s", err)
	}
	if len(hosts) != 1 {
		t.Fatalf("Failed to list hosts: got %d; want 1\n", len(hosts))
	}
}

func TestDatastoreFailures(t *testing.T) {
	// NB: we store a partial Host record for brevity.
	h := Host{
		Name:     "mlab1.iad1t.measurement-lab.org",
		IPv4Addr: "165.117.240.9",
		Boot: Sequence{
			Stage1ChainURL: "https://example.com/path/stage1to2/stage1to2.ipxe",
		},
		CurrentSessionIDs: SessionIDs{
			Stage2ID: "01234",
		},
	}
	// Declare the fake datastore client outside the function below so we can access member elements.
	f := &errDatastoreClient{fmt.Errorf("Fake failure")}
	c := &DatastoreConfig{f}

	// Store host record.
	err := c.Save(&h)
	if err != f.err {
		t.Fatalf("Saved without error: got %q; want %q\n", err, f.err)
	}

	// Retrieve host record.
	_, err = c.Load("mlab1.iad1t.measurement-lab.org")
	if err != f.err {
		t.Fatalf("Load without error: got %q; want %q\n", err, f.err)
	}

	// GetAll all hosts.
	_, err = c.List()
	if err != f.err {
		t.Fatalf("List without error: got %q; want %q\n", err, f.err)
	}
}
<|endoftext|>


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

package server

import (
	"encoding/hex"
	"io"
	"net/http"
	"strconv"
	"time"

	"github.com/juju/errors"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"

	"github.com/juju/juju/resource"
)

// UploadDataStore describes the the portion of Juju's "state"
// needed for handling upload requests.
type UploadDataStore interface {
	// GetResource returns the identified resource.
	GetResource(serviceID, name string) (resource.Resource, error)

	// SetResource adds the resource to blob storage and updates the metadata.
	SetResource(serviceID string, res resource.Resource, r io.Reader) error
}

// UploadedResource holds both the information about an uploaded
// resource and the reader containing its data.
type UploadedResource struct {
	// Service is the name of the service associated with the resource.
	Service string

	// Resource is the information about the resource.
	Resource resource.Resource

	// Data holds the resource blob.
	Data io.ReadCloser
}

// UploadHandler
type UploadHandler struct {
	Username string
	Store    UploadDataStore

	CurrentTimestamp func() time.Time
}

// HandleRequest handles a resource upload request.
func (uh UploadHandler) HandleRequest(req *http.Request) error {
	defer req.Body.Close()

	uploaded, err := uh.ReadResource(req)
	if err != nil {
		return errors.Trace(err)
	}

	if err := uh.Store.SetResource(uploaded.Service, uploaded.Resource, uploaded.Data); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// ReadResource extracts the relevant info from the request.
func (uh UploadHandler) ReadResource(req *http.Request) (*UploadedResource, error) {
	ctype := req.Header.Get("Content-Type")
	if ctype != "application/octet-stream" {
		return nil, errors.Errorf("unsupported content type %q", ctype)
	}

	// See HTTPEndpoint in server.go and pattern handling in apiserver/apiserver.go.
	service := req.URL.Query().Get(":service")
	name := req.URL.Query().Get(":resource")

	fingerprint := req.URL.Query().Get("fingerprint")
	size := req.Header.Get("Content-Length")

	res, err := uh.Store.GetResource(service, name)
	if err != nil {
		return nil, errors.Trace(err)
	}

	res, err = uh.updateResource(res, fingerprint, size)
	if err != nil {
		return nil, errors.Trace(err)
	}

	uploaded := &UploadedResource{
		Service:  service,
		Resource: res,
		Data:     req.Body,
	}
	return uploaded, nil
}

// updateResource returns a copy of the provided resource, updated with
// the given information.
func (uh UploadHandler) updateResource(res resource.Resource, fingerprint, size string) (resource.Resource, error) {
	data, err := hex.DecodeString(fingerprint)
	if err != nil {
		return res, errors.Annotate(err, "invalid fingerprint")
	}
	fp, err := charmresource.NewFingerprint(data)
	if err != nil {
		return res, errors.Annotate(err, "invalid fingerprint")
	}

	sizeInt, err := strconv.ParseInt(size, 10, 64)
	if err != nil {
		return res, errors.Annotate(err, "invalid size")
	}

	res.Origin = charmresource.OriginUpload
	res.Revision = 0
	res.Fingerprint = fp
	res.Size = sizeInt
	res.Username = uh.Username
	res.Timestamp = uh.CurrentTimestamp().UTC()

	if err := res.Validate(); err != nil {
		return res, errors.Trace(err)
	}
	return res, nil
}
<commit_msg>Add doc comments.<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package server

import (
	"encoding/hex"
	"io"
	"net/http"
	"strconv"
	"time"

	"github.com/juju/errors"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"

	"github.com/juju/juju/resource"
)

// UploadDataStore describes the the portion of Juju's "state"
// needed for handling upload requests.
type UploadDataStore interface {
	// GetResource returns the identified resource.
	GetResource(serviceID, name string) (resource.Resource, error)

	// SetResource adds the resource to blob storage and updates the metadata.
	SetResource(serviceID string, res resource.Resource, r io.Reader) error
}

// UploadedResource holds both the information about an uploaded
// resource and the reader containing its data.
type UploadedResource struct {
	// Service is the name of the service associated with the resource.
	Service string

	// Resource is the information about the resource.
	Resource resource.Resource

	// Data holds the resource blob.
	Data io.ReadCloser
}

// UploadHandler provides the functionality to handle upload requests.
type UploadHandler struct {
	// Username is the ID of the user making the upload request.
	Username string

	// Store is the data store into which the resource will be stored.
	Store UploadDataStore

	// CurrentTimestamp is the function that provides the current timestamp.
	CurrentTimestamp func() time.Time
}

// HandleRequest handles a resource upload request.
func (uh UploadHandler) HandleRequest(req *http.Request) error {
	defer req.Body.Close()

	uploaded, err := uh.ReadResource(req)
	if err != nil {
		return errors.Trace(err)
	}

	if err := uh.Store.SetResource(uploaded.Service, uploaded.Resource, uploaded.Data); err != nil {
		return errors.Trace(err)
	}

	return nil
}

// ReadResource extracts the relevant info from the request.
func (uh UploadHandler) ReadResource(req *http.Request) (*UploadedResource, error) {
	ctype := req.Header.Get("Content-Type")
	if ctype != "application/octet-stream" {
		return nil, errors.Errorf("unsupported content type %q", ctype)
	}

	// See HTTPEndpoint in server.go and pattern handling in apiserver/apiserver.go.
	service := req.URL.Query().Get(":service")
	name := req.URL.Query().Get(":resource")

	fingerprint := req.URL.Query().Get("fingerprint")
	size := req.Header.Get("Content-Length")

	res, err := uh.Store.GetResource(service, name)
	if err != nil {
		return nil, errors.Trace(err)
	}

	res, err = uh.updateResource(res, fingerprint, size)
	if err != nil {
		return nil, errors.Trace(err)
	}

	uploaded := &UploadedResource{
		Service:  service,
		Resource: res,
		Data:     req.Body,
	}
	return uploaded, nil
}

// updateResource returns a copy of the provided resource, updated with
// the given information.
func (uh UploadHandler) updateResource(res resource.Resource, fingerprint, size string) (resource.Resource, error) {
	data, err := hex.DecodeString(fingerprint)
	if err != nil {
		return res, errors.Annotate(err, "invalid fingerprint")
	}
	fp, err := charmresource.NewFingerprint(data)
	if err != nil {
		return res, errors.Annotate(err, "invalid fingerprint")
	}

	sizeInt, err := strconv.ParseInt(size, 10, 64)
	if err != nil {
		return res, errors.Annotate(err, "invalid size")
	}

	res.Origin = charmresource.OriginUpload
	res.Revision = 0
	res.Fingerprint = fp
	res.Size = sizeInt
	res.Username = uh.Username
	res.Timestamp = uh.CurrentTimestamp().UTC()

	if err := res.Validate(); err != nil {
		return res, errors.Trace(err)
	}
	return res, nil
}
<|endoftext|>


<commit_before>package boardgame

import (
	"errors"
)

//StorageManager is an interface that anything can implement to handle the
//persistence of Games and States.
type StorageManager interface {
	//State returns the StateWrapper for the game at the given version, or
	//nil.
	State(game *Game, version int) *StateWrapper
	//SaveState puts the given stateWrapper (at the specified version and
	//schema) into storage.
	SaveState(game *Game, state *StateWrapper) error
}

type memoryStateRecord struct {
	Schema          int
	Version         int
	SerializedState []byte
}

type inMemoryStorageManager struct {
	states map[string]map[int]*memoryStateRecord
}

func NewInMemoryStorageManager() StorageManager {
	//InMemoryStorageManager is an extremely simple StorageManager that just keeps
	//track of the objects in memory.
	return &inMemoryStorageManager{
		states: make(map[string]map[int]*memoryStateRecord),
	}
}

func (i *inMemoryStorageManager) State(game *Game, version int) *StateWrapper {
	if game == nil {
		return nil
	}

	if version < 0 || version > game.StateWrapper.Version {
		return nil
	}

	versionMap, ok := i.states[game.Id()]

	if !ok {
		return nil
	}

	record, ok := versionMap[version]

	if !ok {
		return nil
	}

	state, err := game.Delegate.StateFromBlob(record.SerializedState, record.Schema)

	if err != nil {
		return nil
	}

	return &StateWrapper{
		Version: record.Version,
		Schema:  record.Schema,
		State:   state,
	}
}

func (i *inMemoryStorageManager) SaveState(game *Game, state *StateWrapper) error {
	//TODO: do something
	return errors.New("That method is not yet implemented")
}
<commit_msg>(Untested) implementation of inMemoryStorageManager.SaveState. Part of #81.<commit_after>package boardgame

import (
	"encoding/json"
	"errors"
)

//StorageManager is an interface that anything can implement to handle the
//persistence of Games and States.
type StorageManager interface {
	//State returns the StateWrapper for the game at the given version, or
	//nil.
	State(game *Game, version int) *StateWrapper
	//SaveState puts the given stateWrapper (at the specified version and
	//schema) into storage.
	SaveState(game *Game, state *StateWrapper) error
}

type memoryStateRecord struct {
	Schema          int
	Version         int
	SerializedState []byte
}

type inMemoryStorageManager struct {
	states map[string]map[int]*memoryStateRecord
}

func NewInMemoryStorageManager() StorageManager {
	//InMemoryStorageManager is an extremely simple StorageManager that just keeps
	//track of the objects in memory.
	return &inMemoryStorageManager{
		states: make(map[string]map[int]*memoryStateRecord),
	}
}

func (i *inMemoryStorageManager) State(game *Game, version int) *StateWrapper {
	if game == nil {
		return nil
	}

	if version < 0 || version > game.StateWrapper.Version {
		return nil
	}

	versionMap, ok := i.states[game.Id()]

	if !ok {
		return nil
	}

	record, ok := versionMap[version]

	if !ok {
		return nil
	}

	state, err := game.Delegate.StateFromBlob(record.SerializedState, record.Schema)

	if err != nil {
		return nil
	}

	return &StateWrapper{
		Version: record.Version,
		Schema:  record.Schema,
		State:   state,
	}
}

func (i *inMemoryStorageManager) SaveState(game *Game, state *StateWrapper) error {
	if game == nil {
		return errors.New("No game provided")
	}

	//TODO: validate that state.Version is reasonable.

	if _, ok := i.states[game.Id()]; !ok {
		i.states[game.Id()] = make(map[int]*memoryStateRecord)
	}

	versionMap := i.states[game.Id()]

	if _, ok := versionMap[state.Version]; ok {
		//Wait, there was already a version stored there?
		return errors.New("There was already a version for that game stored")
	}

	blob, err := json.Marshal(state.State)

	if err != nil {
		return errors.New("Error marshalling State: " + err.Error())
	}

	versionMap[state.Version] = &memoryStateRecord{
		Version:         state.Version,
		Schema:          state.Schema,
		SerializedState: blob,
	}

	return nil
}
<|endoftext|>


<commit_before>package sched

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
	"time"

	"github.com/bosun-monitor/bosun/_third_party/github.com/bosun-monitor/opentsdb"
	"github.com/bosun-monitor/bosun/conf"
)

func init() {
	log.SetOutput(ioutil.Discard)
}

type schedState struct {
	key, status string
}

type schedTest struct {
	conf    string
	queries map[string]opentsdb.ResponseSet
	// state -> active
	state map[schedState]bool
}

func testSched(t *testing.T, st *schedTest) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var req opentsdb.Request
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			log.Fatal(err)
		}
		var resp opentsdb.ResponseSet
		for _, rq := range req.Queries {
			qs := fmt.Sprintf(`q("%s", "%v", "%v")`, rq, req.Start, req.End)
			q := st.queries[qs]
			if q == nil {
				t.Errorf("unknown query: %s", qs)
				return
			}
			resp = append(resp, q...)
		}
		if err := json.NewEncoder(w).Encode(&resp); err != nil {
			log.Fatal(err)
		}
	}))
	defer ts.Close()
	u, err := url.Parse(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	confs := "tsdbHost = " + u.Host + "\n" + st.conf
	start := time.Date(2000, time.January, 1, 12, 0, 0, 0, time.UTC)
	c, err := conf.New("testconf", confs)
	if err != nil {
		t.Error(err)
		t.Logf("conf:\n%s", confs)
		return
	}
	c.StateFile = ""
	time.Sleep(time.Millisecond * 250)
	s := new(Schedule)
	s.Init(c)
	s.Check(nil, start)
	groups, err := s.MarshalGroups("")
	if err != nil {
		t.Error(err)
		return
	}
	var check func(g *StateGroup)
	check = func(g *StateGroup) {
		for _, c := range g.Children {
			check(c)
		}
		if g.AlertKey == "" {
			return
		}
		ss := schedState{string(g.AlertKey), g.Status.String()}
		v, ok := st.state[ss]
		if !ok {
			t.Errorf("unexpected state: %s, %s", g.AlertKey, g.Status)
			return
		}
		if v != g.Active {
			t.Errorf("bad active: %s, %s", g.AlertKey, g.Status)
			return
		}
		delete(st.state, ss)
	}
	for _, v := range groups.Groups.NeedAck {
		check(v)
	}
	for _, v := range groups.Groups.Acknowledged {
		check(v)
	}
	for k := range st.state {
		t.Errorf("unused state: %s", k)
	}
}

func TestCrit(t *testing.T) {
	testSched(t, &schedTest{
		conf: `alert a {
			crit = avg(q("avg:m{a=b}", "5m", "")) > 0
		}`,
		queries: map[string]opentsdb.ResponseSet{
			`q("avg:m{a=b}", "2000/01/01-11:55:00", "2000/01/01-12:00:00")`: {
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "b"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
			},
		},
		state: map[schedState]bool{
			schedState{"a{a=b}", "critical"}: true,
		},
	})
}

func TestBandDisableUnjoined(t *testing.T) {
	testSched(t, &schedTest{
		conf: `alert a {
			$sum = "sum:m{a=*}"
			$band = band($sum, "1m", "1h", 1)
			crit = avg(q($sum, "1m", "")) > avg($band) + dev($band)
		}`,
		queries: map[string]opentsdb.ResponseSet{
			`q("sum:m{a=*}", "2000/01/01-11:59:00", "2000/01/01-12:00:00")`: {
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "b"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
			},
			`q("sum:m{a=*}", "9.4672434e+08", "9.467244e+08")`: {
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "c"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
			},
		},
	})
}

func TestCount(t *testing.T) {
	testSched(t, &schedTest{
		conf: `alert a {
			crit = count("sum:m{a=*}", "1m", "") != 2
		}`,
		queries: map[string]opentsdb.ResponseSet{
			`q("sum:m{a=*}", "2000/01/01-11:59:00", "2000/01/01-12:00:00")`: {
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "b"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "c"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
			},
		},
	})
}
<commit_msg>Pass dem tests<commit_after>package sched

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"testing"
	"time"

	"github.com/bosun-monitor/bosun/_third_party/github.com/MiniProfiler/go/miniprofiler"
	"github.com/bosun-monitor/bosun/_third_party/github.com/bosun-monitor/opentsdb"
	"github.com/bosun-monitor/bosun/conf"
)

func init() {
	log.SetOutput(ioutil.Discard)
}

type schedState struct {
	key, status string
}

type schedTest struct {
	conf    string
	queries map[string]opentsdb.ResponseSet
	// state -> active
	state map[schedState]bool
}

func testSched(t *testing.T, st *schedTest) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		var req opentsdb.Request
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			log.Fatal(err)
		}
		var resp opentsdb.ResponseSet
		for _, rq := range req.Queries {
			qs := fmt.Sprintf(`q("%s", "%v", "%v")`, rq, req.Start, req.End)
			q := st.queries[qs]
			if q == nil {
				t.Errorf("unknown query: %s", qs)
				return
			}
			resp = append(resp, q...)
		}
		if err := json.NewEncoder(w).Encode(&resp); err != nil {
			log.Fatal(err)
		}
	}))
	defer ts.Close()
	u, err := url.Parse(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	confs := "tsdbHost = " + u.Host + "\n" + st.conf
	start := time.Date(2000, time.January, 1, 12, 0, 0, 0, time.UTC)
	c, err := conf.New("testconf", confs)
	if err != nil {
		t.Error(err)
		t.Logf("conf:\n%s", confs)
		return
	}
	c.StateFile = ""
	time.Sleep(time.Millisecond * 250)
	s := new(Schedule)
	s.Init(c)
	s.Check(nil, start)
	groups, err := s.MarshalGroups(new(miniprofiler.Profile), "")
	if err != nil {
		t.Error(err)
		return
	}
	var check func(g *StateGroup)
	check = func(g *StateGroup) {
		for _, c := range g.Children {
			check(c)
		}
		if g.AlertKey == "" {
			return
		}
		ss := schedState{string(g.AlertKey), g.Status.String()}
		v, ok := st.state[ss]
		if !ok {
			t.Errorf("unexpected state: %s, %s", g.AlertKey, g.Status)
			return
		}
		if v != g.Active {
			t.Errorf("bad active: %s, %s", g.AlertKey, g.Status)
			return
		}
		delete(st.state, ss)
	}
	for _, v := range groups.Groups.NeedAck {
		check(v)
	}
	for _, v := range groups.Groups.Acknowledged {
		check(v)
	}
	for k := range st.state {
		t.Errorf("unused state: %s", k)
	}
}

func TestCrit(t *testing.T) {
	testSched(t, &schedTest{
		conf: `alert a {
			crit = avg(q("avg:m{a=b}", "5m", "")) > 0
		}`,
		queries: map[string]opentsdb.ResponseSet{
			`q("avg:m{a=b}", "2000/01/01-11:55:00", "2000/01/01-12:00:00")`: {
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "b"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
			},
		},
		state: map[schedState]bool{
			schedState{"a{a=b}", "critical"}: true,
		},
	})
}

func TestBandDisableUnjoined(t *testing.T) {
	testSched(t, &schedTest{
		conf: `alert a {
			$sum = "sum:m{a=*}"
			$band = band($sum, "1m", "1h", 1)
			crit = avg(q($sum, "1m", "")) > avg($band) + dev($band)
		}`,
		queries: map[string]opentsdb.ResponseSet{
			`q("sum:m{a=*}", "2000/01/01-11:59:00", "2000/01/01-12:00:00")`: {
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "b"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
			},
			`q("sum:m{a=*}", "9.4672434e+08", "9.467244e+08")`: {
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "c"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
			},
		},
	})
}

func TestCount(t *testing.T) {
	testSched(t, &schedTest{
		conf: `alert a {
			crit = count("sum:m{a=*}", "1m", "") != 2
		}`,
		queries: map[string]opentsdb.ResponseSet{
			`q("sum:m{a=*}", "2000/01/01-11:59:00", "2000/01/01-12:00:00")`: {
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "b"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
				{
					Metric: "m",
					Tags:   opentsdb.TagSet{"a": "c"},
					DPS:    map[string]opentsdb.Point{"0": 1},
				},
			},
		},
	})
}
<|endoftext|>


<commit_before>package common

import (
	"crypto/tls"
	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/go-cleanhttp"
)

// ConsulSeparator is the consul kvp separator
const ConsulSeparator = "/"

// ConsulConfig contains consul client configuration and TLSConfig in a single struct
type ConsulConfig struct {
	api.Config
	tls *api.TLSConfig
}

// ConsulClient contains a consul client implementation
type ConsulClient struct {
	*api.Client
}

// NewClient returns an initialized consul client
func (cc *ConsulConfig) NewClient() (*ConsulClient, error) {
	var c *api.Config        // upstream client configuration
	var client *ConsulClient // client wrapper
	var err error            // general error holder

	// init upstream config
	c = api.DefaultConfig()

	// overwrite address if needed
	if cc.Address != "" {
		c.Address = cc.Address
	}

	// overwrite scheme if needed
	if cc.Scheme != "" {
		c.Scheme = cc.Scheme
	}

	// overwrite dc if needed
	if cc.Datacenter != "" {
		c.Datacenter = cc.Datacenter
	}

	// overwrite token if needed
	if cc.Token != "" {
		c.Token = cc.Token
	}

	// configure if any TLS specific options were passed
	if cc.tls.CAFile != "" || cc.tls.CertFile != "" || cc.tls.KeyFile != "" || cc.tls.InsecureSkipVerify {
		var tlsConfig *tls.Config // client TLS config
		// attempt to build tls config from passed options
		if tlsConfig, err = api.SetupTLSConfig(cc.tls); err != nil {
			return nil, err
		}
		// build a new http client and transport
		httpClient := cleanhttp.DefaultClient()
		httpTransport := cleanhttp.DefaultTransport()
		httpTransport.TLSClientConfig = tlsConfig
		// set client
		c.HttpClient = httpClient
	}

	// init client wrapper
	client = new(ConsulClient)
	client.Client, err = api.NewClient(c)

	// return client and error
	return client, err
}
<commit_msg>make sure httpClient gets the transport we create (#18)<commit_after>package common

import (
	"crypto/tls"
	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/go-cleanhttp"
)

// ConsulSeparator is the consul kvp separator
const ConsulSeparator = "/"

// ConsulConfig contains consul client configuration and TLSConfig in a single struct
type ConsulConfig struct {
	api.Config
	tls *api.TLSConfig
}

// ConsulClient contains a consul client implementation
type ConsulClient struct {
	*api.Client
}

// NewClient returns an initialized consul client
func (cc *ConsulConfig) NewClient() (*ConsulClient, error) {
	var c *api.Config        // upstream client configuration
	var client *ConsulClient // client wrapper
	var err error            // general error holder

	// init upstream config
	c = api.DefaultConfig()

	// overwrite address if needed
	if cc.Address != "" {
		c.Address = cc.Address
	}

	// overwrite scheme if needed
	if cc.Scheme != "" {
		c.Scheme = cc.Scheme
	}

	// overwrite dc if needed
	if cc.Datacenter != "" {
		c.Datacenter = cc.Datacenter
	}

	// overwrite token if needed
	if cc.Token != "" {
		c.Token = cc.Token
	}

	// configure if any TLS specific options were passed
	if cc.tls.CAFile != "" || cc.tls.CertFile != "" || cc.tls.KeyFile != "" || cc.tls.InsecureSkipVerify {
		var tlsConfig *tls.Config // client TLS config
		// attempt to build tls config from passed options
		if tlsConfig, err = api.SetupTLSConfig(cc.tls); err != nil {
			return nil, err
		}
		// build a new http client and transport
		httpClient := cleanhttp.DefaultClient()
		httpTransport := cleanhttp.DefaultTransport()
		httpTransport.TLSClientConfig = tlsConfig
		httpClient.Transport = httpTransport

		// set client
		c.HttpClient = httpClient
	}

	// init client wrapper
	client = new(ConsulClient)
	client.Client, err = api.NewClient(c)

	// return client and error
	return client, err
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"runtime"
)

//----------------------------------------
// Convenience method.

func ErrorWrap(cause interface{}, format string, args ...interface{}) Error {
	if causeCmnError, ok := cause.(*cmnError); ok {
		msg := Fmt(format, args...)
		return causeCmnError.Stacktrace().Trace(1, msg)
	} else if cause == nil {
		return newCmnError(FmtError{format, args}).Stacktrace()
	} else {
		// NOTE: causeCmnError is a typed nil here.
		msg := Fmt(format, args...)
		return newCmnError(cause).Stacktrace().Trace(1, msg)
	}
}

//----------------------------------------
// Error & cmnError

/*

Usage with arbitrary error data:

```go
	// Error construction
	type MyError struct{}
	var err1 error = NewErrorWithData(MyError{}, "my message")
	...
	// Wrapping
	var err2 error  = ErrorWrap(err1, "another message")
	if (err1 != err2) { panic("should be the same")
	...
	// Error handling
	switch err2.Data().(type){
		case MyError: ...
	    default: ...
	}
```
*/
type Error interface {
	Error() string
	Stacktrace() Error
	Trace(offset int, format string, args ...interface{}) Error
	Data() interface{}
}

// New Error with formatted message.
// The Error's Data will be a FmtError type.
func NewError(format string, args ...interface{}) Error {
	err := FmtError{format, args}
	return newCmnError(err)
}

// New Error with specified data.
func NewErrorWithData(data interface{}) Error {
	return newCmnError(data)
}

type cmnError struct {
	data       interface{}    // associated data
	msgtraces  []msgtraceItem // all messages traced
	stacktrace []uintptr      // first stack trace
}

var _ Error = &cmnError{}

// NOTE: do not expose.
func newCmnError(data interface{}) *cmnError {
	return &cmnError{
		data:       data,
		msgtraces:  nil,
		stacktrace: nil,
	}
}

// Implements error.
func (err *cmnError) Error() string {
	return fmt.Sprintf("%v", err)
}

// Captures a stacktrace if one was not already captured.
func (err *cmnError) Stacktrace() Error {
	if err.stacktrace == nil {
		var offset = 3
		var depth = 32
		err.stacktrace = captureStacktrace(offset, depth)
	}
	return err
}

// Add tracing information with msg.
// Set n=0 unless wrapped with some function, then n > 0.
func (err *cmnError) Trace(offset int, format string, args ...interface{}) Error {
	msg := Fmt(format, args...)
	return err.doTrace(msg, offset)
}

// Return the "data" of this error.
// Data could be used for error handling/switching,
// or for holding general error/debug information.
func (err *cmnError) Data() interface{} {
	return err.data
}

func (err *cmnError) doTrace(msg string, n int) Error {
	pc, _, _, _ := runtime.Caller(n + 2) // +1 for doTrace().  +1 for the caller.
	// Include file & line number & msg.
	// Do not include the whole stack trace.
	err.msgtraces = append(err.msgtraces, msgtraceItem{
		pc:  pc,
		msg: msg,
	})
	return err
}

func (err *cmnError) Format(s fmt.State, verb rune) {
	switch verb {
	case 'p':
		s.Write([]byte(fmt.Sprintf("%p", &err)))
	default:
		if s.Flag('#') {
			s.Write([]byte("--= Error =--\n"))
			// Write data.
			s.Write([]byte(fmt.Sprintf("Data: %#v\n", err.data)))
			// Write msg trace items.
			s.Write([]byte(fmt.Sprintf("Msg Traces:\n")))
			for i, msgtrace := range err.msgtraces {
				s.Write([]byte(fmt.Sprintf(" %4d  %s\n", i, msgtrace.String())))
			}
			// Write stack trace.
			if err.stacktrace != nil {
				s.Write([]byte(fmt.Sprintf("Stack Trace:\n")))
				for i, pc := range err.stacktrace {
					fnc := runtime.FuncForPC(pc)
					file, line := fnc.FileLine(pc)
					s.Write([]byte(fmt.Sprintf(" %4d  %s:%d\n", i, file, line)))
				}
			}
			s.Write([]byte("--= /Error =--\n"))
		} else {
			// Write msg.
			s.Write([]byte(fmt.Sprintf("Error{%v}", err.data))) // TODO tick-esc?
		}
	}
}

//----------------------------------------
// stacktrace & msgtraceItem

func captureStacktrace(offset int, depth int) []uintptr {
	var pcs = make([]uintptr, depth)
	n := runtime.Callers(offset, pcs)
	return pcs[0:n]
}

type msgtraceItem struct {
	pc  uintptr
	msg string
}

func (mti msgtraceItem) String() string {
	fnc := runtime.FuncForPC(mti.pc)
	file, line := fnc.FileLine(mti.pc)
	return fmt.Sprintf("%s:%d - %s",
		file, line,
		mti.msg,
	)
}

//----------------------------------------
// fmt error

/*

FmtError is the data type for NewError() (e.g. NewError().Data().(FmtError))
Theoretically it could be used to switch on the format string.

```go
	// Error construction
	var err1 error = NewError("invalid username %v", "BOB")
	var err2 error = NewError("another kind of error")
	...
	// Error handling
	switch err1.Data().(cmn.FmtError).Format {
		case "invalid username %v": ...
		case "another kind of error": ...
	    default: ...
	}
```
*/
type FmtError struct {
	format string
	args   []interface{}
}

func (fe FmtError) Error() string {
	return fmt.Sprintf(fe.format, fe.args...)
}

func (fe FmtError) String() string {
	return fmt.Sprintf("FmtError{format:%v,args:%v}",
		fe.format, fe.args)
}

func (fe FmtError) Format() string {
	return fe.format
}

//----------------------------------------
// Panic wrappers
// XXX DEPRECATED

// A panic resulting from a sanity check means there is a programmer error
// and some guarantee is not satisfied.
// XXX DEPRECATED
func PanicSanity(v interface{}) {
	panic(Fmt("Panicked on a Sanity Check: %v", v))
}

// A panic here means something has gone horribly wrong, in the form of data corruption or
// failure of the operating system. In a correct/healthy system, these should never fire.
// If they do, it's indicative of a much more serious problem.
// XXX DEPRECATED
func PanicCrisis(v interface{}) {
	panic(Fmt("Panicked on a Crisis: %v", v))
}

// Indicates a failure of consensus. Someone was malicious or something has
// gone horribly wrong. These should really boot us into an "emergency-recover" mode
// XXX DEPRECATED
func PanicConsensus(v interface{}) {
	panic(Fmt("Panicked on a Consensus Failure: %v", v))
}

// For those times when we're not sure if we should panic
// XXX DEPRECATED
func PanicQ(v interface{}) {
	panic(Fmt("Panicked questionably: %v", v))
}
<commit_msg>Fix comment<commit_after>package common

import (
	"fmt"
	"runtime"
)

//----------------------------------------
// Convenience method.

func ErrorWrap(cause interface{}, format string, args ...interface{}) Error {
	if causeCmnError, ok := cause.(*cmnError); ok {
		msg := Fmt(format, args...)
		return causeCmnError.Stacktrace().Trace(1, msg)
	} else if cause == nil {
		return newCmnError(FmtError{format, args}).Stacktrace()
	} else {
		// NOTE: causeCmnError is a typed nil here.
		msg := Fmt(format, args...)
		return newCmnError(cause).Stacktrace().Trace(1, msg)
	}
}

//----------------------------------------
// Error & cmnError

/*

Usage with arbitrary error data:

```go
	// Error construction
	type MyError struct{}
	var err1 error = NewErrorWithData(MyError{}, "my message")
	...
	// Wrapping
	var err2 error  = ErrorWrap(err1, "another message")
	if (err1 != err2) { panic("should be the same")
	...
	// Error handling
	switch err2.Data().(type){
		case MyError: ...
	    default: ...
	}
```
*/
type Error interface {
	Error() string
	Stacktrace() Error
	Trace(offset int, format string, args ...interface{}) Error
	Data() interface{}
}

// New Error with formatted message.
// The Error's Data will be a FmtError type.
func NewError(format string, args ...interface{}) Error {
	err := FmtError{format, args}
	return newCmnError(err)
}

// New Error with specified data.
func NewErrorWithData(data interface{}) Error {
	return newCmnError(data)
}

type cmnError struct {
	data       interface{}    // associated data
	msgtraces  []msgtraceItem // all messages traced
	stacktrace []uintptr      // first stack trace
}

var _ Error = &cmnError{}

// NOTE: do not expose.
func newCmnError(data interface{}) *cmnError {
	return &cmnError{
		data:       data,
		msgtraces:  nil,
		stacktrace: nil,
	}
}

// Implements error.
func (err *cmnError) Error() string {
	return fmt.Sprintf("%v", err)
}

// Captures a stacktrace if one was not already captured.
func (err *cmnError) Stacktrace() Error {
	if err.stacktrace == nil {
		var offset = 3
		var depth = 32
		err.stacktrace = captureStacktrace(offset, depth)
	}
	return err
}

// Add tracing information with msg.
// Set n=0 unless wrapped with some function, then n > 0.
func (err *cmnError) Trace(offset int, format string, args ...interface{}) Error {
	msg := Fmt(format, args...)
	return err.doTrace(msg, offset)
}

// Return the "data" of this error.
// Data could be used for error handling/switching,
// or for holding general error/debug information.
func (err *cmnError) Data() interface{} {
	return err.data
}

func (err *cmnError) doTrace(msg string, n int) Error {
	pc, _, _, _ := runtime.Caller(n + 2) // +1 for doTrace().  +1 for the caller.
	// Include file & line number & msg.
	// Do not include the whole stack trace.
	err.msgtraces = append(err.msgtraces, msgtraceItem{
		pc:  pc,
		msg: msg,
	})
	return err
}

func (err *cmnError) Format(s fmt.State, verb rune) {
	switch verb {
	case 'p':
		s.Write([]byte(fmt.Sprintf("%p", &err)))
	default:
		if s.Flag('#') {
			s.Write([]byte("--= Error =--\n"))
			// Write data.
			s.Write([]byte(fmt.Sprintf("Data: %#v\n", err.data)))
			// Write msg trace items.
			s.Write([]byte(fmt.Sprintf("Msg Traces:\n")))
			for i, msgtrace := range err.msgtraces {
				s.Write([]byte(fmt.Sprintf(" %4d  %s\n", i, msgtrace.String())))
			}
			// Write stack trace.
			if err.stacktrace != nil {
				s.Write([]byte(fmt.Sprintf("Stack Trace:\n")))
				for i, pc := range err.stacktrace {
					fnc := runtime.FuncForPC(pc)
					file, line := fnc.FileLine(pc)
					s.Write([]byte(fmt.Sprintf(" %4d  %s:%d\n", i, file, line)))
				}
			}
			s.Write([]byte("--= /Error =--\n"))
		} else {
			// Write msg.
			s.Write([]byte(fmt.Sprintf("Error{%v}", err.data))) // TODO tick-esc?
		}
	}
}

//----------------------------------------
// stacktrace & msgtraceItem

func captureStacktrace(offset int, depth int) []uintptr {
	var pcs = make([]uintptr, depth)
	n := runtime.Callers(offset, pcs)
	return pcs[0:n]
}

type msgtraceItem struct {
	pc  uintptr
	msg string
}

func (mti msgtraceItem) String() string {
	fnc := runtime.FuncForPC(mti.pc)
	file, line := fnc.FileLine(mti.pc)
	return fmt.Sprintf("%s:%d - %s",
		file, line,
		mti.msg,
	)
}

//----------------------------------------
// fmt error

/*

FmtError is the data type for NewError() (e.g. NewError().Data().(FmtError))
Theoretically it could be used to switch on the format string.

```go
	// Error construction
	var err1 error = NewError("invalid username %v", "BOB")
	var err2 error = NewError("another kind of error")
	...
	// Error handling
	switch err1.Data().(cmn.FmtError).Format() {
		case "invalid username %v": ...
		case "another kind of error": ...
	    default: ...
	}
```
*/
type FmtError struct {
	format string
	args   []interface{}
}

func (fe FmtError) Error() string {
	return fmt.Sprintf(fe.format, fe.args...)
}

func (fe FmtError) String() string {
	return fmt.Sprintf("FmtError{format:%v,args:%v}",
		fe.format, fe.args)
}

func (fe FmtError) Format() string {
	return fe.format
}

//----------------------------------------
// Panic wrappers
// XXX DEPRECATED

// A panic resulting from a sanity check means there is a programmer error
// and some guarantee is not satisfied.
// XXX DEPRECATED
func PanicSanity(v interface{}) {
	panic(Fmt("Panicked on a Sanity Check: %v", v))
}

// A panic here means something has gone horribly wrong, in the form of data corruption or
// failure of the operating system. In a correct/healthy system, these should never fire.
// If they do, it's indicative of a much more serious problem.
// XXX DEPRECATED
func PanicCrisis(v interface{}) {
	panic(Fmt("Panicked on a Crisis: %v", v))
}

// Indicates a failure of consensus. Someone was malicious or something has
// gone horribly wrong. These should really boot us into an "emergency-recover" mode
// XXX DEPRECATED
func PanicConsensus(v interface{}) {
	panic(Fmt("Panicked on a Consensus Failure: %v", v))
}

// For those times when we're not sure if we should panic
// XXX DEPRECATED
func PanicQ(v interface{}) {
	panic(Fmt("Panicked questionably: %v", v))
}
<|endoftext|>